Skip to content

Commit

Permalink
fix WSDL generation, change the way protocols are instantiated, and add
Browse files Browse the repository at this point in the history
the ability to override the namespace used in WSDL instead of always forcing
'urn:ActionWebService'


git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1501 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information
leonbreedt committed Jun 25, 2005
1 parent af33a6a commit ebb6fb0
Show file tree
Hide file tree
Showing 14 changed files with 112 additions and 56 deletions.
4 changes: 4 additions & 0 deletions actionwebservice/CHANGELOG
Original file line number Original file line Diff line number Diff line change
@@ -1,5 +1,9 @@
*SVN* *SVN*


* Fix WSDL generation by aliasing #inherited instead of trying to overwrite it, or the WSDL action may end up not being defined in the controller

* Add ActionController::Base.wsdl_namespace option, to allow overriding of the namespace used in generated WSDL and SOAP messages. This is equivalent to the [WebService(Namespace = "Value")] attribute in .NET.

* Add workaround for Ruby 1.8.3's SOAP4R changing the return value of SOAP::Mapping::Registry#find_mapped_soap_class #1414 [Shugo Maeda] * Add workaround for Ruby 1.8.3's SOAP4R changing the return value of SOAP::Mapping::Registry#find_mapped_soap_class #1414 [Shugo Maeda]


* Fix moduled controller URLs in WSDL, and add unit test to verify the generated URL #1428 * Fix moduled controller URLs in WSDL, and add unit test to verify the generated URL #1428
Expand Down
31 changes: 25 additions & 6 deletions actionwebservice/README
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -78,15 +78,15 @@ modes of dispatching protocol requests, _Direct_, and _Delegated_.


=== Direct dispatching === Direct dispatching


This is the default mode. In this mode, controller actions implement the API This is the default mode. In this mode, public controller instance methods
methods, and parameters for incoming method calls will be placed in implement the API methods, and parameters are passed through to the methods in
<tt>@params</tt> (keyed by name), and <tt>@method_params</tt> (ordered list). accordance with the API specification.


The return value of the action is sent back as the return value to the The return value of the method is sent back as the return value to the
caller. caller.


In this mode, a special <tt>api</tt> action is generated in the target In this mode, a special <tt>api</tt> action is generated in the target
controller to unwrap the protocol request, forward it on to the relevant action controller to unwrap the protocol request, forward it on to the relevant method
and send back the wrapped return value. <em>This action must not be and send back the wrapped return value. <em>This action must not be
overridden.</em> overridden.</em>


Expand All @@ -108,7 +108,7 @@ overridden.</em>




For this example, protocol requests for +Add+ and +Remove+ methods sent to For this example, protocol requests for +Add+ and +Remove+ methods sent to
<tt>/person/api</tt> will be routed to the actions +add+ and +remove+. <tt>/person/api</tt> will be routed to the controller methods +add+ and +remove+.




=== Delegated dispatching === Delegated dispatching
Expand Down Expand Up @@ -196,6 +196,25 @@ For this example, an XML-RPC call for a method with a name like
method on the <tt>:mt</tt> service. method on the <tt>:mt</tt> service.




== Customizing WSDL generation

You can customize the names used for the SOAP bindings in the generated
WSDL by using the wsdl_service_name option in a controller:

class WsController < ApplicationController
wsdl_service_name 'MyApp'
end

You can also customize the namespace used in the generated WSDL for
custom types and message definition types:

class WsController < ApplicationController
wsdl_namespace 'http://my.company.com/app/wsapi'
end

The default namespace used is 'urn:ActionWebService', if you don't supply
one.

== Testing your APIs == Testing your APIs




