actionservice 0.2.99 → 0.2.100
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/CHANGELOG +2 -2
- data/Rakefile +1 -1
- data/TODO +6 -1
- data/lib/action_service/base.rb +1 -8
- data/lib/action_service/container.rb +56 -15
- data/lib/action_service/invocation.rb +18 -7
- data/lib/action_service/protocol/abstract.rb +37 -4
- data/lib/action_service/protocol/soap.rb +57 -60
- data/lib/action_service/protocol/xmlrpc.rb +97 -0
- data/lib/action_service/protocol.rb +1 -0
- data/lib/action_service/router/action_controller.rb +2 -2
- data/lib/action_service/router/wsdl.rb +7 -5
- data/lib/action_service.rb +1 -0
- data/test/base_test.rb +4 -0
- data/test/container_test.rb +20 -3
- data/test/protocol_soap_test.rb +89 -2
- data/test/protocol_xmlrpc_test.rb +130 -0
- data/test/router_wsdl_test.rb +5 -1
- metadata +20 -18
data/CHANGELOG
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
TBA
|
|
2
2
|
|
|
3
|
-
* First release
|
|
3
|
+
* First public release
|
data/Rakefile
CHANGED
|
@@ -8,7 +8,7 @@ require 'rake/contrib/rubyforgepublisher'
|
|
|
8
8
|
|
|
9
9
|
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
|
10
10
|
PKG_NAME = 'actionservice'
|
|
11
|
-
PKG_VERSION = '0.2.
|
|
11
|
+
PKG_VERSION = '0.2.100' + PKG_BUILD
|
|
12
12
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
|
13
13
|
|
|
14
14
|
desc "Default Task"
|
data/TODO
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
= Features Remaining
|
|
2
|
-
- XML-RPC support
|
|
3
2
|
- Support for ActiveRecord model classes as structure types as well, since
|
|
4
3
|
we can reflect all the details to do proper mapping from model classes.
|
|
5
4
|
|
|
@@ -21,5 +20,11 @@
|
|
|
21
20
|
* Use the return value of the action to send back to the client
|
|
22
21
|
|
|
23
22
|
= Warts
|
|
23
|
+
- Come up with a cleaner way for supporting XML-RPC introspection that doesn't
|
|
24
|
+
involve throwing a SystemExportNotHandledError exception.
|
|
25
|
+
- Come up with a cleaner approach for 'default_export' implementations.
|
|
26
|
+
But NOT method_missing!
|
|
27
|
+
- Create abstract SOAP test that provides helpers for doing SOAP method
|
|
28
|
+
calls, get rid of the copy & paste SOAP crap in the SOAP protocol tests
|
|
24
29
|
- Don't have clean way to go from SOAP Class object to the xsd:NAME type
|
|
25
30
|
string
|
data/lib/action_service/base.rb
CHANGED
|
@@ -8,6 +8,7 @@ module ActionService
|
|
|
8
8
|
class_inheritable_option :export_name_mangling, true
|
|
9
9
|
class_inheritable_option :report_exceptions, true
|
|
10
10
|
class_inheritable_option :logger
|
|
11
|
+
class_inheritable_option :default_export
|
|
11
12
|
|
|
12
13
|
class << self
|
|
13
14
|
def export(name, options={})
|
|
@@ -19,14 +20,6 @@ module ActionService
|
|
|
19
20
|
expects = options[:expects]
|
|
20
21
|
returns = options[:returns]
|
|
21
22
|
end
|
|
22
|
-
if expects.nil?
|
|
23
|
-
arity = instance_method(name).arity
|
|
24
|
-
expects = [Object] * arity if arity > 0
|
|
25
|
-
end
|
|
26
|
-
if returns.nil?
|
|
27
|
-
returns = [NilClass]
|
|
28
|
-
end
|
|
29
|
-
|
|
30
23
|
name = name.to_sym
|
|
31
24
|
public_name = public_export_name(name)
|
|
32
25
|
info = { :expects => expects, :returns => returns }
|
|
@@ -36,15 +36,6 @@ module ActionService
|
|
|
36
36
|
read_inheritable_attribute("action_services") || {}
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
def service_object(service_name)
|
|
40
|
-
info = services[service_name.to_sym]
|
|
41
|
-
unless info
|
|
42
|
-
raise(ContainerError, "no such service '#{service_name}'")
|
|
43
|
-
end
|
|
44
|
-
service = info[:block]
|
|
45
|
-
service ? instance_eval(&service) : info[:object]
|
|
46
|
-
end
|
|
47
|
-
|
|
48
39
|
private
|
|
49
40
|
def call_service_definition_callbacks(container_klass, service_name, service_info)
|
|
50
41
|
(read_inheritable_attribute("action_service_definition_callbacks") || []).each do |block|
|
|
@@ -54,14 +45,64 @@ module ActionService
|
|
|
54
45
|
end
|
|
55
46
|
|
|
56
47
|
module InstanceMethods
|
|
48
|
+
def service_object(service_name)
|
|
49
|
+
info = self.class.services[service_name.to_sym]
|
|
50
|
+
unless info
|
|
51
|
+
raise(ContainerError, "no such service '#{service_name}'")
|
|
52
|
+
end
|
|
53
|
+
service = info[:block]
|
|
54
|
+
service ? instance_eval(&service) : info[:object]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
57
|
private
|
|
58
58
|
def dispatch_service_invocation_request(protocol, info)
|
|
59
|
-
service =
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
service = service_object(info.service_name)
|
|
60
|
+
service_klass = service.class
|
|
61
|
+
method_name = service_klass.internal_export_name(info.public_method_name)
|
|
62
|
+
opts = {}
|
|
63
|
+
params = []
|
|
64
|
+
if method_name
|
|
65
|
+
export_info = service_klass.exports[method_name]
|
|
66
|
+
strict = true
|
|
67
|
+
else
|
|
68
|
+
system_exports = self.class.read_inheritable_attribute('default_system_exports') || {}
|
|
69
|
+
method_name = system_exports[protocol.class]
|
|
70
|
+
if method_name
|
|
71
|
+
opts[:system_call] = [info.public_method_name, system_exports[protocol.class]]
|
|
72
|
+
params.unshift service_klass
|
|
73
|
+
else
|
|
74
|
+
method_name = service_klass.default_export
|
|
75
|
+
method_name = method_name.to_sym if method_name
|
|
76
|
+
unless method_name
|
|
77
|
+
raise(ContainerError, "no such method /#{info.service_name}##{info.public_method_name}()")
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
export_info = {}
|
|
81
|
+
strict = false
|
|
82
|
+
end
|
|
83
|
+
opts[:require_exported] = false unless strict
|
|
84
|
+
params = params + protocol.unmarshal_request(info, export_info, strict)
|
|
85
|
+
canceled_reason = nil
|
|
86
|
+
canceled_block = lambda{|r| canceled_reason = r}
|
|
87
|
+
perform_invoke = lambda do
|
|
88
|
+
service.perform_invocation(method_name, params, opts, &canceled_block)
|
|
89
|
+
end
|
|
90
|
+
begin
|
|
91
|
+
result = perform_invoke.call
|
|
92
|
+
rescue ActionService::Protocol::SystemExportNotHandledError => e
|
|
93
|
+
params.shift
|
|
94
|
+
method_name = service_klass.default_export
|
|
95
|
+
opts.delete(:system_call)
|
|
96
|
+
if method_name
|
|
97
|
+
method_name = method_name.to_sym
|
|
98
|
+
export_info = {}
|
|
99
|
+
strict = false
|
|
100
|
+
else
|
|
101
|
+
raise(ContainerError, "no such method /#{info.service_name}##{info.public_method_name}()")
|
|
102
|
+
end
|
|
103
|
+
result = perform_invoke.call
|
|
104
|
+
end
|
|
105
|
+
protocol.marshal_response(info, export_info, result, strict)
|
|
65
106
|
end
|
|
66
107
|
|
|
67
108
|
end
|
|
@@ -86,7 +86,7 @@ module ActionService
|
|
|
86
86
|
end
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
-
module InstanceMethods
|
|
89
|
+
module InstanceMethods
|
|
90
90
|
def self.append_features(base)
|
|
91
91
|
super
|
|
92
92
|
base.class_eval do
|
|
@@ -95,19 +95,30 @@ module ActionService
|
|
|
95
95
|
end
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
-
def perform_invocation_with_interception(name, args=nil, &block)
|
|
98
|
+
def perform_invocation_with_interception(name, args=nil, options={}, &block)
|
|
99
99
|
return if before_invocation(name, args, &block) == false
|
|
100
|
-
result = perform_invocation_without_interception(name, args)
|
|
100
|
+
result = perform_invocation_without_interception(name, args, options)
|
|
101
101
|
after_invocation(name, args, result)
|
|
102
102
|
result
|
|
103
103
|
end
|
|
104
104
|
|
|
105
|
-
def perform_invocation(name, args=nil)
|
|
106
|
-
unless
|
|
107
|
-
|
|
105
|
+
def perform_invocation(name, args=nil, options={})
|
|
106
|
+
unless options[:require_exported] == false
|
|
107
|
+
unless self.respond_to?(name) && self.class.has_export?(name)
|
|
108
|
+
raise InvocationError, "no such exported method '#{name}'"
|
|
109
|
+
end
|
|
108
110
|
end
|
|
109
111
|
args ||= []
|
|
110
|
-
|
|
112
|
+
if options[:system_call]
|
|
113
|
+
name, block = options[:system_call]
|
|
114
|
+
if block.respond_to?('call')
|
|
115
|
+
block.call(name, *args)
|
|
116
|
+
else
|
|
117
|
+
self.send(block, *args)
|
|
118
|
+
end
|
|
119
|
+
else
|
|
120
|
+
self.send(name, *args)
|
|
121
|
+
end
|
|
111
122
|
end
|
|
112
123
|
|
|
113
124
|
def before_invocation(name, args, &block)
|
|
@@ -2,6 +2,8 @@ module ActionService
|
|
|
2
2
|
module Protocol
|
|
3
3
|
class ProtocolError < ActionService::ActionServiceError
|
|
4
4
|
end
|
|
5
|
+
class SystemExportNotHandledError < ProtocolError
|
|
6
|
+
end
|
|
5
7
|
|
|
6
8
|
class AbstractProtocol
|
|
7
9
|
attr :container_klass
|
|
@@ -10,11 +12,11 @@ module ActionService
|
|
|
10
12
|
@container_klass = container_klass
|
|
11
13
|
end
|
|
12
14
|
|
|
13
|
-
def unmarshal_request(request_info, export_info)
|
|
15
|
+
def unmarshal_request(request_info, export_info, strict=true)
|
|
14
16
|
raise NotImplementedError
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
def marshal_response(request_info, export_info, return_value)
|
|
19
|
+
def marshal_response(request_info, export_info, return_value, strict=true)
|
|
18
20
|
raise NotImplementedError
|
|
19
21
|
end
|
|
20
22
|
|
|
@@ -22,13 +24,44 @@ module ActionService
|
|
|
22
24
|
raise NotImplementedError
|
|
23
25
|
end
|
|
24
26
|
|
|
25
|
-
def request_info
|
|
27
|
+
def request_info
|
|
26
28
|
raise NotImplementedError
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
def request_supported?(request)
|
|
30
32
|
raise NotImplementedError
|
|
31
33
|
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
def validate_types(method_name, signature, params, kind)
|
|
37
|
+
unless signature.length == params.length
|
|
38
|
+
raise(ProtocolError, "signature/parameter mismatch")
|
|
39
|
+
end
|
|
40
|
+
case kind
|
|
41
|
+
when :in
|
|
42
|
+
extra_msg = ' (Input parameter %d of method "%s")'
|
|
43
|
+
when :out
|
|
44
|
+
extra_msg = ' (Return value %d of method "%s")'
|
|
45
|
+
end
|
|
46
|
+
i = 0
|
|
47
|
+
signature.each do |klass|
|
|
48
|
+
check_compatibility(params[i].class, klass, extra_msg % [i+1, method_name])
|
|
49
|
+
i += 1
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def check_compatibility(given_klass, signature_klass, extra_msg=nil)
|
|
54
|
+
if (given_klass == TrueClass or given_klass == FalseClass) and \
|
|
55
|
+
(signature_klass == TrueClass or signature_klass == FalseClass)
|
|
56
|
+
return true
|
|
57
|
+
end
|
|
58
|
+
unless given_klass.ancestors.include?(signature_klass) || \
|
|
59
|
+
signature_klass.ancestors.include?(given_klass)
|
|
60
|
+
raise(ProtocolError, "value of type #{given_klass.name} is not compatible " +
|
|
61
|
+
"with expected type #{signature_klass.name}" +
|
|
62
|
+
(extra_msg ? extra_msg : ''))
|
|
63
|
+
end
|
|
64
|
+
end
|
|
32
65
|
end
|
|
33
66
|
|
|
34
67
|
class ServiceRequestInfo
|
|
@@ -38,7 +71,7 @@ module ActionService
|
|
|
38
71
|
attr :content_type
|
|
39
72
|
attr :protocol_info
|
|
40
73
|
|
|
41
|
-
def initialize(service_name, public_method_name, raw_body, content_type, protocol_info)
|
|
74
|
+
def initialize(service_name, public_method_name, raw_body, content_type, protocol_info=nil)
|
|
42
75
|
@service_name = service_name
|
|
43
76
|
@public_method_name = public_method_name
|
|
44
77
|
@raw_body = raw_body
|
|
@@ -28,30 +28,52 @@ module ActionService
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
class SoapProtocol < AbstractProtocol
|
|
31
|
-
def unmarshal_request(request_info, export_info)
|
|
31
|
+
def unmarshal_request(request_info, export_info, strict=true)
|
|
32
32
|
expects = export_info[:expects]
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
unmarshal_soap_message = lambda do
|
|
34
|
+
envelope = SOAP::Processor.unmarshal(request_info.raw_body)
|
|
35
|
+
request = envelope.body.request
|
|
36
|
+
params = request.collect{|k, v| request[k]}
|
|
37
|
+
soap_to_ruby_array(params)
|
|
38
|
+
end if expects || !strict
|
|
39
|
+
if expects
|
|
40
|
+
map_types(expects)
|
|
41
|
+
params = unmarshal_soap_message.call
|
|
42
|
+
validate_types(request_info.public_method_name, expects, params, :in) if expects
|
|
43
|
+
params
|
|
44
|
+
else
|
|
45
|
+
if strict
|
|
46
|
+
[]
|
|
47
|
+
else
|
|
48
|
+
unmarshal_soap_message.call
|
|
49
|
+
end
|
|
50
|
+
end
|
|
40
51
|
end
|
|
41
52
|
|
|
42
|
-
def marshal_response(request_info, export_info, return_value)
|
|
53
|
+
def marshal_response(request_info, export_info, return_value, strict=true)
|
|
43
54
|
returns = export_info[:returns]
|
|
55
|
+
create_param_def = lambda do |ret|
|
|
56
|
+
map_types(ret)
|
|
57
|
+
mapping = mapper.lookup(ret[0])
|
|
58
|
+
ret = [mapping.ruby_klass]
|
|
59
|
+
retval = fixup_array_types(mapping, return_value)
|
|
60
|
+
validate_types(request_info.public_method_name, ret, [retval], :out)
|
|
61
|
+
retval = ruby_to_soap(retval)
|
|
62
|
+
param_def = [['retval', 'return', mapping.registry_mapping]]
|
|
63
|
+
[param_def, ret, retval]
|
|
64
|
+
end if returns || !strict
|
|
44
65
|
if returns
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
66
|
+
param_def, returns, return_value = create_param_def.call(returns)
|
|
67
|
+
else
|
|
68
|
+
if strict
|
|
69
|
+
param_def = []
|
|
70
|
+
else
|
|
71
|
+
param_def, returns, return_value = create_param_def.call([return_value.class])
|
|
72
|
+
end
|
|
48
73
|
end
|
|
49
|
-
validate_types(request_info.public_method_name, returns, [return_value], :out)
|
|
50
|
-
return_value = ruby_to_soap(return_value)
|
|
51
|
-
param_def = returns ? [['retval', 'return', mapping.registry_mapping]] : []
|
|
52
74
|
qname = XSD::QName.new(mapper.custom_namespace, request_info.public_method_name)
|
|
53
75
|
response = SOAP::RPC::SOAPMethodResponse.new(qname, param_def)
|
|
54
|
-
response.retval = return_value
|
|
76
|
+
response.retval = return_value if returns
|
|
55
77
|
ServiceResponseInfo.new(create_response(response), 'text/xml')
|
|
56
78
|
end
|
|
57
79
|
|
|
@@ -59,19 +81,20 @@ module ActionService
|
|
|
59
81
|
ServiceResponseInfo.new(create_exception_response(exception), 'text/xml')
|
|
60
82
|
end
|
|
61
83
|
|
|
62
|
-
def request_info
|
|
84
|
+
def request_info
|
|
85
|
+
@request_info
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def request_supported?(request)
|
|
63
89
|
soap_action = extract_soap_action(request)
|
|
90
|
+
return false unless soap_action
|
|
64
91
|
service_name = request.parameters['action']
|
|
65
92
|
public_method_name = soap_action.gsub(/^[\/]+/, '').split(/[\/]+/)[-1]
|
|
66
|
-
ServiceRequestInfo.new(service_name,
|
|
93
|
+
@request_info = ServiceRequestInfo.new(service_name,
|
|
67
94
|
public_method_name,
|
|
68
95
|
request.raw_post,
|
|
69
|
-
request.env['HTTP_CONTENT_TYPE'] || 'text/xml'
|
|
70
|
-
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def request_supported?(request)
|
|
74
|
-
extract_soap_action(request) ? true : false
|
|
96
|
+
request.env['HTTP_CONTENT_TYPE'] || 'text/xml')
|
|
97
|
+
true
|
|
75
98
|
end
|
|
76
99
|
|
|
77
100
|
private
|
|
@@ -89,9 +112,10 @@ module ActionService
|
|
|
89
112
|
end
|
|
90
113
|
if mapping.is_a?(SoapArrayMapping)
|
|
91
114
|
obj = mapping.ruby_klass.new(obj)
|
|
92
|
-
|
|
93
|
-
obj
|
|
115
|
+
# man, this is going to be slow for big arrays :(
|
|
116
|
+
obj.each{|el| fixup_array_types(mapping.element_mapping, el)}
|
|
94
117
|
end
|
|
118
|
+
obj
|
|
95
119
|
end
|
|
96
120
|
|
|
97
121
|
def extract_soap_action(request)
|
|
@@ -111,36 +135,6 @@ module ActionService
|
|
|
111
135
|
types.collect{|type| mapper.map(type)}
|
|
112
136
|
end
|
|
113
137
|
|
|
114
|
-
def validate_types(method_name, signature, params, kind)
|
|
115
|
-
unless signature.length == params.length
|
|
116
|
-
raise(ProtocolError, "signature/parameter mismatch")
|
|
117
|
-
end
|
|
118
|
-
case kind
|
|
119
|
-
when :in
|
|
120
|
-
extra_msg = ' (Input parameter %d of method "%s")'
|
|
121
|
-
when :out
|
|
122
|
-
extra_msg = ' (Return value %d of method "%s")'
|
|
123
|
-
end
|
|
124
|
-
i = 0
|
|
125
|
-
signature.each do |klass|
|
|
126
|
-
check_compatibility(params[i].class, klass, extra_msg % [i, method_name])
|
|
127
|
-
i += 1
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def check_compatibility(klass1, klass2, extra_msg=nil)
|
|
132
|
-
if (klass1 == TrueClass or klass1 == FalseClass) and \
|
|
133
|
-
(klass2 == TrueClass or klass2 == FalseClass)
|
|
134
|
-
return true
|
|
135
|
-
end
|
|
136
|
-
unless klass1.ancestors.include?(klass2) || \
|
|
137
|
-
klass2.ancestors.include?(klass1)
|
|
138
|
-
raise(ProtocolError, "value of type #{klass1.name} is not compatible " +
|
|
139
|
-
"with expected type #{klass2.name}" +
|
|
140
|
-
(extra_msg ? extra_msg : ''))
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
|
|
144
138
|
def create_response(body, is_error=false)
|
|
145
139
|
header = SOAP::SOAPHeader.new
|
|
146
140
|
body = SOAP::SOAPBody.new(body)
|
|
@@ -261,9 +255,9 @@ module ActionService
|
|
|
261
255
|
end
|
|
262
256
|
alias :map :lookup
|
|
263
257
|
|
|
264
|
-
def map_container_services(
|
|
265
|
-
|
|
266
|
-
object =
|
|
258
|
+
def map_container_services(container, &block)
|
|
259
|
+
container.class.services.each do |service_name, service_info|
|
|
260
|
+
object = container.service_object(service_name)
|
|
267
261
|
service_klass = object.class
|
|
268
262
|
service_exports = {}
|
|
269
263
|
object.class.exports.each do |export_name, export_info|
|
|
@@ -286,7 +280,8 @@ module ActionService
|
|
|
286
280
|
mapping
|
|
287
281
|
end
|
|
288
282
|
expects_signature = expects ? expects.map{|klass| lookup_proc.call(klass)} : nil
|
|
289
|
-
|
|
283
|
+
returns = export_info[:returns]
|
|
284
|
+
returns_signature = returns ? returns.map{|klass| lookup_proc.call(klass)} : nil
|
|
290
285
|
service_exports[export_name] = {
|
|
291
286
|
:expects => expects_signature,
|
|
292
287
|
:returns => returns_signature
|
|
@@ -380,6 +375,8 @@ module ActionService
|
|
|
380
375
|
def type_name
|
|
381
376
|
super + "Array"
|
|
382
377
|
end
|
|
378
|
+
|
|
379
|
+
def each_attribute(&block); end
|
|
383
380
|
end
|
|
384
381
|
end
|
|
385
382
|
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
require 'xmlrpc/parser'
|
|
2
|
+
require 'xmlrpc/utils'
|
|
3
|
+
|
|
4
|
+
module ActionService
|
|
5
|
+
module Protocol
|
|
6
|
+
module XmlRpc
|
|
7
|
+
def self.append_features(base)
|
|
8
|
+
super
|
|
9
|
+
base.register_protocol(BodyOnly, XmlRpcProtocol)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class XmlRpcProtocol < AbstractProtocol
|
|
13
|
+
include XMLRPC::ParserWriterChooseMixin
|
|
14
|
+
|
|
15
|
+
def initialize(container_klass)
|
|
16
|
+
@container_klass = container_klass
|
|
17
|
+
@container_klass.write_inheritable_hash('default_system_exports', XmlRpcProtocol => method(:xmlrpc_default_system_handler))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def unmarshal_request(request_info, export_info, strict=true)
|
|
21
|
+
expects = export_info[:expects]
|
|
22
|
+
params = request_info.protocol_info[:xmlrpc][:params]
|
|
23
|
+
if expects
|
|
24
|
+
expects = array_types(expects)
|
|
25
|
+
validate_types(request_info.public_method_name, expects, params, :in)
|
|
26
|
+
params
|
|
27
|
+
else
|
|
28
|
+
strict ? [] : params
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def marshal_response(request_info, export_info, return_value, strict=true)
|
|
33
|
+
returns = export_info[:returns]
|
|
34
|
+
if returns
|
|
35
|
+
returns = array_types(returns)
|
|
36
|
+
validate_types(request_info.public_method_name, returns, [return_value], :out)
|
|
37
|
+
raw_response = create().methodResponse(true, return_value)
|
|
38
|
+
else
|
|
39
|
+
# XML-RPC doesn't have the concept of a void method, nor does it
|
|
40
|
+
# support a nil return value, so return true if we would have returned
|
|
41
|
+
# nil
|
|
42
|
+
if strict
|
|
43
|
+
raw_response = create().methodResponse(true, true)
|
|
44
|
+
else
|
|
45
|
+
return_value = true if return_value.nil?
|
|
46
|
+
raw_response = create().methodResponse(true, return_value)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
ServiceResponseInfo.new(raw_response, 'text/xml')
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def marshal_exception(exception)
|
|
53
|
+
raw_response = create().methodResponse(false, exception)
|
|
54
|
+
ServiceResponseInfo.new(raw_response, 'text/xml')
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def request_info
|
|
58
|
+
@request_info
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def request_supported?(request)
|
|
62
|
+
begin
|
|
63
|
+
service_name = request.parameters['action']
|
|
64
|
+
methodname, params = parser().parseMethodCall(request.raw_post)
|
|
65
|
+
@request_info = ServiceRequestInfo.new(service_name,
|
|
66
|
+
methodname,
|
|
67
|
+
request.raw_post,
|
|
68
|
+
request.env['HTTP_CONTENT_TYPE'] || 'text/xml',
|
|
69
|
+
:xmlrpc => { :params => params })
|
|
70
|
+
true
|
|
71
|
+
rescue
|
|
72
|
+
false
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
def xmlrpc_default_system_handler(name, service_klass, *args)
|
|
78
|
+
case name
|
|
79
|
+
when 'system.listMethods'
|
|
80
|
+
methods = []
|
|
81
|
+
service_klass.exports.each do |name, info|
|
|
82
|
+
methods << service_klass.public_export_name(name)
|
|
83
|
+
end
|
|
84
|
+
methods.sort
|
|
85
|
+
else
|
|
86
|
+
raise SystemExportNotHandledError
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def array_types(signature)
|
|
91
|
+
signature.map{|x| x.is_a?(Array) ? Array : x}
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -19,7 +19,7 @@ module ActionService
|
|
|
19
19
|
request_info = nil
|
|
20
20
|
begin
|
|
21
21
|
protocol = probe_request_protocol(self.request)
|
|
22
|
-
request_info = protocol.request_info
|
|
22
|
+
request_info = protocol.request_info
|
|
23
23
|
if request_info
|
|
24
24
|
log_request request_info
|
|
25
25
|
response_info = dispatch_service_invocation_request(protocol, request_info)
|
|
@@ -35,7 +35,7 @@ module ActionService
|
|
|
35
35
|
end
|
|
36
36
|
rescue Exception => e
|
|
37
37
|
log_error e unless logger.nil?
|
|
38
|
-
service_object =
|
|
38
|
+
service_object = service_object(request_info.service_name)
|
|
39
39
|
exc_response = nil
|
|
40
40
|
if service_object.class.report_exceptions
|
|
41
41
|
exc_response_info = protocol.marshal_exception(e) rescue nil
|
|
@@ -13,15 +13,15 @@ module ActionService
|
|
|
13
13
|
SoapEncodingNs = 'http://schemas.xmlsoap.org/soap/encoding/'
|
|
14
14
|
SoapHttpTransport = 'http://schemas.xmlsoap.org/soap/http'
|
|
15
15
|
|
|
16
|
-
def to_wsdl(
|
|
16
|
+
def to_wsdl(container, uri, soap_action_base)
|
|
17
17
|
wsdl = ""
|
|
18
18
|
|
|
19
|
-
namespace =
|
|
19
|
+
namespace = container.class.soap_mapper.custom_namespace
|
|
20
20
|
wsdl_service_name = namespace.split(/:/)[1]
|
|
21
21
|
|
|
22
22
|
mapper = ActionService::Protocol::Soap::SoapMapper.new(namespace)
|
|
23
23
|
services = {}
|
|
24
|
-
mapper.map_container_services(
|
|
24
|
+
mapper.map_container_services(container) do |name, klass, exports|
|
|
25
25
|
services[name] = [klass, exports]
|
|
26
26
|
end
|
|
27
27
|
custom_types = mapper.custom_types
|
|
@@ -78,7 +78,9 @@ module ActionService
|
|
|
78
78
|
xm.message('name' => msg_name) do
|
|
79
79
|
sym = nil
|
|
80
80
|
if direction == :out
|
|
81
|
-
|
|
81
|
+
if export_signature[:returns]
|
|
82
|
+
xm.part('name' => 'return', 'type' => export_signature[:returns][0].qualified_type_name)
|
|
83
|
+
end
|
|
82
84
|
else
|
|
83
85
|
mapping_list = export_signature[:expects]
|
|
84
86
|
i = 1
|
|
@@ -165,7 +167,7 @@ module ActionService
|
|
|
165
167
|
begin
|
|
166
168
|
uri = "http://#{@request.env['HTTP_HOST']||@request.env['SERVER_NAME']}/#{controller_name}/"
|
|
167
169
|
soap_action_base = "/#{controller_name}"
|
|
168
|
-
xml = self.class.to_wsdl(self
|
|
170
|
+
xml = self.class.to_wsdl(self, uri, soap_action_base)
|
|
169
171
|
send_data(xml, :type => 'text/xml', :disposition => 'inline')
|
|
170
172
|
rescue Exception => e
|
|
171
173
|
render_text('', "500 #{e.message}")
|
data/lib/action_service.rb
CHANGED
|
@@ -45,6 +45,7 @@ ActionController::Base.class_eval do
|
|
|
45
45
|
include ActionService::Container
|
|
46
46
|
include ActionService::Protocol::Registry
|
|
47
47
|
include ActionService::Protocol::Soap
|
|
48
|
+
include ActionService::Protocol::XmlRpc
|
|
48
49
|
include ActionService::Router::ActionController
|
|
49
50
|
include ActionService::Router::Wsdl
|
|
50
51
|
end
|
data/test/base_test.rb
CHANGED
|
@@ -44,4 +44,8 @@ class BaseTest < Test::Unit::TestCase
|
|
|
44
44
|
assert(BaseTestService.internal_export_name('Add') == :add)
|
|
45
45
|
assert(UnmangledOrReportedService.public_export_name(:custom_name_casing) == 'custom_name_casing')
|
|
46
46
|
end
|
|
47
|
+
|
|
48
|
+
def test_missing_method
|
|
49
|
+
assert(BaseTestService.has_public_export?('NoSuchMethod') == false)
|
|
50
|
+
end
|
|
47
51
|
end
|
data/test/container_test.rb
CHANGED
|
@@ -11,11 +11,23 @@ $immediate_service = Object.new
|
|
|
11
11
|
$deferred_service = Object.new
|
|
12
12
|
|
|
13
13
|
class TestContainer < AbstractTestContainer
|
|
14
|
+
attr :flag
|
|
15
|
+
attr :previous_flag
|
|
16
|
+
|
|
17
|
+
def initialize
|
|
18
|
+
@previous_flag = nil
|
|
19
|
+
@flag = true
|
|
20
|
+
end
|
|
21
|
+
|
|
14
22
|
service :immediate_service, $immediate_service
|
|
15
|
-
service(:deferred_service) { $deferred_service }
|
|
23
|
+
service(:deferred_service) { @previous_flag = @flag; @flag = false; $deferred_service }
|
|
16
24
|
end
|
|
17
25
|
|
|
18
26
|
class ContainerTest < Test::Unit::TestCase
|
|
27
|
+
def setup
|
|
28
|
+
@container = TestContainer.new
|
|
29
|
+
end
|
|
30
|
+
|
|
19
31
|
def test_registration
|
|
20
32
|
assert(TestContainer.has_service?(:immediate_service))
|
|
21
33
|
assert(TestContainer.has_service?(:deferred_service))
|
|
@@ -23,7 +35,12 @@ class ContainerTest < Test::Unit::TestCase
|
|
|
23
35
|
end
|
|
24
36
|
|
|
25
37
|
def test_service_object
|
|
26
|
-
assert(
|
|
27
|
-
assert(
|
|
38
|
+
assert(@container.flag == true)
|
|
39
|
+
assert(@container.service_object(:immediate_service) == $immediate_service)
|
|
40
|
+
assert(@container.previous_flag.nil?)
|
|
41
|
+
assert(@container.flag == true)
|
|
42
|
+
assert(@container.service_object(:deferred_service) == $deferred_service)
|
|
43
|
+
assert(@container.previous_flag == true)
|
|
44
|
+
assert(@container.flag == false)
|
|
28
45
|
end
|
|
29
46
|
end
|
data/test/protocol_soap_test.rb
CHANGED
|
@@ -4,10 +4,13 @@ require 'soap/rpc/element'
|
|
|
4
4
|
class SoapService < ActionService::Base
|
|
5
5
|
attr :int
|
|
6
6
|
attr :string
|
|
7
|
+
attr :values
|
|
8
|
+
attr :default_args
|
|
7
9
|
|
|
8
10
|
def initialize
|
|
9
11
|
@int = 20
|
|
10
12
|
@string = "wrong string value"
|
|
13
|
+
@default_args = nil
|
|
11
14
|
end
|
|
12
15
|
|
|
13
16
|
def some_method(int, string)
|
|
@@ -16,7 +19,19 @@ class SoapService < ActionService::Base
|
|
|
16
19
|
true
|
|
17
20
|
end
|
|
18
21
|
|
|
22
|
+
def array_returner
|
|
23
|
+
@values = [1, 2, 3]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def default(*args)
|
|
27
|
+
@default_args = args
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
30
|
+
|
|
19
31
|
export :some_method, :expects => [Integer, String], :returns => [TrueClass]
|
|
32
|
+
export :array_returner, :returns => [[Integer]]
|
|
33
|
+
|
|
34
|
+
default_export :default
|
|
20
35
|
end
|
|
21
36
|
|
|
22
37
|
class SoapContainer
|
|
@@ -68,7 +83,7 @@ class ProtocolSoapTest < Test::Unit::TestCase
|
|
|
68
83
|
test_request.env['RAW_POST_DATA'] = raw_request
|
|
69
84
|
protocol = @container.request_protocol(test_request)
|
|
70
85
|
assert(protocol.is_a?(ActionService::Protocol::Soap::SoapProtocol))
|
|
71
|
-
request_info = protocol.request_info
|
|
86
|
+
request_info = protocol.request_info
|
|
72
87
|
assert(request_info.service_name == service_name)
|
|
73
88
|
assert(request_info.public_method_name == public_method_name)
|
|
74
89
|
method_name = SoapService.internal_export_name(public_method_name)
|
|
@@ -77,7 +92,7 @@ class ProtocolSoapTest < Test::Unit::TestCase
|
|
|
77
92
|
assert(params.length == 2)
|
|
78
93
|
assert(params == [int_value, string_value])
|
|
79
94
|
response = @container.dispatch_request(protocol, request_info)
|
|
80
|
-
service =
|
|
95
|
+
service = @container.service_object(:soap_service)
|
|
81
96
|
assert(service.int == int_value)
|
|
82
97
|
assert(service.string == string_value)
|
|
83
98
|
raw_response = response.raw_body
|
|
@@ -91,4 +106,76 @@ class ProtocolSoapTest < Test::Unit::TestCase
|
|
|
91
106
|
def test_service_name
|
|
92
107
|
assert(SoapContainer.soap_mapper.custom_namespace == 'urn:Test')
|
|
93
108
|
end
|
|
109
|
+
|
|
110
|
+
def test_array_returning
|
|
111
|
+
service_name = 'soap_service'
|
|
112
|
+
public_method_name = 'ArrayReturner'
|
|
113
|
+
qname = XSD::QName.new('urn:ActionService', public_method_name)
|
|
114
|
+
request = SOAP::RPC::SOAPMethodRequest.new(qname)
|
|
115
|
+
header = SOAP::SOAPHeader.new
|
|
116
|
+
body = SOAP::SOAPBody.new(request)
|
|
117
|
+
envelope = SOAP::SOAPEnvelope.new(header, body)
|
|
118
|
+
raw_request = SOAP::Processor.marshal(envelope)
|
|
119
|
+
test_request = ActionController::TestRequest.new
|
|
120
|
+
test_request.request_parameters['action'] = service_name
|
|
121
|
+
test_request.env['REQUEST_METHOD'] = "POST"
|
|
122
|
+
test_request.env['HTTP_CONTENTTYPE'] = 'text/xml'
|
|
123
|
+
test_request.env['HTTP_SOAPACTION'] = "/soap/#{service_name}/#{public_method_name}"
|
|
124
|
+
test_request.env['RAW_POST_DATA'] = raw_request
|
|
125
|
+
protocol = @container.request_protocol(test_request)
|
|
126
|
+
assert(protocol.is_a?(ActionService::Protocol::Soap::SoapProtocol))
|
|
127
|
+
request_info = protocol.request_info
|
|
128
|
+
method_name = SoapService.internal_export_name(public_method_name)
|
|
129
|
+
export_info = SoapService.exports[method_name]
|
|
130
|
+
response = @container.dispatch_request(protocol, request_info)
|
|
131
|
+
service = @container.service_object(:soap_service)
|
|
132
|
+
assert(service.values == [1, 2, 3])
|
|
133
|
+
raw_response = response.raw_body
|
|
134
|
+
envelope = SOAP::Processor.unmarshal(raw_response)
|
|
135
|
+
assert(envelope.is_a?(SOAP::SOAPEnvelope))
|
|
136
|
+
resp = envelope.body.response
|
|
137
|
+
assert(resp.is_a?(SOAP::SOAPArray))
|
|
138
|
+
assert(SOAP::Mapping.soap2obj(resp) == [1, 2, 3])
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def test_default_export
|
|
142
|
+
service_name = 'soap_service'
|
|
143
|
+
public_method_name = 'NonExistentMethodName'
|
|
144
|
+
qname = XSD::QName.new('urn:ActionService', public_method_name)
|
|
145
|
+
int_value = 50
|
|
146
|
+
bool_value = false
|
|
147
|
+
param_def = [
|
|
148
|
+
['in', 'param1', [SOAP::SOAPInt]],
|
|
149
|
+
['in', 'param2', [SOAP::SOAPBoolean]],
|
|
150
|
+
]
|
|
151
|
+
request = SOAP::RPC::SOAPMethodRequest.new(qname, param_def)
|
|
152
|
+
request.set_param([
|
|
153
|
+
['param1', SOAP::Mapping.obj2soap(int_value)],
|
|
154
|
+
['param2', SOAP::Mapping.obj2soap(bool_value)]
|
|
155
|
+
])
|
|
156
|
+
header = SOAP::SOAPHeader.new
|
|
157
|
+
body = SOAP::SOAPBody.new(request)
|
|
158
|
+
envelope = SOAP::SOAPEnvelope.new(header, body)
|
|
159
|
+
raw_request = SOAP::Processor.marshal(envelope)
|
|
160
|
+
test_request = ActionController::TestRequest.new
|
|
161
|
+
test_request.request_parameters['action'] = service_name
|
|
162
|
+
test_request.env['REQUEST_METHOD'] = "POST"
|
|
163
|
+
test_request.env['HTTP_CONTENTTYPE'] = 'text/xml'
|
|
164
|
+
test_request.env['HTTP_SOAPACTION'] = "/soap/#{service_name}/#{public_method_name}"
|
|
165
|
+
test_request.env['RAW_POST_DATA'] = raw_request
|
|
166
|
+
protocol = @container.request_protocol(test_request)
|
|
167
|
+
assert(protocol.is_a?(ActionService::Protocol::Soap::SoapProtocol))
|
|
168
|
+
request_info = protocol.request_info
|
|
169
|
+
method_name = SoapService.internal_export_name(public_method_name)
|
|
170
|
+
export_info = SoapService.exports[method_name]
|
|
171
|
+
service = @container.service_object(:soap_service)
|
|
172
|
+
assert(service.default_args.nil?)
|
|
173
|
+
response = @container.dispatch_request(protocol, request_info)
|
|
174
|
+
raw_response = response.raw_body
|
|
175
|
+
envelope = SOAP::Processor.unmarshal(raw_response)
|
|
176
|
+
assert(envelope.is_a?(SOAP::SOAPEnvelope))
|
|
177
|
+
resp = envelope.body.response
|
|
178
|
+
assert(resp.is_a?(SOAP::SOAPNil))
|
|
179
|
+
assert(service.default_args == [50, false])
|
|
180
|
+
end
|
|
94
181
|
end
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/abstract_unit'
|
|
2
|
+
require 'xmlrpc/parser'
|
|
3
|
+
require 'xmlrpc/create'
|
|
4
|
+
require 'xmlrpc/config'
|
|
5
|
+
|
|
6
|
+
module XMLRPC
|
|
7
|
+
class XmlRpcHelper
|
|
8
|
+
include ParserWriterChooseMixin
|
|
9
|
+
|
|
10
|
+
def create_request(methodName, *args)
|
|
11
|
+
create().methodCall(methodName, *args)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def parse_response(response)
|
|
15
|
+
parser().parseMethodResponse(response)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class XmlRpcService < ActionService::Base
|
|
21
|
+
attr :result
|
|
22
|
+
attr :hashvalue
|
|
23
|
+
attr :default_args
|
|
24
|
+
|
|
25
|
+
def initialize
|
|
26
|
+
@result = nil
|
|
27
|
+
@hashvalue = nil
|
|
28
|
+
@default_args = nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def add(a, b)
|
|
32
|
+
@result = a + b
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def something_hash(hash)
|
|
36
|
+
@hashvalue = hash
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def array_returner
|
|
40
|
+
[1, 2, 3]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def hash_returner
|
|
44
|
+
{'name' => 1, 'value' => 2}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def default(*args)
|
|
48
|
+
@default_args = args
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
export :add, :expects => [Integer, Integer], :returns => [Integer]
|
|
53
|
+
export :hash_returner, :returns => [Hash]
|
|
54
|
+
export :array_returner, :returns => [[Integer]]
|
|
55
|
+
export :something_hash, :expects => [Hash]
|
|
56
|
+
|
|
57
|
+
default_export :default
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
$service = XmlRpcService.new
|
|
61
|
+
|
|
62
|
+
class XmlRpcContainer
|
|
63
|
+
include ActionService::Container
|
|
64
|
+
include ActionService::Protocol::Registry
|
|
65
|
+
include ActionService::Protocol::Soap
|
|
66
|
+
include ActionService::Protocol::XmlRpc
|
|
67
|
+
|
|
68
|
+
def request_protocol(request)
|
|
69
|
+
probe_request_protocol(request)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def dispatch_request(protocol, info)
|
|
73
|
+
dispatch_service_invocation_request(protocol, info)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
service :xmlrpc, $service
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
class ProtocolXmlRpcTest < Test::Unit::TestCase
|
|
80
|
+
def setup
|
|
81
|
+
@helper = XMLRPC::XmlRpcHelper.new
|
|
82
|
+
@container = XmlRpcContainer.new
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def test_xmlrpc_request_dispatching
|
|
86
|
+
retval = do_xmlrpc_call('Add', 50, 30)
|
|
87
|
+
assert(retval == [true, 80])
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def test_array_returning
|
|
91
|
+
retval = do_xmlrpc_call('ArrayReturner')
|
|
92
|
+
assert(retval == [true, [1, 2, 3]])
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def test_hash_returning
|
|
96
|
+
retval = do_xmlrpc_call('HashReturner')
|
|
97
|
+
assert(retval == [true, {'name' => 1, 'value' => 2}])
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def test_hash_parameter
|
|
101
|
+
retval = do_xmlrpc_call('SomethingHash', {'name' => 1, 'value' => 2})
|
|
102
|
+
assert(retval == [true, true])
|
|
103
|
+
assert($service.hashvalue == {'name' => 1, 'value' => 2})
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def test_default_export
|
|
107
|
+
retval = do_xmlrpc_call('SomeNonexistentMethod', 'test', [1, 2], {'name'=>'value'})
|
|
108
|
+
assert(retval == [true, true])
|
|
109
|
+
assert($service.default_args == ['test', [1, 2], {'name'=>'value'}])
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def test_xmlrpc_introspection
|
|
113
|
+
retval = do_xmlrpc_call('system.listMethods', 'test', [1, 2], {'name'=>'value'})
|
|
114
|
+
assert(retval == [true, ["Add", "ArrayReturner", "HashReturner", "SomethingHash"]])
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
private
|
|
118
|
+
def do_xmlrpc_call(public_method_name, *args)
|
|
119
|
+
service_name = 'xmlrpc'
|
|
120
|
+
raw_request = @helper.create_request(public_method_name, *args)
|
|
121
|
+
test_request = ActionController::TestRequest.new
|
|
122
|
+
test_request.request_parameters['action'] = service_name
|
|
123
|
+
test_request.env['REQUEST_METHOD'] = "POST"
|
|
124
|
+
test_request.env['HTTP_CONTENTTYPE'] = 'text/xml'
|
|
125
|
+
test_request.env['RAW_POST_DATA'] = raw_request
|
|
126
|
+
protocol = @container.request_protocol(test_request)
|
|
127
|
+
response = @container.dispatch_request(protocol, protocol.request_info)
|
|
128
|
+
@helper.parse_response(response.raw_body)
|
|
129
|
+
end
|
|
130
|
+
end
|
data/test/router_wsdl_test.rb
CHANGED
|
@@ -17,8 +17,12 @@ class WsdlTestService < ActionService::Base
|
|
|
17
17
|
[]
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
def nil_returner
|
|
21
|
+
end
|
|
22
|
+
|
|
20
23
|
export :add, :expects => [Integer, Integer], :returns => [Integer]
|
|
21
24
|
export :find_people, :returns => [[TestPerson]]
|
|
25
|
+
export :nil_returner
|
|
22
26
|
end
|
|
23
27
|
|
|
24
28
|
class WsdlController < ActionController::Base
|
|
@@ -27,7 +31,7 @@ end
|
|
|
27
31
|
|
|
28
32
|
class RouterWsdlTest < Test::Unit::TestCase
|
|
29
33
|
def test_wsdl_generation
|
|
30
|
-
wsdl = WsdlController.to_wsdl(WsdlController, 'http://localhost:3000/test/', '/test')
|
|
34
|
+
wsdl = WsdlController.to_wsdl(WsdlController.new, 'http://localhost:3000/test/', '/test')
|
|
31
35
|
assert(WSDL::Parser.new.parse(wsdl).is_a?(WSDL::Definitions))
|
|
32
36
|
end
|
|
33
37
|
|
metadata
CHANGED
|
@@ -3,8 +3,8 @@ rubygems_version: 0.8.4
|
|
|
3
3
|
specification_version: 1
|
|
4
4
|
name: actionservice
|
|
5
5
|
version: !ruby/object:Gem::Version
|
|
6
|
-
version: 0.2.
|
|
7
|
-
date: 2005-02-
|
|
6
|
+
version: 0.2.100
|
|
7
|
+
date: 2005-02-08
|
|
8
8
|
summary: Web service support for Action Pack.
|
|
9
9
|
require_paths:
|
|
10
10
|
- lib
|
|
@@ -35,38 +35,40 @@ files:
|
|
|
35
35
|
- CHANGELOG
|
|
36
36
|
- MIT-LICENSE
|
|
37
37
|
- examples/soap
|
|
38
|
-
- examples/soap/app
|
|
39
38
|
- examples/soap/lib
|
|
40
39
|
- examples/soap/README
|
|
40
|
+
- examples/soap/app
|
|
41
|
+
- examples/soap/lib/google_search_service.rb
|
|
41
42
|
- examples/soap/app/controllers
|
|
42
43
|
- examples/soap/app/controllers/search_controller.rb
|
|
43
|
-
- examples/soap/lib/google_search_service.rb
|
|
44
44
|
- lib/action_service
|
|
45
45
|
- lib/action_service.rb
|
|
46
|
-
- lib/action_service/router
|
|
47
46
|
- lib/action_service/protocol
|
|
48
|
-
- lib/action_service/
|
|
49
|
-
- lib/action_service/router.rb
|
|
50
|
-
- lib/action_service/protocol.rb
|
|
51
|
-
- lib/action_service/container.rb
|
|
52
|
-
- lib/action_service/struct.rb
|
|
47
|
+
- lib/action_service/router
|
|
53
48
|
- lib/action_service/base.rb
|
|
49
|
+
- lib/action_service/container.rb
|
|
54
50
|
- lib/action_service/support
|
|
51
|
+
- lib/action_service/protocol.rb
|
|
52
|
+
- lib/action_service/router.rb
|
|
53
|
+
- lib/action_service/struct.rb
|
|
54
|
+
- lib/action_service/invocation.rb
|
|
55
|
+
- lib/action_service/protocol/registry.rb
|
|
56
|
+
- lib/action_service/protocol/soap.rb
|
|
57
|
+
- lib/action_service/protocol/xmlrpc.rb
|
|
58
|
+
- lib/action_service/protocol/abstract.rb
|
|
55
59
|
- lib/action_service/router/action_controller.rb
|
|
56
60
|
- lib/action_service/router/wsdl.rb
|
|
57
|
-
- lib/action_service/protocol/abstract.rb
|
|
58
|
-
- lib/action_service/protocol/soap.rb
|
|
59
|
-
- lib/action_service/protocol/registry.rb
|
|
60
61
|
- lib/action_service/support/class_inheritable_options.rb
|
|
62
|
+
- test/struct_test.rb
|
|
63
|
+
- test/abstract_unit.rb
|
|
61
64
|
- test/base_test.rb
|
|
62
65
|
- test/container_test.rb
|
|
63
|
-
- test/
|
|
64
|
-
- test/router_action_controller_test.rb
|
|
65
|
-
- test/abstract_unit.rb
|
|
66
|
+
- test/protocol_registry_test.rb
|
|
66
67
|
- test/protocol_soap_test.rb
|
|
67
|
-
- test/
|
|
68
|
+
- test/invocation_test.rb
|
|
68
69
|
- test/router_wsdl_test.rb
|
|
69
|
-
- test/
|
|
70
|
+
- test/protocol_xmlrpc_test.rb
|
|
71
|
+
- test/router_action_controller_test.rb
|
|
70
72
|
test_files: []
|
|
71
73
|
rdoc_options: []
|
|
72
74
|
extra_rdoc_files: []
|