QMF
Releasing Simrpc
Submitted by mmorsi on Fri, 2009-10-16 23:09Simrpc is a simple rpc implementation written in Ruby, relying on Apache QPID for the transport mechanism. I modeled it after Apache QMF, though nowhere near as complex (simrpc is procedural based for example, with data structures only encapsulating data, and not methods), intended to be a placeholder until QMF becomes a bit more stable.
I was able to whip it up pretty quick, it only took me a week to write end-to-end, and thus I'm releasing it under the MIT License instead of my usual favorite, the AGPL. Eventually its a possibility that I might rewrite it in C++ as there isn't anything ruby-specific in it and I could easily then after write a Ruby wrapper (or any other).
Have at it!
- mmorsi's blog
- Login to post comments
- Read more
Getting Started w/ Apache QMF
Submitted by mmorsi on Mon, 2009-09-21 17:25The Qpid Management Framework is a powerful open source remoting framework which developers can use to query and invoke methods on managed objects residing on a remote host. As with most other things its fairly straightforward to use when you know it, but it is currently still relatively early in development, and thus there isn't a whole lot of great documentation out there.
To start of, you should read this document thoroughly to familiarize yourself with all the necessary terms. In a gist, a developer will write an 'agent' who is responsible for dispatching requests to managed objects locally, returning results as neccessary. The objects provided and associated properties/methods are detailed via a 'schema'. The agent will register the object classes that it is managing with a 'broker' who is responsible for establishing and maintaining the communication channels, locating the correct agent when a client, known as a 'console', makes a request for a certain object class. With Apache QMF, the Apache QPID daemon also provides QMF broker functionality.
I've written and attached a sample QMF agent/console I've written for anyone who'se looking to start off. It is based of the more complete/robust ovirt-agent (though simplified greatly since its a new developer tutorial), and confusingly enough the agent was written using the Ruby QMF module while the console was written using Ruby QPID::QMF (see my findings on the difference here, I went this way since the example I'm basing this off of, ovirt-agent, does as well).
######################################## Agent #!/usr/bin/ruby # # Simple QMF Agent Example require 'qmf' # class which will do the work # we need for our application class Widget public attr_accessor :socket def initialize @socket = "foo" end def do_something(data) puts "doing something with " + data.to_s end end # setup the Widget Qmf schema # -or- use something like # http://git.et.redhat.com/?p=ovirt-server.git;a=blob;f=src/ovirt-agent/lib/ovirt/schema_parser.rb $widget_schema = Qmf::SchemaObjectClass.new("org.morsi.test", "Widget") $widget_schema.add_property(Qmf::SchemaProperty.new("socket", Qmf::TYPE_SSTR)) $do_something_schema = Qmf::SchemaMethod.new("do_something") $do_something_schema.add_argument(Qmf::SchemaArgument.new("data", Qmf::TYPE_SSTR, {:dir => Qmf::DIR_IN})) $widget_schema.add_method($do_something_schema) # will handle incoming requests for objects and method invocations class WidgetAgent < Qmf::AgentHandler # implementation of Qmf::AgentHandler.get_query callback # called when a client requests an object def get_query(context, query, user_id) puts "Query: context=#{context} class=#{query.class_name} object_id=#{query.object_id} user_id=#{user_id}" # !!! you should actually handle get_query here, by using the specified # class_name and query attributes to lookup and return matching objects widget = Widget.new obj = Qmf::AgentObject.new($widget_schema) obj[:socket] = widget.socket obj.set_object_id(@agent.alloc_object_id) # get_query must perform these steps to return the response @agent.query_response(context, obj) @agent.query_complete(context) end # implementation of Qmf::AgentHandler.method_call callback # called when a client invokes a method on an object def method_call(context, name, object_id, args, user_id) puts "Method: context=#{context} method=#{name} object_id=#{object_id}, args=#{args} user_id=#{user_id}" # !!! you should actually handle method_call here, by using the speicifed # class_name, object_id, and method name / args to invoke the correct method # on the correct object Widget.new.do_something(args["data"]) @agent.method_response(context, 0, "OK", args) end def initialize # connect to specified broker & register self as agent handler @settings = Qmf::ConnectionSettings.new @settings.host = "localhost" #@settings.port = port @connection = Qmf::Connection.new(@settings) @agent = Qmf::Agent.new(self) # register classes that we provide @agent.register_class($widget_schema) end def mainloop Thread.abort_on_exception = true @agent.set_connection(@connection) sleep end end widget_agent = WidgetAgent.new widget_agent.mainloop ######################################## Console #!/usr/bin/ruby # # Simple QMF Console Example require 'qpid' @session = Qpid::Qmf::Session.new @session.add_broker @session.objects(:class => "queue", :package => "org.apache.qpid.broker").each { |q| puts "Queue " + q.to_s } widgets = @session.objects(:class => "Widget", :package => "org.morsi.test") widgets.each { |w| puts "Widget " + w.to_s + " " + w.socket.to_s for (key, val) in w.properties puts " property: #{key}, #{val}" end result = w.do_something('4.20') } ########################################
Check this blog again (or subscribe to the feed) for more about qmf in the future. Enjoy!
- mmorsi's blog
- Login to post comments
- Read more
Warning: Ruby's Qpid::Qmf Module != Qmf Module
Submitted by mmorsi on Sat, 2009-09-19 02:17Something to look out for for anyone interested in using Apache QMF.
The Ruby Qpid::Qmf module (as provided by the ruby-qpid package in fedora) is a qmf implementation written purely in ruby (history/source can be found here).
The Ruby Qmf module (as provided by the ruby-qmf package in fedora) is the ruby binding to the C++ QMF library. It is autogenerated along w/ the ruby bindings to the qpid library (qmf / qpid are seperate libraries now)
It is my understanding based on how these things work, that the Ruby QMF module is more complete and robust, containing the full implementation of the C++ QMF library, adapted to ruby. The QPID::QMF module is a more convenient utility, with nicer methods / classes to use, but a bit more limited in functionality. Which module the developer uses depends on their needs.
As I explore QMF so more I'll make sure to report back with my finding on the differences. I'm already hosting the QPID::QMF API docs, and have just updloaded the QMF API docs for anyone thats interested (at least until they are officially hosted on qpid.apache.org).
Enjoy!





