# WSDL4R - Creating MappingRegistry support. # Copyright (C) 2000-2007 NAKAMURA, Hiroshi . # This program is copyrighted free software by NAKAMURA, Hiroshi. You can # redistribute it and/or modify it under the same terms of Ruby's license; # either the dual license version in 2003, or any later version. require 'wsdl/soap/classDefCreatorSupport' module WSDL module SOAP # requires @defined_const = {}, @dump_with_inner, @modulepath module MappingRegistryCreatorSupport include ClassDefCreatorSupport include XSD::CodeGen def dump_with_inner @dump_with_inner = [] @dump_with_inner.unshift(yield) @dump_with_inner.join("\n") end def dump_complextypedef(mpath, qname, typedef, as_element = nil, opt = {}) case typedef.compoundtype when :TYPE_STRUCT, :TYPE_EMPTY dump_complex_typemap(mpath, qname, typedef, as_element, opt) when :TYPE_ARRAY dump_array_typemap(mpath, qname, typedef, as_element, opt) when :TYPE_SIMPLE dump_simple_typemap(mpath, qname, typedef, as_element, opt) when :TYPE_MAP # mapped as a general Hash nil else raise RuntimeError.new( "unknown kind of complexContent: #{typedef.compoundtype}") end end def dump_array_typemap(mpath, qname, typedef, as_element, opt) if typedef.find_soapenc_arytype if opt[:encoded] dump_encoded_array_typemap(mpath, qname, typedef, as_element, opt) end else dump_literal_array_typemap(mpath, qname, typedef, as_element, opt) end end def dump_complex_typemap(mpath, qname, typedef, as_element, opt) var = {} define_dump_class(var, mpath, qname, typedef, as_element, opt) schema_ns = (var[:schema_name] || var[:schema_type]).namespace if var[:schema_type] and typedef.base var[:schema_basetype] = typedef.base end parentmodule = var[:class] parsed_element = parse_elements(typedef.elements, qname.namespace, parentmodule, opt) if typedef.choice? parsed_element.unshift(:choice) end var[:schema_element] = dump_schema_element_definition(parsed_element, 2) unless typedef.attributes.empty? var[:schema_attribute] = define_attribute(typedef.attributes) end assign_const(schema_ns, 'Ns') dump_entry(@varname, var) end def dump_simple_typemap(mpath, qname, typedef, as_element, opt) var = {} define_dump_class(var, mpath, qname, typedef, as_element, opt) schema_ns = (var[:schema_name] || var[:schema_type]).namespace unless typedef.attributes.empty? var[:schema_attribute] = define_attribute(typedef.attributes) end assign_const(schema_ns, 'Ns') dump_entry(@varname, var) end def dump_schema_element_definition(definition, indent = 0) return '[]' if definition.empty? sp = ' ' * indent if definition[0] == :choice definition.shift "[ :choice,\n" + dump_schema_element(definition, indent + 2) + "\n" + sp + "]" elsif definition[0].is_a?(::Array) "[\n" + dump_schema_element(definition, indent + 2) + "\n" + sp + "]" else varname, name, type, occurrence = definition '[' + [ varname.dump, dump_type(name, type), dump_occurrence(occurrence) ].compact.join(', ') + ']' end end def dump_schema_element(schema_element, indent = 0) sp = ' ' * indent delimiter = ",\n" + sp sp + schema_element.collect { |definition| dump_schema_element_definition(definition, indent) }.join(delimiter) end def dump_type(name, type) if name assign_const(name.namespace, 'Ns') '[' + ndq(type) + ', ' + dqname(name) + ']' else ndq(type) end end def dump_occurrence(occurrence) if occurrence and occurrence != [1, 1] # default minoccurs, maxoccurs = occurrence maxoccurs ||= 'nil' "[#{minoccurs}, #{maxoccurs}]" end end def parse_elements(elements, base_namespace, mpath, opt) schema_element = [] any = false elements.each do |element| case element when XMLSchema::Any # only 1 is allowed for now. raise RuntimeError.new("duplicated 'any'") if any any = true varname = 'any' # not used eleqname = XSD::AnyTypeName type = nil occurrence = nil schema_element << [varname, eleqname, type, occurrence] when XMLSchema::Element next if element.ref == SchemaName typebase = @modulepath if element.anonymous_type? child_opt = { :qualified => (element.elementform == 'qualified'), :is_anonymous => true } @dump_with_inner << dump_complextypedef(mpath, element.name, element.local_complextype, nil, child_opt) typebase = mpath end type = create_type_name(typebase, element) name = name_element(element).name varname = safevarname(name) if element.map_as_array? if type type += '[]' else type = '[]' end end # nil means @@schema_ns + varname eleqname = element.name || element.ref if eleqname && varname == name && eleqname.namespace == base_namespace eleqname = nil end occurrence = [element.minoccurs, element.maxoccurs] schema_element << [varname, eleqname, type, occurrence] when WSDL::XMLSchema::Sequence child_schema_element = parse_elements(element.elements, base_namespace, mpath, opt) schema_element << child_schema_element when WSDL::XMLSchema::Choice child_schema_element = parse_elements(element.elements, base_namespace, mpath, opt) if !element.map_as_array? # choice + maxOccurs="unbounded" is treated just as 'all' now. child_schema_element.unshift(:choice) end schema_element << child_schema_element when WSDL::XMLSchema::Group if element.content.nil? warn("no group definition found: #{element}") next end child_schema_element = parse_elements(element.content.elements, base_namespace, mpath, opt) schema_element.concat(child_schema_element) else raise RuntimeError.new("unknown type: #{element}") end end schema_element end def define_attribute(attributes) schema_attribute = [] attributes.each do |attribute| name = name_attribute(attribute) if klass = attribute_basetype(attribute) type = klass.name else warn("unresolved attribute type #{attribute.type} for #{name}") type = nil end schema_attribute << [name, type] end "{\n " + schema_attribute.collect { |name, type| assign_const(name.namespace, 'Ns') dqname(name) + ' => ' + ndq(type) }.join(",\n ") + "\n }" end def dump_entry(regname, var) "#{regname}.register(\n " + [ dump_entry_item(var, :class), dump_entry_item(var, :soap_class), dump_entry_item(var, :schema_name, :qname), dump_entry_item(var, :schema_type, :qname), dump_entry_item(var, :is_anonymous), dump_entry_item(var, :schema_basetype, :qname), dump_entry_item(var, :schema_qualified), dump_entry_item(var, :schema_element), dump_entry_item(var, :schema_attribute) ].compact.join(",\n ") + "\n)\n" end def dump_entry_item(var, key, dump_type = :none) if var.key?(key) case dump_type when :none ":#{key} => #{var[key]}" when :string if @defined_const.key?(var[key]) ":#{key} => #{@defined_const[var[key]]}" else ":#{key} => #{ndq(var[key])}" end when :qname qname = var[key] if @defined_const.key?(qname.namespace) ns = @defined_const[qname.namespace] else ns = ndq(qname.namespace) end ":#{key} => XSD::QName.new(#{ns}, #{ndq(qname.name)})" else raise "Unknown dump type: #{dump_type}" end end end def dump_simpletypedef(mpath, qname, simpletype, as_element = nil, opt = {}) if simpletype.restriction dump_simpletypedef_restriction(mpath, qname, simpletype, as_element, opt) elsif simpletype.list dump_simpletypedef_list(mpath, qname, simpletype, as_element, opt) elsif simpletype.union dump_simpletypedef_union(mpath, qname, simpletype, as_element, opt) else raise RuntimeError.new("unknown kind of simpletype: #{simpletype}") end end def dump_simpletypedef_restriction(mpath, qname, typedef, as_element, opt) restriction = typedef.restriction unless restriction.enumeration? # not supported. minlength? return nil end var = {} define_dump_class(var, mpath, qname, typedef, as_element, opt) schema_ns = (var[:schema_name] || var[:schema_type]).namespace assign_const(schema_ns, 'Ns') dump_entry(@varname, var) end def dump_simpletypedef_list(mpath, qname, typedef, as_element, opt) nil end def dump_simpletypedef_union(mpath, qname, typedef, as_element, opt) nil end DEFAULT_ITEM_NAME = XSD::QName.new(nil, 'item') def dump_literal_array_typemap(mpath, qname, typedef, as_element, opt) var = {} define_dump_class(var, mpath, qname, typedef, as_element, opt) schema_ns = (var[:schema_name] || var[:schema_type]).namespace parsed_element = parse_elements(typedef.elements, qname.namespace, var[:class], opt) if parsed_element.empty? parsed_element = [create_array_element_definition(typedef, mpath)] end var[:schema_element] = dump_schema_element_definition(parsed_element, 2) assign_const(schema_ns, 'Ns') dump_entry(@varname, var) end def dump_encoded_array_typemap(mpath, qname, typedef, as_element, opt) arytype = typedef.find_arytype || XSD::AnyTypeName type = XSD::QName.new(arytype.namespace, arytype.name.sub(/\[(?:,)*\]$/, '')) return <<__EOD__ #{@varname}.set( #{mapped_class_name(qname, mpath)}, ::SOAP::SOAPArray, ::SOAP::Mapping::EncodedRegistry::TypedArrayFactory, { :type => #{dqname(type)} } ) __EOD__ end # used when "soapenc:arrayType" definition def create_array_element_definition(typedef, mpath) child_type = typedef.child_type child_element = typedef.find_aryelement if child_type == XSD::AnyTypeName type = nil elsif child_element if klass = element_basetype(child_element) type = klass.name else typename = child_element.type || child_element.name type = mapped_class_name(typename, mpath) end elsif child_type type = mapped_class_name(child_type, mpath) else type = nil end occurrence = [0, nil] if child_element and child_element.name if child_element.map_as_array? type << '[]' if type occurrence = [child_element.minoccurs, child_element.maxoccurs] end child_element_name = child_element.name else child_element_name = DEFAULT_ITEM_NAME end [child_element_name.name, child_element_name, type, occurrence] end def define_dump_class(var, mpath, qname, typedef, as_element, opt) var[:class] = mapped_class_name(qname, mpath) if as_element var[:schema_name] = as_element schema_ns = as_element.namespace elsif typedef.name.nil? var[:schema_name] = qname schema_ns = qname.namespace else var[:schema_type] = qname schema_ns = qname.namespace end var[:is_anonymous] = opt[:is_anonymous] if opt.key?(:is_anonymous) # true, false, or nil if opt.key?(:qualified) var[:schema_qualified] = opt[:qualified].to_s end end end end end