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