[ap4r-devel] [185] trunk: Support block argument for async_to method.\n Support ActiveRecord object for async parameter.

kato-k at rubyforge.org kato-k at rubyforge.org
Fri May 18 06:16:19 EDT 2007


Revision: 185
Author:   kato-k
Date:     2007-05-18 06:16:17 -0400 (Fri, 18 May 2007)

Log Message:
-----------
Support block argument for async_to method.\n Support ActiveRecord object for async parameter. \n Support xml over http protocol.

Modified Paths:
--------------
    trunk/ap4r/lib/ap4r/dispatcher.rb
    trunk/samples/HelloWorld/app/controllers/sync_hello_controller.rb
    trunk/samples/HelloWorld/vendor/plugins/ap4r/lib/ap4r_client.rb
    trunk/samples/HelloWorld/vendor/plugins/ap4r/lib/async_helper.rb
    trunk/samples/HelloWorld/vendor/plugins/ap4r/lib/message_builder.rb

Modified: trunk/ap4r/lib/ap4r/dispatcher.rb
===================================================================
--- trunk/ap4r/lib/ap4r/dispatcher.rb	2007-05-18 06:23:27 UTC (rev 184)
+++ trunk/ap4r/lib/ap4r/dispatcher.rb	2007-05-18 10:16:17 UTC (rev 185)
@@ -208,10 +208,25 @@
         # TODO: should be added some request headers 2006/10/12 shino
         #       e.g. X-Ap4r-Version, Accept(need it?)
         # TODO: Now supports POST only, 2006/10/12 shino
-        @response = Net::HTTP.post_form(URI.parse(@message[:target_url]),
-                                       @message.object)
+        @response = nil
+        uri = URI.parse(@message[:target_url])
+        headers = make_header
+        
+        Net::HTTP.start(uri.host, uri.port) do |http|
+          @response, = http.post(uri.path, @message.object, headers)
+        end
       end
       
+      def make_header
+        headers = { }
+        @message.headers.map do |k,v|
+          s = StringScanner.new(k.to_s)
+          s.scan(/\Ahttp_header_/)
+          headers[s.post_match] = v if s.post_match
+        end
+        headers
+      end
+      
       def validate_response
         logger.debug{"response status [#{@response.code} #{@response.message}]"}
         validate_response_status(Net::HTTPOK)

Modified: trunk/samples/HelloWorld/app/controllers/sync_hello_controller.rb
===================================================================
--- trunk/samples/HelloWorld/app/controllers/sync_hello_controller.rb	2007-05-18 06:23:27 UTC (rev 184)
+++ trunk/samples/HelloWorld/app/controllers/sync_hello_controller.rb	2007-05-18 10:16:17 UTC (rev 185)
@@ -19,51 +19,32 @@
   def execute_with_block
     write('Hello')
 
-    # TODO: should change first argument like the following sample, 2007/5/10 kato-k
-    #  e.g.
-    #  ap4r.async_to(:url => {:contoroller => 'foo', :action => 'bar'}, ...)
-    #
-    # TODO: should support more flexible description in a block, 2007/5/10 kato-k
-    ap4r.async_to({:controller => 'async_world', :action => 'execute_via_http'}, req = {} ) do |b|
+    ap4r.async_to({:controller => 'async_world', :action => 'execute_via_http'}) do
 
-      # message body
-      # basically, use block argumennt
-      b.hoge1 = "hoge1"
-      b[:hoge2] = "hoge2"
+      # basic
+      #body :hoge, "hoge"
+      #header :priority, 2
 
-      b.hoge3 "hoge3" # this pattern is possible, but unrecommend
-      b.id = 1 # method "id" is also available.
+      # AR object
+      #body :sm, Ap4r::StoredMessage.find(:first), :except => :id
 
-      # TODO: should support ActiveRecord object, 2007/5/11 kato-k
-      b.order = @order #?
+      # by xml/http
+      body :hoge, "hoge"
+      body :sm, Ap4r::StoredMessage.find(:first), :except => :id
+      format :xml
 
-      # message header
-      b.headers[:target_url] = "http://localhost:3000/async_world/execute_via_http"
-      b.headers[:priority] = 2
-      b.headers[:druby_url] = "druby://:6438"
+      # ..or explicit setting for http header
+      #body :hoge, "hoge"
+      #body :sm, Ap4r::StoredMessage.find(:first), :except => :id
+      #http_header "Content-type", "application/x-xml"
 
