Skip to content

Commit

Permalink
first short at following wsdl imports
Browse files Browse the repository at this point in the history
this required a pretty major re-architecture and we're not even done.
  • Loading branch information
rubiii committed May 9, 2013
1 parent b16b9e2 commit da11893
Show file tree
Hide file tree
Showing 29 changed files with 948 additions and 322 deletions.
25 changes: 10 additions & 15 deletions lib/wasabi.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'wasabi/version'
require 'wasabi/document'
require 'wasabi/resolver'
require 'wasabi/importer'

class Wasabi

Expand All @@ -12,38 +13,32 @@ class Wasabi

def initialize(wsdl, request = nil)
resolver = Resolver.new(request)
importer = Importer.new(resolver, self)

xml = resolver.resolve(wsdl)
document = Nokogiri.XML(xml)

@parser = Parser.new(document)
@documents, @schemas = importer.import(wsdl)
end

attr_reader :parser
attr_reader :documents, :schemas

def service_name
@parser.service_name
@documents.service_name
end

# TODO: move this to an operation.
# TODO: move this up to the operation.
def endpoint
@parser.endpoint
@documents.endpoint
end

def target_namespace
@parser.target_namespace
@documents.target_namespace
end

def namespaces
@parser.namespaces
end

def schemas
@parser.schemas
@documents.namespaces
end

def operation(operation_name)
@parser.operations[operation_name]
@documents.operations[operation_name]
end

end
123 changes: 39 additions & 84 deletions lib/wasabi/document.rb
Original file line number Diff line number Diff line change
@@ -1,115 +1,70 @@
require "nokogiri"
require "wasabi/resolver"
require "wasabi/parser"
require 'wasabi/schema'
require 'wasabi/legacy_operation_parser'

class Wasabi

# = Wasabi::Document
#
# Represents a WSDL document.
class Document

# Accepts a WSDL +document+ to parse.
def initialize(document = nil)
self.document = document
def initialize(document, wsdl)
@document = document
@wsdl = wsdl
end

attr_accessor :document, :request, :xml

alias_method :document?, :document

# Returns the SOAP endpoint.
def endpoint
@endpoint ||= parser.endpoint
def service_name
@document.root['name']
end

# Sets the SOAP endpoint.
attr_writer :endpoint

# Returns the target namespace.
def target_namespace
@target_namespace ||= parser.target_namespace
@document.root['targetNamespace']
end

# Sets the target namespace.
attr_writer :target_namespace

# Returns a list of available SOAP actions.
def soap_actions
@soap_actions ||= parser.operations.keys
end

# Returns a map of SOAP operations.
def operations
@operations ||= parser.operations
def namespaces
@namespaces ||= collect_namespaces(@document, *schema_nodes)
end

# Returns the service name.
def service_name
@service_name ||= parser.service_name
def schemas
@schemas ||= schema_nodes.map { |node| Schema.new(node, @wsdl) }
end

attr_writer :service_name
def imports
imports = []

def namespaces
parser.namespaces
end

# XXX: legacy interface. change savon to use the new types interface.
def type_namespaces
@type_namespaces ||= begin
namespaces = []
parser.schemas.types.each do |name, type|
namespaces << [[name], type.namespace]
type.children.each { |child| namespaces << [[name, child[:name]], type.namespace] }
end if document
namespaces
@document.xpath('/wsdl:definitions/wsdl:import', 'wsdl' => Wasabi::WSDL).each do |node|
location = node['location']
imports << location if location
end
end

# XXX: legacy interface. change savon to use the new types interface.
def type_definitions
@type_definitions ||= begin
result = []
parser.schemas.types.each do |name, type|
type.children.each do |child|
# how can we properly handle anyType elements here?
# see Type#parse_element
next unless child[:type]

tag, nsid = child[:type].split(":").reverse
result << [[name, child[:name]], tag] if user_defined(nsid)
end
end if document
result
end
imports
end

