wash_out_fork 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/.travis.yml +36 -0
- data/Appraisals +25 -0
- data/CHANGELOG.md +102 -0
- data/Gemfile +17 -0
- data/Guardfile +12 -0
- data/LICENSE +22 -0
- data/README.md +242 -0
- data/Rakefile +25 -0
- data/app/helpers/wash_out_fork_helper.rb +110 -0
- data/app/views/wash_out_fork/document/error.builder +9 -0
- data/app/views/wash_out_fork/document/response.builder +8 -0
- data/app/views/wash_out_fork/document/wsdl.builder +68 -0
- data/app/views/wash_out_fork/rpc/error.builder +10 -0
- data/app/views/wash_out_fork/rpc/response.builder +9 -0
- data/app/views/wash_out_fork/rpc/wsdl.builder +68 -0
- data/gemfiles/rails_3.2.13.gemfile +21 -0
- data/gemfiles/rails_4.0.0.gemfile +20 -0
- data/gemfiles/rails_4.1.0.gemfile +20 -0
- data/gemfiles/rails_4.2.0.gemfile +20 -0
- data/gemfiles/rails_5.0.0.beta2.gemfile +19 -0
- data/gemfiles/rails_5.0.0.gemfile +19 -0
- data/init.rb +1 -0
- data/lib/wash_out_fork.rb +60 -0
- data/lib/wash_out_fork/configurable.rb +41 -0
- data/lib/wash_out_fork/dispatcher.rb +232 -0
- data/lib/wash_out_fork/engine.rb +12 -0
- data/lib/wash_out_fork/middleware.rb +41 -0
- data/lib/wash_out_fork/model.rb +29 -0
- data/lib/wash_out_fork/param.rb +200 -0
- data/lib/wash_out_fork/router.rb +131 -0
- data/lib/wash_out_fork/soap.rb +48 -0
- data/lib/wash_out_fork/soap_config.rb +93 -0
- data/lib/wash_out_fork/type.rb +29 -0
- data/lib/wash_out_fork/version.rb +3 -0
- data/lib/wash_out_fork/wsse.rb +101 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +51 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +23 -0
- data/spec/dummy/config/environments/test.rb +30 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +8 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/stylesheets/.gitkeep +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/fixtures/nested_refs_to_arrays.xml +19 -0
- data/spec/fixtures/ref_to_one_array.xml +11 -0
- data/spec/fixtures/refs_to_arrays.xml +16 -0
- data/spec/lib/wash_out/dispatcher_spec.rb +206 -0
- data/spec/lib/wash_out/middleware_spec.rb +33 -0
- data/spec/lib/wash_out/param_spec.rb +94 -0
- data/spec/lib/wash_out/router_spec.rb +50 -0
- data/spec/lib/wash_out/type_spec.rb +41 -0
- data/spec/lib/wash_out_spec.rb +797 -0
- data/spec/spec_helper.rb +88 -0
- data/wash_out_fork.gemspec +20 -0
- metadata +130 -0
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'wash_out_fork'
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'wash_out_fork/configurable'
|
2
|
+
require 'wash_out_fork/soap_config'
|
3
|
+
require 'wash_out_fork/soap'
|
4
|
+
require 'wash_out_fork/engine'
|
5
|
+
require 'wash_out_fork/param'
|
6
|
+
require 'wash_out_fork/dispatcher'
|
7
|
+
require 'wash_out_fork/soap'
|
8
|
+
require 'wash_out_fork/router'
|
9
|
+
require 'wash_out_fork/type'
|
10
|
+
require 'wash_out_fork/model'
|
11
|
+
require 'wash_out_fork/wsse'
|
12
|
+
require 'wash_out_fork/middleware'
|
13
|
+
|
14
|
+
module WashOutFork
|
15
|
+
def self.root
|
16
|
+
File.expand_path '../..', __FILE__
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module ActionDispatch::Routing
|
21
|
+
class Mapper
|
22
|
+
# Adds the routes for a SOAP endpoint at +controller+.
|
23
|
+
def wash_out_fork(controller_name, options={})
|
24
|
+
if @scope
|
25
|
+
scope_frame = @scope.respond_to?(:frame) ? @scope.frame : @scope
|
26
|
+
options.each{ |key, value| scope_frame[key] = value }
|
27
|
+
end
|
28
|
+
|
29
|
+
controller_class_name = [scope_frame[:module], controller_name].compact.join("/").underscore
|
30
|
+
|
31
|
+
match "#{controller_name}/wsdl" => "#{controller_name}#_generate_wsdl", :via => :get, :format => false,
|
32
|
+
:as => "#{controller_class_name}_wsdl"
|
33
|
+
match "#{controller_name}/action" => WashOutFork::Router.new(controller_class_name), :via => [:get, :post],
|
34
|
+
:defaults => { :controller => controller_class_name, :action => 'soap' }, :format => false,
|
35
|
+
:as => "#{controller_class_name}_soap"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Mime::Type.register "application/soap+xml", :soap
|
41
|
+
ActiveRecord::Base.send :extend, WashOutFork::Model if defined?(ActiveRecord)
|
42
|
+
|
43
|
+
ActionController::Renderers.add :soap do |what, options|
|
44
|
+
_render_soap(what, options)
|
45
|
+
end
|
46
|
+
|
47
|
+
ActionController::Base.class_eval do
|
48
|
+
|
49
|
+
# Define a SOAP service. The function has no required +options+:
|
50
|
+
# but allow any of :parser, :namespace, :wsdl_style, :snakecase_input,
|
51
|
+
# :camelize_wsdl, :wsse_username, :wsse_password and :catch_xml_errors.
|
52
|
+
#
|
53
|
+
# Any of the the params provided allows for overriding the defaults
|
54
|
+
# (like supporting multiple namespaces instead of application wide such)
|
55
|
+
#
|
56
|
+
def self.soap_service(options={})
|
57
|
+
include WashOutFork::SOAP
|
58
|
+
self.soap_config = options
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module WashOutFork
|
2
|
+
module Configurable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
cattr_reader :soap_config
|
7
|
+
class_variable_set :@@soap_config, WashOutFork::SoapConfig.new({})
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
def soap_config=(obj)
|
13
|
+
|
14
|
+
unless obj.is_a?(Hash)
|
15
|
+
raise "Value needs to be a Hash."
|
16
|
+
end
|
17
|
+
|
18
|
+
if class_variable_defined?(:@@soap_config)
|
19
|
+
class_variable_get(:@@soap_config).configure obj
|
20
|
+
else
|
21
|
+
class_variable_set :@@soap_config, WashOutFork::SoapConfig.new(obj)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def soap_config=(obj)
|
27
|
+
|
28
|
+
unless obj.is_a?(Hash)
|
29
|
+
raise "Value needs to be a Hash."
|
30
|
+
end
|
31
|
+
|
32
|
+
class_eval do
|
33
|
+
if class_variable_defined?(:@@soap_config)
|
34
|
+
class_variable_get(:@@soap_config).configure obj
|
35
|
+
else
|
36
|
+
class_variable_set :@@soap_config, WashOutFork::SoapConfig.new(obj)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
module WashOutFork
|
2
|
+
# The WashOutFork::Dispatcher module should be included in a controller acting
|
3
|
+
# as a SOAP endpoint. It includes actions for generating WSDL and handling
|
4
|
+
# SOAP requests.
|
5
|
+
module Dispatcher
|
6
|
+
# A SOAPError exception can be raised to return a correct SOAP error
|
7
|
+
# response.
|
8
|
+
class SOAPError < Exception
|
9
|
+
attr_accessor :code
|
10
|
+
def initialize(message, code=nil)
|
11
|
+
super(message)
|
12
|
+
@code = code
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class ProgrammerError < Exception; end
|
17
|
+
|
18
|
+
def _authenticate_wsse
|
19
|
+
begin
|
20
|
+
xml_security = request.env['wash_out_fork.soap_data'].values_at(:envelope, :Envelope).compact.first
|
21
|
+
xml_security = xml_security.values_at(:header, :Header).compact.first
|
22
|
+
xml_security = xml_security.values_at(:security, :Security).compact.first
|
23
|
+
username_token = xml_security.values_at(:username_token, :UsernameToken).compact.first
|
24
|
+
rescue
|
25
|
+
username_token = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
WashOutFork::Wsse.authenticate soap_config, username_token
|
29
|
+
|
30
|
+
request.env['WSSE_TOKEN'] = username_token.with_indifferent_access unless username_token.blank?
|
31
|
+
end
|
32
|
+
|
33
|
+
def _map_soap_parameters
|
34
|
+
@_params = _load_params action_spec[:in],
|
35
|
+
_strip_empty_nodes(action_spec[:in], xml_data)
|
36
|
+
end
|
37
|
+
|
38
|
+
def _strip_empty_nodes(params, hash)
|
39
|
+
hash.keys.each do |key|
|
40
|
+
param = params.detect { |a| a.raw_name.to_s == key.to_s }
|
41
|
+
next if !(param && hash[key].is_a?(Hash))
|
42
|
+
|
43
|
+
value = hash[key].delete_if do |k, _|
|
44
|
+
k.to_s[0] == '@' && !param.map.detect { |a| a.raw_name.to_s == k.to_s }
|
45
|
+
end
|
46
|
+
|
47
|
+
if value.length > 0
|
48
|
+
hash[key] = _strip_empty_nodes param.map, value
|
49
|
+
else
|
50
|
+
hash[key] = nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
hash
|
55
|
+
end
|
56
|
+
|
57
|
+
# Creates the final parameter hash based on the request spec and xml_data from the request
|
58
|
+
def _load_params(spec, xml_data)
|
59
|
+
params = HashWithIndifferentAccess.new
|
60
|
+
spec.each do |param|
|
61
|
+
key = param.raw_name.to_sym
|
62
|
+
if xml_data.has_key? key
|
63
|
+
params[param.raw_name] = param.load(xml_data, key)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
params
|
67
|
+
end
|
68
|
+
|
69
|
+
# This action generates the WSDL for defined SOAP methods.
|
70
|
+
def _generate_wsdl
|
71
|
+
@map = self.class.soap_actions
|
72
|
+
@namespace = soap_config.namespace
|
73
|
+
@name = controller_path
|
74
|
+
|
75
|
+
render :template => "wash_out_fork/#{soap_config.wsdl_style}/wsdl", :layout => false,
|
76
|
+
:content_type => 'text/xml'
|
77
|
+
end
|
78
|
+
|
79
|
+
# Render a SOAP response.
|
80
|
+
def _render_soap(result, options)
|
81
|
+
@namespace = soap_config.namespace
|
82
|
+
@operation = soap_action = request.env['wash_out_fork.soap_action']
|
83
|
+
@action_spec = self.class.soap_actions[soap_action]
|
84
|
+
|
85
|
+
result = { 'value' => result } unless result.is_a? Hash
|
86
|
+
result = HashWithIndifferentAccess.new(result)
|
87
|
+
|
88
|
+
inject = lambda {|data, map|
|
89
|
+
result_spec = []
|
90
|
+
return result_spec if data.nil?
|
91
|
+
|
92
|
+
map.each_with_index do |param, i|
|
93
|
+
result_spec[i] = param.flat_copy
|
94
|
+
|
95
|
+
unless data.is_a?(Hash)
|
96
|
+
raise ProgrammerError,
|
97
|
+
"SOAP response used #{data.inspect} (which is #{data.class.name}), " +
|
98
|
+
"in the context where a Hash with key of '#{param.raw_name}' " +
|
99
|
+
"was expected."
|
100
|
+
end
|
101
|
+
|
102
|
+
value = data[param.raw_name]
|
103
|
+
|
104
|
+
unless value.nil?
|
105
|
+
if param.multiplied && !value.is_a?(Array)
|
106
|
+
raise ProgrammerError,
|
107
|
+
"SOAP response tried to use '#{value.inspect}' " +
|
108
|
+
"(which is of type #{value.class.name}), as the value for " +
|
109
|
+
"'#{param.raw_name}' (which expects an Array)."
|
110
|
+
end
|
111
|
+
|
112
|
+
# Inline complex structure {:foo => {bar: ...}}
|
113
|
+
if param.struct? && !param.multiplied
|
114
|
+
result_spec[i].map = inject.call(value, param.map)
|
115
|
+
|
116
|
+
# Inline array of complex structures {:foo => [{bar: ...}]}
|
117
|
+
elsif param.struct? && param.multiplied
|
118
|
+
result_spec[i].map = value.map{|e| inject.call(e, param.map)}
|
119
|
+
|
120
|
+
# Inline scalar {:foo => :string}
|
121
|
+
else
|
122
|
+
result_spec[i].value = value
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
return result_spec
|
128
|
+
}
|
129
|
+
|
130
|
+
render :template => "wash_out_fork/#{soap_config.wsdl_style}/response",
|
131
|
+
:layout => false,
|
132
|
+
:locals => { :result => inject.call(result, @action_spec[:out]) },
|
133
|
+
:content_type => 'text/xml'
|
134
|
+
end
|
135
|
+
|
136
|
+
# This action is a fallback for all undefined SOAP actions.
|
137
|
+
def _invalid_action
|
138
|
+
render_soap_error("Cannot find SOAP action mapping for #{request.env['wash_out_fork.soap_action']}")
|
139
|
+
end
|
140
|
+
|
141
|
+
def _invalid_request
|
142
|
+
render_soap_error("Invalid SOAP request")
|
143
|
+
end
|
144
|
+
|
145
|
+
def _catch_soap_errors
|
146
|
+
yield
|
147
|
+
rescue SOAPError => error
|
148
|
+
render_soap_error(error.message, error.code)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Render a SOAP error response.
|
152
|
+
#
|
153
|
+
# Rails do not support sequental rescue_from handling, that is, rescuing an
|
154
|
+
# exception from a rescue_from handler. Hence this function is a public API.
|
155
|
+
def render_soap_error(message, code=nil)
|
156
|
+
render :template => "wash_out_fork/#{soap_config.wsdl_style}/error", :status => 500,
|
157
|
+
:layout => false,
|
158
|
+
:locals => { :error_message => message, :error_code => (code || 'Server') },
|
159
|
+
:content_type => 'text/xml'
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.included(controller)
|
163
|
+
entity = if defined?(Rails::VERSION::MAJOR) && (Rails::VERSION::MAJOR >= 4)
|
164
|
+
'action'
|
165
|
+
else
|
166
|
+
'filter'
|
167
|
+
end
|
168
|
+
|
169
|
+
controller.send :"around_#{entity}", :_catch_soap_errors
|
170
|
+
controller.send :helper, :wash_out_fork
|
171
|
+
controller.send :"before_#{entity}", :_authenticate_wsse, :if => :soap_action?
|
172
|
+
controller.send :"before_#{entity}", :_map_soap_parameters, :if => :soap_action?
|
173
|
+
controller.send :"skip_before_#{entity}", :verify_authenticity_token
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.deep_select(collection, result=[], &blk)
|
177
|
+
values = collection.respond_to?(:values) ? collection.values : collection
|
178
|
+
result += values.select(&blk)
|
179
|
+
|
180
|
+
values.each do |value|
|
181
|
+
if value.is_a?(Hash) || value.is_a?(Array)
|
182
|
+
result = deep_select(value, result, &blk)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
result
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.deep_replace_href(element, replace)
|
190
|
+
return element unless element.is_a?(Array) || element.is_a?(Hash)
|
191
|
+
|
192
|
+
if element.is_a?(Array) # Traverse arrays
|
193
|
+
return element.map{|x| deep_replace_href(x, replace)}
|
194
|
+
end
|
195
|
+
|
196
|
+
if element.has_key?(:@href) # Replace needle and traverse replacement
|
197
|
+
return deep_replace_href(replace[element[:@href]], replace)
|
198
|
+
end
|
199
|
+
|
200
|
+
element.each do |key, value| # Traverse hashes
|
201
|
+
element[key] = deep_replace_href(value, replace)
|
202
|
+
end
|
203
|
+
|
204
|
+
element
|
205
|
+
end
|
206
|
+
|
207
|
+
private
|
208
|
+
def soap_action?
|
209
|
+
soap_action.present?
|
210
|
+
end
|
211
|
+
|
212
|
+
def action_spec
|
213
|
+
self.class.soap_actions[soap_action]
|
214
|
+
end
|
215
|
+
|
216
|
+
def request_input_tag
|
217
|
+
action_spec[:request_tag]
|
218
|
+
end
|
219
|
+
|
220
|
+
def soap_action
|
221
|
+
request.env['wash_out_fork.soap_action']
|
222
|
+
end
|
223
|
+
|
224
|
+
def xml_data
|
225
|
+
xml_data = request.env['wash_out_fork.soap_data'].values_at(:envelope, :Envelope).compact.first
|
226
|
+
xml_data = xml_data.values_at(:body, :Body).compact.first || {}
|
227
|
+
return xml_data if soap_config.wsdl_style == "document"
|
228
|
+
xml_data = xml_data.values_at(soap_action.underscore.to_sym, soap_action.to_sym, request_input_tag.to_sym).compact.first || {}
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
module WashOutFork
|
3
|
+
class Engine < ::Rails::Engine
|
4
|
+
config.wash_out_fork = ActiveSupport::OrderedOptions.new
|
5
|
+
initializer "wash_out_fork.configuration" do |app|
|
6
|
+
if app.config.wash_out_fork[:catch_xml_errors]
|
7
|
+
app.config.middleware.insert_after 'ActionDispatch::ShowExceptions', WashOutFork::Middleware
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class WashOutFork::Middleware
|
2
|
+
def initialize app
|
3
|
+
@app = app
|
4
|
+
end
|
5
|
+
|
6
|
+
def call env
|
7
|
+
begin
|
8
|
+
@app.call env
|
9
|
+
rescue REXML::ParseException => e
|
10
|
+
self.class.raise_or_render_rexml_parse_error e, env
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.raise_or_render_rexml_parse_error e, env
|
15
|
+
raise e unless env.has_key? 'HTTP_SOAPACTION'
|
16
|
+
|
17
|
+
# Normally input would be a StringIO, but Passenger has a different API:
|
18
|
+
input = env['rack.input']
|
19
|
+
req = if input.respond_to? :string then input.string else input.read end
|
20
|
+
|
21
|
+
env['rack.errors'].puts <<-EOERR
|
22
|
+
WashOutFork::Exception: #{e.continued_exception} for:
|
23
|
+
#{req}
|
24
|
+
EOERR
|
25
|
+
[400, {'Content-Type' => 'text/xml'},
|
26
|
+
[render_client_soap_fault("Error parsing SOAP Request XML")]]
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.render_client_soap_fault msg
|
30
|
+
xml = Builder::XmlMarkup.new
|
31
|
+
xml.tag! 'soap:Envelope', 'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/',
|
32
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance' do
|
33
|
+
xml.tag! 'soap:Body' do
|
34
|
+
xml.tag! 'soap:Fault', :encodingStyle => 'http://schemas.xmlsoap.org/soap/encoding/' do
|
35
|
+
xml.faultcode 'Client'
|
36
|
+
xml.faultstring msg
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module WashOutFork
|
2
|
+
module Model
|
3
|
+
def wash_out_fork_columns
|
4
|
+
columns_hash
|
5
|
+
end
|
6
|
+
|
7
|
+
def wash_out_fork_param_map
|
8
|
+
types = {
|
9
|
+
:text => :string,
|
10
|
+
:float => :double,
|
11
|
+
:decimal => :double,
|
12
|
+
:timestamp => :string
|
13
|
+
}
|
14
|
+
map = {}
|
15
|
+
|
16
|
+
wash_out_fork_columns.each do |key, column|
|
17
|
+
type = column.type
|
18
|
+
type = types[type] if types.has_key?(type)
|
19
|
+
map[key] = type
|
20
|
+
end
|
21
|
+
|
22
|
+
map
|
23
|
+
end
|
24
|
+
|
25
|
+
def wash_out_fork_param_name(*args)
|
26
|
+
return name.underscore
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
module WashOutFork
|
2
|
+
class Param
|
3
|
+
attr_accessor :raw_name
|
4
|
+
attr_accessor :name
|
5
|
+
attr_accessor :map
|
6
|
+
attr_accessor :type
|
7
|
+
attr_accessor :multiplied
|
8
|
+
attr_accessor :value
|
9
|
+
attr_accessor :source_class
|
10
|
+
attr_accessor :soap_config
|
11
|
+
|
12
|
+
# Defines a WSDL parameter with name +name+ and type specifier +type+.
|
13
|
+
# The type specifier format is described in #parse_def.
|
14
|
+
def initialize(soap_config, name, type, multiplied = false)
|
15
|
+
type ||= {}
|
16
|
+
@soap_config = soap_config
|
17
|
+
@name = name.to_s
|
18
|
+
@raw_name = name.to_s
|
19
|
+
@map = {}
|
20
|
+
@multiplied = multiplied
|
21
|
+
|
22
|
+
if soap_config.camelize_wsdl.to_s == 'lower'
|
23
|
+
@name = @name.camelize(:lower)
|
24
|
+
elsif soap_config.camelize_wsdl
|
25
|
+
@name = @name.camelize
|
26
|
+
end
|
27
|
+
|
28
|
+
if type.is_a?(Symbol)
|
29
|
+
@type = type.to_s
|
30
|
+
elsif type.is_a?(Class)
|
31
|
+
@type = 'struct'
|
32
|
+
@map = self.class.parse_def(soap_config, type.wash_out_fork_param_map)
|
33
|
+
@source_class = type
|
34
|
+
else
|
35
|
+
@type = 'struct'
|
36
|
+
@map = self.class.parse_def(soap_config, type)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Converts a generic externally derived Ruby value, such as String or
|
41
|
+
# Hash, to a native Ruby object according to the definition of this type.
|
42
|
+
def load(data, key)
|
43
|
+
if !data.has_key? key
|
44
|
+
raise WashOutFork::Dispatcher::SOAPError, "Required SOAP parameter '#{key}' is missing"
|
45
|
+
end
|
46
|
+
|
47
|
+
data = data[key]
|
48
|
+
data = [data] if @multiplied && !data.is_a?(Array)
|
49
|
+
|
50
|
+
if struct?
|
51
|
+
data ||= {}
|
52
|
+
if @multiplied
|
53
|
+
data.map do |x|
|
54
|
+
map_struct x do |param, dat, elem|
|
55
|
+
param.load(dat, elem)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
else
|
59
|
+
map_struct data do |param, dat, elem|
|
60
|
+
param.load(dat, elem)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
else
|
64
|
+
operation = case type
|
65
|
+
when 'string'; :to_s
|
66
|
+
when 'integer'; :to_i
|
67
|
+
when 'long'; :to_i
|
68
|
+
when 'double'; :to_f
|
69
|
+
when 'boolean'; lambda{|dat| dat === "0" ? false : !!dat}
|
70
|
+
when 'date'; :to_date
|
71
|
+
when 'datetime'; :to_datetime
|
72
|
+
when 'time'; :to_time
|
73
|
+
when 'base64Binary'; lambda{|dat| Base64.decode64(dat)}
|
74
|
+
else raise RuntimeError, "Invalid WashOutFork simple type: #{type}"
|
75
|
+
end
|
76
|
+
|
77
|
+
begin
|
78
|
+
if data.nil?
|
79
|
+
data
|
80
|
+
elsif @multiplied
|
81
|
+
return data.map{|x| x.send(operation)} if operation.is_a?(Symbol)
|
82
|
+
return data.map{|x| operation.call(x)} if operation.is_a?(Proc)
|
83
|
+
elsif operation.is_a? Symbol
|
84
|
+
data.send(operation)
|
85
|
+
else
|
86
|
+
operation.call(data)
|
87
|
+
end
|
88
|
+
rescue
|
89
|
+
raise WashOutFork::Dispatcher::SOAPError, "Invalid SOAP parameter '#{key}' format"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Checks if this Param defines a complex type.
|
95
|
+
def struct?
|
96
|
+
type == 'struct'
|
97
|
+
end
|
98
|
+
|
99
|
+
def classified?
|
100
|
+
!source_class.nil?
|
101
|
+
end
|
102
|
+
|
103
|
+
def basic_type
|
104
|
+
return name unless classified?
|
105
|
+
return source_class.wash_out_fork_param_name(@soap_config)
|
106
|
+
end
|
107
|
+
|
108
|
+
def xsd_type
|
109
|
+
return 'int' if type.to_s == 'integer'
|
110
|
+
return 'dateTime' if type.to_s == 'datetime'
|
111
|
+
return type
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns a WSDL namespaced identifier for this type.
|
115
|
+
def namespaced_type
|
116
|
+
struct? ? "tns:#{basic_type}" : "xsd:#{xsd_type}"
|
117
|
+
end
|
118
|
+
|
119
|
+
# Parses a +definition+. The format of the definition is best described
|
120
|
+
# by the following BNF-like grammar.
|
121
|
+
#
|
122
|
+
# simple_type := :string | :integer | :double | :boolean
|
123
|
+
# nested_type := type_hash | simple_type | WashOutFork::Param instance
|
124
|
+
# type_hash := { :parameter_name => nested_type, ... }
|
125
|
+
# definition := [ WashOutFork::Param, ... ] |
|
126
|
+
# type_hash |
|
127
|
+
# simple_type
|
128
|
+
#
|
129
|
+
# If a simple type is passed as the +definition+, a single Param is returned
|
130
|
+
# with the +name+ set to "value".
|
131
|
+
# If a WashOutFork::Param instance is passed as a +nested_type+, the corresponding
|
132
|
+
# +:parameter_name+ is ignored.
|
133
|
+
#
|
134
|
+
# This function returns an array of WashOutFork::Param objects.
|
135
|
+
def self.parse_def(soap_config, definition)
|
136
|
+
raise RuntimeError, "[] should not be used in your params. Use nil if you want to mark empty set." if definition == []
|
137
|
+
return [] if definition == nil
|
138
|
+
|
139
|
+
if definition.is_a?(Class) && definition.ancestors.include?(WashOutFork::Type)
|
140
|
+
definition = definition.wash_out_fork_param_map
|
141
|
+
end
|
142
|
+
|
143
|
+
if [Array, Symbol].include?(definition.class)
|
144
|
+
definition = { :value => definition }
|
145
|
+
end
|
146
|
+
|
147
|
+
if definition.is_a? Hash
|
148
|
+
definition.map do |name, opt|
|
149
|
+
if opt.is_a? WashOutFork::Param
|
150
|
+
opt
|
151
|
+
elsif opt.is_a? Array
|
152
|
+
WashOutFork::Param.new(soap_config, name, opt[0], true)
|
153
|
+
else
|
154
|
+
WashOutFork::Param.new(soap_config, name, opt)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
else
|
158
|
+
raise RuntimeError, "Wrong definition: #{definition.inspect}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def flat_copy
|
163
|
+
copy = self.class.new(@soap_config, @name, @type.to_sym, @multiplied)
|
164
|
+
copy.raw_name = raw_name
|
165
|
+
copy.source_class = source_class
|
166
|
+
copy
|
167
|
+
end
|
168
|
+
|
169
|
+
def attribute?
|
170
|
+
name[0] == "@"
|
171
|
+
end
|
172
|
+
|
173
|
+
def attr_name
|
174
|
+
raise 'Not attribute' unless attribute?
|
175
|
+
name[1..-1]
|
176
|
+
end
|
177
|
+
|
178
|
+
private
|
179
|
+
|
180
|
+
# Used to load an entire structure.
|
181
|
+
def map_struct(data)
|
182
|
+
unless data.is_a?(Hash)
|
183
|
+
raise WashOutFork::Dispatcher::SOAPError, "SOAP message structure is broken"
|
184
|
+
end
|
185
|
+
|
186
|
+
data = data.with_indifferent_access
|
187
|
+
struct = {}.with_indifferent_access
|
188
|
+
|
189
|
+
# RUBY18 Enumerable#each_with_object is better, but 1.9 only.
|
190
|
+
@map.map do |param|
|
191
|
+
if data.has_key? param.raw_name
|
192
|
+
param_name = param.attribute? ? param.attr_name : param.raw_name
|
193
|
+
struct[param_name] = yield param, data, param.raw_name
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
struct
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|