-      # TODO: should support http headers, 2007/5/11 kato-k
-      #b.http_headers[:accept] = "text/plain"
-      #b.http_headers["content-type"] = "application/json"
-      #b.headers[:http_header_accept] = "text/plain"
+      # directly dealing with xml message
+      #body_as_xml Ap4r::StoredMessage.find(:first).to_xml(:except => :id)
 
-      #tricky pattern, but definition in method arguments is necessary.
-      req[:_num] = rand(100)
-      req[:_str] = "World"
-      req[:_hash] = {:a => 1, :b => 2}
-      req[:_array] = [0, 1, 2]
-
-
-      # TODO: should support various request formats such as xml and json, 2007/5/11 kato-k
-      #b.queue_message = @order, :include => :details, :format => :json
-      #b.queue_message = @order, :include => :details, :format => :xml
-
-
-      # contents of message are referable
-      p b.queue_name
-      p b.queue_message
-      p b.queue_headers
-
+      # TODO: referable, but should change longer and unique name?, 2007/5/17 kato-k
+      # p @queue_name
+      # p @queue_message
+      # p @queue_headers
     end
 
     render :nothing => true

Modified: trunk/samples/HelloWorld/vendor/plugins/ap4r/lib/ap4r_client.rb
===================================================================
--- trunk/samples/HelloWorld/vendor/plugins/ap4r/lib/ap4r_client.rb	2007-05-18 06:23:27 UTC (rev 184)
+++ trunk/samples/HelloWorld/vendor/plugins/ap4r/lib/ap4r_client.rb	2007-05-18 10:16:17 UTC (rev 185)
@@ -19,9 +19,5 @@
     alias :async_to :async_dispatch
     alias :transaction :transaction_with_saf
 
-    def message
-      @message ||= {}
-    end
-
   end
 end

Modified: trunk/samples/HelloWorld/vendor/plugins/ap4r/lib/async_helper.rb
===================================================================
--- trunk/samples/HelloWorld/vendor/plugins/ap4r/lib/async_helper.rb	2007-05-18 06:23:27 UTC (rev 184)
+++ trunk/samples/HelloWorld/vendor/plugins/ap4r/lib/async_helper.rb	2007-05-18 10:16:17 UTC (rev 185)
@@ -125,7 +125,7 @@
       # Object of argumemts (async_params, options and rm_options) will not be modified.
       # Implementors (of this class and converters) should not modify them.
       #
-      def async_dispatch(url_options = {}, async_params = nil, rm_options = nil, &block)
+      def async_dispatch(url_options = {}, async_params = {}, rm_options = {}, &block)
 
         # TODO: add :url to url_options to specify :target_url shortly 2007/05/02 by shino
         if logger.debug?
@@ -151,30 +151,28 @@
         queue_message = converter.make_params
         queue_headers = converter.make_rm_options
 
+        message_builder = ::Ap4r::MessageBuilder.new(queue_name, queue_message, queue_headers)
         if block_given?
-          message_builder = ::Ap4r::MessageBuilder.new(queue_name, queue_message, queue_headers)
-
-          yield message_builder
-
-          queue_name = message_builder.queue_name
-          queue_message = queue_message.merge(message_builder.queue_message)
-          queue_headers = queue_headers.merge(message_builder.queue_headers)
+          message_builder.instance_eval(&block)
         end
+        queue_name = message_builder.queue_name
+        formatted_queue_message = message_builder.format_queue_message
+        queue_headers = message_builder.queue_headers
 
         if Thread.current[:use_saf]
-          stored_message = ::Ap4r::StoredMessage.store(queue_name, queue_message, queue_headers)
+          stored_message = ::Ap4r::StoredMessage.store(queue_name, formatted_queue_message, queue_headers)
 
           Thread.current[:stored_messages].store(
                                                  stored_message.id,
                                                  {
-                                                   :queue_message => queue_message,
+                                                   :queue_message => formatted_queue_message,
                                                    :queue_name => queue_name,
                                                    :queue_headers => queue_headers
                                                  } )
           return stored_message.id
         end
 
-        __queue_put(queue_name, queue_message, queue_headers)
+        __queue_put(queue_name, formatted_queue_message, queue_headers)
       end
 
       private