# Returns whether the given +namespace+ was defined manually.
def user_defined(namespace)
uri = parser.namespaces[namespace]
!(uri =~ %r{^http://schemas.xmlsoap.org} || uri =~ %r{^http://www.w3.org})
def operations
@operations ||= LegacyOperationParser.new(@document).operations
end

# Returns the raw WSDL document.
# Can be used as a hook to extend the library.
def xml
@xml ||= Resolver.new(request).resolve(document)
def service_node
@document.at_xpath('/wsdl:definitions/wsdl:service', 'wsdl' => Wasabi::WSDL)
end

def parser
@parser ||= guard_parse && parse
private

def schema_nodes
@schema_nodes ||= begin
types = @document.at_xpath('/wsdl:definitions/wsdl:types', 'wsdl' => Wasabi::WSDL)
types ? types.element_children : []
end
end

private
def collect_namespaces(*nodes)
namespaces = {}

def guard_parse
return true if document
raise ArgumentError, "Wasabi needs a WSDL document"
end
nodes.each do |node|
node.namespaces.each do |k, v|
key = k.sub(/^xmlns:/, '')
namespaces[key] = v
end
end

def parse
Parser.new Nokogiri::XML(xml)
namespaces.delete('xmlns')
namespaces
end

end
Expand Down
57 changes: 57 additions & 0 deletions lib/wasabi/document_collection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
require 'uri'

class Wasabi
class DocumentCollection
include Enumerable

def initialize
@documents = []
end

def <<(document)
@documents << document
end

def each(&block)
@documents.each(&block)
end

def service_name
@service_name ||= first.service_name
end

def target_namespace
@target_namespace ||= first.target_namespace
end

def target_namespace
@target_namespace ||= first.target_namespace
end

def namespaces
@namespaces ||= inject({}) { |memo, document| memo.merge(document.namespaces) }
end

def operations
@operations ||= inject({}) { |memo, document| memo.merge(document.operations) }
end

# TODO: this works for now, but it should be moved into the Operation,
# because there can be different endpoints for different operations.
def endpoint
return @endpoint if @endpoint

if service = first.service_node
endpoint = service.at_xpath(".//soap11:address/@location", 'soap11' => Wasabi::SOAP_1_1)
endpoint ||= service.at_xpath(service_node, ".//soap12:address/@location", 'soap12' => Wasabi::SOAP_1_2)
end

begin
@endpoint = URI(URI.escape(endpoint.to_s)) if endpoint
rescue URI::InvalidURIError
@endpoint = nil
end
end

end
end
40 changes: 40 additions & 0 deletions lib/wasabi/importer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require 'nokogiri'
require 'wasabi/document'
require 'wasabi/document_collection'
require 'wasabi/schema_collection'

class Wasabi
class Importer

def initialize(resolver, wsdl)
@resolver = resolver
@wsdl = wsdl
end

def import(location)
documents = DocumentCollection.new
schemas = SchemaCollection.new

import! [location] do |document|
documents << document
schemas.push(document.schemas)
end

[documents, schemas]
end

private

def import!(locations, &block)
locations.each do |location|
xml = @resolver.resolve(location)
document = Document.new Nokogiri.XML(xml), @wsdl

block.call(document)

import! document.imports, &block
end
end

end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
require 'wasabi/operation'

class Wasabi
class Operations
class LegacyOperationParser

def initialize(parser)
@parser = parser
def initialize(document)
@document = document

@operations = {}
parse
Expand All @@ -21,12 +21,12 @@ def parse
end

def parse_messages
messages = @parser.document.root.element_children.select { |node| node.name == 'message' }
messages = @document.root.element_children.select { |node| node.name == 'message' }
@messages = Hash[messages.map { |node| [node['name'], node] }]
end

def parse_port_types
port_types = @parser.document.root.element_children.select { |node| node.name == 'portType' }
port_types = @document.root.element_children.select { |node| node.name == 'portType' }
@port_types = Hash[port_types.map { |node| [node['name'], node] }]
end

Expand All @@ -40,7 +40,7 @@ def parse_port_type_operations
end

def parse_operations
operations = @parser.document.xpath("wsdl:definitions/wsdl:binding/wsdl:operation", 'wsdl' => Wasabi::WSDL)
operations = @document.xpath("wsdl:definitions/wsdl:binding/wsdl:operation", 'wsdl' => Wasabi::WSDL)
operations.each do |operation|
name = operation.attribute("name").to_s

Expand Down

0 comments on commit da11893

Please sign in to comment.