soap4r-middleware 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in soap4r-middleware.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+ Soap4r Rack Middleware
2
+ ======================
3
+
4
+ This small library provides a Rack Middleware interface to exposing
5
+ Soap4r server endpoints. This is a lightweight alternative to using
6
+ ActionWebService for exposing SOAP in a Rails application, as well as
7
+ allowing SOAP endpoints in any other Rack-based application. It's been
8
+ tested with Rails 2.3.x, but should work fine in Rails 3 as well.
9
+
10
+ Install
11
+ -------
12
+
13
+ $ gem install soap4r-middleware
14
+
15
+ Usage
16
+ -----
17
+
18
+ First, get yourself some Soap4r endpoint code. The easiest way to do
19
+ this is to generate it from a WSDL file. Details are in the Soap4r
20
+ documentation, or see http://dev.ctor.org/soap4r/wiki/HowtouseWSDL4R ,
21
+ but basically:
22
+
23
+ $ wsdl2ruby.rb --wsdl /path/to/definiton.wsdl --type server
24
+
25
+ You'll get some generated files. One of them will be named
26
+ like `*APIService.rb`, near the bottom will be a class of the same name.
27
+ To enable middleware functionality, you want to copy this class'
28
+ initialization code into a new class that subclasses `Soap4r::Middleware::Base`, and replace the initialize method with a block passed to `setup`. For instance:
29
+
30
+ gem 'soap4r-middleware' # or use Bundler
31
+ require 'soap4r-middleware'
32
+
33
+ class MyAPIMiddleware < Soap4r::Middleware::Base
34
+ setup do
35
+ self.endpoint = %r{^/url/to/soap/endpoint/}
36
+ servant MyAPIPort.new
37
+ MyAPIPort::Methods.each do |definitions|
38
+ opt = definitions.last
39
+ if opt[:request_style] == :document
40
+ @router.add_document_operation(servant, *definitions)
41
+ else
42
+ @router.add_rpc_operation(servant, *definitions)
43
+ end
44
+ end
45
+ self.mapping_registry = UrnMyAPIMappingRegistry::EncodedRegistry
46
+ self.literal_mapping_registry = UrnMyAPIMappingRegistry::LiteralRegistry
47
+ end
48
+ end
49
+
50
+ Then use this middleware anywhere you'd use a Rack middleware. It
51
+ doubles as a Rack application as well, so you can host it directly using
52
+ `run MyAPIMiddleware.new` in your `rackup.ru` file.
53
+
54
+ ### TODO
55
+
56
+ I guess I could wrap `wsdl2ruby.rb` and make this automatic.
57
+
58
+ ### Wait, This is For Seriously??
59
+
60
+ Sometimes you just gotta SOAP. Might as well make it suck as little as
61
+ possible.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,171 @@
1
+ class Soap4r::Middleware::Base
2
+ include SOAP
3
+
4
+ def self.setup
5
+ raise("Please subclass first") if self == Soap4r::Middleware::Base
6
+ @router = ::SOAP::RPC::Router.new(self.class.name)
7
+ yield self
8
+ self
9
+ end
10
+
11
+ def self.router
12
+ @router
13
+ end
14
+
15
+ def self.endpoint=(regex)
16
+ @endpoint = regex
17
+ end
18
+
19
+ def self.endpoint
20
+ @endpoint
21
+ end
22
+
23
+ def initialize(app = nil)
24
+ @app = app
25
+ @endpoint = self.class.endpoint
26
+ unless @endpoint.is_a?(Regexp)
27
+ raise ArgumentError, "Endpoint has not been defined"
28
+ end
29
+ end
30
+
31
+ def call(env)
32
+ if env['PATH_INFO'].match(@endpoint)
33
+ handle(env)
34
+ else
35
+ # we can act as both a middleware and an app
36
+ @app ?
37
+ @app.call(env) :
38
+ [ 404, { "Content-Type" => "text/html" }, "Not Found" ]
39
+ end
40
+ end
41
+
42
+ def handle(env)
43
+ # yeah, all soap calls are over POST
44
+ if env['REQUEST_METHOD'] != 'POST'
45
+ return 405, { 'Content-Length' => '0',
46
+ 'Allow' => 'POST',
47
+ 'Content-Type' => 'text/plain' }, []
48
+ end
49
+
50
+ conn_data = ::SOAP::StreamHandler::ConnectionData.new
51
+ setup_request(conn_data, env)
52
+ conn_data = self.class.router.route(conn_data)
53
+ status, headers, body = setup_response(conn_data, env)
54
+ [ status, headers, body ]
55
+ rescue
56
+ raise # TODO -- do we 500 right here, or let the exception bubble up?
57
+ end
58
+
59
+ def setup_request(conn_data, env)
60
+ # TODO: we're reading the whole input here, which kind of stinks if rack is
61
+ # reading from the client on demand. We can't just pass in the rack input
62
+ # object, since REXML needs an IO that responds to :eof? -- we'd need a
63
+ # wrapper IO-like object.
64
+ conn_data.receive_string = env['rack.input'].read
65
+ conn_data.receive_contenttype = env['CONTENT_TYPE']
66
+ conn_data.soapaction = parse_soapaction(env['HTTP_SOAPAction'])
67
+ end
68
+
69
+ def setup_response(conn_data, env)
70
+ status = 200
71
+ headers = {}
72
+ body = []
73
+ headers['content-type'] = conn_data.send_contenttype
74
+ # TODO: cookies?
75
+ if conn_data.is_nocontent
76
+ status = 202 # ACCEPTED
77
+ elsif conn_data.is_fault
78
+ status = 500 # INTERNAL_SERVER_ERROR
79
+ else
80
+ body = conn_data.send_string
81
+ end
82
+ return status, headers, body
83
+ end
84
+
85
+ def parse_soapaction(soapaction)
86
+ if !soapaction.nil? and !soapaction.empty?
87
+ if /\A"(.+)"\z/ =~ soapaction
88
+ return $1
89
+ end
90
+ end
91
+ nil
92
+ end
93
+
94
+ class << self
95
+
96
+ # SOAP interface
97
+
98
+ def mapping_registry
99
+ router.mapping_registry
100
+ end
101
+
102
+ def mapping_registry=(mapping_registry)
103
+ router.mapping_registry = mapping_registry
104
+ end
105
+
106
+ def literal_mapping_registry
107
+ router.literal_mapping_registry
108
+ end
109
+
110
+ def literal_mapping_registry=(literal_mapping_registry)
111
+ router.literal_mapping_registry = literal_mapping_registry
112
+ end
113
+
114
+ def generate_explicit_type
115
+ router.generate_explicit_type
116
+ end
117
+
118
+ def generate_explicit_type=(generate_explicit_type)
119
+ router.generate_explicit_type = generate_explicit_type
120
+ end
121
+
122
+ # servant entry interface
123
+
124
+ def add_rpc_servant(obj, namespace = self.default_namespace)
125
+ router.add_rpc_servant(obj, namespace)
126
+ end
127
+ alias add_servant add_rpc_servant
128
+
129
+ def add_headerhandler(obj)
130
+ router.add_headerhandler(obj)
131
+ end
132
+ alias add_rpc_headerhandler add_headerhandler
133
+
134
+ def filterchain
135
+ router.filterchain
136
+ end
137
+
138
+ # method entry interface
139
+
140
+ def add_rpc_method(obj, name, *param)
141
+ add_rpc_method_with_namespace_as(default_namespace, obj, name, name, *param)
142
+ end
143
+ alias add_method add_rpc_method
144
+
145
+ def add_rpc_method_as(obj, name, name_as, *param)
146
+ add_rpc_method_with_namespace_as(default_namespace, obj, name, name_as, *param)
147
+ end
148
+ alias add_method_as add_rpc_method_as
149
+
150
+ def add_rpc_method_with_namespace(namespace, obj, name, *param)
151
+ add_rpc_method_with_namespace_as(namespace, obj, name, name, *param)
152
+ end
153
+ alias add_method_with_namespace add_rpc_method_with_namespace
154
+
155
+ def add_rpc_method_with_namespace_as(namespace, obj, name, name_as, *param)
156
+ qname = XSD::QName.new(namespace, name_as)
157
+ soapaction = nil
158
+ param_def = SOAPMethod.derive_rpc_param_def(obj, name, *param)
159
+ router.add_rpc_operation(obj, qname, soapaction, name, param_def)
160
+ end
161
+ alias add_method_with_namespace_as add_rpc_method_with_namespace_as
162
+
163
+ def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {})
164
+ router.add_rpc_operation(receiver, qname, soapaction, name, param_def, opt)
165
+ end
166
+
167
+ def add_document_operation(receiver, soapaction, name, param_def, opt = {})
168
+ router.add_document_operation(receiver, soapaction, name, param_def, opt)
169
+ end
170
+ end # class << self
171
+ end
@@ -0,0 +1,5 @@
1
+ module Soap4r
2
+ module Middleware
3
+ VERSION = "0.8.0"
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ require 'soap/rpc/router'
2
+
3
+ module Soap4r
4
+ module Middleware
5
+ end
6
+ end
7
+
8
+ require 'soap4r-middleware/base'
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "soap4r-middleware/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "soap4r-middleware"
7
+ s.version = Soap4r::Middleware::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Brian Palmer"]
10
+ s.email = ["brian@codekitchen.net"]
11
+ s.homepage = "https://www.github.com/codekitchen/soap4r-middleware"
12
+ s.summary = %q{Provides a Rack middleware for exposing SOAP server endpoints}
13
+ s.description = %q{Sometimes, you just gotta SOAP.}
14
+
15
+ s.rubyforge_project = "soap4r-middleware"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency 'soap4r', '~> 1.5'
23
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: soap4r-middleware
3
+ version: !ruby/object:Gem::Version
4
+ hash: 63
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 8
9
+ - 0
10
+ version: 0.8.0
11
+ platform: ruby
12
+ authors:
13
+ - Brian Palmer
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-08 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: soap4r
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 5
30
+ segments:
31
+ - 1
32
+ - 5
33
+ version: "1.5"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ description: Sometimes, you just gotta SOAP.
37
+ email:
38
+ - brian@codekitchen.net
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - .gitignore
47
+ - Gemfile
48
+ - README.md
49
+ - Rakefile
50
+ - lib/soap4r-middleware.rb
51
+ - lib/soap4r-middleware/base.rb
52
+ - lib/soap4r-middleware/version.rb
53
+ - soap4r-middleware.gemspec
54
+ has_rdoc: true
55
+ homepage: https://www.github.com/codekitchen/soap4r-middleware
56
+ licenses: []
57
+
58
+ post_install_message:
59
+ rdoc_options: []
60
+
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 3
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ requirements: []
82
+
83
+ rubyforge_project: soap4r-middleware
84
+ rubygems_version: 1.3.7
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Provides a Rack middleware for exposing SOAP server endpoints
88
+ test_files: []
89
+