Checkout of Instiki Trunk 1/21/2007.
This commit is contained in:
commit
69b62b6f33
1138 changed files with 139586 additions and 0 deletions
249
vendor/rails/actionwebservice/lib/action_web_service/api.rb
vendored
Normal file
249
vendor/rails/actionwebservice/lib/action_web_service/api.rb
vendored
Normal file
|
@ -0,0 +1,249 @@
|
|||
module ActionWebService # :nodoc:
|
||||
module API # :nodoc:
|
||||
# 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.
|
||||
#
|
||||
# It is not intended to be instantiated.
|
||||
#
|
||||
# It is attached to web service implementation classes like
|
||||
# ActionWebService::Base and ActionController::Base derivatives by using
|
||||
# <tt>container.web_service_api</tt>, where <tt>container</tt> is an
|
||||
# ActionController::Base or a ActionWebService::Base.
|
||||
#
|
||||
# See ActionWebService::Container::Direct::ClassMethods for an example
|
||||
# of use.
|
||||
class Base
|
||||
# Action WebService API subclasses should be reloaded by the dispatcher in Rails
|
||||
# when Dependencies.mechanism = :load.
|
||||
include Reloadable::Subclasses
|
||||
|
||||
# Whether to transform the public API method names into camel-cased names
|
||||
class_inheritable_option :inflect_names, true
|
||||
|
||||
# Whether to allow ActiveRecord::Base models in <tt>:expects</tt>.
|
||||
# The default is +false+; you should be aware of the security implications
|
||||
# of allowing this, and ensure that you don't allow remote callers to
|
||||
# easily overwrite data they should not have access to.
|
||||
class_inheritable_option :allow_active_record_expects, false
|
||||
|
||||
# If present, the name of a method to call when the remote caller
|
||||
# tried to call a nonexistent method. Semantically equivalent to
|
||||
# +method_missing+.
|
||||
class_inheritable_option :default_api_method
|
||||
|
||||
# Disallow instantiation
|
||||
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.
|
||||
#
|
||||
# The signatures for the method input parameters and return value can
|
||||
# by specified in +options+.
|
||||
#
|
||||
# A signature is an array of one or more parameter specifiers.
|
||||
# A parameter specifier can be one of the following:
|
||||
#
|
||||
# * A symbol or string representing one of the Action Web Service base types.
|
||||
# See ActionWebService::SignatureTypes for a canonical list of the base types.
|
||||
# * The Class object of the parameter type
|
||||
# * A single-element Array containing one of the two preceding items. This
|
||||
# will cause Action Web Service to treat the parameter at that position
|
||||
# as an array containing only values of the given type.
|
||||
# * A Hash containing as key the name of the parameter, and as value
|
||||
# one of the three preceding items
|
||||
#
|
||||
# If no method input parameter or method return value signatures are given,
|
||||
# the method is assumed to take no parameters and/or return no values of
|
||||
# interest, and any values that are received by the server will be
|
||||
# discarded and ignored.
|
||||
#
|
||||
# Valid options:
|
||||
# [<tt>:expects</tt>] Signature for the method input parameters
|
||||
# [<tt>:returns</tt>] Signature for the method return value
|
||||
# [<tt>:expects_and_returns</tt>] Signature for both input parameters and return value
|
||||
def api_method(name, options={})
|
||||
unless options.is_a?(Hash)
|
||||
raise(ActionWebServiceError, "Expected a Hash for options")
|
||||
end
|
||||
validate_options([:expects, :returns, :expects_and_returns], options.keys)
|
||||
if options[:expects_and_returns]
|
||||
expects = options[:expects_and_returns]
|
||||
returns = options[:expects_and_returns]
|
||||
else
|
||||
expects = options[:expects]
|
||||
returns = options[:returns]
|
||||
end
|
||||
expects = canonical_signature(expects)
|
||||
returns = canonical_signature(returns)
|
||||
if 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
|
||||
end
|
||||
name = name.to_sym
|
||||
public_name = public_api_method_name(name)
|
||||
method = Method.new(name, public_name, expects, returns)
|
||||
write_inheritable_hash("api_methods", name => method)
|
||||
write_inheritable_hash("api_public_method_names", public_name => name)
|
||||
end
|
||||
|
||||
# Whether the given method name is a service method on this API
|
||||
def has_api_method?(name)
|
||||
api_methods.has_key?(name)
|
||||
end
|
||||
|
||||
# Whether the given public method name has a corresponding service method
|
||||
# on this API
|
||||
def has_public_api_method?(public_name)
|
||||
api_public_method_names.has_key?(public_name)
|
||||
end
|
||||
|
||||
# The corresponding public method name for the given service method name
|
||||
def public_api_method_name(name)
|
||||
if inflect_names
|
||||
name.to_s.camelize
|
||||
else
|
||||
name.to_s
|
||||
end
|
||||
end
|
||||
|
||||
# The corresponding service method name for the given public method name
|
||||
def api_method_name(public_name)
|
||||
api_public_method_names[public_name]
|
||||
end
|
||||
|
||||
# A Hash containing all service methods on this API, and their
|
||||
# associated metadata.
|
||||
def api_methods
|
||||
read_inheritable_attribute("api_methods") || {}
|
||||
end
|
||||
|
||||
# The Method instance for the given public API method name, if any
|
||||
def public_api_method_instance(public_method_name)
|
||||
api_method_instance(api_method_name(public_method_name))
|
||||
end
|
||||
|
||||
# The Method instance for the given API method name, if any
|
||||
def api_method_instance(method_name)
|
||||
api_methods[method_name]
|
||||
end
|
||||
|
||||
# The Method instance for the default API method, if any
|
||||
def default_api_method_instance
|
||||
return nil unless name = default_api_method
|
||||
instance = read_inheritable_attribute("default_api_method_instance")
|
||||
if instance && instance.name == name
|
||||
return instance
|
||||
end
|
||||
instance = Method.new(name, public_api_method_name(name), nil, nil)
|
||||
write_inheritable_attribute("default_api_method_instance", instance)
|
||||
instance
|
||||
end
|
||||
|
||||
private
|
||||
def api_public_method_names
|
||||
read_inheritable_attribute("api_public_method_names") || {}
|
||||
end
|
||||
|
||||
def validate_options(valid_option_keys, supplied_option_keys)
|
||||
unknown_option_keys = supplied_option_keys - valid_option_keys
|
||||
unless unknown_option_keys.empty?
|
||||
raise(ActionWebServiceError, "Unknown options: #{unknown_option_keys}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Represents an API method and its associated metadata, and provides functionality
|
||||
# to assist in commonly performed API method tasks.
|
||||
class Method
|
||||
attr :name
|
||||
attr :public_name
|
||||
attr :expects
|
||||
attr :returns
|
||||
|
||||
def initialize(name, public_name, expects, returns)
|
||||
@name = name
|
||||
@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
|
||||
@expects.map{ |type| type.name }
|
||||
end
|
||||
|
||||
# Casts a set of Ruby values into the expected Ruby values
|
||||
def cast_expects(params)
|
||||
@caster.cast_expects(params)
|
||||
end
|
||||
|
||||
# Cast a Ruby return value into the expected Ruby value
|
||||
def cast_returns(return_value)
|
||||
@caster.cast_returns(return_value)
|
||||
end
|
||||
|
||||
# Returns the index of the first expected parameter
|
||||
# with the given name
|
||||
def expects_index_of(param_name)
|
||||
return -1 if @expects.nil?
|
||||
(0..(@expects.length-1)).each do |i|
|
||||
return i if @expects[i].name.to_s == param_name.to_s
|
||||
end
|
||||
-1
|
||||
end
|
||||
|
||||
# Returns a hash keyed by parameter name for the given
|
||||
# parameter list
|
||||
def expects_to_hash(params)
|
||||
return {} if @expects.nil?
|
||||
h = {}
|
||||
@expects.zip(params){ |type, param| h[type.name] = param }
|
||||
h
|
||||
end
|
||||
|
||||
# Backwards compatibility with previous API
|
||||
def [](sig_type)
|
||||
case sig_type
|
||||
when :expects
|
||||
@expects.map{|x| compat_signature_entry(x)}
|
||||
when :returns
|
||||
@returns.map{|x| compat_signature_entry(x)}
|
||||
end
|
||||
end
|
||||
|
||||
# String representation of this method
|
||||
def to_s
|
||||
fqn = ""
|
||||
fqn << (@returns ? (@returns[0].human_name(false) + " ") : "void ")
|
||||
fqn << "#{@public_name}("
|
||||
fqn << @expects.map{ |p| p.human_name }.join(", ") if @expects
|
||||
fqn << ")"
|
||||
fqn
|
||||
end
|
||||
|
||||
private
|
||||
def compat_signature_entry(entry)
|
||||
if entry.array?
|
||||
[compat_signature_entry(entry.element_type)]
|
||||
else
|
||||
if entry.spec.is_a?(Hash)
|
||||
{entry.spec.keys.first => entry.type_class}
|
||||
else
|
||||
entry.type_class
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
42
vendor/rails/actionwebservice/lib/action_web_service/base.rb
vendored
Normal file
42
vendor/rails/actionwebservice/lib/action_web_service/base.rb
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
module ActionWebService # :nodoc:
|
||||
class ActionWebServiceError < StandardError # :nodoc:
|
||||
end
|
||||
|
||||
# An Action Web Service object implements a specified API.
|
||||
#
|
||||
# Used by controllers operating in _Delegated_ dispatching mode.
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# class PersonService < ActionWebService::Base
|
||||
# web_service_api PersonAPI
|
||||
#
|
||||
# def find_person(criteria)
|
||||
# Person.find_all [...]
|
||||
# end
|
||||
#
|
||||
# def delete_person(id)
|
||||
# Person.find_by_id(id).destroy
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# class PersonAPI < ActionWebService::API::Base
|
||||
# api_method :find_person, :expects => [SearchCriteria], :returns => [[Person]]
|
||||
# api_method :delete_person, :expects => [:int]
|
||||
# end
|
||||
#
|
||||
# class SearchCriteria < ActionWebService::Struct
|
||||
# member :firstname, :string
|
||||
# member :lastname, :string
|
||||
# member :email, :string
|
||||
# end
|
||||
class Base
|
||||
# Action WebService subclasses should be reloaded by the dispatcher in Rails
|
||||
# when Dependencies.mechanism = :load.
|
||||
include Reloadable::Subclasses
|
||||
|
||||
# Whether to report exceptions back to the caller in the protocol's exception
|
||||
# format
|
||||
class_inheritable_option :web_service_exception_reporting, true
|
||||
end
|
||||
end
|
136
vendor/rails/actionwebservice/lib/action_web_service/casting.rb
vendored
Normal file
136
vendor/rails/actionwebservice/lib/action_web_service/casting.rb
vendored
Normal file
|
@ -0,0 +1,136 @@
|
|||
require 'time'
|
||||
require 'date'
|
||||
require 'xmlrpc/datetime'
|
||||
|
||||
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 # :nodoc:
|
||||
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 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?
|
||||
api_method.expects.zip(params).map{ |type, param| cast(param, type) }
|
||||
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
|
||||
return nil if value.nil?
|
||||
# XMLRPC protocol doesn't support nil values. It uses false instead.
|
||||
# It should never happen for SOAP.
|
||||
if signature_type.structured? && value.equal?(false)
|
||||
return nil
|
||||
end
|
||||
unless signature_type.array? || signature_type.structured?
|
||||
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:
|
||||
# This is a work-around for the fact that XML-RPC special-cases DateTime values into its own DateTime type
|
||||
# in order to support iso8601 dates. This doesn't work too well for us, so we'll convert it into a Time,
|
||||
# with the caveat that we won't be able to handle pre-1970 dates that are sent to us.
|
||||
#
|
||||
# See http://dev.rubyonrails.com/ticket/2516
|
||||
value = value.to_time if value.is_a?(XMLRPC::DateTime)
|
||||
|
||||
case signature_type.type
|
||||
when :int
|
||||
Integer(value)
|
||||
when :string
|
||||
value.to_s
|
||||
when :base64
|
||||
if value.is_a?(ActionWebService::Base64)
|
||||
value
|
||||
else
|
||||
ActionWebService::Base64.new(value.to_s)
|
||||
end
|
||||
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
|
||||
value = "#{value['2']}/#{value['3']}/#{value['1']} #{value['4']}:#{value['5']}:#{value['6']}" if value.kind_of?(Hash)
|
||||
Time.parse(value.to_s)
|
||||
when :date
|
||||
value = "#{value['2']}/#{value['3']}/#{value['1']}" if value.kind_of?(Hash)
|
||||
Date.parse(value.to_s)
|
||||
when :datetime
|
||||
value = "#{value['2']}/#{value['3']}/#{value['1']} #{value['4']}:#{value['5']}:#{value['6']}" if value.kind_of?(Hash)
|
||||
DateTime.parse(value.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def cast_to_structured_type(value, signature_type) # :nodoc:
|
||||
obj = nil
|
||||
obj = value if canonical_type(value.class) == canonical_type(signature_type.type)
|
||||
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
|
||||
# See http://dev.rubyonrails.com/ticket/3567
|
||||
val = val.to_time if val.is_a?(XMLRPC::DateTime)
|
||||
obj.__send__("#{name}=", val) if obj.respond_to?(name)
|
||||
end
|
||||
elsif value.respond_to?(:attributes)
|
||||
signature_type.each_member do |name, type|
|
||||
val = value.__send__(name)
|
||||
obj.__send__("#{name}=", cast(val, type)) if obj.respond_to?(name)
|
||||
end
|
||||
else
|
||||
raise CastingError, "Don't know how to cast #{value.class} to #{signature_type.type_class}"
|
||||
end
|
||||
obj
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
3
vendor/rails/actionwebservice/lib/action_web_service/client.rb
vendored
Normal file
3
vendor/rails/actionwebservice/lib/action_web_service/client.rb
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
require 'action_web_service/client/base'
|
||||
require 'action_web_service/client/soap_client'
|
||||
require 'action_web_service/client/xmlrpc_client'
|
28
vendor/rails/actionwebservice/lib/action_web_service/client/base.rb
vendored
Normal file
28
vendor/rails/actionwebservice/lib/action_web_service/client/base.rb
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
module ActionWebService # :nodoc:
|
||||
module Client # :nodoc:
|
||||
class ClientError < StandardError # :nodoc:
|
||||
end
|
||||
|
||||
class Base # :nodoc:
|
||||
def initialize(api, endpoint_uri)
|
||||
@api = api
|
||||
@endpoint_uri = endpoint_uri
|
||||
end
|
||||
|
||||
def method_missing(name, *args) # :nodoc:
|
||||
call_name = method_name(name)
|
||||
return super(name, *args) if call_name.nil?
|
||||
self.perform_invocation(call_name, args)
|
||||
end
|
||||
|
||||
private
|
||||
def method_name(name)
|
||||
if @api.has_api_method?(name.to_sym)
|
||||
name.to_s
|
||||
elsif @api.has_public_api_method?(name.to_s)
|
||||
@api.api_method_name(name.to_s).to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
111
vendor/rails/actionwebservice/lib/action_web_service/client/soap_client.rb
vendored
Normal file
111
vendor/rails/actionwebservice/lib/action_web_service/client/soap_client.rb
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
require 'soap/rpc/driver'
|
||||
require 'uri'
|
||||
|
||||
module ActionWebService # :nodoc:
|
||||
module Client # :nodoc:
|
||||
|
||||
# Implements SOAP client support (using RPC encoding for the messages).
|
||||
#
|
||||
# ==== Example Usage
|
||||
#
|
||||
# class PersonAPI < ActionWebService::API::Base
|
||||
# api_method :find_all, :returns => [[Person]]
|
||||
# end
|
||||
#
|
||||
# soap_client = ActionWebService::Client::Soap.new(PersonAPI, "http://...")
|
||||
# persons = soap_client.find_all
|
||||
#
|
||||
class Soap < Base
|
||||
|
||||
# Creates a new web service client using the SOAP RPC protocol.
|
||||
#
|
||||
# +api+ must be an ActionWebService::API::Base derivative, and
|
||||
# +endpoint_uri+ must point at the relevant URL to which protocol requests
|
||||
# will be sent with HTTP POST.
|
||||
#
|
||||
# Valid options:
|
||||
# [<tt>:namespace</tt>] If the remote server has used a custom namespace to
|
||||
# declare its custom types, you can specify it here. This would
|
||||
# be the namespace declared with a [WebService(Namespace = "http://namespace")] attribute
|
||||
# in .NET, for example.
|
||||
# [<tt>:driver_options</tt>] If you want to supply any custom SOAP RPC driver
|
||||
# options, you can provide them as a Hash here
|
||||
#
|
||||
# The <tt>:driver_options</tt> option can be used to configure the backend SOAP
|
||||
# RPC driver. An example of configuring the SOAP backend to do
|
||||
# client-certificate authenticated SSL connections to the server:
|
||||
#
|
||||
# opts = {}
|
||||
# opts['protocol.http.ssl_config.verify_mode'] = 'OpenSSL::SSL::VERIFY_PEER'
|
||||
# opts['protocol.http.ssl_config.client_cert'] = client_cert_file_path
|
||||
# opts['protocol.http.ssl_config.client_key'] = client_key_file_path
|
||||
# opts['protocol.http.ssl_config.ca_file'] = ca_cert_file_path
|
||||
# client = ActionWebService::Client::Soap.new(api, 'https://some/service', :driver_options => opts)
|
||||
def initialize(api, endpoint_uri, options={})
|
||||
super(api, endpoint_uri)
|
||||
@namespace = options[:namespace] || 'urn:ActionWebService'
|
||||
@driver_options = options[:driver_options] || {}
|
||||
@protocol = ActionWebService::Protocol::Soap::SoapProtocol.new @namespace
|
||||
@soap_action_base = options[:soap_action_base]
|
||||
@soap_action_base ||= URI.parse(endpoint_uri).path
|
||||
@driver = create_soap_rpc_driver(api, endpoint_uri)
|
||||
@driver_options.each do |name, value|
|
||||
@driver.options[name.to_s] = value
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def perform_invocation(method_name, args)
|
||||
method = @api.api_methods[method_name.to_sym]
|
||||
args = method.cast_expects(args.dup) rescue args
|
||||
return_value = @driver.send(method_name, *args)
|
||||
method.cast_returns(return_value.dup) rescue return_value
|
||||
end
|
||||
|
||||
def soap_action(method_name)
|
||||
"#{@soap_action_base}/#{method_name}"
|
||||
end
|
||||
|
||||
private
|
||||
def create_soap_rpc_driver(api, endpoint_uri)
|
||||
@protocol.register_api(api)
|
||||
driver = SoapDriver.new(endpoint_uri, nil)
|
||||
driver.mapping_registry = @protocol.marshaler.registry
|
||||
api.api_methods.each do |name, method|
|
||||
qname = XSD::QName.new(@namespace, method.public_name)
|
||||
action = soap_action(method.public_name)
|
||||
expects = method.expects
|
||||
returns = method.returns
|
||||
param_def = []
|
||||
if expects
|
||||
expects.each do |type|
|
||||
type_binding = @protocol.marshaler.lookup_type(type)
|
||||
if SOAP::Version >= "1.5.5"
|
||||
param_def << ['in', type.name.to_s, [type_binding.type.type_class.to_s]]
|
||||
else
|
||||
param_def << ['in', type.name, type_binding.mapping]
|
||||
end
|
||||
end
|
||||
end
|
||||
if returns
|
||||
type_binding = @protocol.marshaler.lookup_type(returns[0])
|
||||
if SOAP::Version >= "1.5.5"
|
||||
param_def << ['retval', 'return', [type_binding.type.type_class.to_s]]
|
||||
else
|
||||
param_def << ['retval', 'return', type_binding.mapping]
|
||||
end
|
||||
end
|
||||
driver.add_method(qname, action, method.name.to_s, param_def)
|
||||
end
|
||||
driver
|
||||
end
|
||||
|
||||
class SoapDriver < SOAP::RPC::Driver # :nodoc:
|
||||
def add_method(qname, soapaction, name, param_def)
|
||||
@proxy.add_rpc_method(qname, soapaction, name, param_def)
|
||||
add_rpc_method_interface(name, param_def)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
58
vendor/rails/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb
vendored
Normal file
58
vendor/rails/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
require 'uri'
|
||||
require 'xmlrpc/client'
|
||||
|
||||
module ActionWebService # :nodoc:
|
||||
module Client # :nodoc:
|
||||
|
||||
# Implements XML-RPC client support
|
||||
#
|
||||
# ==== Example Usage
|
||||
#
|
||||
# class BloggerAPI < ActionWebService::API::Base
|
||||
# inflect_names false
|
||||
# api_method :getRecentPosts, :returns => [[Blog::Post]]
|
||||
# end
|
||||
#
|
||||
# blog = ActionWebService::Client::XmlRpc.new(BloggerAPI, "http://.../RPC", :handler_name => "blogger")
|
||||
# posts = blog.getRecentPosts
|
||||
class XmlRpc < Base
|
||||
|
||||
# Creates a new web service client using the XML-RPC protocol.
|
||||
#
|
||||
# +api+ must be an ActionWebService::API::Base derivative, and
|
||||
# +endpoint_uri+ must point at the relevant URL to which protocol requests
|
||||
# will be sent with HTTP POST.
|
||||
#
|
||||
# Valid options:
|
||||
# [<tt>:handler_name</tt>] If the remote server defines its services inside special
|
||||
# handler (the Blogger API uses a <tt>"blogger"</tt> handler name for example),
|
||||
# provide it here, or your method calls will fail
|
||||
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])
|
||||
end
|
||||
|
||||
protected
|
||||
def perform_invocation(method_name, args)
|
||||
method = @api.api_methods[method_name.to_sym]
|
||||
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(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(return_value.dup) rescue return_value) if ok
|
||||
raise(ClientError, "#{return_value.faultCode}: #{return_value.faultString}")
|
||||
end
|
||||
|
||||
def public_name(method_name)
|
||||
public_name = @api.public_api_method_name(method_name)
|
||||
@handler_name ? "#{@handler_name}.#{public_name}" : public_name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
3
vendor/rails/actionwebservice/lib/action_web_service/container.rb
vendored
Normal file
3
vendor/rails/actionwebservice/lib/action_web_service/container.rb
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
require 'action_web_service/container/direct_container'
|
||||
require 'action_web_service/container/delegated_container'
|
||||
require 'action_web_service/container/action_controller_container'
|
95
vendor/rails/actionwebservice/lib/action_web_service/container/action_controller_container.rb
vendored
Normal file
95
vendor/rails/actionwebservice/lib/action_web_service/container/action_controller_container.rb
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
module ActionWebService # :nodoc:
|
||||
module Container # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
def self.append_features(base) # :nodoc:
|
||||
class << base
|
||||
include ClassMethods
|
||||
alias_method :inherited_without_api, :inherited
|
||||
alias_method :inherited, :inherited_with_api
|
||||
alias_method :web_service_api_without_require, :web_service_api
|
||||
alias_method :web_service_api, :web_service_api_with_require
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Creates a client for accessing remote web services, using the
|
||||
# given +protocol+ to communicate with the +endpoint_uri+.
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# class MyController < ActionController::Base
|
||||
# web_client_api :blogger, :xmlrpc, "http://blogger.com/myblog/api/RPC2", :handler_name => 'blogger'
|
||||
# end
|
||||
#
|
||||
# In this example, a protected method named <tt>blogger</tt> will
|
||||
# now exist on the controller, and calling it will return the
|
||||
# XML-RPC client object for working with that remote service.
|
||||
#
|
||||
# +options+ is the set of protocol client specific options (see
|
||||
# a protocol client class for details).
|
||||
#
|
||||
# If your API definition does not exist on the load path with the
|
||||
# correct rules for it to be found using +name+, you can pass in
|
||||
# the API definition class via +options+, using a key of <tt>:api</tt>
|
||||
def web_client_api(name, protocol, endpoint_uri, options={})
|
||||
unless method_defined?(name)
|
||||
api_klass = options.delete(:api) || require_web_service_api(name)
|
||||
class_eval do
|
||||
define_method(name) do
|
||||
create_web_service_client(api_klass, protocol, endpoint_uri, options)
|
||||
end
|
||||
protected name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def web_service_api_with_require(definition=nil) # :nodoc:
|
||||
return web_service_api_without_require if definition.nil?
|
||||
case definition
|
||||
when String, Symbol
|
||||
klass = require_web_service_api(definition)
|
||||
else
|
||||
klass = definition
|
||||
end
|
||||
web_service_api_without_require(klass)
|
||||
end
|
||||
|
||||
def require_web_service_api(name) # :nodoc:
|
||||
case name
|
||||
when String, Symbol
|
||||
file_name = name.to_s.underscore + "_api"
|
||||
class_name = file_name.camelize
|
||||
class_names = [class_name, class_name.sub(/Api$/, 'API')]
|
||||
begin
|
||||
require_dependency(file_name)
|
||||
rescue LoadError => load_error
|
||||
requiree = / -- (.*?)(\.rb)?$/.match(load_error).to_a[1]
|
||||
msg = requiree == file_name ? "Missing API definition file in apis/#{file_name}.rb" : "Can't load file: #{requiree}"
|
||||
raise LoadError.new(msg).copy_blame!(load_error)
|
||||
end
|
||||
klass = nil
|
||||
class_names.each do |name|
|
||||
klass = name.constantize rescue nil
|
||||
break unless klass.nil?
|
||||
end
|
||||
unless klass
|
||||
raise(NameError, "neither #{class_names[0]} or #{class_names[1]} found")
|
||||
end
|
||||
klass
|
||||
else
|
||||
raise(ArgumentError, "expected String or Symbol argument")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def inherited_with_api(child)
|
||||
inherited_without_api(child)
|
||||
begin child.web_service_api(child.controller_path)
|
||||
rescue MissingSourceFile => e
|
||||
raise unless e.is_missing?("apis/#{child.controller_path}_api")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
87
vendor/rails/actionwebservice/lib/action_web_service/container/delegated_container.rb
vendored
Normal file
87
vendor/rails/actionwebservice/lib/action_web_service/container/delegated_container.rb
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
module ActionWebService # :nodoc:
|
||||
module Container # :nodoc:
|
||||
module Delegated # :nodoc:
|
||||
class ContainerError < ActionWebServiceError # :nodoc:
|
||||
end
|
||||
|
||||
def self.append_features(base) # :nodoc:
|
||||
super
|
||||
base.extend(ClassMethods)
|
||||
base.send(:include, ActionWebService::Container::Delegated::InstanceMethods)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Declares a web service that will provide access to the API of the given
|
||||
# +object+. +object+ must be an ActionWebService::Base derivative.
|
||||
#
|
||||
# Web service object creation can either be _immediate_, where the object
|
||||
# instance is given at class definition time, or _deferred_, where
|
||||
# object instantiation is delayed until request time.
|
||||
#
|
||||
# ==== Immediate web service object example
|
||||
#
|
||||
# class ApiController < ApplicationController
|
||||
# web_service_dispatching_mode :delegated
|
||||
#
|
||||
# web_service :person, PersonService.new
|
||||
# end
|
||||
#
|
||||
# For deferred instantiation, a block should be given instead of an
|
||||
# object instance. This block will be executed in controller instance
|
||||
# context, so it can rely on controller instance variables being present.
|
||||
#
|
||||
# ==== Deferred web service object example
|
||||
#
|
||||
# class ApiController < ApplicationController
|
||||
# web_service_dispatching_mode :delegated
|
||||
#
|
||||
# web_service(:person) { PersonService.new(request.env) }
|
||||
# end
|
||||
def web_service(name, object=nil, &block)
|
||||
if (object && block_given?) || (object.nil? && block.nil?)
|
||||
raise(ContainerError, "either service, or a block must be given")
|
||||
end
|
||||
name = name.to_sym
|
||||
if block_given?
|
||||
info = { name => { :block => block } }
|
||||
else
|
||||
info = { name => { :object => object } }
|
||||
end
|
||||
write_inheritable_hash("web_services", info)
|
||||
call_web_service_definition_callbacks(self, name, info)
|
||||
end
|
||||
|
||||
# Whether this service contains a service with the given +name+
|
||||
def has_web_service?(name)
|
||||
web_services.has_key?(name.to_sym)
|
||||
end
|
||||
|
||||
def web_services # :nodoc:
|
||||
read_inheritable_attribute("web_services") || {}
|
||||
end
|
||||
|
||||
def add_web_service_definition_callback(&block) # :nodoc:
|
||||
write_inheritable_array("web_service_definition_callbacks", [block])
|
||||
end
|
||||
|
||||
private
|
||||
def call_web_service_definition_callbacks(container_class, web_service_name, service_info)
|
||||
(read_inheritable_attribute("web_service_definition_callbacks") || []).each do |block|
|
||||
block.call(container_class, web_service_name, service_info)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods # :nodoc:
|
||||
def web_service_object(web_service_name)
|
||||
info = self.class.web_services[web_service_name.to_sym]
|
||||
unless info
|
||||
raise(ContainerError, "no such web service '#{web_service_name}'")
|
||||
end
|
||||
service = info[:block]
|
||||
service ? self.instance_eval(&service) : info[:object]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
70
vendor/rails/actionwebservice/lib/action_web_service/container/direct_container.rb
vendored
Normal file
70
vendor/rails/actionwebservice/lib/action_web_service/container/direct_container.rb
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
module ActionWebService # :nodoc:
|
||||
module Container # :nodoc:
|
||||
module Direct # :nodoc:
|
||||
class ContainerError < ActionWebServiceError # :nodoc:
|
||||
end
|
||||
|
||||
def self.append_features(base) # :nodoc:
|
||||
super
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Attaches ActionWebService API +definition+ to the calling class.
|
||||
#
|
||||
# Action Controllers can have a default associated API, removing the need
|
||||
# to call this method if you follow the Action Web Service naming conventions.
|
||||
#
|
||||
# A controller with a class name of GoogleSearchController will
|
||||
# implicitly load <tt>app/apis/google_search_api.rb</tt>, and expect the
|
||||
# API definition class to be named <tt>GoogleSearchAPI</tt> or
|
||||
# <tt>GoogleSearchApi</tt>.
|
||||
#
|
||||
# ==== Service class example
|
||||
#
|
||||
# class MyService < ActionWebService::Base
|
||||
# web_service_api MyAPI
|
||||
# end
|
||||
#
|
||||
# class MyAPI < ActionWebService::API::Base
|
||||
# ...
|
||||
# end
|
||||
#
|
||||
# ==== Controller class example
|
||||
#
|
||||
# class MyController < ActionController::Base
|
||||
# web_service_api MyAPI
|
||||
# end
|
||||
#
|
||||
# class MyAPI < ActionWebService::API::Base
|
||||
# ...
|
||||
# end
|
||||
def web_service_api(definition=nil)
|
||||
if definition.nil?
|
||||
read_inheritable_attribute("web_service_api")
|
||||
else
|
||||
if definition.is_a?(Symbol)
|
||||
raise(ContainerError, "symbols can only be used for #web_service_api inside of a controller")
|
||||
end
|
||||
unless definition.respond_to?(:ancestors) && definition.ancestors.include?(ActionWebService::API::Base)
|
||||
raise(ContainerError, "#{definition.to_s} is not a valid API definition")
|
||||
end
|
||||
write_inheritable_attribute("web_service_api", definition)
|
||||
call_web_service_api_callbacks(self, definition)
|
||||
end
|
||||
end
|
||||
|
||||
def add_web_service_api_callback(&block) # :nodoc:
|
||||
write_inheritable_array("web_service_api_callbacks", [block])
|
||||
end
|
||||
|
||||
private
|
||||
def call_web_service_api_callbacks(container_class, definition)
|
||||
(read_inheritable_attribute("web_service_api_callbacks") || []).each do |block|
|
||||
block.call(container_class, definition)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
2
vendor/rails/actionwebservice/lib/action_web_service/dispatcher.rb
vendored
Normal file
2
vendor/rails/actionwebservice/lib/action_web_service/dispatcher.rb
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
require 'action_web_service/dispatcher/abstract'
|
||||
require 'action_web_service/dispatcher/action_controller_dispatcher'
|
201
vendor/rails/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
vendored
Normal file
201
vendor/rails/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
vendored
Normal file
|
@ -0,0 +1,201 @@
|
|||
require 'benchmark'
|
||||
|
||||
module ActionWebService # :nodoc:
|
||||
module Dispatcher # :nodoc:
|
||||
class DispatcherError < ActionWebService::ActionWebServiceError # :nodoc:
|
||||
end
|
||||
|
||||
def self.append_features(base) # :nodoc:
|
||||
super
|
||||
base.class_inheritable_option(:web_service_dispatching_mode, :direct)
|
||||
base.class_inheritable_option(:web_service_exception_reporting, true)
|
||||
base.send(:include, ActionWebService::Dispatcher::InstanceMethods)
|
||||
end
|
||||
|
||||
module InstanceMethods # :nodoc:
|
||||
private
|
||||
def invoke_web_service_request(protocol_request)
|
||||
invocation = web_service_invocation(protocol_request)
|
||||
if invocation.is_a?(Array) && protocol_request.protocol.is_a?(Protocol::XmlRpc::XmlRpcProtocol)
|
||||
xmlrpc_multicall_invoke(invocation)
|
||||
else
|
||||
web_service_invoke(invocation)
|
||||
end
|
||||
end
|
||||
|
||||
def web_service_direct_invoke(invocation)
|
||||
@method_params = invocation.method_ordered_params
|
||||
arity = method(invocation.api_method.name).arity rescue 0
|
||||
if arity < 0 || arity > 0
|
||||
params = @method_params
|
||||
else
|
||||
params = []
|
||||
end
|
||||
web_service_filtered_invoke(invocation, params)
|
||||
end
|
||||
|
||||
def web_service_delegated_invoke(invocation)
|
||||
web_service_filtered_invoke(invocation, invocation.method_ordered_params)
|
||||
end
|
||||
|
||||
def web_service_filtered_invoke(invocation, params)
|
||||
cancellation_reason = nil
|
||||
return_value = invocation.service.perform_invocation(invocation.api_method.name, params) do |x|
|
||||
cancellation_reason = x
|
||||
end
|
||||
if cancellation_reason
|
||||
raise(DispatcherError, "request canceled: #{cancellation_reason}")
|
||||
end
|
||||
return_value
|
||||
end
|
||||
|
||||
def web_service_invoke(invocation)
|
||||
case web_service_dispatching_mode
|
||||
when :direct
|
||||
return_value = web_service_direct_invoke(invocation)
|
||||
when :delegated, :layered
|
||||
return_value = web_service_delegated_invoke(invocation)
|
||||
end
|
||||
web_service_create_response(invocation.protocol, invocation.protocol_options, invocation.api, invocation.api_method, return_value)
|
||||
end
|
||||
|
||||
def xmlrpc_multicall_invoke(invocations)
|
||||
responses = []
|
||||
invocations.each do |invocation|
|
||||
if invocation.is_a?(Hash)
|
||||
responses << invocation
|
||||
next
|
||||
end
|
||||
begin
|
||||
case web_service_dispatching_mode
|
||||
when :direct
|
||||
return_value = web_service_direct_invoke(invocation)
|
||||
when :delegated, :layered
|
||||
return_value = web_service_delegated_invoke(invocation)
|
||||
end
|
||||
api_method = invocation.api_method
|
||||
if invocation.api.has_api_method?(api_method.name)
|
||||
return_value = api_method.cast_returns(return_value)
|
||||
end
|
||||
responses << [return_value]
|
||||
rescue Exception => e
|
||||
responses << { 'faultCode' => 3, 'faultString' => e.message }
|
||||
end
|
||||
end
|
||||
invocation = invocations[0]
|
||||
invocation.protocol.encode_response('system.multicall', responses, nil, invocation.protocol_options)
|
||||
end
|
||||
|
||||
def web_service_invocation(request, level = 0)
|
||||
public_method_name = request.method_name
|
||||
invocation = Invocation.new
|
||||
invocation.protocol = request.protocol
|
||||
invocation.protocol_options = request.protocol_options
|
||||
invocation.service_name = request.service_name
|
||||
if web_service_dispatching_mode == :layered
|
||||
case invocation.protocol
|
||||
when Protocol::Soap::SoapProtocol
|
||||
soap_action = request.protocol_options[:soap_action]
|
||||
if soap_action && soap_action =~ /^\/\w+\/(\w+)\//
|
||||
invocation.service_name = $1
|
||||
end
|
||||
when Protocol::XmlRpc::XmlRpcProtocol
|
||||
if request.method_name =~ /^([^\.]+)\.(.*)$/
|
||||
public_method_name = $2
|
||||
invocation.service_name = $1
|
||||
end
|
||||
end
|
||||
end
|
||||
if invocation.protocol.is_a? Protocol::XmlRpc::XmlRpcProtocol
|
||||
if public_method_name == 'multicall' && invocation.service_name == 'system'
|
||||
if level > 0
|
||||
raise(DispatcherError, "Recursive system.multicall invocations not allowed")
|
||||
end
|
||||
multicall = request.method_params.dup
|
||||
unless multicall.is_a?(Array) && multicall[0].is_a?(Array)
|
||||
raise(DispatcherError, "Malformed multicall (expected array of Hash elements)")
|
||||
end
|
||||
multicall = multicall[0]
|
||||
return multicall.map do |item|
|
||||
raise(DispatcherError, "Multicall elements must be Hash") unless item.is_a?(Hash)
|
||||
raise(DispatcherError, "Multicall elements must contain a 'methodName' key") unless item.has_key?('methodName')
|
||||
method_name = item['methodName']
|
||||
params = item.has_key?('params') ? item['params'] : []
|
||||
multicall_request = request.dup
|
||||
multicall_request.method_name = method_name
|
||||
multicall_request.method_params = params
|
||||
begin
|
||||
web_service_invocation(multicall_request, level + 1)
|
||||
rescue Exception => e
|
||||
{'faultCode' => 4, 'faultMessage' => e.message}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
case web_service_dispatching_mode
|
||||
when :direct
|
||||
invocation.api = self.class.web_service_api
|
||||
invocation.service = self
|
||||
when :delegated, :layered
|
||||
invocation.service = web_service_object(invocation.service_name)
|
||||
invocation.api = invocation.service.class.web_service_api
|
||||
end
|
||||
if invocation.api.nil?
|
||||
raise(DispatcherError, "no API attached to #{invocation.service.class}")
|
||||
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)
|
||||
else
|
||||
if invocation.api.default_api_method.nil?
|
||||
raise(DispatcherError, "no such method '#{public_method_name}' on API #{invocation.api}")
|
||||
else
|
||||
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})")
|
||||
end
|
||||
request.api_method = invocation.api_method
|
||||
begin
|
||||
invocation.method_ordered_params = invocation.api_method.cast_expects(request.method_params.dup)
|
||||
rescue
|
||||
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]
|
||||
m + 1
|
||||
end
|
||||
invocation
|
||||
end
|
||||
|
||||
def web_service_create_response(protocol, protocol_options, 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, protocol_options)
|
||||
end
|
||||
|
||||
class Invocation # :nodoc:
|
||||
attr_accessor :protocol
|
||||
attr_accessor :protocol_options
|
||||
attr_accessor :service_name
|
||||
attr_accessor :api
|
||||
attr_accessor :api_method
|
||||
attr_accessor :method_ordered_params
|
||||
attr_accessor :method_named_params
|
||||
attr_accessor :service
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
380
vendor/rails/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb
vendored
Normal file
380
vendor/rails/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb
vendored
Normal file
|
@ -0,0 +1,380 @@
|
|||
require 'benchmark'
|
||||
require 'builder/xmlmarkup'
|
||||
|
||||
module ActionWebService # :nodoc:
|
||||
module Dispatcher # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
def self.append_features(base) # :nodoc:
|
||||
super
|
||||
class << base
|
||||
include ClassMethods
|
||||
alias_method :inherited_without_action_controller, :inherited
|
||||
alias_method :inherited, :inherited_with_action_controller
|
||||
end
|
||||
base.class_eval do
|
||||
alias_method :web_service_direct_invoke_without_controller, :web_service_direct_invoke
|
||||
end
|
||||
base.add_web_service_api_callback do |klass, api|
|
||||
if klass.web_service_dispatching_mode == :direct
|
||||
klass.class_eval 'def api; dispatch_web_service_request; end'
|
||||
end
|
||||
end
|
||||
base.add_web_service_definition_callback do |klass, name, info|
|
||||
if klass.web_service_dispatching_mode == :delegated
|
||||
klass.class_eval "def #{name}; dispatch_web_service_request; end"
|
||||
elsif klass.web_service_dispatching_mode == :layered
|
||||
klass.class_eval 'def api; dispatch_web_service_request; end'
|
||||
end
|
||||
end
|
||||
base.send(:include, ActionWebService::Dispatcher::ActionController::InstanceMethods)
|
||||
end
|
||||
|
||||
module ClassMethods # :nodoc:
|
||||
def inherited_with_action_controller(child)
|
||||
inherited_without_action_controller(child)
|
||||
child.send(:include, ActionWebService::Dispatcher::ActionController::WsdlAction)
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods # :nodoc:
|
||||
private
|
||||
def dispatch_web_service_request
|
||||
exception = nil
|
||||
begin
|
||||
ws_request = discover_web_service_request(request)
|
||||
rescue Exception => e
|
||||
exception = e
|
||||
end
|
||||
if ws_request
|
||||
ws_response = nil
|
||||
exception = nil
|
||||
bm = Benchmark.measure do
|
||||
begin
|
||||
ws_response = invoke_web_service_request(ws_request)
|
||||
rescue Exception => e
|
||||
exception = e
|
||||
end
|
||||
end
|
||||
log_request(ws_request, request.raw_post)
|
||||
if exception
|
||||
log_error(exception) unless logger.nil?
|
||||
send_web_service_error_response(ws_request, exception)
|
||||
else
|
||||
send_web_service_response(ws_response, bm.real)
|
||||
end
|
||||
else
|
||||
exception ||= DispatcherError.new("Malformed SOAP or XML-RPC protocol message")
|
||||
log_error(exception) unless logger.nil?
|
||||
send_web_service_error_response(ws_request, exception)
|
||||
end
|
||||
rescue Exception => e
|
||||
log_error(e) unless logger.nil?
|
||||
send_web_service_error_response(ws_request, e)
|
||||
end
|
||||
|
||||
def send_web_service_response(ws_response, elapsed=nil)
|
||||
log_response(ws_response, elapsed)
|
||||
options = { :type => ws_response.content_type, :disposition => 'inline' }
|
||||
send_data(ws_response.body, options)
|
||||
end
|
||||
|
||||
def send_web_service_error_response(ws_request, exception)
|
||||
if ws_request
|
||||
unless self.class.web_service_exception_reporting
|
||||
exception = DispatcherError.new("Internal server error (exception raised)")
|
||||
end
|
||||
api_method = ws_request.api_method
|
||||
public_method_name = api_method ? api_method.public_name : ws_request.method_name
|
||||
return_type = ActionWebService::SignatureTypes.canonical_signature_entry(Exception, 0)
|
||||
ws_response = ws_request.protocol.encode_response(public_method_name + 'Response', exception, return_type, ws_request.protocol_options)
|
||||
send_web_service_response(ws_response)
|
||||
else
|
||||
if self.class.web_service_exception_reporting
|
||||
message = exception.message
|
||||
backtrace = "\nBacktrace:\n#{exception.backtrace.join("\n")}"
|
||||
else
|
||||
message = "Exception raised"
|
||||
backtrace = ""
|
||||
end
|
||||
render_text("Internal protocol error: #{message}#{backtrace}", "500 Internal Protocol Error")
|
||||
end
|
||||
end
|
||||
|
||||
def web_service_direct_invoke(invocation)
|
||||
invocation.method_named_params.each do |name, value|
|
||||
params[name] = value
|
||||
end
|
||||
params['action'] = invocation.api_method.name.to_s
|
||||
if before_action == false
|
||||
raise(DispatcherError, "Method filtered")
|
||||
end
|
||||
return_value = web_service_direct_invoke_without_controller(invocation)
|
||||
after_action
|
||||
return_value
|
||||
end
|
||||
|
||||
def log_request(ws_request, body)
|
||||
unless logger.nil?
|
||||
name = ws_request.method_name
|
||||
api_method = ws_request.api_method
|
||||
params = ws_request.method_params
|
||||
if api_method && api_method.expects
|
||||
params = api_method.expects.zip(params).map{ |type, param| "#{type.name}=>#{param.inspect}" }
|
||||
else
|
||||
params = params.map{ |param| param.inspect }
|
||||
end
|
||||
service = ws_request.service_name
|
||||
logger.debug("\nWeb Service Request: #{name}(#{params.join(", ")}) Entrypoint: #{service}")
|
||||
logger.debug(indent(body))
|
||||
end
|
||||
end
|
||||
|
||||
def log_response(ws_response, elapsed=nil)
|
||||
unless logger.nil?
|
||||
elapsed = (elapsed ? " (%f):" % elapsed : ":")
|
||||
logger.debug("\nWeb Service Response" + elapsed + " => #{ws_response.return_value.inspect}")
|
||||
logger.debug(indent(ws_response.body))
|
||||
end
|
||||
end
|
||||
|
||||
def indent(body)
|
||||
body.split(/\n/).map{|x| " #{x}"}.join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
module WsdlAction # :nodoc:
|
||||
XsdNs = 'http://www.w3.org/2001/XMLSchema'
|
||||
WsdlNs = 'http://schemas.xmlsoap.org/wsdl/'
|
||||
SoapNs = 'http://schemas.xmlsoap.org/wsdl/soap/'
|
||||
SoapEncodingNs = 'http://schemas.xmlsoap.org/soap/encoding/'
|
||||
SoapHttpTransport = 'http://schemas.xmlsoap.org/soap/http'
|
||||
|
||||
def wsdl
|
||||
case request.method
|
||||
when :get
|
||||
begin
|
||||
options = { :type => 'text/xml', :disposition => 'inline' }
|
||||
send_data(to_wsdl, options)
|
||||
rescue Exception => e
|
||||
log_error(e) unless logger.nil?
|
||||
end
|
||||
when :post
|
||||
render_text('POST not supported', '500 POST not supported')
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def base_uri
|
||||
host = request.env['HTTP_HOST'] || request.env['SERVER_NAME'] || 'localhost'
|
||||
relative_url_root = request.relative_url_root
|
||||
scheme = request.ssl? ? 'https' : 'http'
|
||||
'%s://%s%s/%s/' % [scheme, host, relative_url_root, self.class.controller_path]
|
||||
end
|
||||
|
||||
def to_wsdl
|
||||
xml = ''
|
||||
dispatching_mode = web_service_dispatching_mode
|
||||
global_service_name = wsdl_service_name
|
||||
namespace = wsdl_namespace || 'urn:ActionWebService'
|
||||
soap_action_base = "/#{controller_name}"
|
||||
|
||||
marshaler = ActionWebService::Protocol::Soap::SoapMarshaler.new(namespace)
|
||||
apis = {}
|
||||
case dispatching_mode
|
||||
when :direct
|
||||
api = self.class.web_service_api
|
||||
web_service_name = controller_class_name.sub(/Controller$/, '').underscore
|
||||
apis[web_service_name] = [api, register_api(api, marshaler)]
|
||||
when :delegated, :layered
|
||||
self.class.web_services.each do |web_service_name, info|
|
||||
service = web_service_object(web_service_name)
|
||||
api = service.class.web_service_api
|
||||
apis[web_service_name] = [api, register_api(api, marshaler)]
|
||||
end
|
||||
end
|
||||
custom_types = []
|
||||
apis.values.each do |api, bindings|
|
||||
bindings.each do |b|
|
||||
custom_types << b unless custom_types.include?(b)
|
||||
end
|
||||
end
|
||||
|
||||
xm = Builder::XmlMarkup.new(:target => xml, :indent => 2)
|
||||
xm.instruct!
|
||||
xm.definitions('name' => wsdl_service_name,
|
||||
'targetNamespace' => namespace,
|
||||
'xmlns:typens' => namespace,
|
||||
'xmlns:xsd' => XsdNs,
|
||||
'xmlns:soap' => SoapNs,
|
||||
'xmlns:soapenc' => SoapEncodingNs,
|
||||
'xmlns:wsdl' => WsdlNs,
|
||||
'xmlns' => WsdlNs) do
|
||||
# Generate XSD
|
||||
if custom_types.size > 0
|
||||
xm.types do
|
||||
xm.xsd(:schema, 'xmlns' => XsdNs, 'targetNamespace' => namespace) do
|
||||
custom_types.each do |binding|
|
||||
case
|
||||
when binding.type.array?
|
||||
xm.xsd(:complexType, 'name' => binding.type_name) do
|
||||
xm.xsd(:complexContent) do
|
||||
xm.xsd(:restriction, 'base' => 'soapenc:Array') do
|
||||
xm.xsd(:attribute, 'ref' => 'soapenc:arrayType',
|
||||
'wsdl:arrayType' => binding.element_binding.qualified_type_name('typens') + '[]')
|
||||
end
|
||||
end
|
||||
end
|
||||
when binding.type.structured?
|
||||
xm.xsd(:complexType, 'name' => binding.type_name) do
|
||||
xm.xsd(:all) do
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# APIs
|
||||
apis.each do |api_name, values|
|
||||
api = values[0]
|
||||
api.api_methods.each do |name, method|
|
||||
gen = lambda do |msg_name, direction|
|
||||
xm.message('name' => message_name_for(api_name, msg_name)) do
|
||||
sym = nil
|
||||
if direction == :out
|
||||
returns = method.returns
|
||||
if returns
|
||||
binding = marshaler.register_type(returns[0])
|
||||
xm.part('name' => 'return', 'type' => binding.qualified_type_name('typens'))
|
||||
end
|
||||
else
|
||||
expects = method.expects
|
||||
expects.each do |type|
|
||||
binding = marshaler.register_type(type)
|
||||
xm.part('name' => type.name, 'type' => binding.qualified_type_name('typens'))
|
||||
end if expects
|
||||
end
|
||||
end
|
||||
end
|
||||
public_name = method.public_name
|
||||
gen.call(public_name, :in)
|
||||
gen.call("#{public_name}Response", :out)
|
||||
end
|
||||
|
||||
# Port
|
||||
port_name = port_name_for(global_service_name, api_name)
|
||||
xm.portType('name' => port_name) do
|
||||
api.api_methods.each do |name, method|
|
||||
xm.operation('name' => method.public_name) do
|
||||
xm.input('message' => "typens:" + message_name_for(api_name, method.public_name))
|
||||
xm.output('message' => "typens:" + message_name_for(api_name, "#{method.public_name}Response"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Bind it
|
||||
binding_name = binding_name_for(global_service_name, api_name)
|
||||
xm.binding('name' => binding_name, 'type' => "typens:#{port_name}") do
|
||||
xm.soap(:binding, 'style' => 'rpc', 'transport' => SoapHttpTransport)
|
||||
api.api_methods.each do |name, method|
|
||||
xm.operation('name' => method.public_name) do
|
||||
case web_service_dispatching_mode
|
||||
when :direct
|
||||
soap_action = soap_action_base + "/api/" + method.public_name
|
||||
when :delegated, :layered
|
||||
soap_action = soap_action_base \
|
||||
+ "/" + api_name.to_s \
|
||||
+ "/" + method.public_name
|
||||
end
|
||||
xm.soap(:operation, 'soapAction' => soap_action)
|
||||
xm.input do
|
||||
xm.soap(:body,
|
||||
'use' => 'encoded',
|
||||
'namespace' => namespace,
|
||||
'encodingStyle' => SoapEncodingNs)
|
||||
end
|
||||
xm.output do
|
||||
xm.soap(:body,
|
||||
'use' => 'encoded',
|
||||
'namespace' => namespace,
|
||||
'encodingStyle' => SoapEncodingNs)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Define it
|
||||
xm.service('name' => "#{global_service_name}Service") do
|
||||
apis.each do |api_name, values|
|
||||
port_name = port_name_for(global_service_name, api_name)
|
||||
binding_name = binding_name_for(global_service_name, api_name)
|
||||
case web_service_dispatching_mode
|
||||
when :direct, :layered
|
||||
binding_target = 'api'
|
||||
when :delegated
|
||||
binding_target = api_name.to_s
|
||||
end
|
||||
xm.port('name' => port_name, 'binding' => "typens:#{binding_name}") do
|
||||
xm.soap(:address, 'location' => "#{base_uri}#{binding_target}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def port_name_for(global_service, service)
|
||||
"#{global_service}#{service.to_s.camelize}Port"
|
||||
end
|
||||
|
||||
def binding_name_for(global_service, service)
|
||||
"#{global_service}#{service.to_s.camelize}Binding"
|
||||
end
|
||||
|
||||
def message_name_for(api_name, message_name)
|
||||
mode = web_service_dispatching_mode
|
||||
if mode == :layered || mode == :delegated
|
||||
api_name.to_s + '-' + message_name
|
||||
else
|
||||
message_name
|
||||
end
|
||||
end
|
||||
|
||||
def register_api(api, marshaler)
|
||||
bindings = {}
|
||||
traverse_custom_types(api, marshaler, bindings) do |binding|
|
||||
bindings[binding] = nil unless bindings.has_key?(binding)
|
||||
element_binding = binding.element_binding
|
||||
bindings[element_binding] = nil if element_binding && !bindings.has_key?(element_binding)
|
||||
end
|
||||
bindings.keys
|
||||
end
|
||||
|
||||
def traverse_custom_types(api, marshaler, bindings, &block)
|
||||
api.api_methods.each do |name, method|
|
||||
expects, returns = method.expects, method.returns
|
||||
expects.each{ |type| traverse_type(marshaler, type, bindings, &block) if type.custom? } if expects
|
||||
returns.each{ |type| traverse_type(marshaler, type, bindings, &block) if type.custom? } if returns
|
||||
end
|
||||
end
|
||||
|
||||
def traverse_type(marshaler, type, bindings, &block)
|
||||
binding = marshaler.register_type(type)
|
||||
return if bindings.has_key?(binding)
|
||||
bindings[binding] = nil
|
||||
yield binding
|
||||
if type.array?
|
||||
yield marshaler.register_type(type.element_type)
|
||||
type = type.element_type
|
||||
end
|
||||
type.each_member{ |name, type| traverse_type(marshaler, type, bindings, &block) } if type.structured?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
205
vendor/rails/actionwebservice/lib/action_web_service/invocation.rb
vendored
Normal file
205
vendor/rails/actionwebservice/lib/action_web_service/invocation.rb
vendored
Normal file
|
@ -0,0 +1,205 @@
|
|||
module ActionWebService # :nodoc:
|
||||
module Invocation # :nodoc:
|
||||
class InvocationError < ActionWebService::ActionWebServiceError # :nodoc:
|
||||
end
|
||||
|
||||
def self.append_features(base) # :nodoc:
|
||||
super
|
||||
base.extend(ClassMethods)
|
||||
base.send(:include, ActionWebService::Invocation::InstanceMethods)
|
||||
end
|
||||
|
||||
# Invocation interceptors provide a means to execute custom code before
|
||||
# and after method invocations on ActionWebService::Base objects.
|
||||
#
|
||||
# When running in _Direct_ dispatching mode, ActionController filters
|
||||
# should be used for this functionality instead.
|
||||
#
|
||||
# The semantics of invocation interceptors are the same as ActionController
|
||||
# filters, and accept the same parameters and options.
|
||||
#
|
||||
# A _before_ interceptor can also cancel execution by returning +false+,
|
||||
# or returning a <tt>[false, "cancel reason"]</tt> array if it wishes to supply
|
||||
# a reason for canceling the request.
|
||||
#
|
||||
# === Example
|
||||
#
|
||||
# class CustomService < ActionWebService::Base
|
||||
# before_invocation :intercept_add, :only => [:add]
|
||||
#
|
||||
# def add(a, b)
|
||||
# a + b
|
||||
# end
|
||||
#
|
||||
# private
|
||||
# def intercept_add
|
||||
# return [false, "permission denied"] # cancel it
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# Options:
|
||||
# [<tt>:except</tt>] A list of methods for which the interceptor will NOT be called
|
||||
# [<tt>:only</tt>] A list of methods for which the interceptor WILL be called
|
||||
module ClassMethods
|
||||
# Appends the given +interceptors+ to be called
|
||||
# _before_ method invocation.
|
||||
def append_before_invocation(*interceptors, &block)
|
||||
conditions = extract_conditions!(interceptors)
|
||||
interceptors << block if block_given?
|
||||
add_interception_conditions(interceptors, conditions)
|
||||
append_interceptors_to_chain("before", interceptors)
|
||||
end
|
||||
|
||||
# Prepends the given +interceptors+ to be called
|
||||
# _before_ method invocation.
|
||||
def prepend_before_invocation(*interceptors, &block)
|
||||
conditions = extract_conditions!(interceptors)
|
||||
interceptors << block if block_given?
|
||||
add_interception_conditions(interceptors, conditions)
|
||||
prepend_interceptors_to_chain("before", interceptors)
|
||||
end
|
||||
|
||||
alias :before_invocation :append_before_invocation
|
||||
|
||||
# Appends the given +interceptors+ to be called
|
||||
# _after_ method invocation.
|
||||
def append_after_invocation(*interceptors, &block)
|
||||
conditions = extract_conditions!(interceptors)
|
||||
interceptors << block if block_given?
|
||||
add_interception_conditions(interceptors, conditions)
|
||||
append_interceptors_to_chain("after", interceptors)
|
||||
end
|
||||
|
||||
# Prepends the given +interceptors+ to be called
|
||||
# _after_ method invocation.
|
||||
def prepend_after_invocation(*interceptors, &block)
|
||||
conditions = extract_conditions!(interceptors)
|
||||
interceptors << block if block_given?
|
||||
add_interception_conditions(interceptors, conditions)
|
||||
prepend_interceptors_to_chain("after", interceptors)
|
||||
end
|
||||
|
||||
alias :after_invocation :append_after_invocation
|
||||
|
||||
def before_invocation_interceptors # :nodoc:
|
||||
read_inheritable_attribute("before_invocation_interceptors")
|
||||
end
|
||||
|
||||
def after_invocation_interceptors # :nodoc:
|
||||
read_inheritable_attribute("after_invocation_interceptors")
|
||||
end
|
||||
|
||||
def included_intercepted_methods # :nodoc:
|
||||
read_inheritable_attribute("included_intercepted_methods") || {}
|
||||
end
|
||||
|
||||
def excluded_intercepted_methods # :nodoc:
|
||||
read_inheritable_attribute("excluded_intercepted_methods") || {}
|
||||
end
|
||||
|
||||
private
|
||||
def append_interceptors_to_chain(condition, interceptors)
|
||||
write_inheritable_array("#{condition}_invocation_interceptors", interceptors)
|
||||
end
|
||||
|
||||
def prepend_interceptors_to_chain(condition, interceptors)
|
||||
interceptors = interceptors + read_inheritable_attribute("#{condition}_invocation_interceptors")
|
||||
write_inheritable_attribute("#{condition}_invocation_interceptors", interceptors)
|
||||
end
|
||||
|
||||
def extract_conditions!(interceptors)
|
||||
return nil unless interceptors.last.is_a? Hash
|
||||
interceptors.pop
|
||||
end
|
||||
|
||||
def add_interception_conditions(interceptors, conditions)
|
||||
return unless conditions
|
||||
included, excluded = conditions[:only], conditions[:except]
|
||||
write_inheritable_hash("included_intercepted_methods", condition_hash(interceptors, included)) && return if included
|
||||
write_inheritable_hash("excluded_intercepted_methods", condition_hash(interceptors, excluded)) if excluded
|
||||
end
|
||||
|
||||
def condition_hash(interceptors, *methods)
|
||||
interceptors.inject({}) {|hash, interceptor| hash.merge(interceptor => methods.flatten.map {|method| method.to_s})}
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods # :nodoc:
|
||||
def self.append_features(base)
|
||||
super
|
||||
base.class_eval do
|
||||
alias_method :perform_invocation_without_interception, :perform_invocation
|
||||
alias_method :perform_invocation, :perform_invocation_with_interception
|
||||
end
|
||||
end
|
||||
|
||||
def perform_invocation_with_interception(method_name, params, &block)
|
||||
return if before_invocation(method_name, params, &block) == false
|
||||
return_value = perform_invocation_without_interception(method_name, params)
|
||||
after_invocation(method_name, params, return_value)
|
||||
return_value
|
||||
end
|
||||
|
||||
def perform_invocation(method_name, params)
|
||||
send(method_name, *params)
|
||||
end
|
||||
|
||||
def before_invocation(name, args, &block)
|
||||
call_interceptors(self.class.before_invocation_interceptors, [name, args], &block)
|
||||
end
|
||||
|
||||
def after_invocation(name, args, result)
|
||||
call_interceptors(self.class.after_invocation_interceptors, [name, args, result])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def call_interceptors(interceptors, interceptor_args, &block)
|
||||
if interceptors and not interceptors.empty?
|
||||
interceptors.each do |interceptor|
|
||||
next if method_exempted?(interceptor, interceptor_args[0].to_s)
|
||||
result = case
|
||||
when interceptor.is_a?(Symbol)
|
||||
self.send(interceptor, *interceptor_args)
|
||||
when interceptor_block?(interceptor)
|
||||
interceptor.call(self, *interceptor_args)
|
||||
when interceptor_class?(interceptor)
|
||||
interceptor.intercept(self, *interceptor_args)
|
||||
else
|
||||
raise(
|
||||
InvocationError,
|
||||
"Interceptors need to be either a symbol, proc/method, or a class implementing a static intercept method"
|
||||
)
|
||||
end
|
||||
reason = nil
|
||||
if result.is_a?(Array)
|
||||
reason = result[1] if result[1]
|
||||
result = result[0]
|
||||
end
|
||||
if result == false
|
||||
block.call(reason) if block && reason
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def interceptor_block?(interceptor)
|
||||
interceptor.respond_to?("call") && (interceptor.arity == 3 || interceptor.arity == -1)
|
||||
end
|
||||
|
||||
def interceptor_class?(interceptor)
|
||||
interceptor.respond_to?("intercept")
|
||||
end
|
||||
|
||||
def method_exempted?(interceptor, method_name)
|
||||
case
|
||||
when self.class.included_intercepted_methods[interceptor]
|
||||
!self.class.included_intercepted_methods[interceptor].include?(method_name)
|
||||
when self.class.excluded_intercepted_methods[interceptor]
|
||||
self.class.excluded_intercepted_methods[interceptor].include?(method_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
4
vendor/rails/actionwebservice/lib/action_web_service/protocol.rb
vendored
Normal file
4
vendor/rails/actionwebservice/lib/action_web_service/protocol.rb
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
require 'action_web_service/protocol/abstract'
|
||||
require 'action_web_service/protocol/discovery'
|
||||
require 'action_web_service/protocol/soap_protocol'
|
||||
require 'action_web_service/protocol/xmlrpc_protocol'
|
112
vendor/rails/actionwebservice/lib/action_web_service/protocol/abstract.rb
vendored
Normal file
112
vendor/rails/actionwebservice/lib/action_web_service/protocol/abstract.rb
vendored
Normal file
|
@ -0,0 +1,112 @@
|
|||
module ActionWebService # :nodoc:
|
||||
module Protocol # :nodoc:
|
||||
class ProtocolError < ActionWebServiceError # :nodoc:
|
||||
end
|
||||
|
||||
class AbstractProtocol # :nodoc:
|
||||
def setup(controller)
|
||||
end
|
||||
|
||||
def decode_action_pack_request(action_pack_request)
|
||||
end
|
||||
|
||||
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
|
||||
request.env['RAW_POST_DATA'] = raw_body
|
||||
request.env['REQUEST_METHOD'] = 'POST'
|
||||
request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
|
||||
request
|
||||
end
|
||||
|
||||
def decode_request(raw_request, service_name, protocol_options={})
|
||||
end
|
||||
|
||||
def encode_request(method_name, params, param_types)
|
||||
end
|
||||
|
||||
def decode_response(raw_response)
|
||||
end
|
||||
|
||||
def encode_response(method_name, return_value, return_type, protocol_options={})
|
||||
end
|
||||
|
||||
def protocol_client(api, protocol_name, endpoint_uri, options)
|
||||
end
|
||||
|
||||
def register_api(api)
|
||||
end
|
||||
end
|
||||
|
||||
class Request # :nodoc:
|
||||
attr :protocol
|
||||
attr_accessor :method_name
|
||||
attr_accessor :method_params
|
||||
attr :service_name
|
||||
attr_accessor :api
|
||||
attr_accessor :api_method
|
||||
attr :protocol_options
|
||||
|
||||
def initialize(protocol, method_name, method_params, service_name, api=nil, api_method=nil, protocol_options=nil)
|
||||
@protocol = protocol
|
||||
@method_name = method_name
|
||||
@method_params = method_params
|
||||
@service_name = service_name
|
||||
@api = api
|
||||
@api_method = api_method
|
||||
@protocol_options = protocol_options || {}
|
||||
end
|
||||
end
|
||||
|
||||
class Response # :nodoc:
|
||||
attr :body
|
||||
attr :content_type
|
||||
attr :return_value
|
||||
|
||||
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
|
||||
end
|
37
vendor/rails/actionwebservice/lib/action_web_service/protocol/discovery.rb
vendored
Normal file
37
vendor/rails/actionwebservice/lib/action_web_service/protocol/discovery.rb
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
module ActionWebService # :nodoc:
|
||||
module Protocol # :nodoc:
|
||||
module Discovery # :nodoc:
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
base.send(:include, ActionWebService::Protocol::Discovery::InstanceMethods)
|
||||
end
|
||||
|
||||
module ClassMethods # :nodoc:
|
||||
def register_protocol(klass)
|
||||
write_inheritable_array("web_service_protocols", [klass])
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods # :nodoc:
|
||||
private
|
||||
def discover_web_service_request(action_pack_request)
|
||||
(self.class.read_inheritable_attribute("web_service_protocols") || []).each do |protocol|
|
||||
protocol = protocol.create(self)
|
||||
request = protocol.decode_action_pack_request(action_pack_request)
|
||||
return request unless request.nil?
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def create_web_service_client(api, protocol_name, endpoint_uri, options)
|
||||
(self.class.read_inheritable_attribute("web_service_protocols") || []).each do |protocol|
|
||||
protocol = protocol.create(self)
|
||||
client = protocol.protocol_client(api, protocol_name, endpoint_uri, options)
|
||||
return client unless client.nil?
|
||||
end
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
176
vendor/rails/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
vendored
Normal file
176
vendor/rails/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
vendored
Normal file
|
@ -0,0 +1,176 @@
|
|||
require 'action_web_service/protocol/soap_protocol/marshaler'
|
||||
require 'soap/streamHandler'
|
||||
require 'action_web_service/client/soap_client'
|
||||
|
||||
module ActionWebService # :nodoc:
|
||||
module API # :nodoc:
|
||||
class Base # :nodoc:
|
||||
def self.soap_client(endpoint_uri, options={})
|
||||
ActionWebService::Client::Soap.new self, endpoint_uri, options
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Protocol # :nodoc:
|
||||
module Soap # :nodoc:
|
||||
def self.included(base)
|
||||
base.register_protocol(SoapProtocol)
|
||||
base.class_inheritable_option(:wsdl_service_name)
|
||||
base.class_inheritable_option(:wsdl_namespace)
|
||||
end
|
||||
|
||||
class SoapProtocol < AbstractProtocol # :nodoc:
|
||||
AWSEncoding = 'UTF-8'
|
||||
XSDEncoding = 'UTF8'
|
||||
|
||||
attr :marshaler
|
||||
|
||||
def initialize(namespace=nil)
|
||||
namespace ||= 'urn:ActionWebService'
|
||||
@marshaler = SoapMarshaler.new namespace
|
||||
end
|
||||
|
||||
def self.create(controller)
|
||||
SoapProtocol.new(controller.wsdl_namespace)
|
||||
end
|
||||
|
||||
def decode_action_pack_request(action_pack_request)
|
||||
return nil unless soap_action = has_valid_soap_action?(action_pack_request)
|
||||
service_name = action_pack_request.parameters['action']
|
||||
input_encoding = parse_charset(action_pack_request.env['HTTP_CONTENT_TYPE'])
|
||||
protocol_options = {
|
||||
:soap_action => soap_action,
|
||||
:charset => input_encoding
|
||||
}
|
||||
decode_request(action_pack_request.raw_post, service_name, protocol_options)
|
||||
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 decode_request(raw_request, service_name, protocol_options={})
|
||||
envelope = SOAP::Processor.unmarshal(raw_request, :charset => protocol_options[:charset])
|
||||
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, nil, nil, protocol_options)
|
||||
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.namespace, method_name)
|
||||
param_def = []
|
||||
if param_types
|
||||
params = param_types.zip(params).map do |type, param|
|
||||
param_def << ['in', type.name, marshaler.lookup_type(type).mapping]
|
||||
[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, protocol_options={})
|
||||
if return_type
|
||||
return_binding = marshaler.register_type(return_type)
|
||||
marshaler.annotate_arrays(return_binding, return_value)
|
||||
end
|
||||
qname = XSD::QName.new(marshaler.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)
|
||||
|
||||
# FIXME: This is not thread-safe, but StringFactory_ in SOAP4R only
|
||||
# reads target encoding from the XSD::Charset.encoding variable.
|
||||
# This is required to ensure $KCODE strings are converted
|
||||
# correctly to UTF-8 for any values of $KCODE.
|
||||
previous_encoding = XSD::Charset.encoding
|
||||
XSD::Charset.encoding = XSDEncoding
|
||||
response_body = SOAP::Processor.marshal(envelope, :charset => AWSEncoding)
|
||||
XSD::Charset.encoding = previous_encoding
|
||||
|
||||
Response.new(response_body, "text/xml; charset=#{AWSEncoding}", 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 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
|
||||
def has_valid_soap_action?(request)
|
||||
return nil unless request.method == :post
|
||||
soap_action = request.env['HTTP_SOAPACTION']
|
||||
return nil unless soap_action
|
||||
soap_action = soap_action.dup
|
||||
soap_action.gsub!(/^"/, '')
|
||||
soap_action.gsub!(/"$/, '')
|
||||
soap_action.strip!
|
||||
return nil if soap_action.empty?
|
||||
soap_action
|
||||
end
|
||||
|
||||
def create_soap_envelope(body)
|
||||
header = SOAP::SOAPHeader.new
|
||||
body = SOAP::SOAPBody.new(body)
|
||||
SOAP::SOAPEnvelope.new(header, body)
|
||||
end
|
||||
|
||||
def parse_charset(content_type)
|
||||
return AWSEncoding if content_type.nil?
|
||||
if /^text\/xml(?:\s*;\s*charset=([^"]+|"[^"]+"))$/i =~ content_type
|
||||
$1
|
||||
else
|
||||
AWSEncoding
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
241
vendor/rails/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb
vendored
Normal file
241
vendor/rails/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb
vendored
Normal file
|
@ -0,0 +1,241 @@
|
|||
require 'soap/mapping'
|
||||
|
||||
module ActionWebService
|
||||
module Protocol
|
||||
module Soap
|
||||
# Workaround for SOAP4R return values changing
|
||||
class Registry < SOAP::Mapping::Registry
|
||||
if SOAP::Version >= "1.5.4"
|
||||
def find_mapped_soap_class(obj_class)
|
||||
return @map.instance_eval { @obj2soap[obj_class][0] }
|
||||
end
|
||||
|
||||
def find_mapped_obj_class(soap_class)
|
||||
return @map.instance_eval { @soap2obj[soap_class][0] }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class SoapMarshaler
|
||||
attr :namespace
|
||||
attr :registry
|
||||
|
||||
def initialize(namespace=nil)
|
||||
@namespace = namespace || 'urn:ActionWebService'
|
||||
@registry = Registry.new
|
||||
@type2binding = {}
|
||||
register_static_factories
|
||||
end
|
||||
|
||||
def soap_to_ruby(obj)
|
||||
SOAP::Mapping.soap2obj(obj, @registry)
|
||||
end
|
||||
|
||||
def ruby_to_soap(obj)
|
||||
soap = SOAP::Mapping.obj2soap(obj, @registry)
|
||||
soap.elename = XSD::QName.new if SOAP::Version >= "1.5.5" && soap.elename == XSD::QName::EMPTY
|
||||
soap
|
||||
end
|
||||
|
||||
def register_type(type)
|
||||
return @type2binding[type] if @type2binding.has_key?(type)
|
||||
|
||||
if type.array?
|
||||
array_mapping = @registry.find_mapped_soap_class(Array)
|
||||
qname = XSD::QName.new(@namespace, soap_type_name(type.element_type.type_class.name) + 'Array')
|
||||
element_type_binding = register_type(type.element_type)
|
||||
@type2binding[type] = SoapBinding.new(self, qname, type, array_mapping, element_type_binding)
|
||||
elsif (mapping = @registry.find_mapped_soap_class(type.type_class) rescue nil)
|
||||
qname = mapping[2] ? mapping[2][:type] : nil
|
||||
qname ||= soap_base_type_name(mapping[0])
|
||||
@type2binding[type] = SoapBinding.new(self, qname, type, mapping)
|
||||
else
|
||||
qname = XSD::QName.new(@namespace, soap_type_name(type.type_class.name))
|
||||
@registry.add(type.type_class,
|
||||
SOAP::SOAPStruct,
|
||||
typed_struct_factory(type.type_class),
|
||||
{ :type => qname })
|
||||
mapping = @registry.find_mapped_soap_class(type.type_class)
|
||||
@type2binding[type] = SoapBinding.new(self, qname, type, mapping)
|
||||
end
|
||||
|
||||
if type.structured?
|
||||
type.each_member do |m_name, m_type|
|
||||
register_type(m_type)
|
||||
end
|
||||
end
|
||||
|
||||
@type2binding[type]
|
||||
end
|
||||
alias :lookup_type :register_type
|
||||
|
||||
def annotate_arrays(binding, value)
|
||||
if value.nil?
|
||||
return
|
||||
elsif 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(@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
|
||||
|
||||
def register_static_factories
|
||||
@registry.add(ActionWebService::Base64,
|
||||
SOAP::SOAPBase64,
|
||||
SoapBase64Factory.new,
|
||||
nil)
|
||||
mapping = @registry.find_mapped_soap_class(ActionWebService::Base64)
|
||||
@type2binding[ActionWebService::Base64] =
|
||||
SoapBinding.new(self, SOAP::SOAPBase64::Type,
|
||||
ActionWebService::Base64, mapping)
|
||||
@registry.add(Array,
|
||||
SOAP::SOAPArray,
|
||||
SoapTypedArrayFactory.new,
|
||||
nil)
|
||||
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)
|
||||
ns.assign(SOAP::EncodingNamespace, "soapenc")
|
||||
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
|
||||
|
||||
class SoapBase64Factory < SOAP::Mapping::Factory
|
||||
def obj2soap(soap_class, obj, info, map)
|
||||
unless obj.is_a?(ActionWebService::Base64)
|
||||
return nil
|
||||
end
|
||||
return soap_class.new(obj)
|
||||
end
|
||||
|
||||
def soap2obj(obj_class, node, info, map)
|
||||
unless node.type == SOAP::SOAPBase64::Type
|
||||
return false
|
||||
end
|
||||
return true, obj_class.new(node.string)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
97
vendor/rails/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb
vendored
Normal file
97
vendor/rails/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb
vendored
Normal file
|
@ -0,0 +1,97 @@
|
|||
require 'xmlrpc/marshal'
|
||||
require 'action_web_service/client/xmlrpc_client'
|
||||
|
||||
module XMLRPC # :nodoc:
|
||||
class FaultException # :nodoc:
|
||||
alias :message :faultString
|
||||
end
|
||||
end
|
||||
|
||||
module ActionWebService # :nodoc:
|
||||
module API # :nodoc:
|
||||
class Base # :nodoc:
|
||||
def self.xmlrpc_client(endpoint_uri, options={})
|
||||
ActionWebService::Client::XmlRpc.new self, endpoint_uri, options
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Protocol # :nodoc:
|
||||
module XmlRpc # :nodoc:
|
||||
def self.included(base)
|
||||
base.register_protocol(XmlRpcProtocol)
|
||||
end
|
||||
|
||||
class XmlRpcProtocol < AbstractProtocol # :nodoc:
|
||||
def self.create(controller)
|
||||
XmlRpcProtocol.new
|
||||
end
|
||||
|
||||
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 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, protocol_options={})
|
||||
if return_value && return_type
|
||||
return_value = value_to_xmlrpc_wire_format(return_value, return_type)
|
||||
end
|
||||
return_value = false if return_value.nil?
|
||||
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|
|
||||
member_value = value[name]
|
||||
next if member_value.nil?
|
||||
struct[name.to_s] = value_to_xmlrpc_wire_format(member_value, type)
|
||||
end
|
||||
struct
|
||||
elsif value.is_a?(ActiveRecord::Base)
|
||||
struct = {}
|
||||
value.attributes.each do |key, member_value|
|
||||
next if member_value.nil?
|
||||
struct[key.to_s] = member_value
|
||||
end
|
||||
struct
|
||||
elsif value.is_a?(ActionWebService::Base64)
|
||||
XMLRPC::Base64.new(value)
|
||||
elsif value.is_a?(Exception) && !value.is_a?(XMLRPC::FaultException)
|
||||
XMLRPC::FaultException.new(2, value.message)
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
284
vendor/rails/actionwebservice/lib/action_web_service/scaffolding.rb
vendored
Normal file
284
vendor/rails/actionwebservice/lib/action_web_service/scaffolding.rb
vendored
Normal file
|
@ -0,0 +1,284 @@
|
|||
require 'benchmark'
|
||||
require 'pathname'
|
||||
|
||||
module ActionWebService
|
||||
module Scaffolding # :nodoc:
|
||||
class ScaffoldingError < ActionWebServiceError # :nodoc:
|
||||
end
|
||||
|
||||
def self.append_features(base)
|
||||
super
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
|
||||
# Web service invocation scaffolding provides a way to quickly invoke web service methods in a controller. The
|
||||
# generated scaffold actions have default views to let you enter the method parameters and view the
|
||||
# results.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# class ApiController < ActionController
|
||||
# web_service_scaffold :invoke
|
||||
# end
|
||||
#
|
||||
# This example generates an +invoke+ action in the +ApiController+ that you can navigate to from
|
||||
# your browser, select the API method, enter its parameters, and perform the invocation.
|
||||
#
|
||||
# If you want to customize the default views, create the following views in "app/views":
|
||||
#
|
||||
# * <tt>action_name/methods.rhtml</tt>
|
||||
# * <tt>action_name/parameters.rhtml</tt>
|
||||
# * <tt>action_name/result.rhtml</tt>
|
||||
# * <tt>action_name/layout.rhtml</tt>
|
||||
#
|
||||
# Where <tt>action_name</tt> is the name of the action you gave to ClassMethods#web_service_scaffold.
|
||||
#
|
||||
# You can use the default views in <tt>RAILS_DIR/lib/action_web_service/templates/scaffolds</tt> as
|
||||
# a guide.
|
||||
module ClassMethods
|
||||
# Generates web service invocation scaffolding for the current controller. The given action name
|
||||
# can then be used as the entry point for invoking API methods from a web browser.
|
||||
def web_service_scaffold(action_name)
|
||||
add_template_helper(Helpers)
|
||||
module_eval <<-"end_eval", __FILE__, __LINE__
|
||||
def #{action_name}
|
||||
if request.method == :get
|
||||
setup_invocation_assigns
|
||||
render_invocation_scaffold 'methods'
|
||||
end
|
||||
end
|
||||
|
||||
def #{action_name}_method_params
|
||||
if request.method == :get
|
||||
setup_invocation_assigns
|
||||
render_invocation_scaffold 'parameters'
|
||||
end
|
||||
end
|
||||
|
||||
def #{action_name}_submit
|
||||
if request.method == :post
|
||||
setup_invocation_assigns
|
||||
protocol_name = params['protocol'] ? params['protocol'].to_sym : :soap
|
||||
case protocol_name
|
||||
when :soap
|
||||
@protocol = Protocol::Soap::SoapProtocol.create(self)
|
||||
when :xmlrpc
|
||||
@protocol = Protocol::XmlRpc::XmlRpcProtocol.create(self)
|
||||
end
|
||||
bm = Benchmark.measure do
|
||||
@protocol.register_api(@scaffold_service.api)
|
||||
post_params = params['method_params'] ? params['method_params'].dup : nil
|
||||
params = []
|
||||
@scaffold_method.expects.each_with_index do |spec, i|
|
||||
params << post_params[i.to_s]
|
||||
end if @scaffold_method.expects
|
||||
params = @scaffold_method.cast_expects(params)
|
||||
method_name = public_method_name(@scaffold_service.name, @scaffold_method.public_name)
|
||||
@method_request_xml = @protocol.encode_request(method_name, params, @scaffold_method.expects)
|
||||
new_request = @protocol.encode_action_pack_request(@scaffold_service.name, @scaffold_method.public_name, @method_request_xml)
|
||||
prepare_request(new_request, @scaffold_service.name, @scaffold_method.public_name)
|
||||
@request = new_request
|
||||
if @scaffold_container.dispatching_mode != :direct
|
||||
request.parameters['action'] = @scaffold_service.name
|
||||
end
|
||||
dispatch_web_service_request
|
||||
@method_response_xml = @response.body
|
||||
method_name, obj = @protocol.decode_response(@method_response_xml)
|
||||
return if handle_invocation_exception(obj)
|
||||
@method_return_value = @scaffold_method.cast_returns(obj)
|
||||
end
|
||||
@method_elapsed = bm.real
|
||||
add_instance_variables_to_assigns
|
||||
reset_invocation_response
|
||||
render_invocation_scaffold 'result'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def setup_invocation_assigns
|
||||
@scaffold_class = self.class
|
||||
@scaffold_action_name = "#{action_name}"
|
||||
@scaffold_container = WebServiceModel::Container.new(self)
|
||||
if params['service'] && params['method']
|
||||
@scaffold_service = @scaffold_container.services.find{ |x| x.name == params['service'] }
|
||||
@scaffold_method = @scaffold_service.api_methods[params['method']]
|
||||
end
|
||||
add_instance_variables_to_assigns
|
||||
end
|
||||
|
||||
def render_invocation_scaffold(action)
|
||||
customized_template = "\#{self.class.controller_path}/#{action_name}/\#{action}"
|
||||
default_template = scaffold_path(action)
|
||||
if template_exists?(customized_template)
|
||||
content = @template.render_file(customized_template)
|
||||
else
|
||||
content = @template.render_file(default_template, false)
|
||||
end
|
||||
@template.instance_variable_set("@content_for_layout", content)
|
||||
if self.active_layout.nil?
|
||||
render_file(scaffold_path("layout"))
|
||||
else
|
||||
render_file(self.active_layout, "200 OK", true)
|
||||
end
|
||||
end
|
||||
|
||||
def scaffold_path(template_name)
|
||||
File.dirname(__FILE__) + "/templates/scaffolds/" + template_name + ".rhtml"
|
||||
end
|
||||
|
||||
def reset_invocation_response
|
||||
erase_render_results
|
||||
@response.headers = ::ActionController::AbstractResponse::DEFAULT_HEADERS.merge("cookie" => [])
|
||||
end
|
||||
|
||||
def public_method_name(service_name, method_name)
|
||||
if web_service_dispatching_mode == :layered && @protocol.is_a?(ActionWebService::Protocol::XmlRpc::XmlRpcProtocol)
|
||||
service_name + '.' + method_name
|
||||
else
|
||||
method_name
|
||||
end
|
||||
end
|
||||
|
||||
def prepare_request(new_request, service_name, method_name)
|
||||
new_request.parameters.update(request.parameters)
|
||||
request.env.each{ |k, v| new_request.env[k] = v unless new_request.env.has_key?(k) }
|
||||
if web_service_dispatching_mode == :layered && @protocol.is_a?(ActionWebService::Protocol::Soap::SoapProtocol)
|
||||
new_request.env['HTTP_SOAPACTION'] = "/\#{controller_name()}/\#{service_name}/\#{method_name}"
|
||||
end
|
||||
end
|
||||
|
||||
def handle_invocation_exception(obj)
|
||||
exception = nil
|
||||
if obj.respond_to?(:detail) && obj.detail.respond_to?(:cause) && obj.detail.cause.is_a?(Exception)
|
||||
exception = obj.detail.cause
|
||||
elsif obj.is_a?(XMLRPC::FaultException)
|
||||
exception = obj
|
||||
end
|
||||
return unless exception
|
||||
reset_invocation_response
|
||||
rescue_action(exception)
|
||||
true
|
||||
end
|
||||
end_eval
|
||||
end
|
||||
end
|
||||
|
||||
module Helpers # :nodoc:
|
||||
def method_parameter_input_fields(method, type, field_name_base, idx, was_structured=false)
|
||||
if type.array?
|
||||
return content_tag('em', "Typed array input fields not supported yet (#{type.name})")
|
||||
end
|
||||
if type.structured?
|
||||
return content_tag('em', "Nested structural types not supported yet (#{type.name})") if was_structured
|
||||
parameters = ""
|
||||
type.each_member do |member_name, member_type|
|
||||
label = method_parameter_label(member_name, member_type)
|
||||
nested_content = method_parameter_input_fields(
|
||||
method,
|
||||
member_type,
|
||||
"#{field_name_base}[#{idx}][#{member_name}]",
|
||||
idx,
|
||||
true)
|
||||
if member_type.custom?
|
||||
parameters << content_tag('li', label)
|
||||
parameters << content_tag('ul', nested_content)
|
||||
else
|
||||
parameters << content_tag('li', label + ' ' + nested_content)
|
||||
end
|
||||
end
|
||||
content_tag('ul', parameters)
|
||||
else
|
||||
# If the data source was structured previously we already have the index set
|
||||
field_name_base = "#{field_name_base}[#{idx}]" unless was_structured
|
||||
|
||||
case type.type
|
||||
when :int
|
||||
text_field_tag "#{field_name_base}"
|
||||
when :string
|
||||
text_field_tag "#{field_name_base}"
|
||||
when :base64
|
||||
text_area_tag "#{field_name_base}", nil, :size => "40x5"
|
||||
when :bool
|
||||
radio_button_tag("#{field_name_base}", "true") + " True" +
|
||||
radio_button_tag("#{field_name_base}", "false") + "False"
|
||||
when :float
|
||||
text_field_tag "#{field_name_base}"
|
||||
when :time, :datetime
|
||||
time = Time.now
|
||||
i = 0
|
||||
%w|year month day hour minute second|.map do |name|
|
||||
i += 1
|
||||
send("select_#{name}", time, :prefix => "#{field_name_base}[#{i}]", :discard_type => true)
|
||||
end.join
|
||||
when :date
|
||||
date = Date.today
|
||||
i = 0
|
||||
%w|year month day|.map do |name|
|
||||
i += 1
|
||||
send("select_#{name}", date, :prefix => "#{field_name_base}[#{i}]", :discard_type => true)
|
||||
end.join
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def method_parameter_label(name, type)
|
||||
name.to_s.capitalize + ' (' + type.human_name(false) + ')'
|
||||
end
|
||||
|
||||
def service_method_list(service)
|
||||
action = @scaffold_action_name + '_method_params'
|
||||
methods = service.api_methods_full.map do |desc, name|
|
||||
content_tag("li", link_to(desc, :action => action, :service => service.name, :method => name))
|
||||
end
|
||||
content_tag("ul", methods.join("\n"))
|
||||
end
|
||||
end
|
||||
|
||||
module WebServiceModel # :nodoc:
|
||||
class Container # :nodoc:
|
||||
attr :services
|
||||
attr :dispatching_mode
|
||||
|
||||
def initialize(real_container)
|
||||
@real_container = real_container
|
||||
@dispatching_mode = @real_container.class.web_service_dispatching_mode
|
||||
@services = []
|
||||
if @dispatching_mode == :direct
|
||||
@services << Service.new(@real_container.controller_name, @real_container)
|
||||
else
|
||||
@real_container.class.web_services.each do |name, obj|
|
||||
@services << Service.new(name, @real_container.instance_eval{ web_service_object(name) })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Service # :nodoc:
|
||||
attr :name
|
||||
attr :object
|
||||
attr :api
|
||||
attr :api_methods
|
||||
attr :api_methods_full
|
||||
|
||||
def initialize(name, real_service)
|
||||
@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|
|
||||
@api_methods[method.public_name.to_s] = method
|
||||
@api_methods_full << [method.to_s, method.public_name.to_s]
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
self.name.camelize
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
68
vendor/rails/actionwebservice/lib/action_web_service/struct.rb
vendored
Normal file
68
vendor/rails/actionwebservice/lib/action_web_service/struct.rb
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
module ActionWebService
|
||||
# To send structured types across the wire, derive from ActionWebService::Struct,
|
||||
# and use +member+ to declare structure members.
|
||||
#
|
||||
# ActionWebService::Struct should be used in method signatures when you want to accept or return
|
||||
# structured types that have no Active Record model class representations, or you don't
|
||||
# want to expose your entire Active Record model to remote callers.
|
||||
#
|
||||
# === Example
|
||||
#
|
||||
# class Person < ActionWebService::Struct
|
||||
# member :id, :int
|
||||
# member :firstnames, [:string]
|
||||
# member :lastname, :string
|
||||
# member :email, :string
|
||||
# end
|
||||
# person = Person.new(:id => 5, :firstname => 'john', :lastname => 'doe')
|
||||
#
|
||||
# Active Record model classes are already implicitly supported in method
|
||||
# signatures.
|
||||
class Struct
|
||||
# Action WebService Struct subclasses should be reloaded by the dispatcher in Rails
|
||||
# when Dependencies.mechanism = :load.
|
||||
include Reloadable::Subclasses
|
||||
|
||||
# If a Hash is given as argument to an ActionWebService::Struct constructor,
|
||||
# it can contain initial values for the structure member.
|
||||
def initialize(values={})
|
||||
if values.is_a?(Hash)
|
||||
values.map{|k,v| __send__('%s=' % k.to_s, v)}
|
||||
end
|
||||
end
|
||||
|
||||
# The member with the given name
|
||||
def [](name)
|
||||
send(name.to_s)
|
||||
end
|
||||
|
||||
# Iterates through each member
|
||||
def each_pair(&block)
|
||||
self.class.members.each do |name, type|
|
||||
yield name, self.__send__(name)
|
||||
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)
|
||||
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
|
||||
END
|
||||
end
|
||||
|
||||
def members # :nodoc:
|
||||
read_inheritable_attribute("struct_members") || {}
|
||||
end
|
||||
|
||||
def member_type(name) # :nodoc:
|
||||
members[name.to_sym]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
26
vendor/rails/actionwebservice/lib/action_web_service/support/class_inheritable_options.rb
vendored
Normal file
26
vendor/rails/actionwebservice/lib/action_web_service/support/class_inheritable_options.rb
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
class Class # :nodoc:
|
||||
def class_inheritable_option(sym, default_value=nil)
|
||||
write_inheritable_attribute sym, default_value
|
||||
class_eval <<-EOS
|
||||
def self.#{sym}(value=nil)
|
||||
if !value.nil?
|
||||
write_inheritable_attribute(:#{sym}, value)
|
||||
else
|
||||
read_inheritable_attribute(:#{sym})
|
||||
end
|
||||
end
|
||||
|
||||
def self.#{sym}=(value)
|
||||
write_inheritable_attribute(:#{sym}, value)
|
||||
end
|
||||
|
||||
def #{sym}
|
||||
self.class.#{sym}
|
||||
end
|
||||
|
||||
def #{sym}=(value)
|
||||
self.class.#{sym} = value
|
||||
end
|
||||
EOS
|
||||
end
|
||||
end
|
222
vendor/rails/actionwebservice/lib/action_web_service/support/signature_types.rb
vendored
Normal file
222
vendor/rails/actionwebservice/lib/action_web_service/support/signature_types.rb
vendored
Normal file
|
@ -0,0 +1,222 @@
|
|||
module ActionWebService # :nodoc:
|
||||
# Action Web Service supports the following base types in a signature:
|
||||
#
|
||||
# [<tt>:int</tt>] Represents an integer value, will be cast to an integer using <tt>Integer(value)</tt>
|
||||
# [<tt>:string</tt>] Represents a string value, will be cast to an string using the <tt>to_s</tt> method on an object
|
||||
# [<tt>:base64</tt>] Represents a Base 64 value, will contain the binary bytes of a Base 64 value sent by the caller
|
||||
# [<tt>:bool</tt>] Represents a boolean value, whatever is passed will be cast to boolean (<tt>true</tt>, '1', 'true', 'y', 'yes' are taken to represent true; <tt>false</tt>, '0', 'false', 'n', 'no' and <tt>nil</tt> represent false)
|
||||
# [<tt>:float</tt>] Represents a floating point value, will be cast to a float using <tt>Float(value)</tt>
|
||||
# [<tt>:time</tt>] Represents a timestamp, will be cast to a <tt>Time</tt> object
|
||||
# [<tt>:datetime</tt>] Represents a timestamp, will be cast to a <tt>DateTime</tt> object
|
||||
# [<tt>:date</tt>] Represents a date, will be cast to a <tt>Date</tt> object
|
||||
#
|
||||
# For structured types, you'll need to pass in the Class objects of
|
||||
# ActionWebService::Struct and ActiveRecord::Base derivatives.
|
||||
module SignatureTypes
|
||||
def canonical_signature(signature) # :nodoc:
|
||||
return nil if signature.nil?
|
||||
unless signature.is_a?(Array)
|
||||
raise(ActionWebServiceError, "Expected signature to be an Array")
|
||||
end
|
||||
i = -1
|
||||
signature.map{ |spec| canonical_signature_entry(spec, i += 1) }
|
||||
end
|
||||
|
||||
def canonical_signature_entry(spec, i) # :nodoc:
|
||||
orig_spec = spec
|
||||
name = "param#{i}"
|
||||
if spec.is_a?(Hash)
|
||||
name, spec = spec.keys.first, spec.values.first
|
||||
end
|
||||
type = spec
|
||||
if spec.is_a?(Array)
|
||||
ArrayType.new(orig_spec, canonical_signature_entry(spec[0], 0), name)
|
||||
else
|
||||
type = canonical_type(type)
|
||||
if type.is_a?(Symbol)
|
||||
BaseType.new(orig_spec, type, name)
|
||||
else
|
||||
StructuredType.new(orig_spec, type, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def canonical_type(type) # :nodoc:
|
||||
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) # :nodoc:
|
||||
name = name.to_sym
|
||||
case name
|
||||
when :int, :integer, :fixnum, :bignum
|
||||
:int
|
||||
when :string, :text
|
||||
:string
|
||||
when :base64, :binary
|
||||
:base64
|
||||
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) # :nodoc:
|
||||
type = canonical_type(type)
|
||||
type.is_a?(Symbol) ? type_name_to_class(type) : type
|
||||
end
|
||||
|
||||
def symbol_name(name) # :nodoc:
|
||||
return name.to_sym if name.is_a?(Symbol) || name.is_a?(String)
|
||||
nil
|
||||
end
|
||||
|
||||
def class_to_type_name(klass) # :nodoc:
|
||||
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 == Base64
|
||||
:base64
|
||||
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) # :nodoc:
|
||||
case canonical_type_name(name)
|
||||
when :int
|
||||
Integer
|
||||
when :string
|
||||
String
|
||||
when :base64
|
||||
Base64
|
||||
when :bool
|
||||
TrueClass
|
||||
when :float
|
||||
Float
|
||||
when :time
|
||||
Time
|
||||
when :date
|
||||
Date
|
||||
when :datetime
|
||||
DateTime
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def derived_from?(ancestor, child) # :nodoc:
|
||||
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 :spec
|
||||
attr :type
|
||||
attr :type_class
|
||||
attr :name
|
||||
|
||||
def initialize(spec, type, name)
|
||||
@spec = spec
|
||||
@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
|
||||
|
||||
def human_name(show_name=true)
|
||||
type_type = array? ? element_type.type.to_s : self.type.to_s
|
||||
str = array? ? (type_type + '[]') : type_type
|
||||
show_name ? (str + " " + name.to_s) : str
|
||||
end
|
||||
end
|
||||
|
||||
class ArrayType < BaseType # :nodoc:
|
||||
attr :element_type
|
||||
|
||||
def initialize(spec, element_type, name)
|
||||
super(spec, 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 = -1
|
||||
@type_class.columns.each do |column|
|
||||
yield column.name, canonical_signature_entry(column.type, i += 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def custom?
|
||||
true
|
||||
end
|
||||
|
||||
def structured?
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
class Base64 < String # :nodoc:
|
||||
end
|
||||
end
|
65
vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/layout.rhtml
vendored
Normal file
65
vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/layout.rhtml
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
<html>
|
||||
<head>
|
||||
<title><%= @scaffold_class.wsdl_service_name %> Web Service</title>
|
||||
<style>
|
||||
body { background-color: #fff; color: #333; }
|
||||
|
||||
body, p, ol, ul, td {
|
||||
font-family: verdana, arial, helvetica, sans-serif;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #eee;
|
||||
padding: 10px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
a { color: #000; }
|
||||
a:visited { color: #666; }
|
||||
a:hover { color: #fff; background-color:#000; }
|
||||
|
||||
.fieldWithErrors {
|
||||
padding: 2px;
|
||||
background-color: red;
|
||||
display: table;
|
||||
}
|
||||
|
||||
#errorExplanation {
|
||||
width: 400px;
|
||||
border: 2px solid red;
|
||||
padding: 7px;
|
||||
padding-bottom: 12px;
|
||||
margin-bottom: 20px;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
#errorExplanation h2 {
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
padding: 5px 5px 5px 15px;
|
||||
font-size: 12px;
|
||||
margin: -7px;
|
||||
background-color: #c00;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#errorExplanation p {
|
||||
color: #333;
|
||||
margin-bottom: 0;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#errorExplanation ul li {
|
||||
font-size: 12px;
|
||||
list-style: square;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<%= @content_for_layout %>
|
||||
|
||||
</body>
|
||||
</html>
|
6
vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/methods.rhtml
vendored
Normal file
6
vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/methods.rhtml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
<% @scaffold_container.services.each do |service| %>
|
||||
|
||||
<h4>API Methods for <%= service %></h4>
|
||||
<%= service_method_list(service) %>
|
||||
|
||||
<% end %>
|
29
vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml
vendored
Normal file
29
vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
<h4>Method Invocation Details for <em><%= @scaffold_service %>#<%= @scaffold_method.public_name %></em></h4>
|
||||
|
||||
<%= form_tag :action => @scaffold_action_name + '_submit' %>
|
||||
<%= hidden_field_tag "service", @scaffold_service.name %>
|
||||
<%= hidden_field_tag "method", @scaffold_method.public_name %>
|
||||
|
||||
<p>
|
||||
<label for="protocol">Protocol:</label><br />
|
||||
<%= select_tag 'protocol', options_for_select([['SOAP', 'soap'], ['XML-RPC', 'xmlrpc']], @params['protocol']) %>
|
||||
</p>
|
||||
|
||||
<% if @scaffold_method.expects %>
|
||||
|
||||
<strong>Method Parameters:</strong><br />
|
||||
<% @scaffold_method.expects.each_with_index do |type, i| %>
|
||||
<p>
|
||||
<label for="method_params[<%= i %>]"><%= method_parameter_label(type.name, type) %> </label><br />
|
||||
<%= method_parameter_input_fields(@scaffold_method, type, "method_params", i) %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<% end %>
|
||||
|
||||
<%= submit_tag "Invoke" %>
|
||||
<%= end_form_tag %>
|
||||
|
||||
<p>
|
||||
<%= link_to "Back", :action => @scaffold_action_name %>
|
||||
</p>
|
30
vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/result.rhtml
vendored
Normal file
30
vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/result.rhtml
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
<h4>Method Invocation Result for <em><%= @scaffold_service %>#<%= @scaffold_method.public_name %></em></h4>
|
||||
|
||||
<p>
|
||||
Invocation took <tt><%= '%f' % @method_elapsed %></tt> seconds
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Return Value:</strong><br />
|
||||
<pre>
|
||||
<%= h @method_return_value.inspect %>
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Request XML:</strong><br />
|
||||
<pre>
|
||||
<%= h @method_request_xml %>
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Response XML:</strong><br />
|
||||
<pre>
|
||||
<%= h @method_response_xml %>
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<%= link_to "Back", :action => @scaffold_action_name + '_method_params', :method => @scaffold_method.public_name, :service => @scaffold_service.name %>
|
||||
</p>
|
110
vendor/rails/actionwebservice/lib/action_web_service/test_invoke.rb
vendored
Normal file
110
vendor/rails/actionwebservice/lib/action_web_service/test_invoke.rb
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
require 'test/unit'
|
||||
|
||||
module Test # :nodoc:
|
||||
module Unit # :nodoc:
|
||||
class TestCase # :nodoc:
|
||||
private
|
||||
# invoke the specified API method
|
||||
def invoke_direct(method_name, *args)
|
||||
prepare_request('api', 'api', method_name, *args)
|
||||
@controller.process(@request, @response)
|
||||
decode_rpc_response
|
||||
end
|
||||
alias_method :invoke, :invoke_direct
|
||||
|
||||
# invoke the specified API method on the specified service
|
||||
def invoke_delegated(service_name, method_name, *args)
|
||||
prepare_request(service_name.to_s, service_name, method_name, *args)
|
||||
@controller.process(@request, @response)
|
||||
decode_rpc_response
|
||||
end
|
||||
|
||||
# invoke the specified layered API method on the correct service
|
||||
def invoke_layered(service_name, method_name, *args)
|
||||
prepare_request('api', service_name, method_name, *args)
|
||||
@controller.process(@request, @response)
|
||||
decode_rpc_response
|
||||
end
|
||||
|
||||
# ---------------------- internal ---------------------------
|
||||
|
||||
def prepare_request(action, service_name, api_method_name, *args)
|
||||
@request.recycle!
|
||||
@request.request_parameters['action'] = action
|
||||
@request.env['REQUEST_METHOD'] = 'POST'
|
||||
@request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
|
||||
@request.env['RAW_POST_DATA'] = encode_rpc_call(service_name, api_method_name, *args)
|
||||
case protocol
|
||||
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 ActionWebService::Protocol::XmlRpc::XmlRpcProtocol
|
||||
@request.env.delete('HTTP_SOAPACTION')
|
||||
end
|
||||
end
|
||||
|
||||
def encode_rpc_call(service_name, api_method_name, *args)
|
||||
case @controller.web_service_dispatching_mode
|
||||
when :direct
|
||||
api = @controller.class.web_service_api
|
||||
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]
|
||||
raise ArgumentError, "wrong number of arguments for rpc call (#{args.length} for #{method.expects.length})" unless args.length == method.expects.length
|
||||
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 = protocol.decode_response(@response.body)
|
||||
exception = is_exception?(return_value)
|
||||
raise exception if exception
|
||||
return_value
|
||||
end
|
||||
|
||||
def public_method_name(service_name, api_method_name)
|
||||
public_name = service_api(service_name).public_api_method_name(api_method_name)
|
||||
if @controller.web_service_dispatching_mode == :layered && protocol.is_a?(ActionWebService::Protocol::XmlRpc::XmlRpcProtocol)
|
||||
'%s.%s' % [service_name.to_s, public_name]
|
||||
else
|
||||
public_name
|
||||
end
|
||||
end
|
||||
|
||||
def service_api(service_name)
|
||||
case @controller.web_service_dispatching_mode
|
||||
when :direct
|
||||
@controller.class.web_service_api
|
||||
when :delegated, :layered
|
||||
@controller.web_service_object(service_name.to_sym).class.web_service_api
|
||||
end
|
||||
end
|
||||
|
||||
def protocol
|
||||
if @protocol.nil?
|
||||
@protocol ||= ActionWebService::Protocol::Soap::SoapProtocol.create(@controller)
|
||||
else
|
||||
case @protocol
|
||||
when :xmlrpc
|
||||
@protocol = ActionWebService::Protocol::XmlRpc::XmlRpcProtocol.create(@controller)
|
||||
when :soap
|
||||
@protocol = ActionWebService::Protocol::Soap::SoapProtocol.create(@controller)
|
||||
else
|
||||
@protocol
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def is_exception?(obj)
|
||||
case protocol
|
||||
when :soap, ActionWebService::Protocol::Soap::SoapProtocol
|
||||
(obj.respond_to?(:detail) && obj.detail.respond_to?(:cause) && \
|
||||
obj.detail.cause.is_a?(Exception)) ? obj.detail.cause : nil
|
||||
when :xmlrpc, ActionWebService::Protocol::XmlRpc::XmlRpcProtocol
|
||||
obj.is_a?(XMLRPC::FaultException) ? obj : nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
9
vendor/rails/actionwebservice/lib/action_web_service/version.rb
vendored
Normal file
9
vendor/rails/actionwebservice/lib/action_web_service/version.rb
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
module ActionWebService
|
||||
module VERSION #:nodoc:
|
||||
MAJOR = 1
|
||||
MINOR = 1
|
||||
TINY = 6
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue