ap4r 0.3.2 → 0.3.3
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 → History.txt} +5 -0
- data/Manifest.txt +48 -0
- data/README.txt +82 -0
- data/Rakefile +71 -149
- data/config/queues_mysql.cfg +2 -2
- data/config/queues_pgsql.cfg +19 -0
- data/lib/ap4r.rb +0 -1
- data/lib/ap4r/message_store_ext.rb +230 -0
- data/lib/ap4r/mongrel_ap4r.rb +4 -0
- data/lib/ap4r/postgresql.sql +13 -0
- data/lib/ap4r/retention_history.rb +2 -2
- data/lib/ap4r/script/setup.rb +0 -1
- data/lib/ap4r/stored_message.rb +120 -7
- data/lib/ap4r/version.rb +1 -1
- data/lib/ap4r/xxx_create_table_for_saf.rb +21 -0
- data/lib/ap4r/xxx_create_table_for_saf_to_postgresql.rb +21 -0
- data/rails_plugin/ap4r/init.rb +11 -0
- data/rails_plugin/ap4r/lib/ap4r/queue_put_stub.rb +21 -0
- data/rails_plugin/ap4r/lib/ap4r/service_handler.rb +165 -0
- data/rails_plugin/ap4r/lib/ap4r_client.rb +132 -0
- data/rails_plugin/ap4r/lib/{async_controller.rb → async_helper.rb} +43 -71
- data/rails_plugin/ap4r/lib/message_builder.rb +181 -0
- data/rails_plugin/ap4r/tasks/ap4r.rake +35 -0
- data/spec/local/dispatcher_base_spec.rb +130 -0
- data/spec/spec_helper.rb +7 -0
- metadata +36 -40
- data/README +0 -55
- data/script/loop.cmd +0 -3
- data/script/loop.rb +0 -8
@@ -0,0 +1,132 @@
|
|
1
|
+
# Author:: Kiwamu Kato
|
2
|
+
# Copyright:: Copyright (c) 2007 Future Architect Inc.
|
3
|
+
# Licence:: MIT Licence
|
4
|
+
|
5
|
+
require 'forwardable'
|
6
|
+
require 'async_helper'
|
7
|
+
|
8
|
+
module Ap4r #:nodoc:
|
9
|
+
|
10
|
+
# This +Client+ is the Rails plugin for asynchronous processing.
|
11
|
+
# Asynchronous logics are called via various protocols, such as XML-RPC,
|
12
|
+
# SOAP, HTTP POST, and more. Now default protocol is HTTP POST.
|
13
|
+
#
|
14
|
+
# Examples: The part of calling next asynchronous logics in a controller in the HelloWorld Sample.
|
15
|
+
#
|
16
|
+
# req = WorldRequest.new([:world_id => 1, :message => "World"})
|
17
|
+
# ap4r.async_to({:controller => 'async_world', :action => 'execute'},
|
18
|
+
# {:world_id => 1, :message => "World"},
|
19
|
+
# {:dispatch_mode => :HTTP}) # skippable
|
20
|
+
#
|
21
|
+
# render :action => 'response'
|
22
|
+
#
|
23
|
+
# Complement: Above +ap4r+ method is defiend init.rb in +%RAILS_ROOT%/vendor/plugin/ap4r/+.
|
24
|
+
#
|
25
|
+
class Client
|
26
|
+
extend Forwardable
|
27
|
+
include ::Ap4r::AsyncHelper::Base
|
28
|
+
|
29
|
+
def initialize controller
|
30
|
+
@controller = controller
|
31
|
+
end
|
32
|
+
|
33
|
+
def_delegators :@controller, :logger, :url_for
|
34
|
+
|
35
|
+
# Queue a message for next asynchronous logic. Some options are supported.
|
36
|
+
#
|
37
|
+
# Use options to specify target url, etc.
|
38
|
+
# Accurate meanings are defined by a individual converter class.
|
39
|
+
# * :controller (name of next logic)
|
40
|
+
# * :action (name of next logic)
|
41
|
+
#
|
42
|
+
# Use rm_options to pass parameter in queue-put.
|
43
|
+
# Listings below are AP4R extended options.
|
44
|
+
# See the reliable-msg docuememt for more details.
|
45
|
+
# * :target_url (URL of target, prevail over :controller)
|
46
|
+
# * :target_action (action of target, prevail over :action)
|
47
|
+
# * :target_method (HTTP method, e.g. "GET", "POST", etc.)
|
48
|
+
# * :dispatch_mode (protocol in dispatching)
|
49
|
+
# * :queue_name (prevail over :controller and :action)
|
50
|
+
#
|
51
|
+
# Object of argumemts (async_params, options and rm_options) will not be modified.
|
52
|
+
# Implementors (of this class and converters) should not modify them.
|
53
|
+
#
|
54
|
+
# Examples: the most simple
|
55
|
+
#
|
56
|
+
# ap4r.async_to({:controller => 'next_controller', :action => 'next_action'},
|
57
|
+
# {:world_id => 1, :message => "World"})
|
58
|
+
#
|
59
|
+
#
|
60
|
+
# Examples: taking block
|
61
|
+
#
|
62
|
+
# ap4r.async_to({:controller => 'next_controller', :action => 'next_action'}) do
|
63
|
+
# body :world_id, 1
|
64
|
+
# body :message, "World"
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
#
|
68
|
+
# Examples: transmitting ActiveRecord object
|
69
|
+
#
|
70
|
+
# ap4r.async_to({:controller => 'next_controller', :action => 'next_action'}) do
|
71
|
+
# body :world, World.find(1)
|
72
|
+
# body :message, "World"
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
#
|
76
|
+
# Examples: transmitting with xml format over http (now support text, json and yaml format).
|
77
|
+
#
|
78
|
+
# ap4r.async_to({:controller => 'next_controller', :action => 'next_action'}) do
|
79
|
+
# body :world, World.find(1)
|
80
|
+
# body :message, "World"
|
81
|
+
# format :xml
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
#
|
85
|
+
# Examples: direct assignment for formatted message body
|
86
|
+
#
|
87
|
+
# ap4r.async_to({:controller => 'next_controller', :action => 'next_action'}) do
|
88
|
+
# world = World.find(1).to_xml :except => ...
|
89
|
+
# body_as_xml world
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
#
|
93
|
+
# Examples: setting message header
|
94
|
+
#
|
95
|
+
# ap4r.async_to({:controller => 'next_controller', :action => 'next_action'}) do
|
96
|
+
# body :world_id, 1
|
97
|
+
# body :message, "World"
|
98
|
+
#
|
99
|
+
# header :priority, 1
|
100
|
+
# http_header "Content-type", ...
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
alias :async_to :async_dispatch
|
104
|
+
|
105
|
+
# Provides at-least-once QoS level.
|
106
|
+
# +block+ are tipically composed of database accesses and +async_to+ calls.
|
107
|
+
# Database accesses are executed transactionallly by +active_record_class+'s transaction method.
|
108
|
+
# In the +block+, +async_to+ calls invoke NOT immediate queueing but just storing messages
|
109
|
+
# to the database (assumed to be the same one as application uses).
|
110
|
+
#
|
111
|
+
# If the execution of +block+ finishes successfully, database transaction is committed and
|
112
|
+
# forward process of each stored message begins.
|
113
|
+
# Forward process composed in two parts. First puts the message into a queue, secondary update
|
114
|
+
# or delete the entry from a management table.
|
115
|
+
#
|
116
|
+
# SAF (store and forward) processing like this guarantees that any message
|
117
|
+
# is never lost and keeps reasonable performance (without two phase commit).
|
118
|
+
#
|
119
|
+
# Examples: Just call async_to method in this block.
|
120
|
+
#
|
121
|
+
# ap4r.transaction do
|
122
|
+
# req = WorldRequest.new([:world_id => 1, :message => "World"})
|
123
|
+
# ap4r.async_to({:controller => 'async_world', :action => 'execute'},
|
124
|
+
# {:world_id => 1, :message => "World"})
|
125
|
+
#
|
126
|
+
# render :action => 'response'
|
127
|
+
# end
|
128
|
+
#
|
129
|
+
alias :transaction :transaction_with_saf
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
@@ -3,32 +3,22 @@
|
|
3
3
|
# Licence:: MIT Licence
|
4
4
|
|
5
5
|
require 'reliable-msg'
|
6
|
-
|
6
|
+
require 'ap4r/stored_message'
|
7
|
+
require 'message_builder'
|
7
8
|
|
8
9
|
module Ap4r
|
9
10
|
|
10
|
-
# This +
|
11
|
-
#
|
12
|
-
# SOAP, HTTP POST, and more. Now default protocol is HTTP POST.
|
11
|
+
# This +AsyncHelper+ is included to +Ap4rClient+ and works the Rails plugin
|
12
|
+
# for asynchronous processing.
|
13
13
|
#
|
14
|
-
|
15
|
-
#
|
16
|
-
# req = WorldRequest.new([:world_id => 1, :message => "World"})
|
17
|
-
# async_dispatch(req,
|
18
|
-
# {:controller => 'async_world', :action => 'execute'},
|
19
|
-
# :dispatch_mode => :XMLRPC }) # skippable
|
20
|
-
#
|
21
|
-
# render :action => 'response'
|
22
|
-
#
|
23
|
-
module AsyncController
|
14
|
+
module AsyncHelper
|
24
15
|
|
25
16
|
module Base
|
26
17
|
Converters = {}
|
27
18
|
|
28
|
-
# TODO: constant or class variable, whick is better? 2007/05/02 by shino
|
29
19
|
DRUBY_HOST = ENV['AP4R_DRUBY_HOST'] || 'localhost'
|
30
20
|
DRUBY_PORT = ENV['AP4R_DRUBY_PORT'] || '6438'
|
31
|
-
DRUBY_URI = "druby://#{DRUBY_HOST}:#{DRUBY_PORT}"
|
21
|
+
DRUBY_URI = "druby://#{DRUBY_HOST}:#{DRUBY_PORT}"
|
32
22
|
|
33
23
|
@@default_dispatch_mode = :HTTP
|
34
24
|
@@default_rm_options = { :delivery => :once, :dispatch_mode => @@default_dispatch_mode }
|
@@ -36,30 +26,7 @@ module Ap4r
|
|
36
26
|
|
37
27
|
mattr_accessor :default_dispatch_mode, :default_rm_options, :default_queue_prefix, :saf_delete_mode
|
38
28
|
|
39
|
-
#
|
40
|
-
# +block+ are tipically composed of database accesses and +async_dispatch+ calls.
|
41
|
-
# Database accesses are executed transactionallly by +active_record_class+'s transaction method.
|
42
|
-
# In the +block+, +async_dispatch+ calls invoke NOT immediate queueing but just storing messages
|
43
|
-
# to the database (assumed to be the same one as application uses).
|
44
|
-
#
|
45
|
-
# If the execution of +block+ finishes successfully, database transaction is committed and
|
46
|
-
# forward process of each stored message begins.
|
47
|
-
# Forward process composed in two parts. First puts the message into a queue, secondary update
|
48
|
-
# or delete the entry from a management table.
|
49
|
-
#
|
50
|
-
# SAF (store and forward) processing like this guarantees that any message
|
51
|
-
# is never lost and keeps reasonable performance (without two phase commit).
|
52
|
-
#
|
53
|
-
# Examples: Just call async_dispath method in this block.
|
54
|
-
#
|
55
|
-
# transaction_with saf do
|
56
|
-
# req = WorldRequest.new([:world_id => 1, :message => "World"})
|
57
|
-
# async_dispatch(req,
|
58
|
-
# {:controller => 'async_world', :action => 'execute'},
|
59
|
-
# :dispatch_mode => :XMLRPC }) # skippable
|
60
|
-
#
|
61
|
-
# render :action => 'response'
|
62
|
-
# end
|
29
|
+
# This method is aliased as ::Ap4r::Client#transaction
|
63
30
|
#
|
64
31
|
def transaction_with_saf(active_record_class = ::Ap4r::StoredMessage, *objects, &block)
|
65
32
|
|
@@ -78,7 +45,7 @@ module Ap4r
|
|
78
45
|
# Once some error occured, such as disconnect reliable-msg or server crush,
|
79
46
|
# which is smart to keep to put a message or stop to do it?
|
80
47
|
# In the case of being many async messages, the former strategy is not so good.
|
81
|
-
#
|
48
|
+
#
|
82
49
|
# TODO: add delayed forward mode 2007/05/02 by shino
|
83
50
|
Thread.current[:stored_messages].each {|k,v|
|
84
51
|
__queue_put(v[:queue_name], v[:queue_message], v[:queue_headers])
|
@@ -106,27 +73,10 @@ module Ap4r
|
|
106
73
|
Thread.current[:stored_messages] = nil
|
107
74
|
end
|
108
75
|
|
109
|
-
#
|
110
|
-
#
|
111
|
-
# Use options to specify target url, etc.
|
112
|
-
# Accurate meanings are defined by a individual converter class.
|
113
|
-
# * :controller (name of next logic)
|
114
|
-
# * :action (name of next logic)
|
76
|
+
# This method is aliased as ::Ap4r::Client#async_to
|
115
77
|
#
|
116
|
-
|
117
|
-
|
118
|
-
# See the reliable-msg docuememt for more details.
|
119
|
-
# * :target_url (URL of target, prevail over :controller)
|
120
|
-
# * :target_action (action of target, prevail over :action)
|
121
|
-
# * :target_method (HTTP method, e.g. "GET", "POST", etc.)
|
122
|
-
# * :dispatch_mode (protocol in dispatching)
|
123
|
-
# * :queue_name (prevail over :controller and :action)
|
124
|
-
#
|
125
|
-
# Object of argumemts (async_params, options and rm_options) will not be modified.
|
126
|
-
# Implementors (of this class and converters) should not modify them.
|
127
|
-
#
|
128
|
-
def async_dispatch(url_options = {}, async_params = nil, rm_options = nil)
|
129
|
-
# TODO: add :url to url_options to specify :target_url shortly 2007/05/02 by shino
|
78
|
+
def async_dispatch(url_options = {}, async_params = {}, rm_options = {}, &block)
|
79
|
+
|
130
80
|
if logger.debug?
|
131
81
|
logger.debug("url_options: ")
|
132
82
|
logger.debug(url_options.inspect)
|
@@ -138,7 +88,10 @@ module Ap4r
|
|
138
88
|
|
139
89
|
# TODO: clone it, 2006/10/16 shino
|
140
90
|
url_options ||= {}
|
141
|
-
url_options[:controller] ||=
|
91
|
+
url_options[:controller] ||= @controller.controller_path.gsub("/", ".")
|
92
|
+
url_options[:url] ||= {:controller => url_options[:controller], :action => url_options[:action]}
|
93
|
+
url_options[:url][:controller] ||= url_options[:controller] if url_options[:url].kind_of?(Hash)
|
94
|
+
|
142
95
|
rm_options = @@default_rm_options.merge(rm_options || {})
|
143
96
|
|
144
97
|
# Only async_params is not cloned. options and rm_options are cloned before now.
|
@@ -150,6 +103,21 @@ module Ap4r
|
|
150
103
|
queue_message = converter.make_params
|
151
104
|
queue_headers = converter.make_rm_options
|
152
105
|
|
106
|
+
message_builder = ::Ap4r::MessageBuilder.new(queue_name, queue_message, queue_headers)
|
107
|
+
if block_given?
|
108
|
+
message_builder.instance_eval(&block)
|
109
|
+
end
|
110
|
+
queue_name = message_builder.queue_name
|
111
|
+
queue_headers = message_builder.message_headers
|
112
|
+
# TODO: proces flow of Converter and MessageBuilder should (probably) be reversed 2007/09/19 by shino
|
113
|
+
# This branching is ad-hoc fix
|
114
|
+
if queue_headers[:dispatch_mode] == :HTTP
|
115
|
+
queue_message = message_builder.format_message_body
|
116
|
+
else
|
117
|
+
queue_message = message_builder.message_body
|
118
|
+
end
|
119
|
+
|
120
|
+
|
153
121
|
if Thread.current[:use_saf]
|
154
122
|
stored_message = ::Ap4r::StoredMessage.store(queue_name, queue_message, queue_headers)
|
155
123
|
|
@@ -174,9 +142,14 @@ module Ap4r
|
|
174
142
|
end
|
175
143
|
|
176
144
|
def __get_queue_name(options, rm_options)
|
177
|
-
|
178
|
-
|
179
|
-
|
145
|
+
if options[:url].kind_of?(Hash)
|
146
|
+
rm_options[:queue] ||=
|
147
|
+
@@default_queue_prefix.clone.concat(options[:url][:controller].to_s).concat('.').concat(options[:url][:action].to_s)
|
148
|
+
else
|
149
|
+
rm_options[:queue] ||=
|
150
|
+
@@default_queue_prefix.clone.chomp(".").concat(URI::parse(options[:url]).path.gsub("/", "."))
|
151
|
+
end
|
152
|
+
rm_options[:queue]
|
180
153
|
end
|
181
154
|
|
182
155
|
end
|
@@ -193,7 +166,7 @@ module Ap4r
|
|
193
166
|
# add self to a Converters list.
|
194
167
|
def self.dispatch_mode(mode_symbol)
|
195
168
|
self.const_set(:DISPATCH_MODE, mode_symbol)
|
196
|
-
::Ap4r::
|
169
|
+
::Ap4r::AsyncHelper::Base::Converters[mode_symbol] = self
|
197
170
|
end
|
198
171
|
|
199
172
|
def initialize(url_options, async_params, rm_options, url_for_handler)
|
@@ -220,6 +193,7 @@ module Ap4r
|
|
220
193
|
private
|
221
194
|
# helper method for <tt>ActionController#url_for</tt>
|
222
195
|
def url_for(url_for_options, *parameter_for_method_reference)
|
196
|
+
return url_for_options if url_for_options.kind_of?(String)
|
223
197
|
@url_for_handler.url_for(url_for_options, *parameter_for_method_reference)
|
224
198
|
end
|
225
199
|
|
@@ -233,7 +207,7 @@ module Ap4r
|
|
233
207
|
end
|
234
208
|
|
235
209
|
def make_rm_options
|
236
|
-
@rm_options[:target_url] ||= url_for(@url_options)
|
210
|
+
@rm_options[:target_url] ||= url_for(@url_options[:url])
|
237
211
|
@rm_options[:target_method] ||= 'POST'
|
238
212
|
#TODO: make option key to specify HTTP headers, 2006/10/16 shino
|
239
213
|
@rm_options
|
@@ -254,14 +228,12 @@ module Ap4r
|
|
254
228
|
end
|
255
229
|
|
256
230
|
def action_api_name
|
257
|
-
action_method_name = @url_options[:action]
|
231
|
+
action_method_name = @url_options[:url][:action]
|
258
232
|
action_method_name.camelcase
|
259
233
|
end
|
260
234
|
|
261
235
|
def options_without_action
|
262
|
-
|
263
|
-
new_opts[:action] = nil
|
264
|
-
new_opts
|
236
|
+
@url_options[:url].reject{ |k,v| k == :action }
|
265
237
|
end
|
266
238
|
|
267
239
|
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
# Author:: Kiwamu Kato
|
2
|
+
# Copyright:: Copyright (c) 2007 Future Architect Inc.
|
3
|
+
# Licence:: MIT Licence
|
4
|
+
|
5
|
+
require 'active_record'
|
6
|
+
|
7
|
+
module Ap4r #:nodoc:
|
8
|
+
|
9
|
+
# This +MessageBuilder+ is the class for formatting message body.
|
10
|
+
# Current support formats are text, xml, json and yaml,
|
11
|
+
# and the formatted messages are sent over HTTP.
|
12
|
+
#
|
13
|
+
# Using +format+ method, this class automatically changes the format of
|
14
|
+
# the given message body and adds appropriate +Content-type+ to http header.
|
15
|
+
# Or using +body_as_*+ methods, you can directly assign formatted message body.
|
16
|
+
class MessageBuilder
|
17
|
+
|
18
|
+
def initialize(queue_name, queue_message, queue_headers)
|
19
|
+
@queue_name = queue_name
|
20
|
+
@message_body = queue_message
|
21
|
+
@message_headers = queue_headers
|
22
|
+
@format = nil
|
23
|
+
@message_body_with_format = nil
|
24
|
+
@to_xml_options = {:root => "root"}
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_accessor :queue_name, :message_body, :message_headers
|
28
|
+
attr_reader :format, :to_xml_options
|
29
|
+
|
30
|
+
# Sets message body in async_to block.
|
31
|
+
# The first argument is key and the second one is value.
|
32
|
+
#
|
33
|
+
# options are for to_xml conversion on Array and Hash, ActiveRecord objects.
|
34
|
+
#
|
35
|
+
def body(k, v, options = { })
|
36
|
+
k ||= v.class
|
37
|
+
if v.kind_of? ActiveRecord::Base
|
38
|
+
@message_body[k.to_sym] = v
|
39
|
+
@to_xml_options = @to_xml_options.merge(options)
|
40
|
+
else
|
41
|
+
@message_body[k.to_sym] = v
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Sets message header in async_to block.
|
46
|
+
# The first argument is key and the second one is value.
|
47
|
+
#
|
48
|
+
# Now supports following keys:
|
49
|
+
# :expire
|
50
|
+
# :priority
|
51
|
+
# :delivery
|
52
|
+
# :max_deliveries
|
53
|
+
# :dispatch_mode
|
54
|
+
# :target_method
|
55
|
+
# :target_url
|
56
|
+
# :id
|
57
|
+
#
|
58
|
+
# For details, please refer the reliable-msg.
|
59
|
+
#
|
60
|
+
def header(k, v)
|
61
|
+
@message_headers[k.to_sym] = v
|
62
|
+
end
|
63
|
+
|
64
|
+
# Sets http header in async_to block such as 'Content_type'.
|
65
|
+
# The first argument is key and the second one is value.
|
66
|
+
#
|
67
|
+
def http_header(k, v)
|
68
|
+
@message_headers["http_header_#{k}".to_sym] = v
|
69
|
+
end
|
70
|
+
|
71
|
+
# Sets format message serialization.
|
72
|
+
# As to the format, automatically sets content-type.
|
73
|
+
# Unless any format, content-type is defined as "application/x-www-form-urlencoded".
|
74
|
+
#
|
75
|
+
def format(v)
|
76
|
+
case @format = v
|
77
|
+
when :text
|
78
|
+
set_content_type("text/plain")
|
79
|
+
when :xml
|
80
|
+
set_content_type("text/xml application/x-xml")
|
81
|
+
when :json
|
82
|
+
set_content_type("application/json")
|
83
|
+
when :yaml
|
84
|
+
set_content_type("text/plain text/yaml")
|
85
|
+
else
|
86
|
+
set_content_type("application/x-www-form-urlencoded")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Sets text format message. No need to use +format+.
|
91
|
+
#
|
92
|
+
def body_as_text(text)
|
93
|
+
@message_body_with_format = text
|
94
|
+
format :text
|
95
|
+
end
|
96
|
+
|
97
|
+
# Sets xml format message. No need to use +format+.
|
98
|
+
#
|
99
|
+
def body_as_xml(xml)
|
100
|
+
@message_body_with_format = xml
|
101
|
+
format :xml
|
102
|
+
end
|
103
|
+
|
104
|
+
# Sets json format message. No need to use +format+.
|
105
|
+
#
|
106
|
+
def body_as_json(json)
|
107
|
+
@message_body_with_format = json
|
108
|
+
format :json
|
109
|
+
end
|
110
|
+
|
111
|
+
# Sets yaml format message. No need to use +format+.
|
112
|
+
#
|
113
|
+
def body_as_yaml(yaml)
|
114
|
+
@message_body_with_format = yaml
|
115
|
+
format :yaml
|
116
|
+
end
|
117
|
+
|
118
|
+
# Return converted message body, as to assigned format.
|
119
|
+
#
|
120
|
+
def format_message_body
|
121
|
+
return @message_body_with_format if @message_body_with_format
|
122
|
+
|
123
|
+
case @format
|
124
|
+
when :text
|
125
|
+
return @message_body.to_s
|
126
|
+
when :xml
|
127
|
+
return @message_body.to_xml @to_xml_options
|
128
|
+
when :json
|
129
|
+
return @message_body.to_json
|
130
|
+
when :yaml
|
131
|
+
return @message_body.to_yaml
|
132
|
+
else
|
133
|
+
@message_body.each do |k,v|
|
134
|
+
if v.kind_of? ActiveRecord::Base
|
135
|
+
@message_body[k] = v.attributes
|
136
|
+
end
|
137
|
+
end
|
138
|
+
return query_string(@message_body)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
def query_string(hash)
|
144
|
+
build_query_string(hash, nil, nil)
|
145
|
+
end
|
146
|
+
|
147
|
+
def build_query_string(hash, query = nil, top = nil)
|
148
|
+
query ||= []
|
149
|
+
top ||= ""
|
150
|
+
|
151
|
+
_top = top.dup
|
152
|
+
|
153
|
+
hash.each do |k,v|
|
154
|
+
top = _top
|
155
|
+
top += top == "" ? "#{urlencode(k.to_s)}" : "[#{urlencode(k.to_s)}]"
|
156
|
+
if v.kind_of? Hash
|
157
|
+
build_query_string(v, query, top)
|
158
|
+
elsif v.kind_of? Array
|
159
|
+
v.each do |e|
|
160
|
+
query << "#{top}[]=#{urlencode(e.to_s)}"
|
161
|
+
end
|
162
|
+
else
|
163
|
+
query << "#{top}=#{urlencode(v.to_s)}"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
query.join('&')
|
167
|
+
end
|
168
|
+
|
169
|
+
def simple_url_encoded_form_data(params, sep = '&')
|
170
|
+
params.map {|k,v| "#{urlencode(k.to_s)}=#{urlencode(v.to_s)}" }.join(sep)
|
171
|
+
end
|
172
|
+
|
173
|
+
def urlencode(str)
|
174
|
+
str.gsub(/[^a-zA-Z0-9_\.\-]/n) {|s| sprintf('%%%02x', s[0]) }
|
175
|
+
end
|
176
|
+
|
177
|
+
def set_content_type(type)
|
178
|
+
http_header("Content-type", type)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|