aboutsummaryrefslogtreecommitdiffstats
path: root/actionwebservice/lib/action_web_service/vendor/ws/marshaling
diff options
context:
space:
mode:
Diffstat (limited to 'actionwebservice/lib/action_web_service/vendor/ws/marshaling')
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/marshaling/abstract.rb17
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb224
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb116
3 files changed, 357 insertions, 0 deletions
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/abstract.rb b/actionwebservice/lib/action_web_service/vendor/ws/marshaling/abstract.rb
new file mode 100644
index 0000000000..53120e1447
--- /dev/null
+++ b/actionwebservice/lib/action_web_service/vendor/ws/marshaling/abstract.rb
@@ -0,0 +1,17 @@
+module WS
+ module Marshaling
+ class AbstractMarshaler
+ def marshal(param)
+ raise NotImplementedError
+ end
+
+ def unmarshal(param)
+ raise NotImplementedError
+ end
+
+ def register_type(type)
+ nil
+ end
+ end
+ end
+end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb b/actionwebservice/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb
new file mode 100644
index 0000000000..99e2a7ff28
--- /dev/null
+++ b/actionwebservice/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb
@@ -0,0 +1,224 @@
+require 'soap/mapping'
+require 'xsd/ns'
+
+module WS
+ module Marshaling
+ SoapEncodingNS = 'http://schemas.xmlsoap.org/soap/encoding/'
+
+ class SoapError < WSError
+ end
+
+ class SoapMarshaler < AbstractMarshaler
+ attr :registry
+ attr_accessor :type_namespace
+
+ def initialize(type_namespace='')
+ @type_namespace = type_namespace
+ @registry = SOAP::Mapping::Registry.new
+ @spec2binding = {}
+ end
+
+ def marshal(param)
+ if param.info.type.is_a?(Array)
+ (class << param.value; self; end).class_eval do
+ define_method(:arytype) do
+ param.info.data.qname
+ end
+ end
+ end
+ if param.value.is_a?(Exception)
+ detail = SOAP::Mapping::SOAPException.new(param.value)
+ soap_obj = SOAP::SOAPFault.new(
+ SOAP::SOAPString.new('Server'),
+ SOAP::SOAPString.new(param.value.to_s),
+ SOAP::SOAPString.new(self.class.name),
+ SOAP::Mapping.obj2soap(detail))
+ else
+ soap_obj = SOAP::Mapping.obj2soap(param.value, @registry)
+ end
+ SoapForeignObject.new(param, soap_obj)
+ end
+
+ def unmarshal(obj)
+ param = obj.param
+ soap_object = obj.soap_object
+ soap_type = soap_object ? soap_object.type : nil
+ value = soap_object ? SOAP::Mapping.soap2obj(soap_object, @registry) : nil
+ param.value = value
+ param.info.type = value.class
+ mapping = @registry.find_mapped_soap_class(param.info.type) rescue nil
+ if soap_type && soap_type.name == 'Array' && soap_type.namespace == SoapEncodingNS
+ param.info.data = SoapBinding.new(soap_object.arytype, mapping)
+ else
+ param.info.data = SoapBinding.new(soap_type, mapping)
+ end
+ param
+ end
+
+ def register_type(spec)
+ if @spec2binding.has_key?(spec)
+ return @spec2binding[spec]
+ end
+
+ klass = BaseTypes.canonical_param_type_class(spec)
+ if klass.is_a?(Array)
+ type_class = klass[0]
+ else
+ type_class = klass
+ end
+
+ type_binding = nil
+ if (mapping = @registry.find_mapped_soap_class(type_class) rescue nil)
+ qname = mapping[2] ? mapping[2][:type] : nil
+ qname ||= soap_base_type_name(mapping[0])
+ type_binding = SoapBinding.new(qname, mapping)
+ else
+ qname = XSD::QName.new(@type_namespace, soap_type_name(type_class.name))
+ @registry.add(type_class,
+ SOAP::SOAPStruct,
+ typed_struct_factory(type_class),
+ { :type => qname })
+ mapping = @registry.find_mapped_soap_class(type_class)
+ type_binding = SoapBinding.new(qname, mapping)
+ end
+
+ array_binding = nil
+ if klass.is_a?(Array)
+ array_mapping = @registry.find_mapped_soap_class(Array) rescue nil
+ if (array_mapping && !array_mapping[1].is_a?(SoapTypedArrayFactory)) || array_mapping.nil?
+ @registry.set(Array,
+ SOAP::SOAPArray,
+ SoapTypedArrayFactory.new)
+ array_mapping = @registry.find_mapped_soap_class(Array)
+ end
+ qname = XSD::QName.new(@type_namespace, soap_type_name(type_class.name) + 'Array')
+ array_binding = SoapBinding.new(qname, array_mapping, type_binding)
+ end
+
+ @spec2binding[spec] = array_binding ? array_binding : type_binding
+ end
+
+ protected
+ def typed_struct_factory(type_class)
+ if Object.const_defined?('ActiveRecord')
+ if WS.derived_from?(ActiveRecord::Base, type_class)
+ qname = XSD::QName.new(@type_namespace, soap_type_name(type_class.name))
+ type_class.instance_variable_set('@qname', qname)
+ return SoapActiveRecordStructFactory.new
+ end
+ end
+ SOAP::Mapping::Registry::TypedStructFactory
+ end
+
+ def soap_type_name(type_name)
+ type_name.gsub(/::/, '..')
+ end
+
+ def soap_base_type_name(type)
+ xsd_type = type.ancestors.find{|c| c.const_defined? 'Type'}
+ xsd_type ? xsd_type.const_get('Type') : XSD::XSDAnySimpleType::Type
+ end
+ end
+
+ class SoapForeignObject
+ attr_accessor :param
+ attr_accessor :soap_object
+
+ def initialize(param, soap_object)
+ @param = param
+ @soap_object = soap_object
+ end
+ end
+
+ class SoapBinding
+ attr :qname
+ attr :mapping
+ attr :element_binding
+
+ def initialize(qname, mapping, element_binding=nil)
+ @qname = qname
+ @mapping = mapping
+ @element_binding = element_binding
+ end
+
+ def is_custom_type?
+ is_typed_array? || is_typed_struct?
+ end
+
+ def is_typed_array?
+ @mapping[1].is_a?(WS::Marshaling::SoapTypedArrayFactory)
+ end
+
+ def is_typed_struct?
+ @mapping[1] == SOAP::Mapping::Registry::TypedStructFactory || \
+ @mapping[1].is_a?(WS::Marshaling::SoapActiveRecordStructFactory)
+ end
+
+ def each_member(&block)
+ unless is_typed_struct?
+ raise(SoapError, "not a structured type")
+ end
+ end
+
+ def type_name
+ is_custom_type? ? @qname.name : nil
+ end
+
+ def qualified_type_name(ns=nil)
+ if is_custom_type?
+ "#{ns ? ns : @qname.namespace}:#{@qname.name}"
+ else
+ ns = XSD::NS.new
+ ns.assign(XSD::Namespace, SOAP::XSDNamespaceTag)
+ xsd_klass = mapping[0].ancestors.find{|c| c.const_defined?('Type')}
+ return ns.name(XSD::AnyTypeName) unless xsd_klass
+ ns.name(xsd_klass.const_get('Type'))
+ end
+ end
+ end
+
+ class SoapActiveRecordStructFactory < SOAP::Mapping::Factory
+ def obj2soap(soap_class, obj, info, map)
+ unless obj.is_a?(ActiveRecord::Base)
+ return nil
+ end
+ soap_obj = soap_class.new(obj.class.instance_variable_get('@qname'))
+ obj.attributes.each do |key, value|
+ soap_obj[key] = SOAP::Mapping._obj2soap(value, map)
+ end
+ soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ unless node.type == obj_class.instance_variable_get('@qname')
+ return false
+ end
+ obj = obj_class.new
+ node.each do |key, value|
+ obj[key] = value.data
+ end
+ obj.instance_variable_set('@new_record', false)
+ return true, obj
+ end
+ end
+
+ class SoapTypedArrayFactory < SOAP::Mapping::Factory
+ def obj2soap(soap_class, obj, info, map)
+ unless obj.respond_to?(:arytype)
+ return nil
+ end
+ soap_obj = soap_class.new(SOAP::ValueArrayName, 1, obj.arytype)
+ mark_marshalled_obj(obj, soap_obj)
+ obj.each do |item|
+ child = SOAP::Mapping._obj2soap(item, map)
+ soap_obj.add(child)
+ end
+ soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ return false
+ end
+ end
+ end
+end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb b/actionwebservice/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb
new file mode 100644
index 0000000000..87154f87e1
--- /dev/null
+++ b/actionwebservice/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb
@@ -0,0 +1,116 @@
+module WS
+ module Marshaling
+ class XmlRpcError < WSError
+ end
+
+ class XmlRpcMarshaler < AbstractMarshaler
+ def initialize
+ @caster = BaseTypeCaster.new
+ @spec2binding = {}
+ end
+
+ def marshal(param)
+ transform_outbound(param)
+ end
+
+ def unmarshal(obj)
+ obj.param.value = transform_inbound(obj.param)
+ obj.param
+ end
+
+ def typed_unmarshal(obj, spec)
+ param = obj.param
+ param.info.data = register_type(spec)
+ param.value = transform_inbound(param)
+ param
+ end
+
+ def register_type(spec)
+ if @spec2binding.has_key?(spec)
+ return @spec2binding[spec]
+ end
+
+ klass = BaseTypes.canonical_param_type_class(spec)
+ type_binding = nil
+ if klass.is_a?(Array)
+ type_binding = XmlRpcArrayBinding.new(klass[0])
+ else
+ type_binding = XmlRpcBinding.new(klass)
+ end
+
+ @spec2binding[spec] = type_binding
+ end
+
+ def transform_outbound(param)
+ binding = param.info.data
+ case binding
+ when XmlRpcArrayBinding
+ param.value.map{|x| cast_outbound(x, binding.element_klass)}
+ when XmlRpcBinding
+ cast_outbound(param.value, param.info.type)
+ end
+ end
+
+ def transform_inbound(param)
+ return param.value if param.info.data.nil?
+ binding = param.info.data
+ param.info.type = binding.klass
+ case binding
+ when XmlRpcArrayBinding
+ param.value.map{|x| cast_inbound(x, binding.element_klass)}
+ when XmlRpcBinding
+ cast_inbound(param.value, param.info.type)
+ end
+ end
+
+ def cast_outbound(value, klass)
+ if BaseTypes.base_type?(klass)
+ @caster.cast(value, klass)
+ elsif value.is_a?(Exception)
+ XMLRPC::FaultException.new(2, value.message)
+ elsif Object.const_defined?('ActiveRecord') && value.is_a?(ActiveRecord::Base)
+ value.attributes
+ else
+ struct = {}
+ value.instance_variables.each do |name|
+ key = name.sub(/^@/, '')
+ struct[key] = value.instance_variable_get(name)
+ end
+ struct
+ end
+ end
+
+ def cast_inbound(value, klass)
+ if BaseTypes.base_type?(klass)
+ value = value.to_time if value.is_a?(XMLRPC::DateTime)
+ @caster.cast(value, klass)
+ elsif value.is_a?(XMLRPC::FaultException)
+ value
+ else
+ obj = klass.new
+ value.each do |name, val|
+ obj.send('%s=' % name.to_s, val)
+ end
+ obj
+ end
+ end
+ end
+
+ class XmlRpcBinding
+ attr :klass
+
+ def initialize(klass)
+ @klass = klass
+ end
+ end
+
+ class XmlRpcArrayBinding < XmlRpcBinding
+ attr :element_klass
+
+ def initialize(element_klass)
+ super(Array)
+ @element_klass = element_klass
+ end
+ end
+ end
+end