summaryrefslogtreecommitdiffstats
path: root/vendor/plugins/actionwebservice/lib
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/plugins/actionwebservice/lib')
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service.rb66
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/api.rb297
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/base.rb38
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/casting.rb138
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/client.rb3
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/client/base.rb28
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/client/soap_client.rb113
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb58
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/container.rb3
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/container/action_controller_container.rb93
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/container/delegated_container.rb86
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/container/direct_container.rb69
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/dispatcher.rb2
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/abstract.rb207
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb379
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/invocation.rb202
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/protocol.rb4
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/protocol/abstract.rb112
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/protocol/discovery.rb37
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb176
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb235
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb122
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/scaffolding.rb283
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/struct.rb64
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/support/class_inheritable_options.rb26
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/support/signature_types.rb226
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.erb65
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.rhtml0
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.erb6
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.rhtml0
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.erb29
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml0
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/result.erb30
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/result.rhtml0
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/test_invoke.rb110
-rw-r--r--vendor/plugins/actionwebservice/lib/action_web_service/version.rb9
-rw-r--r--vendor/plugins/actionwebservice/lib/actionwebservice.rb1
37 files changed, 3317 insertions, 0 deletions
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service.rb b/vendor/plugins/actionwebservice/lib/action_web_service.rb
new file mode 100644
index 000000000..0632dd1ec
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service.rb
@@ -0,0 +1,66 @@
+#--
+# Copyright (C) 2005 Leon Breedt
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#++
+
+begin
+ require 'active_support'
+ require 'action_controller'
+ require 'active_record'
+rescue LoadError
+ require 'rubygems'
+ gem 'activesupport', '>= 1.0.2'
+ gem 'actionpack', '>= 1.6.0'
+ gem 'activerecord', '>= 1.9.0'
+end
+
+$:.unshift(File.dirname(__FILE__) + "/action_web_service/vendor/")
+
+require 'action_web_service/support/class_inheritable_options'
+require 'action_web_service/support/signature_types'
+require 'action_web_service/base'
+require 'action_web_service/client'
+require 'action_web_service/invocation'
+require 'action_web_service/api'
+require 'action_web_service/casting'
+require 'action_web_service/struct'
+require 'action_web_service/container'
+require 'action_web_service/protocol'
+require 'action_web_service/dispatcher'
+require 'action_web_service/scaffolding'
+
+ActionWebService::Base.class_eval do
+ include ActionWebService::Container::Direct
+ include ActionWebService::Invocation
+end
+
+ActionController::Base.class_eval do
+ include ActionWebService::Protocol::Discovery
+ include ActionWebService::Protocol::Soap
+ include ActionWebService::Protocol::XmlRpc
+ include ActionWebService::Container::Direct
+ include ActionWebService::Container::Delegated
+ include ActionWebService::Container::ActionController
+ include ActionWebService::Invocation
+ include ActionWebService::Dispatcher
+ include ActionWebService::Dispatcher::ActionController
+ include ActionWebService::Scaffolding
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/api.rb b/vendor/plugins/actionwebservice/lib/action_web_service/api.rb
new file mode 100644
index 000000000..d16dc420d
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/api.rb
@@ -0,0 +1,297 @@
+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
+ # Whether to transform the public API method names into camel-cased names
+ class_inheritable_option :inflect_names, true
+
+ # By default only HTTP POST requests are processed
+ class_inheritable_option :allowed_http_methods, [ :post ]
+
+ # 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
+ #
+ # class ProjectsApi < ActionWebService::API::Base
+ # api_method :getCount, :returns => [:int]
+ # end
+ #
+ # ProjectsApi.has_api_method?('GetCount') #=> false
+ # ProjectsApi.has_api_method?(:getCount) #=> true
+ 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
+ #
+ # class ProjectsApi < ActionWebService::API::Base
+ # api_method :getCount, :returns => [:int]
+ # end
+ #
+ # ProjectsApi.has_api_method?(:getCount) #=> false
+ # ProjectsApi.has_api_method?('GetCount') #=> true
+ 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
+ #
+ # ProjectsApi.public_api_method_name('GetCount') #=> "GetCount"
+ # ProjectsApi.public_api_method_name(:getCount) #=> "GetCount"
+ 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
+ #
+ # class ProjectsApi < ActionWebService::API::Base
+ # api_method :getCount, :returns => [:int]
+ # end
+ #
+ # ProjectsApi.api_method_name('GetCount') #=> :getCount
+ 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.
+ #
+ # class ProjectsApi < ActionWebService::API::Base
+ # api_method :getCount, :returns => [:int]
+ # api_method :getCompletedCount, :returns => [:int]
+ # end
+ #
+ # ProjectsApi.api_methods #=>
+ # {:getCount=>#<ActionWebService::API::Method:0x24379d8 ...>,
+ # :getCompletedCount=>#<ActionWebService::API::Method:0x2437794 ...>}
+ # ProjectsApi.api_methods[:getCount].public_name #=> "GetCount"
+ def api_methods
+ read_inheritable_attribute("api_methods") || {}
+ end
+
+ # The Method instance for the given public API method name, if any
+ #
+ # class ProjectsApi < ActionWebService::API::Base
+ # api_method :getCount, :returns => [:int]
+ # api_method :getCompletedCount, :returns => [:int]
+ # end
+ #
+ # ProjectsApi.public_api_method_instance('GetCount') #=> <#<ActionWebService::API::Method:0x24379d8 ...>
+ # ProjectsApi.public_api_method_instance(:getCount) #=> nil
+ 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
+ #
+ # class ProjectsApi < ActionWebService::API::Base
+ # api_method :getCount, :returns => [:int]
+ # api_method :getCompletedCount, :returns => [:int]
+ # end
+ #
+ # ProjectsApi.api_method_instance(:getCount) #=> <ActionWebService::API::Method:0x24379d8 ...>
+ # ProjectsApi.api_method_instance('GetCount') #=> <ActionWebService::API::Method:0x24379d8 ...>
+ 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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/base.rb b/vendor/plugins/actionwebservice/lib/action_web_service/base.rb
new file mode 100644
index 000000000..6282061d8
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/base.rb
@@ -0,0 +1,38 @@
+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
+ # Whether to report exceptions back to the caller in the protocol's exception
+ # format
+ class_inheritable_option :web_service_exception_reporting, true
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/casting.rb b/vendor/plugins/actionwebservice/lib/action_web_service/casting.rb
new file mode 100644
index 000000000..71f422eae
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/casting.rb
@@ -0,0 +1,138 @@
+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 :decimal
+ BigDecimal(value.to_s)
+ when :time
+ value = "%s/%s/%s %s:%s:%s" % value.values_at(*%w[2 3 1 4 5 6]) if value.kind_of?(Hash)
+ value.kind_of?(Time) ? value : Time.parse(value.to_s)
+ when :date
+ value = "%s/%s/%s" % value.values_at(*%w[2 3 1]) if value.kind_of?(Hash)
+ value.kind_of?(Date) ? value : Date.parse(value.to_s)
+ when :datetime
+ value = "%s/%s/%s %s:%s:%s" % value.values_at(*%w[2 3 1 4 5 6]) if value.kind_of?(Hash)
+ value.kind_of?(DateTime) ? value : 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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/client.rb b/vendor/plugins/actionwebservice/lib/action_web_service/client.rb
new file mode 100644
index 000000000..2a1e33054
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/client.rb
@@ -0,0 +1,3 @@
+require 'action_web_service/client/base'
+require 'action_web_service/client/soap_client'
+require 'action_web_service/client/xmlrpc_client'
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/client/base.rb b/vendor/plugins/actionwebservice/lib/action_web_service/client/base.rb
new file mode 100644
index 000000000..9dada7bf9
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/client/base.rb
@@ -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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/client/soap_client.rb b/vendor/plugins/actionwebservice/lib/action_web_service/client/soap_client.rb
new file mode 100644
index 000000000..ebabd8ea8
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/client/soap_client.rb
@@ -0,0 +1,113 @@
+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
+ # provides access to the underlying soap driver
+ attr_reader :driver
+
+ # 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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb b/vendor/plugins/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb
new file mode 100644
index 000000000..42b5c5d4f
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb
@@ -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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/container.rb b/vendor/plugins/actionwebservice/lib/action_web_service/container.rb
new file mode 100644
index 000000000..13d9d8ab5
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/container.rb
@@ -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'
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/container/action_controller_container.rb b/vendor/plugins/actionwebservice/lib/action_web_service/container/action_controller_container.rb
new file mode 100644
index 000000000..bbc28083c
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/container/action_controller_container.rb
@@ -0,0 +1,93 @@
+module ActionWebService # :nodoc:
+ module Container # :nodoc:
+ module ActionController # :nodoc:
+ def self.included(base) # :nodoc:
+ class << base
+ include ClassMethods
+ alias_method_chain :inherited, :api
+ alias_method_chain :web_service_api, :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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/container/delegated_container.rb b/vendor/plugins/actionwebservice/lib/action_web_service/container/delegated_container.rb
new file mode 100644
index 000000000..5477f8d10
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/container/delegated_container.rb
@@ -0,0 +1,86 @@
+module ActionWebService # :nodoc:
+ module Container # :nodoc:
+ module Delegated # :nodoc:
+ class ContainerError < ActionWebServiceError # :nodoc:
+ end
+
+ def self.included(base) # :nodoc:
+ 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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/container/direct_container.rb b/vendor/plugins/actionwebservice/lib/action_web_service/container/direct_container.rb
new file mode 100644
index 000000000..8818d8f45
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/container/direct_container.rb
@@ -0,0 +1,69 @@
+module ActionWebService # :nodoc:
+ module Container # :nodoc:
+ module Direct # :nodoc:
+ class ContainerError < ActionWebServiceError # :nodoc:
+ end
+
+ def self.included(base) # :nodoc:
+ 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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher.rb b/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher.rb
new file mode 100644
index 000000000..601d83137
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher.rb
@@ -0,0 +1,2 @@
+require 'action_web_service/dispatcher/abstract'
+require 'action_web_service/dispatcher/action_controller_dispatcher'
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/abstract.rb b/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
new file mode 100644
index 000000000..cb94d649e
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
@@ -0,0 +1,207 @@
+require 'benchmark'
+
+module ActionWebService # :nodoc:
+ module Dispatcher # :nodoc:
+ class DispatcherError < ActionWebService::ActionWebServiceError # :nodoc:
+ def initialize(*args)
+ super
+ set_backtrace(caller)
+ end
+ end
+
+ def self.included(base) # :nodoc:
+ 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, nil]
+ 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)
+ response_type = (api_method.returns ? api_method.returns[0] : nil)
+ return_value = api_method.cast_returns(return_value)
+ else
+ response_type = ActionWebService::SignatureTypes.canonical_signature_entry(return_value.class, 0)
+ end
+ responses << [return_value, response_type]
+ rescue Exception => e
+ responses << [{ 'faultCode' => 3, 'faultString' => e.message }, nil]
+ end
+ end
+ invocation = invocations[0]
+ invocation.protocol.encode_multicall_response(responses, 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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb b/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb
new file mode 100644
index 000000000..f9995197a
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb
@@ -0,0 +1,379 @@
+require 'benchmark'
+require 'builder/xmlmarkup'
+
+module ActionWebService # :nodoc:
+ module Dispatcher # :nodoc:
+ module ActionController # :nodoc:
+ def self.included(base) # :nodoc:
+ class << base
+ include ClassMethods
+ alias_method_chain :inherited, :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
+ method = request.method.to_s.upcase
+ allowed_methods = self.class.web_service_api ? (self.class.web_service_api.allowed_http_methods || []) : [ :post ]
+ allowed_methods = allowed_methods.map{|m| m.to_s.upcase }
+ if !allowed_methods.include?(method)
+ render :text => "#{method} not supported", :status=>500
+ return
+ end
+ 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}", :status => 500
+ end
+ end
+
+ def web_service_direct_invoke(invocation)
+ invocation.method_named_params.each do |name, value|
+ params[name] = value
+ end
+ web_service_direct_invoke_without_controller(invocation)
+ 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', :status => 500
+ end
+ end
+
+ private
+ def base_uri
+ host = request.host_with_port
+ 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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/invocation.rb b/vendor/plugins/actionwebservice/lib/action_web_service/invocation.rb
new file mode 100644
index 000000000..2a9121ee2
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/invocation.rb
@@ -0,0 +1,202 @@
+module ActionWebService # :nodoc:
+ module Invocation # :nodoc:
+ class InvocationError < ActionWebService::ActionWebServiceError # :nodoc:
+ end
+
+ def self.included(base) # :nodoc:
+ 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.included(base)
+ base.class_eval do
+ alias_method_chain :perform_invocation, :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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/protocol.rb b/vendor/plugins/actionwebservice/lib/action_web_service/protocol.rb
new file mode 100644
index 000000000..053e9cb4b
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/protocol.rb
@@ -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'
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/protocol/abstract.rb b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/abstract.rb
new file mode 100644
index 000000000..fff5f622c
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/abstract.rb
@@ -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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/protocol/discovery.rb b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/discovery.rb
new file mode 100644
index 000000000..3d4e0818d
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/discovery.rb
@@ -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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
new file mode 100644
index 000000000..1bce496a7
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
@@ -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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb
new file mode 100644
index 000000000..187339627
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb
@@ -0,0 +1,235 @@
+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)
+ @registry.add(::BigDecimal, SOAP::SOAPDouble, SOAP::Mapping::Registry::BasetypeFactory, {:derived_class => true})
+ 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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb
new file mode 100644
index 000000000..dfa4afc67
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb
@@ -0,0 +1,122 @@
+require 'xmlrpc/marshal'
+require 'action_web_service/client/xmlrpc_client'
+
+module XMLRPC # :nodoc:
+ class FaultException # :nodoc:
+ alias :message :faultString
+ end
+
+ class Create
+ def wrong_type(value)
+ if BigDecimal === value
+ [true, value.to_f]
+ else
+ false
+ end
+ end
+ 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)
+ rescue
+ return nil
+ 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 encode_multicall_response(responses, protocol_options={})
+ result = responses.map do |return_value, return_type|
+ if return_value && return_type
+ return_value = value_to_xmlrpc_wire_format(return_value, return_type)
+ return_value = [return_value] unless return_value.nil?
+ end
+ return_value = false if return_value.nil?
+ return_value
+ end
+ raw_response = XMLRPC::Marshal.dump_response(result)
+ Response.new(raw_response, 'text/xml', result)
+ 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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/scaffolding.rb b/vendor/plugins/actionwebservice/lib/action_web_service/scaffolding.rb
new file mode 100644
index 000000000..f94a7ee91
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/scaffolding.rb
@@ -0,0 +1,283 @@
+require 'benchmark'
+require 'pathname'
+
+module ActionWebService
+ module Scaffolding # :nodoc:
+ class ScaffoldingError < ActionWebServiceError # :nodoc:
+ end
+
+ def self.included(base)
+ 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.erb</tt>
+ # * <tt>action_name/parameters.erb</tt>
+ # * <tt>action_name/result.erb</tt>
+ # * <tt>action_name/layout.erb</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__ + 1
+ 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)
+ self.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
+ 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
+ end
+ end
+
+ def scaffold_path(template_name)
+ File.dirname(__FILE__) + "/templates/scaffolds/" + template_name + ".erb"
+ 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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/struct.rb b/vendor/plugins/actionwebservice/lib/action_web_service/struct.rb
new file mode 100644
index 000000000..00eafc169
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/struct.rb
@@ -0,0 +1,64 @@
+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
+ # 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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/support/class_inheritable_options.rb b/vendor/plugins/actionwebservice/lib/action_web_service/support/class_inheritable_options.rb
new file mode 100644
index 000000000..4d1c2ed47
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/support/class_inheritable_options.rb
@@ -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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/support/signature_types.rb b/vendor/plugins/actionwebservice/lib/action_web_service/support/signature_types.rb
new file mode 100644
index 000000000..66c86bf6d
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/support/signature_types.rb
@@ -0,0 +1,226 @@
+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 :decimal
+ :decimal
+ 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 :decimal
+ BigDecimal
+ 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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.erb b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.erb
new file mode 100644
index 000000000..167613f68
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.erb
@@ -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>
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.rhtml b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.rhtml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.rhtml
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.erb b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.erb
new file mode 100644
index 000000000..60dfe23f0
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.erb
@@ -0,0 +1,6 @@
+<% @scaffold_container.services.each do |service| %>
+
+ <h4>API Methods for <%= service %></h4>
+ <%= service_method_list(service) %>
+
+<% end %>
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.rhtml b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.rhtml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.rhtml
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.erb b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.erb
new file mode 100644
index 000000000..767284e0d
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.erb
@@ -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') do -%>
+<%= 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 -%>
+
+<p>
+<%= link_to "Back", :action => @scaffold_action_name %>
+</p>
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/result.erb b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/result.erb
new file mode 100644
index 000000000..5317688fc
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/result.erb
@@ -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>
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/result.rhtml b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/result.rhtml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/result.rhtml
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/test_invoke.rb b/vendor/plugins/actionwebservice/lib/action_web_service/test_invoke.rb
new file mode 100644
index 000000000..7e714c941
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/test_invoke.rb
@@ -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})" if method && method.expects && 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
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/version.rb b/vendor/plugins/actionwebservice/lib/action_web_service/version.rb
new file mode 100644
index 000000000..a1b3d5929
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/version.rb
@@ -0,0 +1,9 @@
+module ActionWebService
+ module VERSION #:nodoc:
+ MAJOR = 1
+ MINOR = 2
+ TINY = 5
+
+ STRING = [MAJOR, MINOR, TINY].join('.')
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/actionwebservice.rb b/vendor/plugins/actionwebservice/lib/actionwebservice.rb
new file mode 100644
index 000000000..25e3aa8e8
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/actionwebservice.rb
@@ -0,0 +1 @@
+require 'action_web_service'