Expand Down
15 changes: 7 additions & 8 deletions actionwebservice/lib/action_web_service/client/soap_client.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ class Soap < Base
# will be sent with HTTP POST. # will be sent with HTTP POST.
# #
# Valid options: # Valid options:
# [<tt>:type_namespace</tt>] If the remote server has used a custom namespace to # [<tt>:namespace</tt>] If the remote server has used a custom namespace to
# declare its custom types, you can specify it here # declare its custom types, you can specify it here. This would
# [<tt>:method_namespace</tt>] If the remote server has used a custom namespace to # be the namespace declared with a [WebService(Namespace = "http://namespace")] attribute
# declare its methods, you can specify it here # in .NET, for example.
# [<tt>:driver_options</tt>] If you want to supply any custom SOAP RPC driver # [<tt>:driver_options</tt>] If you want to supply any custom SOAP RPC driver
# options, you can provide them as a Hash here # options, you can provide them as a Hash here
# #
Expand All @@ -43,10 +43,9 @@ class Soap < Base
# client = ActionWebService::Client::Soap.new(api, 'https://some/service', :driver_options => opts) # client = ActionWebService::Client::Soap.new(api, 'https://some/service', :driver_options => opts)
def initialize(api, endpoint_uri, options={}) def initialize(api, endpoint_uri, options={})
super(api, endpoint_uri) super(api, endpoint_uri)
@type_namespace = options[:type_namespace] || 'urn:ActionWebService' @namespace = options[:namespace] || 'urn:ActionWebService'
@method_namespace = options[:method_namespace] || 'urn:ActionWebService'
@driver_options = options[:driver_options] || {} @driver_options = options[:driver_options] || {}
@protocol = ActionWebService::Protocol::Soap::SoapProtocol.new @protocol = ActionWebService::Protocol::Soap::SoapProtocol.new @namespace
@soap_action_base = options[:soap_action_base] @soap_action_base = options[:soap_action_base]
@soap_action_base ||= URI.parse(endpoint_uri).path @soap_action_base ||= URI.parse(endpoint_uri).path
@driver = create_soap_rpc_driver(api, endpoint_uri) @driver = create_soap_rpc_driver(api, endpoint_uri)
Expand All @@ -73,7 +72,7 @@ def create_soap_rpc_driver(api, endpoint_uri)
driver = SoapDriver.new(endpoint_uri, nil) driver = SoapDriver.new(endpoint_uri, nil)
driver.mapping_registry = @protocol.marshaler.registry driver.mapping_registry = @protocol.marshaler.registry
api.api_methods.each do |name, method| api.api_methods.each do |name, method|
qname = XSD::QName.new(@method_namespace, method.public_name) qname = XSD::QName.new(@namespace, method.public_name)
action = soap_action(method.public_name) action = soap_action(method.public_name)
expects = method.expects expects = method.expects
returns = method.returns returns = method.returns
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ module Dispatcher # :nodoc:
module ActionController # :nodoc: module ActionController # :nodoc:
def self.append_features(base) # :nodoc: def self.append_features(base) # :nodoc:
super super
base.extend(ClassMethods)
base.class_eval do base.class_eval do
class << self class << self
alias_method :inherited_without_action_controller, :inherited alias_method :inherited_without_action_controller, :inherited
alias_method :inherited, :inherited_with_action_controller
end end
alias_method :web_service_direct_invoke_without_controller, :web_service_direct_invoke alias_method :web_service_direct_invoke_without_controller, :web_service_direct_invoke
end end
Expand All @@ -24,12 +26,11 @@ class << self
klass.class_eval 'def api; dispatch_web_service_request; end' klass.class_eval 'def api; dispatch_web_service_request; end'
end end
end end
base.extend(ClassMethods)
base.send(:include, ActionWebService::Dispatcher::ActionController::InstanceMethods) base.send(:include, ActionWebService::Dispatcher::ActionController::InstanceMethods)
end end


module ClassMethods # :nodoc: module ClassMethods # :nodoc:
def inherited(child) def inherited_with_action_controller(child)
inherited_without_action_controller(child) inherited_without_action_controller(child)
child.send(:include, ActionWebService::Dispatcher::ActionController::WsdlAction) child.send(:include, ActionWebService::Dispatcher::ActionController::WsdlAction)
end end
Expand Down Expand Up @@ -174,7 +175,7 @@ def to_wsdl
xml = '' xml = ''
dispatching_mode = web_service_dispatching_mode dispatching_mode = web_service_dispatching_mode
global_service_name = wsdl_service_name global_service_name = wsdl_service_name
namespace = 'urn:ActionWebService' namespace = wsdl_namespace || 'urn:ActionWebService'
soap_action_base = "/#{controller_name}" soap_action_base = "/#{controller_name}"


marshaler = ActionWebService::Protocol::Soap::SoapMarshaler.new(namespace) marshaler = ActionWebService::Protocol::Soap::SoapMarshaler.new(namespace)
Expand Down
3 changes: 3 additions & 0 deletions actionwebservice/lib/action_web_service/protocol/abstract.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ class ProtocolError < ActionWebServiceError # :nodoc:
end end


