actionservice 0.2.102 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|