summaryrefslogtreecommitdiff
path: root/cpp/bindings
diff options
context:
space:
mode:
authorTed Ross <tross@apache.org>2009-06-01 21:24:14 +0000
committerTed Ross <tross@apache.org>2009-06-01 21:24:14 +0000
commitd30c482b6a5070c5fcd97291c901ddcde77f351f (patch)
tree6b7a5f8aad9e10238aea053932c47b3981f1ebd6 /cpp/bindings
parent7f280d95d1bc92a8534d589b537b8e90e913099c (diff)
downloadqpid-python-d30c482b6a5070c5fcd97291c901ddcde77f351f.tar.gz
QPID-1874 - Patch from Ian Main
This patch provides the Ruby binding for QMF Agent and the framework for the Python bindings. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@780837 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/bindings')
-rw-r--r--cpp/bindings/qmf/Makefile.am7
-rw-r--r--cpp/bindings/qmf/python/Makefile.am29
-rw-r--r--cpp/bindings/qmf/python/python.i16
-rw-r--r--cpp/bindings/qmf/qmfengine.i39
-rw-r--r--cpp/bindings/qmf/ruby/Makefile.am30
-rw-r--r--cpp/bindings/qmf/ruby/qmf.rb500
-rw-r--r--cpp/bindings/qmf/ruby/ruby.i46
7 files changed, 667 insertions, 0 deletions
diff --git a/cpp/bindings/qmf/Makefile.am b/cpp/bindings/qmf/Makefile.am
new file mode 100644
index 0000000000..24fcd9a842
--- /dev/null
+++ b/cpp/bindings/qmf/Makefile.am
@@ -0,0 +1,7 @@
+
+INCLUDES = -I$(top_srcdir)/src/qmf
+
+EXTRA_DIST = qmfengine.i
+
+SUBDIRS = ruby python
+
diff --git a/cpp/bindings/qmf/python/Makefile.am b/cpp/bindings/qmf/python/Makefile.am
new file mode 100644
index 0000000000..57f960b9f9
--- /dev/null
+++ b/cpp/bindings/qmf/python/Makefile.am
@@ -0,0 +1,29 @@
+
+if HAVE_PYTHON_DEVEL
+
+INCLUDES = -I$(top_srcdir)/src/qmf -I$(top_srcdir)/src -I$(top_srcdir)/src/gen
+
+EXTRA_DIST = python.i
+
+generated_file_list = \
+ qmfengine.cpp \
+ qmfengine.py
+
+$(generated_file_list): python.i ../qmfengine.i
+ swig -python -c++ -Wall -I/usr/include $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -o qmfengine.cpp python.i
+
+AM_CPPFLAGS = $(QPID_CXXFLAGS) $(INCLUDES) -I$(srcdir)/qmf -I$(PYTHON_INC)
+AM_CXXFLAGS = $(QPID_CXXFLAGS)
+
+pylibdir = $(PYTHON_LIB)
+
+lib_LTLIBRARIES = _qmfengine.la
+
+_qmfengine_la_LDFLAGS = -avoid-version -module -shrext "$(PYTHON_SO)"
+_qmfengine_la_LIBADD = $(PYTHON_LIBS) -L$(QPID_SRC)/.libs -lqpidclient $(top_srcdir)/src/libqmfcommon.la $(top_srcdir)/src/libqmfagent.la
+
+_qmfengine_la_SOURCES = \
+ qmfengine.cpp
+
+endif # HAVE_PYTHON_DEVEL
+
diff --git a/cpp/bindings/qmf/python/python.i b/cpp/bindings/qmf/python/python.i
new file mode 100644
index 0000000000..4ead28ab89
--- /dev/null
+++ b/cpp/bindings/qmf/python/python.i
@@ -0,0 +1,16 @@
+%module qmfengine
+
+// These are probably wrong.. just to get it to compile for now.
+%typemap (in) void *
+{
+ $1 = (void *) $input;
+}
+
+%typemap (out) void *
+{
+ $result = (PyObject *) $1;
+}
+
+
+%include "../qmfengine.i"
+
diff --git a/cpp/bindings/qmf/qmfengine.i b/cpp/bindings/qmf/qmfengine.i
new file mode 100644
index 0000000000..b0c61590f9
--- /dev/null
+++ b/cpp/bindings/qmf/qmfengine.i
@@ -0,0 +1,39 @@
+
+%{
+
+#include "Agent.h"
+#include <ResilientConnection.h>
+
+%}
+
+
+%include <Query.h>
+%include <Message.h>
+%include <Agent.h>
+%include <ResilientConnection.h>
+%include <Typecode.h>
+%include <Schema.h>
+%include <Value.h>
+%include <ObjectId.h>
+%include <Object.h>
+
+%include <qpid/client/ClientImportExport.h>
+%include <qpid/client/ConnectionSettings.h>
+
+
+%inline {
+
+using namespace std;
+using namespace qmf;
+
+namespace qmf {
+
+
+}
+}
+
+
+%{
+
+%};
+
diff --git a/cpp/bindings/qmf/ruby/Makefile.am b/cpp/bindings/qmf/ruby/Makefile.am
new file mode 100644
index 0000000000..7cf053790c
--- /dev/null
+++ b/cpp/bindings/qmf/ruby/Makefile.am
@@ -0,0 +1,30 @@
+
+if HAVE_RUBY_DEVEL
+
+INCLUDES = -I$(top_srcdir)/src/qmf -I$(top_srcdir)/src -I$(top_srcdir)/src/gen
+
+EXTRA_DIST = ruby.i
+
+generated_file_list = \
+ qmfengine.cpp
+
+rubylibdir = $(RUBY_LIB)
+
+dist_rubylib_DATA = qmf.rb
+
+$(generated_file_list): ruby.i ../qmfengine.i
+ swig -ruby -c++ -Wall -I/usr/include $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -o qmfengine.cpp ruby.i
+
+AM_CPPFLAGS = $(QPID_CXXFLAGS) $(INCLUDES) -I$(srcdir) -I$(RUBY_INC) -I$(RUBY_INC_ARCH)
+AM_CXXFLAGS = $(QPID_CXXFLAGS)
+
+rubylibarchdir = $(RUBY_LIB_ARCH)
+rubylibarch_LTLIBRARIES = qmfengine.la
+
+qmfengine_la_LDFLAGS = -avoid-version -module -shrext ".$(RUBY_DLEXT)"
+qmfengine_la_LIBADD = $(RUBY_LIBS) -L$(QPID_SRC)/.libs -lqpidclient $(top_srcdir)/src/libqmfcommon.la
+
+qmfengine_la_SOURCES = \
+ qmfengine.cpp
+
+endif # HAVE_RUBY_DEVEL
diff --git a/cpp/bindings/qmf/ruby/qmf.rb b/cpp/bindings/qmf/ruby/qmf.rb
new file mode 100644
index 0000000000..2c1033f6ae
--- /dev/null
+++ b/cpp/bindings/qmf/ruby/qmf.rb
@@ -0,0 +1,500 @@
+
+require 'qmfengine'
+require 'thread'
+
+module Qmf
+
+ # Pull all the TYPE_* constants into Qmf namespace. Maybe there's an easier way?
+ Qmfengine.constants.each do |c|
+ if c.index('TYPE_') == 0 or c.index('ACCESS_') == 0 or c.index('DIR_') == 0
+ const_set(c, Qmfengine.const_get(c))
+ end
+ end
+
+ class ConnectionSettings < Qmfengine::ConnectionSettings
+ end
+
+ class ConnectionEvent
+ def conn_event_connected(); end
+ def conn_event_disconnected(error); end
+ def conn_event_session_closed(context, error); end
+ def conn_event_recv(context, message); end
+ end
+
+ class Query
+ attr_reader :impl
+ def initialize(i)
+ @impl = i
+ end
+
+ def package_name
+ @impl.getPackage
+ end
+
+ def class_name
+ @impl.getClass
+ end
+
+ def object_id
+ objid = @impl.getObjectId
+ if objid.class == NilClass
+ return nil
+ end
+ return ObjectId.new(objid)
+ end
+ end
+
+ class AgentHandler
+ def get_query(context, query, userId); end
+ def method_call(context, name, object_id, args, userId); end
+ end
+
+ class Connection
+ attr_reader :impl
+
+ def initialize(settings, event_handler = nil, delay_min = 1, delay_max = 128, delay_factor = 2)
+ @impl = Qmfengine::ResilientConnection.new(settings, delay_min, delay_max, delay_factor)
+ @sockEngine, @sock = Socket::socketpair(Socket::PF_UNIX, Socket::SOCK_STREAM, 0)
+ @impl.setNotifyFd(@sockEngine.fileno)
+ @new_conn_handlers = Array.new
+ @conn_handlers = Array.new
+ @sess_handlers = Array.new
+
+ @thread = Thread.new do
+ run
+ end
+ end
+
+ def add_conn_handler(handler)
+ @new_conn_handlers.push(handler)
+ @sockEngine.write("x")
+ end
+
+ def add_sess_handler(handler)
+ @sess_handlers.push(handler)
+ end
+
+ def run()
+ event = Qmfengine::ResilientConnectionEvent.new
+ connected = nil
+ while :true
+ @sock.read(1)
+
+ @new_conn_handlers.each do |nh|
+ @conn_handlers.push(nh)
+ nh.conn_event_connected() if connected
+ end
+ @new_conn_handlers = Array.new
+
+ valid = @impl.getEvent(event)
+ while valid
+ begin
+ case event.kind
+ when Qmfengine::ResilientConnectionEvent::CONNECTED
+ connected = :true
+ @conn_handlers.each { |h| h.conn_event_connected() }
+ when Qmfengine::ResilientConnectionEvent::DISCONNECTED
+ connected = nil
+ @conn_handlers.each { |h| h.conn_event_disconnected(event.errorText) }
+ when Qmfengine::ResilientConnectionEvent::SESSION_CLOSED
+ event.sessionContext.handler.sess_event_session_closed(event.sessionContext, event.errorText)
+ when Qmfengine::ResilientConnectionEvent::RECV
+ event.sessionContext.handler.sess_event_recv(event.sessionContext, event.message)
+ end
+ rescue Exception => ex
+ puts "Event Exception: #{ex}"
+ puts ex.backtrace
+ end
+ @impl.popEvent
+ valid = @impl.getEvent(event)
+ end
+ end
+ end
+ end
+
+ class Session
+ attr_reader :handle, :handler
+
+ def initialize(conn, label, handler)
+ @conn = conn
+ @label = label
+ @handler = handler
+ @handle = Qmfengine::SessionHandle.new
+ @conn.add_sess_handler(@handler)
+ result = @conn.impl.createSession(label, self, @handle)
+ end
+ end
+
+ class ObjectId
+ attr_reader :impl
+ def initialize(impl=nil)
+ if impl
+ @impl = impl
+ else
+ @impl = Qmfengine::ObjectId.new
+ end
+ end
+ def object_num_high
+ return @impl.getObjectNumHi
+ end
+ def object_num_low
+ return @impl.getObjectNumLo
+ end
+ end
+
+ class Arguments
+ attr_reader :map
+ def initialize(map)
+ @map = map
+ @by_hash = {}
+ key_count = @map.keyCount
+ a = 0
+ while a < key_count
+ @by_hash[@map.key(a)] = by_key(@map.key(a))
+ a += 1
+ end
+
+ end
+
+ def [] (key)
+ return @by_hash[key]
+ end
+
+ def []= (key, value)
+ @by_hash[key] = value
+ set(key, value)
+ end
+
+ def each
+ @by_hash.each { |k, v| yield(k, v) }
+ end
+
+ def by_key(key)
+ val = @map.byKey(key)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint
+ when TYPE_UINT64 then val.asUint64
+ when TYPE_SSTR, TYPE_LSTR then val.asString
+ when TYPE_ABSTIME then val.asInt64
+ when TYPE_DELTATIME then val.asUint64
+ when TYPE_REF then val.asObjectId
+ when TYPE_BOOL then val.asBool
+ when TYPE_FLOAT then val.asFloat
+ when TYPE_DOUBLE then val.asDouble
+ when TYPE_UUID then val.asUuid
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt
+ when TYPE_INT64 then val.asInt64
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
+ end
+ end
+
+ def set(key, value)
+ val = @map.byKey(key)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(value)
+ when TYPE_UINT64 then val.setUint64(value)
+ when TYPE_SSTR, TYPE_LSTR then value ? val.setString(value) : val.setString('')
+ when TYPE_ABSTIME then val.setInt64(value)
+ when TYPE_DELTATIME then val.setUint64(value)
+ when TYPE_REF then val.setObjectId(value.impl)
+ when TYPE_BOOL then value ? val.setBool(value) : val.setBool(0)
+ when TYPE_FLOAT then val.setFloat(value)
+ when TYPE_DOUBLE then val.setDouble(value)
+ when TYPE_UUID then val.setUuid(value)
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(value)
+ when TYPE_INT64 then val.setInt64(value)
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
+ end
+ end
+ end
+
+ class Agent
+ def initialize(handler, label="")
+ if label == ""
+ @agentLabel = "rb-%s.%d" % [Socket.gethostname, Process::pid]
+ else
+ @agentLabel = label
+ end
+ @conn = nil
+ @handler = handler
+ @impl = Qmfengine::Agent.new(@agentLabel)
+ @event = Qmfengine::AgentEvent.new
+ @xmtMessage = Qmfengine::Message.new
+ end
+
+ def set_connection(conn)
+ @conn = conn
+ @conn.add_conn_handler(self)
+ end
+
+ def register_class(cls)
+ @impl.registerClass(cls.impl)
+ end
+
+ def alloc_object_id(low = 0, high = 0)
+ ObjectId.new(@impl.allocObjectId(low, high))
+ end
+
+ def query_response(context, object)
+ @impl.queryResponse(context, object.impl)
+ end
+
+ def query_complete(context)
+ @impl.queryComplete(context)
+ end
+
+ def method_response(context, status, text, arguments)
+ @impl.methodResponse(context, status, text, arguments.map)
+ end
+
+ def do_agent_events()
+ count = 0
+ valid = @impl.getEvent(@event)
+ while valid
+ count += 1
+ case @event.kind
+ when Qmfengine::AgentEvent::GET_QUERY
+ @handler.get_query(@event.sequence, Query.new(@event.query), @event.authUserId)
+ when Qmfengine::AgentEvent::START_SYNC
+ when Qmfengine::AgentEvent::END_SYNC
+ when Qmfengine::AgentEvent::METHOD_CALL
+ args = Arguments.new(@event.arguments)
+ @handler.method_call(@event.sequence, @event.name, ObjectId.new(@event.objectId),
+ args, @event.authUserId)
+ when Qmfengine::AgentEvent::DECLARE_QUEUE
+ @conn.impl.declareQueue(@session.handle, @event.name)
+ when Qmfengine::AgentEvent::DELETE_QUEUE
+ @conn.impl.deleteQueue(@session.handle, @event.name)
+ when Qmfengine::AgentEvent::BIND
+ @conn.impl.bind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
+ when Qmfengine::AgentEvent::UNBIND
+ @conn.impl.unbind(@session.handle, @event.exchange, @event.name, @event.bindingKey)
+ when Qmfengine::AgentEvent::SETUP_COMPLETE
+ @impl.startProtocol()
+ end
+ @impl.popEvent
+ valid = @impl.getEvent(@event)
+ end
+ return count
+ end
+
+ def do_agent_messages()
+ count = 0
+ valid = @impl.getXmtMessage(@xmtMessage)
+ while valid
+ count += 1
+ @conn.impl.sendMessage(@session.handle, @xmtMessage)
+ @impl.popXmt
+ valid = @impl.getXmtMessage(@xmtMessage)
+ end
+ return count
+ end
+
+ def do_events()
+ begin
+ ecnt = do_agent_events
+ mcnt = do_agent_messages
+ end until ecnt == 0 and mcnt == 0
+ end
+
+ def conn_event_connected()
+ puts "Agent Connection Established..."
+ @session = Session.new(@conn, "qmfa-%s.%d" % [Socket.gethostname, Process::pid], self)
+ @impl.newSession
+ do_events
+ end
+
+ def conn_event_disconnected(error)
+ puts "Agent Connection Lost"
+ end
+
+ def sess_event_session_closed(context, error)
+ puts "Agent Session Lost"
+ end
+
+ def sess_event_recv(context, message)
+ @impl.handleRcvMessage(message)
+ do_events
+ end
+ end
+
+ class SchemaArgument
+ attr_reader :impl
+ def initialize(name, typecode, kwargs={})
+ @impl = Qmfengine::SchemaArgument.new(name, typecode)
+ @impl.setDirection(kwargs[:dir]) if kwargs.include?(:dir)
+ @impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ end
+ end
+
+ class SchemaMethod
+ attr_reader :impl
+ def initialize(name, kwargs={})
+ @impl = Qmfengine::SchemaMethod.new(name)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ @arguments = []
+ end
+
+ def add_argument(arg)
+ @arguments << arg
+ @impl.addArgument(arg.impl)
+ end
+ end
+
+ class SchemaProperty
+ attr_reader :impl
+ def initialize(name, typecode, kwargs={})
+ @impl = Qmfengine::SchemaProperty.new(name, typecode)
+ @impl.setAccess(kwargs[:access]) if kwargs.include?(:access)
+ @impl.setIndex(kwargs[:index]) if kwargs.include?(:index)
+ @impl.setOptional(kwargs[:optional]) if kwargs.include?(:optional)
+ @impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ end
+ end
+
+ class SchemaStatistic
+ attr_reader :impl
+ def initialize(name, typecode, kwargs={})
+ @impl = Qmfengine::SchemaStatistic.new(name, typecode)
+ @impl.setUnit(kwargs[:unit]) if kwargs.include?(:unit)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ end
+ end
+
+ class SchemaObjectClass
+ attr_reader :impl
+ def initialize(package, name, kwargs={})
+ @impl = Qmfengine::SchemaObjectClass.new(package, name)
+ @properties = []
+ @statistics = []
+ @methods = []
+ end
+
+ def add_property(prop)
+ @properties << prop
+ @impl.addProperty(prop.impl)
+ end
+
+ def add_statistic(stat)
+ @statistics << stat
+ @impl.addStatistic(stat.impl)
+ end
+
+ def add_method(meth)
+ @methods << meth
+ @impl.addMethod(meth.impl)
+ end
+ end
+
+ class SchemaEventClass
+ attr_reader :impl
+ def initialize(package, name, kwargs={})
+ @impl = Qmfengine::SchemaEventClass.new(package, name)
+ @impl.setDesc(kwargs[:desc]) if kwargs.include?(:desc)
+ @arguments = []
+ end
+
+ def add_argument(arg)
+ @arguments << arg
+ @impl.addArgument(arg.impl)
+ end
+ end
+
+ class QmfObject
+ attr_reader :impl, :object_class
+ def initialize(cls)
+ @object_class = cls
+ @impl = Qmfengine::Object.new(@object_class.impl)
+ end
+
+ def destroy
+ @impl.destroy
+ end
+
+ def object_id
+ return ObjectId.new(@impl.getObjectId)
+ end
+
+ def set_object_id(oid)
+ @impl.setObjectId(oid.impl)
+ end
+
+ def get_attr(name)
+ val = value(name)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.asUint
+ when TYPE_UINT64 then val.asUint64
+ when TYPE_SSTR, TYPE_LSTR then val.asString
+ when TYPE_ABSTIME then val.asInt64
+ when TYPE_DELTATIME then val.asUint64
+ when TYPE_REF then val.asObjectId
+ when TYPE_BOOL then val.asBool
+ when TYPE_FLOAT then val.asFloat
+ when TYPE_DOUBLE then val.asDouble
+ when TYPE_UUID then val.asUuid
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.asInt
+ when TYPE_INT64 then val.asInt64
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
+ end
+ end
+
+ def set_attr(name, value)
+ val = value(name)
+ case val.getType
+ when TYPE_UINT8, TYPE_UINT16, TYPE_UINT32 then val.setUint(value)
+ when TYPE_UINT64 then val.setUint64(value)
+ when TYPE_SSTR, TYPE_LSTR then value ? val.setString(value) : val.setString('')
+ when TYPE_ABSTIME then val.setInt64(value)
+ when TYPE_DELTATIME then val.setUint64(value)
+ when TYPE_REF then val.setObjectId(value.impl)
+ when TYPE_BOOL then value ? val.setBool(value) : val.setBool(0)
+ when TYPE_FLOAT then val.setFloat(value)
+ when TYPE_DOUBLE then val.setDouble(value)
+ when TYPE_UUID then val.setUuid(value)
+ when TYPE_INT8, TYPE_INT16, TYPE_INT32 then val.setInt(value)
+ when TYPE_INT64 then val.setInt64(value)
+ when TYPE_MAP
+ when TYPE_OBJECT
+ when TYPE_LIST
+ when TYPE_ARRAY
+ end
+ end
+
+ def [](name)
+ get_attr(name)
+ end
+
+ def []=(name, value)
+ set_attr(name, value)
+ end
+
+ def inc_attr(name, by=1)
+ set_attr(name, get_attr(name) + by)
+ end
+
+ def dec_attr(name, by=1)
+ set_attr(name, get_attr(name) - by)
+ end
+
+ private
+ def value(name)
+ val = @impl.getValue(name.to_s)
+ if val.nil?
+ raise ArgumentError, "Attribute '#{name}' not defined for class #{@object_class.impl.getName}"
+ end
+ return val
+ end
+ end
+
+end
diff --git a/cpp/bindings/qmf/ruby/ruby.i b/cpp/bindings/qmf/ruby/ruby.i
new file mode 100644
index 0000000000..fae7184143
--- /dev/null
+++ b/cpp/bindings/qmf/ruby/ruby.i
@@ -0,0 +1,46 @@
+%include stl.i
+%trackobjects;
+
+%module qmfengine
+
+%typemap (in) void *
+{
+ $1 = (void *) $input;
+}
+
+%typemap (out) void *
+{
+ $result = (VALUE) $1;
+}
+
+%typemap (in) uint32_t
+{
+ $1 = FIX2UINT ((uint32_t) $input);
+}
+
+%typemap (out) uint32_t
+{
+ $result = UINT2NUM((unsigned int) $1);
+}
+
+%typemap (typecheck, precedence=SWIG_TYPECHECK_INTEGER) uint32_t {
+ $1 = FIXNUM_P($input);
+}
+
+%typemap (in) uint64_t
+{
+ $1 = FIX2ULONG ((uint64_t) $input);
+}
+
+%typemap (out) uint64_t
+{
+ $result = ULONG2NUM((unsigned long) $1);
+}
+
+%typemap (typecheck, precedence=SWIG_TYPECHECK_INTEGER) uint64_t {
+ $1 = FIXNUM_P($input);
+}
+
+
+%include "../qmfengine.i"
+