class AbstractProtocol # :nodoc: class AbstractProtocol # :nodoc:
def setup(controller)
end

def decode_action_pack_request(action_pack_request) def decode_action_pack_request(action_pack_request)
end end


Expand Down
4 changes: 2 additions & 2 deletions actionwebservice/lib/action_web_service/protocol/discovery.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module InstanceMethods # :nodoc:
private private
def discover_web_service_request(action_pack_request) def discover_web_service_request(action_pack_request)
(self.class.read_inheritable_attribute("web_service_protocols") || []).each do |protocol| (self.class.read_inheritable_attribute("web_service_protocols") || []).each do |protocol|
protocol = protocol.new protocol = protocol.create(self)
request = protocol.decode_action_pack_request(action_pack_request) request = protocol.decode_action_pack_request(action_pack_request)
return request unless request.nil? return request unless request.nil?
end end
Expand All @@ -25,7 +25,7 @@ def discover_web_service_request(action_pack_request)


def create_web_service_client(api, protocol_name, endpoint_uri, options) def create_web_service_client(api, protocol_name, endpoint_uri, options)
(self.class.read_inheritable_attribute("web_service_protocols") || []).each do |protocol| (self.class.read_inheritable_attribute("web_service_protocols") || []).each do |protocol|
protocol = protocol.new protocol = protocol.create(self)
client = protocol.protocol_client(api, protocol_name, endpoint_uri, options) client = protocol.protocol_client(api, protocol_name, endpoint_uri, options)
return client unless client.nil? return client unless client.nil?
end end
Expand Down
16 changes: 12 additions & 4 deletions actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -7,13 +7,21 @@ module Soap # :nodoc:
def self.included(base) def self.included(base)
base.register_protocol(SoapProtocol) base.register_protocol(SoapProtocol)
base.class_inheritable_option(:wsdl_service_name) base.class_inheritable_option(:wsdl_service_name)
base.class_inheritable_option(:wsdl_namespace)
end end


class SoapProtocol < AbstractProtocol # :nodoc: class SoapProtocol < AbstractProtocol # :nodoc:
DefaultEncoding = 'utf-8' DefaultEncoding = 'utf-8'


def marshaler attr :marshaler
@marshaler ||= SoapMarshaler.new
def initialize(namespace=nil)
namespace ||= 'urn:ActionWebService'
@marshaler = SoapMarshaler.new namespace
end

def self.create(controller)
SoapProtocol.new(controller.wsdl_namespace)
end end


def decode_action_pack_request(action_pack_request) def decode_action_pack_request(action_pack_request)
Expand Down Expand Up @@ -47,7 +55,7 @@ def decode_request(raw_request, service_name, protocol_options={})


def encode_request(method_name, params, param_types) def encode_request(method_name, params, param_types)
param_types.each{ |type| marshaler.register_type(type) } if param_types param_types.each{ |type| marshaler.register_type(type) } if param_types
qname = XSD::QName.new(marshaler.type_namespace, method_name) qname = XSD::QName.new(marshaler.namespace, method_name)
param_def = [] param_def = []
if param_types if param_types
params = param_types.zip(params).map do |type, param| params = param_types.zip(params).map do |type, param|
Expand Down Expand Up @@ -79,7 +87,7 @@ def encode_response(method_name, return_value, return_type, protocol_options={})
return_binding = marshaler.register_type(return_type) return_binding = marshaler.register_type(return_type)
marshaler.annotate_arrays(return_binding, return_value) marshaler.annotate_arrays(return_binding, return_value)
end end
qname = XSD::QName.new(marshaler.type_namespace, method_name) qname = XSD::QName.new(marshaler.namespace, method_name)
if return_value.nil? if return_value.nil?
response = SOAP::RPC::SOAPMethodResponse.new(qname, nil) response = SOAP::RPC::SOAPMethodResponse.new(qname, nil)
else else
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ def find_mapped_obj_class(soap_class)
end end


class SoapMarshaler class SoapMarshaler
attr :type_namespace attr :namespace
attr :registry attr :registry