Modified: trunk/samples/HelloWorld/vendor/plugins/ap4r/lib/message_builder.rb
===================================================================
--- trunk/samples/HelloWorld/vendor/plugins/ap4r/lib/message_builder.rb	2007-05-18 06:23:27 UTC (rev 184)
+++ trunk/samples/HelloWorld/vendor/plugins/ap4r/lib/message_builder.rb	2007-05-18 10:16:17 UTC (rev 185)
@@ -2,41 +2,112 @@
 # Copyright:: Copyright (c) 2007 Future Architect Inc.
 # Licence:: MIT Licence
 
+require 'active_record'
+
 module Ap4r
 
-  # This class has +method_missing+.
-  # Scope of application should be limited ?
   class MessageBuilder
 
     def initialize(queue_name, queue_message, queue_headers)
       @queue_name = queue_name
       @queue_message = queue_message
       @queue_headers = queue_headers
+      @format = :urlencode
+      @xml_encoded_body = nil
+      @to_xml_options = {:root => "root"}
     end
 
     attr_accessor :queue_name, :queue_message, :queue_headers
+    attr_reader :xml_encoded_body, :format, :to_xml_options
 
-    # +Ap4r::Client#async_to+ method has block argument and message header and body and so on
-    # are defined in a block.
-    # This +method_missing+ is for picking up defined parameters in a block..
-    def method_missing(method_name, *args)
-      if method_name == :[]=
-        @queue_message[args[0]] = args[1]
-      elsif method_name == :headers
-        return @queue_headers
-      elsif method_name == :http_headers
-        #TODO implementation, 2007/5/11 kato-k
-        return {}
+    def body(k, v, options = { })
+      k ||= v.class
+      if v.kind_of? ActiveRecord::Base
+        @queue_message[k.to_sym] = v.attributes
+        @to_xml_options = @to_xml_options.merge(options)
       else
-        @queue_message[remove_equal_mark_from(method_name)] = args[0]
+        @queue_message[k.to_sym] = v
       end
+
     end
 
+    def body_as_xml(xml_message)
+      @xml_encoded_body = xml_message
+    end
+
+    def body_as_text(text_message)
+      # TODO: implementation
+    end
+
+    def body_as_yaml(yaml_message)
+      # TODO: implementation
+    end
+
+    def body_as_json(json_message)
+      # TODO: implementation
+    end
+
+    def header(k, v)
+      @queue_headers[k.to_sym] = v
+    end
+
+    def http_header(k, v)
+      @queue_headers["http_header_#{k}".to_sym] = v
+    end
+
+    def format(v)
+      case @format = v
+      when :xml
+        http_header('Content-type', 'application/x-xml')
+      else
+        http_header('Content-type', 'application/x-www-form-urlencoded')
+      end
+    end
+
+    def format_queue_message
+      return @xml_encoded_body  if @xml_encoded_body
+
+      case @format
+      when :xml
+        return @queue_message.to_xml @to_xml_options
+      else
+        return query_string(@queue_message)
+      end
+    end
+
+    def query_string(hash)
+      build_query_string(hash, nil, nil)
+    end
+
     private
-    def remove_equal_mark_from symbol
-      return symbol unless /=$/ =~ symbol.to_s
-      return symbol.to_s.chop.to_sym
+    def build_query_string(hash, query = nil, top = nil)
+      query ||= []
+      top ||= ""
+
+      _top = top.dup
+
+      hash.each do |k,v|
+        top = _top
+        top += top == "" ? "#{urlencode(k.to_s)}" : "[#{urlencode(k.to_s)}]"
+        if v.kind_of? Hash
+          build_query_string(v, query, top)
+        elsif v.kind_of? Array
+          v.each do |e|
+            query << "#{top}[]=#{urlencode(e.to_s)}"
+          end
+        else
+          query << "#{top}=#{urlencode(v.to_s)}"
+        end
+      end
+      query.join('&')
     end
 
+    def simple_url_encoded_form_data params, sep = '&'
+      params.map {|k,v| "#{urlencode(k.to_s)}=#{urlencode(v.to_s)}" }.join(sep)
+    end
+
+    def urlencode(str)
+      str.gsub(/[^a-zA-Z0-9_\.\-]/n) {|s| sprintf('%%%02x', s[0]) }
+    end
   end
 end




More information about the ap4r-devel mailing list