actionservice 0.2.102 → 0.3.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/ChangeLog +1 -1
- data/README +48 -14
- data/Rakefile +6 -15
- data/TODO +2 -0
- data/examples/{soap → googlesearch}/README +26 -10
- data/examples/{soap/lib → googlesearch/delegated}/google_search_service.rb +22 -9
- data/examples/{soap/app/controllers → googlesearch/delegated}/search_controller.rb +0 -0
- data/examples/googlesearch/direct/search_controller.rb +106 -0
- data/examples/metaWeblog/README +28 -0
- data/examples/metaWeblog/blog_controller.rb +117 -0
- data/lib/action_service/base.rb +40 -2
- data/lib/action_service/container.rb +87 -18
- data/lib/action_service/exporting.rb +6 -12
- data/lib/action_service/invocation.rb +51 -10
- data/lib/action_service/protocol/abstract.rb +11 -11
- data/lib/action_service/protocol/registry.rb +7 -7
- data/lib/action_service/protocol/soap.rb +18 -10
- data/lib/action_service/protocol/xmlrpc.rb +65 -32
- data/lib/action_service/router/action_controller.rb +24 -10
- data/lib/action_service/router/wsdl.rb +5 -5
- data/lib/action_service/struct.rb +17 -1
- data/lib/action_service/support/class_inheritable_options.rb +1 -1
- data/test/protocol_xmlrpc_test.rb +23 -3
- metadata +12 -9
@@ -5,13 +5,13 @@ require 'xsd/datatypes'
|
|
5
5
|
require 'xsd/ns'
|
6
6
|
require 'singleton'
|
7
7
|
|
8
|
-
module ActionService
|
9
|
-
module Protocol
|
10
|
-
module Soap
|
11
|
-
class ProtocolError < ActionService::ActionServiceError
|
8
|
+
module ActionService # :nodoc:
|
9
|
+
module Protocol # :nodoc:
|
10
|
+
module Soap # :nodoc:
|
11
|
+
class ProtocolError < ActionService::ActionServiceError # :nodoc:
|
12
12
|
end
|
13
13
|
|
14
|
-
def self.append_features(base)
|
14
|
+
def self.append_features(base) # :nodoc:
|
15
15
|
super
|
16
16
|
base.register_protocol(HeaderAndBody, SoapProtocol)
|
17
17
|
base.extend(ClassMethods)
|
@@ -19,16 +19,24 @@ module ActionService
|
|
19
19
|
end
|
20
20
|
|
21
21
|
module ClassMethods
|
22
|
+
# Specifies the WSDL service name to use when generating WSDL. Highly
|
23
|
+
# recommended that you set this value, or code generators may generate
|
24
|
+
# classes with very generic names.
|
25
|
+
#
|
26
|
+
# === Example
|
27
|
+
# class ApiController < ActionController::Base
|
28
|
+
# wsdl_service_name 'Test'
|
29
|
+
# end
|
22
30
|
def wsdl_service_name(name)
|
23
31
|
write_inheritable_attribute("soap_mapper", SoapMapper.new("urn:#{name}"))
|
24
32
|
end
|
25
33
|
|
26
|
-
def soap_mapper
|
34
|
+
def soap_mapper # :nodoc:
|
27
35
|
read_inheritable_attribute("soap_mapper")
|
28
36
|
end
|
29
37
|
end
|
30
38
|
|
31
|
-
class SoapProtocol < AbstractProtocol
|
39
|
+
class SoapProtocol < AbstractProtocol # :nodoc:
|
32
40
|
def self.create_protocol_request(container_class, action_pack_request)
|
33
41
|
soap_action = extract_soap_action(action_pack_request)
|
34
42
|
return nil unless soap_action
|
@@ -178,7 +186,7 @@ module ActionService
|
|
178
186
|
end
|
179
187
|
end
|
180
188
|
|
181
|
-
class SoapMapper
|
189
|
+
class SoapMapper # :nodoc:
|
182
190
|
attr :registry
|
183
191
|
attr :custom_namespace
|
184
192
|
attr :custom_types
|
@@ -383,7 +391,7 @@ module ActionService
|
|
383
391
|
end
|
384
392
|
end
|
385
393
|
|
386
|
-
class SoapMapping
|
394
|
+
class SoapMapping # :nodoc:
|
387
395
|
attr :ruby_klass
|
388
396
|
attr :generated_klass
|
389
397
|
attr :soap_klass
|
@@ -440,7 +448,7 @@ module ActionService
|
|
440
448
|
end
|
441
449
|
end
|
442
450
|
|
443
|
-
class SoapArrayMapping < SoapMapping
|
451
|
+
class SoapArrayMapping < SoapMapping # :nodoc:
|
444
452
|
attr :element_mapping
|
445
453
|
|
446
454
|
def initialize(mapper, type_name, ruby_klass, soap_klass, registry_mapping, element_mapping)
|
@@ -1,36 +1,41 @@
|
|
1
1
|
require 'xmlrpc/parser'
|
2
|
+
require 'xmlrpc/create'
|
3
|
+
require 'xmlrpc/config'
|
2
4
|
require 'xmlrpc/utils'
|
3
5
|
require 'singleton'
|
4
6
|
|
5
|
-
module
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
module XMLRPC # :nodoc:
|
8
|
+
class XmlRpcHelper # :nodoc:
|
9
|
+
include Singleton
|
10
|
+
include ParserWriterChooseMixin
|
11
|
+
|
12
|
+
def parse_method_call(message)
|
13
|
+
parser().parseMethodCall(message)
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_method_response(successful, return_value)
|
17
|
+
create().methodResponse(successful, return_value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module ActionService # :nodoc:
|
23
|
+
module Protocol # :nodoc:
|
24
|
+
module XmlRpc # :nodoc:
|
25
|
+
def self.append_features(base) # :nodoc:
|
9
26
|
super
|
10
27
|
base.register_protocol(BodyOnly, XmlRpcProtocol)
|
11
28
|
end
|
12
29
|
|
13
|
-
class XmlRpcProtocol < AbstractProtocol
|
14
|
-
private
|
15
|
-
class Helper
|
16
|
-
include Singleton
|
17
|
-
include XMLRPC::ParserWriterChooseMixin
|
18
|
-
|
19
|
-
def get_parser
|
20
|
-
parser()
|
21
|
-
end
|
22
|
-
|
23
|
-
def get_create
|
24
|
-
create()
|
25
|
-
end
|
26
|
-
end
|
30
|
+
class XmlRpcProtocol < AbstractProtocol # :nodoc:
|
27
31
|
|
28
32
|
public
|
29
33
|
|
30
34
|
def self.create_protocol_request(container_class, action_pack_request)
|
31
|
-
|
35
|
+
helper = XMLRPC::XmlRpcHelper.instance
|
32
36
|
service_name = action_pack_request.parameters['action']
|
33
|
-
methodname, params =
|
37
|
+
methodname, params = helper.parse_method_call(action_pack_request.raw_post)
|
38
|
+
methodname.gsub!(/^[^\.]+\./, '') unless methodname =~ /^system\./ # XXX
|
34
39
|
protocol = XmlRpcProtocol.new(container_class)
|
35
40
|
content_type = action_pack_request.env['HTTP_CONTENT_TYPE']
|
36
41
|
content_type ||= 'text/xml'
|
@@ -38,8 +43,8 @@ module ActionService
|
|
38
43
|
action_pack_request.raw_post,
|
39
44
|
service_name.to_sym,
|
40
45
|
methodname,
|
41
|
-
content_type
|
42
|
-
|
46
|
+
content_type,
|
47
|
+
:xmlrpc_values => params)
|
43
48
|
request
|
44
49
|
rescue
|
45
50
|
nil
|
@@ -51,10 +56,11 @@ module ActionService
|
|
51
56
|
end
|
52
57
|
|
53
58
|
def unmarshal_request(protocol_request)
|
54
|
-
values = protocol_request.
|
59
|
+
values = protocol_request.options[:xmlrpc_values]
|
55
60
|
signature = protocol_request.signature
|
56
61
|
if signature
|
57
62
|
signature = array_types(signature)
|
63
|
+
values = transform_expected_params(signature, values)
|
58
64
|
protocol_request.check_parameter_types(values, signature)
|
59
65
|
values
|
60
66
|
else
|
@@ -63,30 +69,31 @@ module ActionService
|
|
63
69
|
end
|
64
70
|
|
65
71
|
def marshal_response(protocol_request, return_value)
|
66
|
-
|
72
|
+
helper = XMLRPC::XmlRpcHelper.instance
|
67
73
|
signature = protocol_request.return_signature
|
68
74
|
if signature
|
69
75
|
signature = array_types(signature)
|
70
76
|
protocol_request.check_parameter_types([return_value], signature)
|
71
|
-
return_value =
|
72
|
-
raw_response =
|
77
|
+
return_value = transform_return_value(return_value)
|
78
|
+
raw_response = helper.create_method_response(true, return_value)
|
73
79
|
else
|
74
80
|
# XML-RPC doesn't have the concept of a void method, nor does it
|
75
81
|
# support a nil return value, so return true if we would have returned
|
76
82
|
# nil
|
77
83
|
if protocol_request.checked?
|
78
|
-
raw_response =
|
84
|
+
raw_response = helper.create_method_response(true, true)
|
79
85
|
else
|
80
86
|
return_value = true if return_value.nil?
|
81
|
-
raw_response =
|
87
|
+
raw_response = helper.create_method_response(true, return_value)
|
82
88
|
end
|
83
89
|
end
|
84
90
|
ProtocolResponse.new(self, raw_response, 'text/xml')
|
85
91
|
end
|
86
92
|
|
87
93
|
def marshal_exception(exception)
|
88
|
-
|
89
|
-
|
94
|
+
helper = XMLRPC::XmlRpcHelper.instance
|
95
|
+
exception = XMLRPC::FaultException.new(1, exception.message)
|
96
|
+
raw_response = helper.create_method_response(false, exception)
|
90
97
|
ProtocolResponse.new(self, raw_response, 'text/xml')
|
91
98
|
end
|
92
99
|
|
@@ -108,14 +115,40 @@ module ActionService
|
|
108
115
|
signature.map{|x| x.is_a?(Array) ? Array : x}
|
109
116
|
end
|
110
117
|
|
111
|
-
def
|
118
|
+
def transform_expected_params(signature, params)
|
119
|
+
(1..signature.size).each do |i|
|
120
|
+
i -= 1
|
121
|
+
if signature[i].ancestors.include?(ActionService::Struct)
|
122
|
+
if params[i].class.ancestors.include?(Hash)
|
123
|
+
new_param = signature[i].new
|
124
|
+
signature[i].members.each do |name, klass|
|
125
|
+
new_param.send('%s=' % name.to_s, params[i][name.to_s])
|
126
|
+
end
|
127
|
+
params[i] = new_param
|
128
|
+
else
|
129
|
+
raise(ProtocolError, "expected input parameter #{i+1} to be a Hash")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
params
|
134
|
+
end
|
135
|
+
|
136
|
+
def transform_return_value(return_value)
|
112
137
|
if return_value.is_a?(Array)
|
113
138
|
(1..return_value.size).each do |i|
|
114
|
-
return_value[i-1] =
|
139
|
+
return_value[i-1] = transform_return_value(return_value[i-1])
|
115
140
|
end
|
116
141
|
else
|
117
142
|
if return_value.is_a?(ActiveRecord::Base)
|
118
143
|
return_value = return_value.instance_variable_get('@attributes')
|
144
|
+
elsif return_value.is_a?(ActionService::Struct)
|
145
|
+
struct = {}
|
146
|
+
return_value.class.members.each do |name, klass|
|
147
|
+
value = return_value.send(name)
|
148
|
+
next if value.nil?
|
149
|
+
struct[name.to_s] = value
|
150
|
+
end
|
151
|
+
return_value = struct
|
119
152
|
end
|
120
153
|
end
|
121
154
|
return_value
|
@@ -1,7 +1,7 @@
|
|
1
|
-
module ActionService
|
2
|
-
module Router
|
3
|
-
module ActionController
|
4
|
-
def self.append_features(base)
|
1
|
+
module ActionService # :nodoc:
|
2
|
+
module Router # :nodoc:
|
3
|
+
module ActionController # :nodoc:
|
4
|
+
def self.append_features(base) # :nodoc:
|
5
5
|
base.add_export_definition_callback do |klass, export_name, export_info|
|
6
6
|
if klass.service_dispatching_mode == :direct && !klass.method_defined?(:api)
|
7
7
|
klass.class_eval <<-EOS
|
@@ -23,16 +23,22 @@ module ActionService
|
|
23
23
|
base.send(:include, ActionService::Router::ActionController::InstanceMethods)
|
24
24
|
end
|
25
25
|
|
26
|
-
module InstanceMethods
|
26
|
+
module InstanceMethods # :nodoc:
|
27
27
|
private
|
28
28
|
def process_action_service_request
|
29
29
|
protocol_request = nil
|
30
30
|
begin
|
31
|
-
|
31
|
+
begin
|
32
|
+
protocol_request = probe_request_protocol(self.request)
|
33
|
+
rescue Exception => e
|
34
|
+
logger.error "Invalid request: #{e.message}"
|
35
|
+
logger.error self.request.raw_post
|
36
|
+
raise
|
37
|
+
end
|
32
38
|
if protocol_request
|
33
39
|
log_request(protocol_request)
|
34
40
|
protocol_response = dispatch_service_request(protocol_request)
|
35
|
-
log_response(
|
41
|
+
log_response(protocol_response)
|
36
42
|
response_options = {
|
37
43
|
:type => protocol_response.content_type,
|
38
44
|
:disposition => 'inline'
|
@@ -44,16 +50,24 @@ module ActionService
|
|
44
50
|
end
|
45
51
|
rescue Exception => e
|
46
52
|
log_error e unless logger.nil?
|
47
|
-
service_object = service_object(protocol_request.service_name) rescue nil
|
48
53
|
exc_response = nil
|
49
|
-
|
50
|
-
|
54
|
+
case service_dispatching_mode
|
55
|
+
when :direct
|
56
|
+
if self.class.report_exceptions
|
57
|
+
exc_response = protocol_request.protocol.marshal_exception(e)
|
58
|
+
end
|
59
|
+
when :delegated
|
60
|
+
service_object = service_object(protocol_request.service_name) rescue nil
|
61
|
+
if service_object && service_object.class.report_exceptions
|
62
|
+
exc_response = protocol_request.protocol.marshal_exception(e) rescue nil
|
63
|
+
end
|
51
64
|
end
|
52
65
|
if exc_response
|
53
66
|
response_options = {
|
54
67
|
:type => exc_response.content_type,
|
55
68
|
:disposition => 'inline'
|
56
69
|
}
|
70
|
+
log_response exc_response
|
57
71
|
send_data(exc_response.raw_body, response_options)
|
58
72
|
else
|
59
73
|
render_text 'Internal protocol error', "500 #{e.message}"
|
@@ -1,11 +1,11 @@
|
|
1
|
-
module ActionService
|
2
|
-
module Router
|
3
|
-
module Wsdl
|
4
|
-
def self.append_features(base)
|
1
|
+
module ActionService # :nodoc:
|
2
|
+
module Router # :nodoc:
|
3
|
+
module Wsdl # :nodoc:
|
4
|
+
def self.append_features(base) # :nodoc:
|
5
5
|
base.send(:include, ActionService::Router::Wsdl::InstanceMethods)
|
6
6
|
end
|
7
7
|
|
8
|
-
module InstanceMethods
|
8
|
+
module InstanceMethods # :nodoc:
|
9
9
|
XsdNs = 'http://www.w3.org/2001/XMLSchema'
|
10
10
|
WsdlNs = 'http://schemas.xmlsoap.org/wsdl/'
|
11
11
|
SoapNs = 'http://schemas.xmlsoap.org/wsdl/soap/'
|
@@ -1,5 +1,21 @@
|
|
1
1
|
module ActionService
|
2
|
+
# To send structured types across the wire, derive from ActionService::Struct,
|
3
|
+
# and use +member+ to declare structure members.
|
4
|
+
#
|
5
|
+
# === Example
|
6
|
+
#
|
7
|
+
# class Person < ActionService::Struct
|
8
|
+
# member :firstnames, [String]
|
9
|
+
# member :lastname, String
|
10
|
+
# member :email, String
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# Active Record model classes are already implicitly supported for return
|
14
|
+
# value signatures. A structure containing its columns as members will be
|
15
|
+
# automatically generated if its present in a signature.
|
2
16
|
class Struct
|
17
|
+
# Creates a structure member accessible using +name+. Generates
|
18
|
+
# accessor methods for reading and writing the member value.
|
3
19
|
def self.member(name, type)
|
4
20
|
write_inheritable_hash("struct_members", name => type)
|
5
21
|
class_eval <<-END
|
@@ -8,7 +24,7 @@ module ActionService
|
|
8
24
|
END
|
9
25
|
end
|
10
26
|
|
11
|
-
def self.members
|
27
|
+
def self.members # :nodoc:
|
12
28
|
read_inheritable_attribute("struct_members") || {}
|
13
29
|
end
|
14
30
|
end
|
@@ -4,7 +4,7 @@ require 'xmlrpc/create'
|
|
4
4
|
require 'xmlrpc/config'
|
5
5
|
|
6
6
|
module XMLRPC
|
7
|
-
class
|
7
|
+
class XmlRpcTestHelper
|
8
8
|
include ParserWriterChooseMixin
|
9
9
|
|
10
10
|
def create_request(methodName, *args)
|
@@ -18,6 +18,12 @@ module XMLRPC
|
|
18
18
|
end
|
19
19
|
|
20
20
|
module ProtocolXmlRpcTest
|
21
|
+
class Person < ActionService::Struct
|
22
|
+
member :firstname, String
|
23
|
+
member :lastname, String
|
24
|
+
member :active, TrueClass
|
25
|
+
end
|
26
|
+
|
21
27
|
class Service < ActionService::Base
|
22
28
|
attr :result
|
23
29
|
attr :hashvalue
|
@@ -44,6 +50,14 @@ module ProtocolXmlRpcTest
|
|
44
50
|
def hash_returner
|
45
51
|
{'name' => 1, 'value' => 2}
|
46
52
|
end
|
53
|
+
|
54
|
+
def struct_array_returner
|
55
|
+
person = Person.new
|
56
|
+
person.firstname = "John"
|
57
|
+
person.lastname = "Doe"
|
58
|
+
person.active = true
|
59
|
+
[person]
|
60
|
+
end
|
47
61
|
|
48
62
|
def default(*args)
|
49
63
|
@default_args = args
|
@@ -54,6 +68,7 @@ module ProtocolXmlRpcTest
|
|
54
68
|
export :hash_returner, :returns => [Hash]
|
55
69
|
export :array_returner, :returns => [[Integer]]
|
56
70
|
export :something_hash, :expects => [Hash]
|
71
|
+
export :struct_array_returner, :returns => [[Person]]
|
57
72
|
|
58
73
|
default_export :default
|
59
74
|
end
|
@@ -81,7 +96,7 @@ end
|
|
81
96
|
|
82
97
|
class TC_ProtocolXmlRpc < Test::Unit::TestCase
|
83
98
|
def setup
|
84
|
-
@helper = XMLRPC::
|
99
|
+
@helper = XMLRPC::XmlRpcTestHelper.new
|
85
100
|
@container = ProtocolXmlRpcTest::Container.new
|
86
101
|
end
|
87
102
|
|
@@ -100,6 +115,11 @@ class TC_ProtocolXmlRpc < Test::Unit::TestCase
|
|
100
115
|
assert(retval == [true, {'name' => 1, 'value' => 2}])
|
101
116
|
end
|
102
117
|
|
118
|
+
def test_struct_array_returning
|
119
|
+
retval = do_xmlrpc_call('StructArrayReturner')
|
120
|
+
assert(retval == [true, [{"firstname"=>"John", "lastname"=>"Doe", "active"=>true}]])
|
121
|
+
end
|
122
|
+
|
103
123
|
def test_hash_parameter
|
104
124
|
retval = do_xmlrpc_call('SomethingHash', {'name' => 1, 'value' => 2})
|
105
125
|
assert(retval == [true, true])
|
@@ -114,7 +134,7 @@ class TC_ProtocolXmlRpc < Test::Unit::TestCase
|
|
114
134
|
|
115
135
|
def test_xmlrpc_introspection
|
116
136
|
retval = do_xmlrpc_call('system.listMethods', 'test', [1, 2], {'name'=>'value'})
|
117
|
-
assert(retval == [true, ["Add", "ArrayReturner", "HashReturner", "SomethingHash"]])
|
137
|
+
assert(retval == [true, ["Add", "ArrayReturner", "HashReturner", "SomethingHash", "StructArrayReturner"]])
|
118
138
|
end
|
119
139
|
|
120
140
|
private
|
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.
|
7
|
-
date: 2005-02-
|
6
|
+
version: 0.3.0
|
7
|
+
date: 2005-02-13
|
8
8
|
summary: Web service support for Action Pack.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -34,13 +34,16 @@ files:
|
|
34
34
|
- HACKING
|
35
35
|
- ChangeLog
|
36
36
|
- MIT-LICENSE
|
37
|
-
- examples/
|
38
|
-
- examples/
|
39
|
-
- examples/
|
40
|
-
- examples/
|
41
|
-
- examples/
|
42
|
-
- examples/
|
43
|
-
- examples/
|
37
|
+
- examples/metaWeblog
|
38
|
+
- examples/googlesearch
|
39
|
+
- examples/metaWeblog/blog_controller.rb
|
40
|
+
- examples/metaWeblog/README
|
41
|
+
- examples/googlesearch/README
|
42
|
+
- examples/googlesearch/direct
|
43
|
+
- examples/googlesearch/delegated
|
44
|
+
- examples/googlesearch/direct/search_controller.rb
|
45
|
+
- examples/googlesearch/delegated/google_search_service.rb
|
46
|
+
- examples/googlesearch/delegated/search_controller.rb
|
44
47
|
- lib/action_service
|
45
48
|
- lib/action_service.rb
|
46
49
|
- lib/action_service/protocol
|