def initialize(type_namespace=nil) def initialize(namespace=nil)
@type_namespace = type_namespace || 'urn:ActionWebService' @namespace = namespace || 'urn:ActionWebService'
@registry = Registry.new @registry = Registry.new
@type2binding = {} @type2binding = {}
register_static_factories register_static_factories
Expand All @@ -46,7 +46,7 @@ def register_type(type)
qname ||= soap_base_type_name(mapping[0]) qname ||= soap_base_type_name(mapping[0])
type_binding = SoapBinding.new(self, qname, type_type, mapping) type_binding = SoapBinding.new(self, qname, type_type, mapping)
else else
qname = XSD::QName.new(@type_namespace, soap_type_name(type_class.name)) qname = XSD::QName.new(@namespace, soap_type_name(type_class.name))
@registry.add(type_class, @registry.add(type_class,
SOAP::SOAPStruct, SOAP::SOAPStruct,
typed_struct_factory(type_class), typed_struct_factory(type_class),
Expand All @@ -58,7 +58,7 @@ def register_type(type)
array_binding = nil array_binding = nil
if type.array? if type.array?
array_mapping = @registry.find_mapped_soap_class(Array) array_mapping = @registry.find_mapped_soap_class(Array)
qname = XSD::QName.new(@type_namespace, soap_type_name(type.element_type.type_class.name) + 'Array') qname = XSD::QName.new(@namespace, soap_type_name(type.element_type.type_class.name) + 'Array')
array_binding = SoapBinding.new(self, qname, type, array_mapping, type_binding) array_binding = SoapBinding.new(self, qname, type, array_mapping, type_binding)
end end


Expand Down Expand Up @@ -88,7 +88,7 @@ def annotate_arrays(binding, value)
def typed_struct_factory(type_class) def typed_struct_factory(type_class)
if Object.const_defined?('ActiveRecord') if Object.const_defined?('ActiveRecord')
if type_class.ancestors.include?(ActiveRecord::Base) if type_class.ancestors.include?(ActiveRecord::Base)
qname = XSD::QName.new(@type_namespace, soap_type_name(type_class.name)) qname = XSD::QName.new(@namespace, soap_type_name(type_class.name))
type_class.instance_variable_set('@qname', qname) type_class.instance_variable_set('@qname', qname)
return SoapActiveRecordStructFactory.new return SoapActiveRecordStructFactory.new
end end
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ def self.included(base)
end end


class XmlRpcProtocol < AbstractProtocol # :nodoc: class XmlRpcProtocol < AbstractProtocol # :nodoc:
def self.create(controller)
XmlRpcProtocol.new
end

def decode_action_pack_request(action_pack_request) def decode_action_pack_request(action_pack_request)
service_name = action_pack_request.parameters['action'] service_name = action_pack_request.parameters['action']
decode_request(action_pack_request.raw_post, service_name) decode_request(action_pack_request.raw_post, service_name)
Expand Down
4 changes: 2 additions & 2 deletions actionwebservice/lib/action_web_service/scaffolding.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ def #{action_name}_submit
protocol_name = params['protocol'] ? params['protocol'].to_sym : :soap protocol_name = params['protocol'] ? params['protocol'].to_sym : :soap
case protocol_name case protocol_name
when :soap when :soap
@protocol = Protocol::Soap::SoapProtocol.new @protocol = Protocol::Soap::SoapProtocol.create(self)
when :xmlrpc when :xmlrpc
@protocol = Protocol::XmlRpc::XmlRpcProtocol.new @protocol = Protocol::XmlRpc::XmlRpcProtocol.create(self)
end end
@invocation_cgi = request.respond_to?(:cgi) ? request.cgi : nil @invocation_cgi = request.respond_to?(:cgi) ? request.cgi : nil
bm = Benchmark.measure do bm = Benchmark.measure do
Expand Down
6 changes: 3 additions & 3 deletions actionwebservice/lib/action_web_service/test_invoke.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -81,13 +81,13 @@ def service_api(service_name)


def protocol def protocol
if @protocol.nil? if @protocol.nil?
@protocol ||= ActionWebService::Protocol::Soap::SoapProtocol.new @protocol ||= ActionWebService::Protocol::Soap::SoapProtocol.new(@controller)
else else
case @protocol case @protocol
when :xmlrpc when :xmlrpc
@protocol = ActionWebService::Protocol::XmlRpc::XmlRpcProtocol.new @protocol = ActionWebService::Protocol::XmlRpc::XmlRpcProtocol.create(@controller)
when :soap when :soap
@protocol = ActionWebService::Protocol::Soap::SoapProtocol.new @protocol = ActionWebService::Protocol::Soap::SoapProtocol.create(@controller)
else else
@protocol @protocol
end end
Expand Down
Loading

0 comments on commit ebb6fb0

Please sign in to comment.