You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by tr...@apache.org on 2013/07/08 23:43:48 UTC

svn commit: r1500977 - in /qpid/trunk/qpid/extras/dispatch: include/qpid/dispatch/ router/src/ src/ src/py/router/ src/py/stubs/ tests/

Author: tross
Date: Mon Jul  8 21:43:48 2013
New Revision: 1500977

URL: http://svn.apache.org/r1500977
Log:
QPID-4968 - Added an IO adapter for python modules to send and receive messages
QPID-4967 - Integrated the python router into the main program
 - Updated the log module: added the full complement of severity levels
 - Added stub versions of the dispatch python adapters so the python components can be
   tested in a standalone environment.

Added:
    qpid/trunk/qpid/extras/dispatch/src/py/stubs/
    qpid/trunk/qpid/extras/dispatch/src/py/stubs/__init__.py   (with props)
    qpid/trunk/qpid/extras/dispatch/src/py/stubs/ioadapter.py   (with props)
    qpid/trunk/qpid/extras/dispatch/src/py/stubs/logadapter.py   (with props)
Modified:
    qpid/trunk/qpid/extras/dispatch/include/qpid/dispatch/log.h
    qpid/trunk/qpid/extras/dispatch/include/qpid/dispatch/python_embedded.h
    qpid/trunk/qpid/extras/dispatch/router/src/main.c
    qpid/trunk/qpid/extras/dispatch/src/dispatch.c
    qpid/trunk/qpid/extras/dispatch/src/log.c
    qpid/trunk/qpid/extras/dispatch/src/py/router/adapter.py
    qpid/trunk/qpid/extras/dispatch/src/py/router/binding.py
    qpid/trunk/qpid/extras/dispatch/src/py/router/data.py
    qpid/trunk/qpid/extras/dispatch/src/py/router/link.py
    qpid/trunk/qpid/extras/dispatch/src/py/router/mobile.py
    qpid/trunk/qpid/extras/dispatch/src/py/router/neighbor.py
    qpid/trunk/qpid/extras/dispatch/src/py/router/path.py
    qpid/trunk/qpid/extras/dispatch/src/py/router/router_engine.py
    qpid/trunk/qpid/extras/dispatch/src/py/router/routing.py
    qpid/trunk/qpid/extras/dispatch/src/python_embedded.c
    qpid/trunk/qpid/extras/dispatch/src/router_node.c
    qpid/trunk/qpid/extras/dispatch/tests/router_engine_test.py

Modified: qpid/trunk/qpid/extras/dispatch/include/qpid/dispatch/log.h
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/include/qpid/dispatch/log.h?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/include/qpid/dispatch/log.h (original)
+++ qpid/trunk/qpid/extras/dispatch/include/qpid/dispatch/log.h Mon Jul  8 21:43:48 2013
@@ -19,10 +19,14 @@
  * under the License.
  */
 
-#define LOG_NONE  0x00000000
-#define LOG_TRACE 0x00000001
-#define LOG_ERROR 0x00000002
-#define LOG_INFO  0x00000004
+#define LOG_NONE     0x00000000
+#define LOG_TRACE    0x00000001
+#define LOG_DEBUG    0x00000002
+#define LOG_INFO     0x00000004
+#define LOG_NOTICE   0x00000008
+#define LOG_WARNING  0x00000010
+#define LOG_ERROR    0x00000020
+#define LOG_CRITICAL 0x00000040
 
 void dx_log_impl(const char *module, int cls, const char *file, int line, const char *fmt, ...);
 #define dx_log(m, c, f, ...) dx_log_impl(m, c, __FILE__, __LINE__, f , ##__VA_ARGS__)

Modified: qpid/trunk/qpid/extras/dispatch/include/qpid/dispatch/python_embedded.h
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/include/qpid/dispatch/python_embedded.h?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/include/qpid/dispatch/python_embedded.h (original)
+++ qpid/trunk/qpid/extras/dispatch/include/qpid/dispatch/python_embedded.h Mon Jul  8 21:43:48 2013
@@ -20,6 +20,7 @@
  */
 
 #include <Python.h>
+#include <qpid/dispatch/dispatch.h>
 #include <qpid/dispatch/compose.h>
 #include <qpid/dispatch/parse.h>
 #include <qpid/dispatch/iterator.h>
@@ -28,7 +29,7 @@
  * Initialize the embedded-python subsystem.  This must be called before
  * any other call into this module is invoked.
  */
-void dx_python_initialize();
+void dx_python_initialize(dx_dispatch_t *dx);
 
 /**
  * Finalize the embedded-python subsystem.  After this is called, there
@@ -50,6 +51,11 @@ void dx_python_start();
 void dx_python_stop();
 
 /**
+ * Get the Python top level "dispatch" module.
+ */
+PyObject *dx_python_module();
+
+/**
  * Convert a Python object to AMQP format and append to a composed_field.
  *
  * @param value A Python Object

Modified: qpid/trunk/qpid/extras/dispatch/router/src/main.c
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/router/src/main.c?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/router/src/main.c (original)
+++ qpid/trunk/qpid/extras/dispatch/router/src/main.c Mon Jul  8 21:43:48 2013
@@ -117,7 +117,7 @@ int main(int argc, char **argv)
         }
     }
 
-    dx_log_set_mask(LOG_INFO | LOG_TRACE | LOG_ERROR);
+    dx_log_set_mask(0xFFFFFFFF);
 
     dispatch = dx_dispatch(config_path);
 

Modified: qpid/trunk/qpid/extras/dispatch/src/dispatch.c
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/dispatch.c?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/dispatch.c (original)
+++ qpid/trunk/qpid/extras/dispatch/src/dispatch.c Mon Jul  8 21:43:48 2013
@@ -61,7 +61,7 @@ dx_dispatch_t *dx_dispatch(const char *c
     DEQ_INIT(dx->config_listeners);
     DEQ_INIT(dx->config_connectors);
 
-    dx_python_initialize();
+    dx_python_initialize(dx);
     dx_log_initialize();
     dx_alloc_initialize();
 

Modified: qpid/trunk/qpid/extras/dispatch/src/log.c
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/log.c?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/log.c (original)
+++ qpid/trunk/qpid/extras/dispatch/src/log.c Mon Jul  8 21:43:48 2013
@@ -51,12 +51,16 @@ static dx_log_list_t  entries;
 static sys_mutex_t   *log_lock = 0;
 
 
-static char *cls_prefix(int cls)
+static const char *cls_prefix(int cls)
 {
     switch (cls) {
-    case LOG_TRACE : return "TRACE";
-    case LOG_ERROR : return "ERROR";
-    case LOG_INFO  : return "INFO";
+    case LOG_TRACE    : return "TRACE";
+    case LOG_DEBUG    : return "DEBUG";
+    case LOG_INFO     : return "INFO";
+    case LOG_NOTICE   : return "NOTICE";
+    case LOG_WARNING  : return "WARNING";
+    case LOG_ERROR    : return "ERROR";
+    case LOG_CRITICAL : return "CRITICAL";
     }
 
     return "";

Modified: qpid/trunk/qpid/extras/dispatch/src/py/router/adapter.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/py/router/adapter.py?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/py/router/adapter.py (original)
+++ qpid/trunk/qpid/extras/dispatch/src/py/router/adapter.py Mon Jul  8 21:43:48 2013
@@ -17,13 +17,10 @@
 # under the License.
 #
 
-TRACE    = 0
-DEBUG    = 1
-INFO     = 2
-NOTICE   = 3
-WARNING  = 4
-ERROR    = 5
-CRITICAL = 6
+try:
+  from dispatch import *
+except ImportError:
+  from stubs import *
 
 ENTRY_OLD     = 1
 ENTRY_CURRENT = 2
@@ -91,12 +88,12 @@ class AdapterEngine(object):
     #       messages to be duplicated.  It's better to have gaps in the routing
     #       tables momentarily because unroutable messages are stored for retry.
     for a,b in to_delete:
-      self.container.adapter.remote_unbind(a, b)
+      self.container.router_adapter.remote_unbind(a, b)
     for a,b in to_add:
-      self.container.adapter.remote_bind(a, b)
+      self.container.router_adapter.remote_bind(a, b)
 
-    self.container.log(INFO, "New Routing Table (class=%s):" % key_class)
+    self.container.log(LOG_INFO, "New Routing Table (class=%s):" % key_class)
     for a,b in new_table:
-      self.container.log(INFO, "  %s => %s" % (a, b))
+      self.container.log(LOG_INFO, "  %s => %s" % (a, b))
 
 

Modified: qpid/trunk/qpid/extras/dispatch/src/py/router/binding.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/py/router/binding.py?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/py/router/binding.py (original)
+++ qpid/trunk/qpid/extras/dispatch/src/py/router/binding.py Mon Jul  8 21:43:48 2013
@@ -17,13 +17,11 @@
 # under the License.
 #
 
-TRACE    = 0
-DEBUG    = 1
-INFO     = 2
-NOTICE   = 3
-WARNING  = 4
-ERROR    = 5
-CRITICAL = 6
+try:
+  from dispatch import *
+except ImportError:
+  from stubs import *
+
 
 class BindingEngine(object):
   """

Modified: qpid/trunk/qpid/extras/dispatch/src/py/router/data.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/py/router/data.py?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/py/router/data.py (original)
+++ qpid/trunk/qpid/extras/dispatch/src/py/router/data.py Mon Jul  8 21:43:48 2013
@@ -18,6 +18,12 @@
 #
 
 
+try:
+  from dispatch import *
+except ImportError:
+  from stubs import *
+
+
 def getMandatory(data, key, cls=None):
   """
   Get the value mapped to the requested key.  If it's not present, raise an exception.

Modified: qpid/trunk/qpid/extras/dispatch/src/py/router/link.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/py/router/link.py?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/py/router/link.py (original)
+++ qpid/trunk/qpid/extras/dispatch/src/py/router/link.py Mon Jul  8 21:43:48 2013
@@ -20,13 +20,10 @@
 from data import MessageRA, MessageLSU, MessageLSR
 from time import time
 
-TRACE    = 0
-DEBUG    = 1
-INFO     = 2
-NOTICE   = 3
-WARNING  = 4
-ERROR    = 5
-CRITICAL = 6
+try:
+  from dispatch import *
+except ImportError:
+  from stubs import *
 
 class LinkStateEngine(object):
   """
@@ -57,9 +54,9 @@ class LinkStateEngine(object):
 
     if self.collection_changed:
       self.collection_changed = False
-      self.container.log(INFO, "New Link-State Collection:")
+      self.container.log(LOG_INFO, "New Link-State Collection:")
       for a,b in self.collection.items():
-        self.container.log(INFO, "  %s => %r" % (a, b.peers))
+        self.container.log(LOG_INFO, "  %s => %r" % (a, b.peers))
       self.container.ls_collection_changed(self.collection)
 
 
@@ -90,7 +87,7 @@ class LinkStateEngine(object):
       self.collection[msg.id] = ls
       self.collection_changed = True
       ls.last_seen = now
-      self.container.log(INFO, "Learned link-state from new router: %s" % msg.id)
+      self.container.log(LOG_INFO, "Learned link-state from new router: %s" % msg.id)
     # Schedule LSRs for any routers referenced in this LS that we don't know about
     for _id in msg.ls.peers:
       if _id not in self.collection:
@@ -103,7 +100,7 @@ class LinkStateEngine(object):
     if self.id not in self.collection:
       return
     my_ls = self.collection[self.id]
-    self.container.send('_topo.%s.%s' % (msg.area, msg.id), MessageLSU(None, self.id, self.area, my_ls.ls_seq, my_ls))
+    self.container.send('_topo/%s/%s' % (msg.area, msg.id), MessageLSU(None, self.id, self.area, my_ls.ls_seq, my_ls))
 
 
   def new_local_link_state(self, link_state):
@@ -127,12 +124,12 @@ class LinkStateEngine(object):
     for key in to_delete:
       ls = self.collection.pop(key)
       self.collection_changed = True
-      self.container.log(INFO, "Expired link-state from router: %s" % key)
+      self.container.log(LOG_INFO, "Expired link-state from router: %s" % key)
 
 
   def _send_lsrs(self):
     for (_area, _id) in self.needed_lsrs.keys():
-      self.container.send('_topo.%s.%s' % (_area, _id), MessageLSR(None, self.id, self.area))
+      self.container.send('_topo/%s/%s' % (_area, _id), MessageLSR(None, self.id, self.area))
     self.needed_lsrs = {}
 
 
@@ -140,4 +137,4 @@ class LinkStateEngine(object):
     ls_seq = 0
     if self.id in self.collection:
       ls_seq = self.collection[self.id].ls_seq
-    self.container.send('_topo.%s.all' % self.area, MessageRA(None, self.id, self.area, ls_seq, self.mobile_seq))
+    self.container.send('_topo/%s/all' % self.area, MessageRA(None, self.id, self.area, ls_seq, self.mobile_seq))

Modified: qpid/trunk/qpid/extras/dispatch/src/py/router/mobile.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/py/router/mobile.py?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/py/router/mobile.py (original)
+++ qpid/trunk/qpid/extras/dispatch/src/py/router/mobile.py Mon Jul  8 21:43:48 2013
@@ -19,6 +19,11 @@
 
 from data import MessageRA, MessageMAR, MessageMAU
 
+try:
+  from dispatch import *
+except ImportError:
+  from stubs import *
+
 class MobileAddressEngine(object):
   """
   This module is responsible for maintaining an up-to-date list of mobile addresses in the domain.

Modified: qpid/trunk/qpid/extras/dispatch/src/py/router/neighbor.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/py/router/neighbor.py?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/py/router/neighbor.py (original)
+++ qpid/trunk/qpid/extras/dispatch/src/py/router/neighbor.py Mon Jul  8 21:43:48 2013
@@ -20,13 +20,11 @@
 from data import LinkState, MessageHELLO
 from time import time
 
-TRACE    = 0
-DEBUG    = 1
-INFO     = 2
-NOTICE   = 3
-WARNING  = 4
-ERROR    = 5
-CRITICAL = 6
+try:
+  from dispatch import *
+except ImportError:
+  from stubs import *
+
 
 class NeighborEngine(object):
   """
@@ -51,7 +49,7 @@ class NeighborEngine(object):
 
     if now - self.last_hello_time >= self.hello_interval:
       self.last_hello_time = now
-      self.container.send('_peer', MessageHELLO(None, self.id, self.area, self.hellos.keys()))
+      self.container.send('_local/qdxrouter', MessageHELLO(None, self.id, self.area, self.hellos.keys()))
 
     if self.link_state_changed:
       self.link_state_changed = False
@@ -66,7 +64,7 @@ class NeighborEngine(object):
     if msg.is_seen(self.id):
       if self.link_state.add_peer(msg.id):
         self.link_state_changed = True
-        self.container.log(INFO, "New neighbor established: %s" % msg.id)
+        self.container.log(LOG_INFO, "New neighbor established: %s" % msg.id)
     ##
     ## TODO - Use this function to detect area boundaries
     ##
@@ -80,6 +78,6 @@ class NeighborEngine(object):
       self.hellos.pop(key)
       if self.link_state.del_peer(key):
         self.link_state_changed = True
-        self.container.log(INFO, "Neighbor lost: %s" % key)
+        self.container.log(LOG_INFO, "Neighbor lost: %s" % key)
         
       

Modified: qpid/trunk/qpid/extras/dispatch/src/py/router/path.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/py/router/path.py?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/py/router/path.py (original)
+++ qpid/trunk/qpid/extras/dispatch/src/py/router/path.py Mon Jul  8 21:43:48 2013
@@ -17,13 +17,10 @@
 # under the License.
 #
 
-TRACE    = 0
-DEBUG    = 1
-INFO     = 2
-NOTICE   = 3
-WARNING  = 4
-ERROR    = 5
-CRITICAL = 6
+try:
+  from dispatch import *
+except ImportError:
+  from stubs import *
 
 class PathEngine(object):
   """

Modified: qpid/trunk/qpid/extras/dispatch/src/py/router/router_engine.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/py/router/router_engine.py?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/py/router/router_engine.py (original)
+++ qpid/trunk/qpid/extras/dispatch/src/py/router/router_engine.py Mon Jul  8 21:43:48 2013
@@ -30,39 +30,44 @@ from routing import RoutingTableEngine
 from binding import BindingEngine
 from adapter import AdapterEngine
 
-TRACE    = 0
-DEBUG    = 1
-INFO     = 2
-NOTICE   = 3
-WARNING  = 4
-ERROR    = 5
-CRITICAL = 6
+##
+## Import the Dispatch adapters from the environment.  If they are not found
+## (i.e. we are in a test bench, etc.), load the stub versions.
+##
+try:
+  from dispatch import *
+except ImportError:
+  from stubs import *
+
 
 class RouterEngine:
   """
   """
 
-  def __init__(self, adapter, domain, router_id=None, area='area', config_override={}):
+  def __init__(self, router_adapter, router_id=None, area='area', config_override={}):
     """
     Initialize an instance of a router for a domain.
     """
     ##
     ## Record important information about this router instance
     ##
-    self.adapter = adapter
-    self.domain = domain
+    self.domain         = "domain"
+    self.router_adapter = router_adapter
+    self.log_adapter    = LogAdapter("dispatch.router")
+    self.io_adapter     = IoAdapter(self, "qdxrouter")
+
     if router_id:
       self.id = router_id
     else:
       self.id = str(uuid4())
     self.area = area
-    self.log(NOTICE, "Router Engine Instantiated: area=%s id=%s" % (self.area, self.id))
+    self.log(LOG_INFO, "Router Engine Instantiated: area=%s id=%s" % (self.area, self.id))
 
     ##
     ## Setup configuration
     ##
     self.config = Configuration(config_override)
-    self.log(INFO, "Config: %r" % self.config)
+    self.log(LOG_INFO, "Config: %r" % self.config)
 
     ##
     ## Launch the sub-module engines
@@ -75,13 +80,6 @@ class RouterEngine:
     self.binding_engine        = BindingEngine(self)
     self.adapter_engine        = AdapterEngine(self)
 
-    ##
-    ## Establish the local bindings so that this router instance can receive
-    ## traffic addressed to it
-    ##
-    self.adapter.local_bind('router')
-    self.adapter.local_bind('_topo/%s/%s' % (self.area, self.id))
-    self.adapter.local_bind('_topo/%s/all' % self.area)
 
 
   ##========================================================================================
@@ -102,7 +100,7 @@ class RouterEngine:
         return
       self.mobile_address_engine.add_local_address(key)
     except Exception, e:
-      self.log(ERROR, "Exception in new-address processing: exception=%r" % e)
+      self.log(LOG_ERROR, "Exception in new-address processing: exception=%r" % e)
 
   def delLocalAddress(self, key):
     """
@@ -112,7 +110,7 @@ class RouterEngine:
         return
       self.mobile_address_engine.del_local_address(key)
     except Exception, e:
-      self.log(ERROR, "Exception in del-address processing: exception=%r" % e)
+      self.log(LOG_ERROR, "Exception in del-address processing: exception=%r" % e)
 
 
   def handleTimerTick(self):
@@ -128,7 +126,7 @@ class RouterEngine:
       self.binding_engine.tick(now)
       self.adapter_engine.tick(now)
     except Exception, e:
-      self.log(ERROR, "Exception in timer processing: exception=%r" % e)
+      self.log(LOG_ERROR, "Exception in timer processing: exception=%r" % e)
 
 
   def handleControlMessage(self, opcode, body):
@@ -138,38 +136,48 @@ class RouterEngine:
       now = time()
       if   opcode == 'HELLO':
         msg = MessageHELLO(body)
-        self.log(TRACE, "RCVD: %r" % msg)
+        self.log(LOG_TRACE, "RCVD: %r" % msg)
         self.neighbor_engine.handle_hello(msg, now)
 
       elif opcode == 'RA':
         msg = MessageRA(body)
-        self.log(TRACE, "RCVD: %r" % msg)
+        self.log(LOG_TRACE, "RCVD: %r" % msg)
         self.link_state_engine.handle_ra(msg, now)
         self.mobile_address_engine.handle_ra(msg, now)
 
       elif opcode == 'LSU':
         msg = MessageLSU(body)
-        self.log(TRACE, "RCVD: %r" % msg)
+        self.log(LOG_TRACE, "RCVD: %r" % msg)
         self.link_state_engine.handle_lsu(msg, now)
 
       elif opcode == 'LSR':
         msg = MessageLSR(body)
-        self.log(TRACE, "RCVD: %r" % msg)
+        self.log(LOG_TRACE, "RCVD: %r" % msg)
         self.link_state_engine.handle_lsr(msg, now)
 
       elif opcode == 'MAU':
         msg = MessageMAU(body)
-        self.log(TRACE, "RCVD: %r" % msg)
+        self.log(LOG_TRACE, "RCVD: %r" % msg)
         self.mobile_address_engine.handle_mau(msg, now)
 
       elif opcode == 'MAR':
         msg = MessageMAR(body)
-        self.log(TRACE, "RCVD: %r" % msg)
+        self.log(LOG_TRACE, "RCVD: %r" % msg)
         self.mobile_address_engine.handle_mar(msg, now)
 
     except Exception, e:
-      self.log(ERROR, "Exception in message processing: opcode=%s body=%r exception=%r" % (opcode, body, e))
+      self.log(LOG_ERROR, "Exception in message processing: opcode=%s body=%r exception=%r" % (opcode, body, e))
+
 
+  def receive(self, message_properties, body):
+    """
+    This is the IoAdapter message-receive handler
+    """
+    try:
+      self.handleControlMessage(message_properties['opcode'], body)
+    except Exception, e:
+      self.log(LOG_ERROR, "Exception in raw message processing: properties=%r body=%r exception=%r" %
+               (message_properties, body, e))
 
   def getRouterData(self, kind):
     """
@@ -196,51 +204,52 @@ class RouterEngine:
 
 
   ##========================================================================================
-  ## Adapter Calls - outbound calls to the adapter
+  ## Adapter Calls - outbound calls to Dispatch
   ##========================================================================================
   def log(self, level, text):
     """
     Emit a log message to the host's event log
     """
-    self.adapter.log(level, text)
+    self.log_adapter.log(level, text)
 
 
   def send(self, dest, msg):
     """
     Send a control message to another router.
     """
-    self.adapter.send(dest, msg.get_opcode(), msg.to_dict())
-    self.log(TRACE, "SENT: %r dest=%s" % (msg, dest))
+    app_props = {'opcode' : msg.get_opcode() }
+    self.io_adapter.send(dest, app_props, msg.to_dict())
+    self.log(LOG_TRACE, "SENT: %r dest=%s" % (msg, dest))
 
 
   ##========================================================================================
   ## Interconnect between the Sub-Modules
   ##========================================================================================
   def local_link_state_changed(self, link_state):
-    self.log(DEBUG, "Event: local_link_state_changed: %r" % link_state)
+    self.log(LOG_DEBUG, "Event: local_link_state_changed: %r" % link_state)
     self.link_state_engine.new_local_link_state(link_state)
 
   def ls_collection_changed(self, collection):
-    self.log(DEBUG, "Event: ls_collection_changed: %r" % collection)
+    self.log(LOG_DEBUG, "Event: ls_collection_changed: %r" % collection)
     self.path_engine.ls_collection_changed(collection)
 
   def next_hops_changed(self, next_hop_table):
-    self.log(DEBUG, "Event: next_hops_changed: %r" % next_hop_table)
+    self.log(LOG_DEBUG, "Event: next_hops_changed: %r" % next_hop_table)
     self.routing_table_engine.next_hops_changed(next_hop_table)
     self.binding_engine.next_hops_changed()
 
   def mobile_sequence_changed(self, mobile_seq):
-    self.log(DEBUG, "Event: mobile_sequence_changed: %d" % mobile_seq)
+    self.log(LOG_DEBUG, "Event: mobile_sequence_changed: %d" % mobile_seq)
     self.link_state_engine.set_mobile_sequence(mobile_seq)
 
   def mobile_keys_changed(self, keys):
-    self.log(DEBUG, "Event: mobile_keys_changed: %r" % keys)
+    self.log(LOG_DEBUG, "Event: mobile_keys_changed: %r" % keys)
     self.binding_engine.mobile_keys_changed(keys)
 
   def get_next_hops(self):
     return self.routing_table_engine.get_next_hops()
 
   def remote_routes_changed(self, key_class, routes):
-    self.log(DEBUG, "Event: remote_routes_changed: class=%s routes=%r" % (key_class, routes))
+    self.log(LOG_DEBUG, "Event: remote_routes_changed: class=%s routes=%r" % (key_class, routes))
     self.adapter_engine.remote_routes_changed(key_class, routes)
 

Modified: qpid/trunk/qpid/extras/dispatch/src/py/router/routing.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/py/router/routing.py?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/py/router/routing.py (original)
+++ qpid/trunk/qpid/extras/dispatch/src/py/router/routing.py Mon Jul  8 21:43:48 2013
@@ -17,13 +17,10 @@
 # under the License.
 #
 
-TRACE    = 0
-DEBUG    = 1
-INFO     = 2
-NOTICE   = 3
-WARNING  = 4
-ERROR    = 5
-CRITICAL = 6
+try:
+  from dispatch import *
+except ImportError:
+  from stubs import *
 
 class RoutingTableEngine(object):
   """

Added: qpid/trunk/qpid/extras/dispatch/src/py/stubs/__init__.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/py/stubs/__init__.py?rev=1500977&view=auto
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/py/stubs/__init__.py (added)
+++ qpid/trunk/qpid/extras/dispatch/src/py/stubs/__init__.py Mon Jul  8 21:43:48 2013
@@ -0,0 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from stubs.logadapter import * 
+from stubs.ioadapter  import *
+

Propchange: qpid/trunk/qpid/extras/dispatch/src/py/stubs/__init__.py
------------------------------------------------------------------------------
    svn:eol-style = native

Added: qpid/trunk/qpid/extras/dispatch/src/py/stubs/ioadapter.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/py/stubs/ioadapter.py?rev=1500977&view=auto
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/py/stubs/ioadapter.py (added)
+++ qpid/trunk/qpid/extras/dispatch/src/py/stubs/ioadapter.py Mon Jul  8 21:43:48 2013
@@ -0,0 +1,27 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+class IoAdapter:
+  def __init__(self, handler, address):
+    self.handler = handler
+    self.address = address
+
+  def send(self, address, app_properties, body):
+    print "IO: send(addr=%s props=%r body=%r" % (address, app_properties, body)
+

Propchange: qpid/trunk/qpid/extras/dispatch/src/py/stubs/ioadapter.py
------------------------------------------------------------------------------
    svn:eol-style = native

Added: qpid/trunk/qpid/extras/dispatch/src/py/stubs/logadapter.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/py/stubs/logadapter.py?rev=1500977&view=auto
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/py/stubs/logadapter.py (added)
+++ qpid/trunk/qpid/extras/dispatch/src/py/stubs/logadapter.py Mon Jul  8 21:43:48 2013
@@ -0,0 +1,33 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+LOG_TRACE    = 1
+LOG_DEBUG    = 2
+LOG_INFO     = 4
+LOG_NOTICE   = 8
+LOG_WARNING  = 16
+LOG_ERROR    = 32
+LOG_CRITICAL = 64
+
+class LogAdapter:
+  def __init__(self, mod_name):
+    self.mod_name = mod_name
+
+  def log(self, level, text):
+    print "LOG: mod=%s level=%d text=%s" % (self.mod_name, level, text)

Propchange: qpid/trunk/qpid/extras/dispatch/src/py/stubs/logadapter.py
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: qpid/trunk/qpid/extras/dispatch/src/python_embedded.c
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/python_embedded.c?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/python_embedded.c (original)
+++ qpid/trunk/qpid/extras/dispatch/src/python_embedded.c Mon Jul  8 21:43:48 2013
@@ -22,21 +22,25 @@
 #include <qpid/dispatch/log.h>
 #include <qpid/dispatch/amqp.h>
 #include <qpid/dispatch/alloc.h>
+#include <qpid/dispatch/router.h>
 
 
 //===============================================================================
 // Control Functions
 //===============================================================================
 
-static uint32_t     ref_count  = 0;
-static sys_mutex_t *lock       = 0;
-static char        *log_module = "PYTHON";
+static dx_dispatch_t *dispatch   = 0;
+static uint32_t       ref_count  = 0;
+static sys_mutex_t   *lock       = 0;
+static char          *log_module = "PYTHON";
+static PyObject      *dispatch_module = 0;
 
 static void dx_python_setup();
 
 
-void dx_python_initialize()
+void dx_python_initialize(dx_dispatch_t *dx)
 {
+    dispatch = dx;
     lock = sys_mutex();
 }
 
@@ -66,6 +70,8 @@ void dx_python_stop()
     sys_mutex_lock(lock);
     ref_count--;
     if (ref_count == 0) {
+        Py_DECREF(dispatch_module);
+        dispatch_module = 0;
         Py_Finalize();
         dx_log(log_module, LOG_TRACE, "Embedded Python Interpreter Shut Down");
     }
@@ -73,6 +79,13 @@ void dx_python_stop()
 }
 
 
+PyObject *dx_python_module()
+{
+    assert(dispatch_module);
+    return dispatch_module;
+}
+
+
 //===============================================================================
 // Data Conversion Functions
 //===============================================================================
@@ -380,49 +393,159 @@ static PyTypeObject LogAdapterType = {
 // Message IO Object
 //===============================================================================
 
-typedef struct dx_python_io_adapter {
-    int x;
-} dx_python_io_adapter;
-
-ALLOC_DECLARE(dx_python_io_adapter);
-ALLOC_DEFINE(dx_python_io_adapter);
-
-//static PyObject* dx_python_send(PyObject *self, PyObject *args)
-//{
-//    return 0;
-//}
+typedef struct {
+    PyObject_HEAD
+    PyObject       *handler;
+    dx_dispatch_t  *dx;
+    dx_address_t   *address;
+} IoAdapter;
+
+
+static void dx_io_rx_handler(void *context, dx_message_t *msg)
+{
+    //IoAdapter *self = (IoAdapter*) context;
+
+    // TODO - Parse the incoming message and send it to the python handler.
+}
+
+
+static int IoAdapter_init(IoAdapter *self, PyObject *args, PyObject *kwds)
+{
+    const char *address;
+    if (!PyArg_ParseTuple(args, "Os", &self->handler, &address))
+        return -1;
+
+    Py_INCREF(self->handler);
+    self->dx = dispatch;
+    self->address = dx_router_register_address(self->dx, true, address, dx_io_rx_handler, self);
+    return 0;
+}
+
+
+static void IoAdapter_dealloc(IoAdapter* self)
+{
+    dx_router_unregister_address(self->address);
+    Py_DECREF(self->handler);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+
+static PyObject* dx_python_send(PyObject *self, PyObject *args)
+{
+    const char *address;
+    PyObject   *app_properties;
+    PyObject   *body;
+    if (!PyArg_ParseTuple(args, "sOO", &address, &app_properties, &body))
+        return 0;
+
+    // TODO - Compose and send a message
+
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+static PyMethodDef IoAdapter_methods[] = {
+    {"send", dx_python_send, METH_VARARGS, "Send a Message"},
+    {0, 0, 0, 0}
+};
+
+
+static PyTypeObject IoAdapterType = {
+    PyObject_HEAD_INIT(0)
+    0,                         /* ob_size*/
+    "dispatch.IoAdapter",      /* tp_name*/
+    sizeof(IoAdapter),         /* tp_basicsize*/
+    0,                         /* tp_itemsize*/
+    (destructor)IoAdapter_dealloc, /* tp_dealloc*/
+    0,                         /* tp_print*/
+    0,                         /* tp_getattr*/
+    0,                         /* tp_setattr*/
+    0,                         /* tp_compare*/
+    0,                         /* tp_repr*/
+    0,                         /* tp_as_number*/
+    0,                         /* tp_as_sequence*/
+    0,                         /* tp_as_mapping*/
+    0,                         /* tp_hash */
+    0,                         /* tp_call*/
+    0,                         /* tp_str*/
+    0,                         /* tp_getattro*/
+    0,                         /* tp_setattro*/
+    0,                         /* tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT,        /* tp_flags*/
+    "Dispatch IO Adapter",     /* tp_doc */
+    0,                         /* tp_traverse */
+    0,                         /* tp_clear */
+    0,                         /* tp_richcompare */
+    0,                         /* tp_weaklistoffset */
+    0,                         /* tp_iter */
+    0,                         /* tp_iternext */
+    IoAdapter_methods,         /* tp_methods */
+    0,                         /* tp_members */
+    0,                         /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    (initproc)IoAdapter_init,  /* tp_init */
+    0,                         /* tp_alloc */
+    0,                         /* tp_new */
+    0,                         /* tp_free */
+    0,                         /* tp_is_gc */
+    0,                         /* tp_bases */
+    0,                         /* tp_mro */
+    0,                         /* tp_cache */
+    0,                         /* tp_subclasses */
+    0,                         /* tp_weaklist */
+    0,                         /* tp_del */
+    0                          /* tp_version_tag */
+};
 
 
 //===============================================================================
 // Initialization of Modules and Types
 //===============================================================================
 
+static void dx_register_log_constant(PyObject *module, const char *name, uint32_t value)
+{
+    PyObject *const_object = PyInt_FromLong((long) value);
+    Py_INCREF(const_object);
+    PyModule_AddObject(module, name, const_object);
+}
+
+
 static void dx_python_setup()
 {
-    //
-    // Add LogAdapter
-    //
     LogAdapterType.tp_new = PyType_GenericNew;
-    if (PyType_Ready(&LogAdapterType) < 0) {
+    IoAdapterType.tp_new  = PyType_GenericNew;
+    if ((PyType_Ready(&LogAdapterType) < 0) || (PyType_Ready(&IoAdapterType) < 0)) {
         PyErr_Print();
-        dx_log(log_module, LOG_ERROR, "Unable to initialize LogAdapter");
+        dx_log(log_module, LOG_ERROR, "Unable to initialize Adapters");
         assert(0);
     } else {
         PyObject *m = Py_InitModule3("dispatch", empty_methods, "Dispatch Adapter Module");
 
+        //
+        // Add LogAdapter
+        //
         Py_INCREF(&LogAdapterType);
         PyModule_AddObject(m, "LogAdapter", (PyObject*) &LogAdapterType);
 
-        PyObject *LogTrace = PyInt_FromLong((long) LOG_TRACE);
-        Py_INCREF(LogTrace);
-        PyModule_AddObject(m, "LOG_TRACE", LogTrace);
-
-        PyObject *LogError = PyInt_FromLong((long) LOG_ERROR);
-        Py_INCREF(LogError);
-        PyModule_AddObject(m, "LOG_ERROR", LogError);
-
-        PyObject *LogInfo = PyInt_FromLong((long) LOG_INFO);
-        Py_INCREF(LogInfo);
-        PyModule_AddObject(m, "LOG_INFO", LogInfo);
+        dx_register_log_constant(m, "LOG_TRACE",    LOG_TRACE);
+        dx_register_log_constant(m, "LOG_DEBUG",    LOG_DEBUG);
+        dx_register_log_constant(m, "LOG_INFO",     LOG_INFO);
+        dx_register_log_constant(m, "LOG_NOTICE",   LOG_NOTICE);
+        dx_register_log_constant(m, "LOG_WARNING",  LOG_WARNING);
+        dx_register_log_constant(m, "LOG_ERROR",    LOG_ERROR);
+        dx_register_log_constant(m, "LOG_CRITICAL", LOG_CRITICAL);
+
+        //
+        Py_INCREF(&IoAdapterType);
+        PyModule_AddObject(m, "IoAdapter", (PyObject*) &IoAdapterType);
+
+        Py_INCREF(m);
+        dispatch_module = m;
     }
 }

Modified: qpid/trunk/qpid/extras/dispatch/src/router_node.c
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/src/router_node.c?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/src/router_node.c (original)
+++ qpid/trunk/qpid/extras/dispatch/src/router_node.c Mon Jul  8 21:43:48 2013
@@ -17,6 +17,7 @@
  * under the License.
  */
 
+#include <qpid/dispatch/python_embedded.h>
 #include <stdio.h>
 #include <string.h>
 #include <qpid/dispatch.h>
@@ -24,6 +25,9 @@
 
 static char *module = "ROUTER";
 
+static void dx_router_python_setup(dx_router_t *router);
+static void dx_pyrouter_tick(dx_router_t *router);
+
 //static char *local_prefix = "_local/";
 //static char *topo_prefix  = "_topo/";
 
@@ -54,6 +58,8 @@ struct dx_router_t {
     dx_timer_t         *timer;
     hash_t             *out_hash;
     uint64_t            dtag;
+    PyObject           *pyRouter;
+    PyObject           *pyTick;
 };
 
 
@@ -459,6 +465,8 @@ static void dx_router_timer_handler(void
     //
     // Periodic processing.
     //
+    dx_pyrouter_tick(router);
+
     dx_timer_schedule(router->timer, 1000);
 }
 
@@ -498,10 +506,10 @@ dx_router_t *dx_router(dx_dispatch_t *dx
     router->router_id   = id;
 
     router->timer = dx_timer(dx, dx_router_timer_handler, (void*) router);
-    dx_timer_schedule(router->timer, 0); // Immediate
 
     router->out_hash = hash(10, 32, 0);
-    router->dtag = 1;
+    router->dtag     = 1;
+    router->pyRouter = 0;
 
     //
     // Inform the field iterator module of this router's id and area.  The field iterator
@@ -509,6 +517,11 @@ dx_router_t *dx_router(dx_dispatch_t *dx
     //
     dx_field_iterator_set_address(area, id);
 
+    //
+    // Set up the usage of the embedded python router module.
+    //
+    dx_python_start();
+
     dx_log(module, LOG_INFO, "Router started, area=%s id=%s", area, id);
 
     return router;
@@ -517,6 +530,9 @@ dx_router_t *dx_router(dx_dispatch_t *dx
 
 void dx_router_setup_agent(dx_dispatch_t *dx)
 {
+    dx_router_python_setup(dx->router);
+    dx_timer_schedule(dx->router->timer, 1000);
+
     // TODO
 }
 
@@ -526,6 +542,7 @@ void dx_router_free(dx_router_t *router)
     dx_container_set_default_node_type(router->dx, 0, 0, DX_DIST_BOTH);
     sys_mutex_free(router->lock);
     free(router);
+    dx_python_stop();
 }
 
 
@@ -595,3 +612,201 @@ void dx_router_send(dx_dispatch_t       
     sys_mutex_unlock(router->lock); // TOINVESTIGATE Move this higher?
 }
 
+
+//===============================================================================
+// Python Router Adapter
+//===============================================================================
+
+typedef struct {
+    PyObject_HEAD
+    dx_router_t *router;
+} RouterAdapter;
+
+
+static PyObject* dx_router_add_route(PyObject *self, PyObject *args)
+{
+    //RouterAdapter *adapter = (RouterAdapter*) self;
+    const char    *addr;
+    const char    *peer;
+
+    if (!PyArg_ParseTuple(args, "ss", &addr, &peer))
+        return 0;
+
+    // TODO
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+static PyObject* dx_router_del_route(PyObject *self, PyObject *args)
+{
+    //RouterAdapter *adapter = (RouterAdapter*) self;
+    const char    *addr;
+    const char    *peer;
+
+    if (!PyArg_ParseTuple(args, "ss", &addr, &peer))
+        return 0;
+
+    // TODO
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+static PyMethodDef RouterAdapter_methods[] = {
+    {"add_route", dx_router_add_route, METH_VARARGS, "Add a newly discovered route"},
+    {"del_route", dx_router_del_route, METH_VARARGS, "Delete a route"},
+    {0, 0, 0, 0}
+};
+
+static PyTypeObject RouterAdapterType = {
+    PyObject_HEAD_INIT(0)
+    0,                         /* ob_size*/
+    "dispatch.RouterAdapter",  /* tp_name*/
+    sizeof(RouterAdapter),     /* tp_basicsize*/
+    0,                         /* tp_itemsize*/
+    0,                         /* tp_dealloc*/
+    0,                         /* tp_print*/
+    0,                         /* tp_getattr*/
+    0,                         /* tp_setattr*/
+    0,                         /* tp_compare*/
+    0,                         /* tp_repr*/
+    0,                         /* tp_as_number*/
+    0,                         /* tp_as_sequence*/
+    0,                         /* tp_as_mapping*/
+    0,                         /* tp_hash */
+    0,                         /* tp_call*/
+    0,                         /* tp_str*/
+    0,                         /* tp_getattro*/
+    0,                         /* tp_setattro*/
+    0,                         /* tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT,        /* tp_flags*/
+    "Dispatch Router Adapter", /* tp_doc */
+    0,                         /* tp_traverse */
+    0,                         /* tp_clear */
+    0,                         /* tp_richcompare */
+    0,                         /* tp_weaklistoffset */
+    0,                         /* tp_iter */
+    0,                         /* tp_iternext */
+    RouterAdapter_methods,     /* tp_methods */
+    0,                         /* tp_members */
+    0,                         /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    0,                         /* tp_init */
+    0,                         /* tp_alloc */
+    0,                         /* tp_new */
+    0,                         /* tp_free */
+    0,                         /* tp_is_gc */
+    0,                         /* tp_bases */
+    0,                         /* tp_mro */
+    0,                         /* tp_cache */
+    0,                         /* tp_subclasses */
+    0,                         /* tp_weaklist */
+    0,                         /* tp_del */
+    0                          /* tp_version_tag */
+};
+
+
+static void dx_router_python_setup(dx_router_t *router)
+{
+    PyObject *pDispatchModule = dx_python_module();
+
+    RouterAdapterType.tp_new = PyType_GenericNew;
+    if (PyType_Ready(&RouterAdapterType) < 0) {
+        PyErr_Print();
+        dx_log(module, LOG_CRITICAL, "Unable to initialize the Python Router Adapter");
+        return;
+    }
+
+    Py_INCREF(&RouterAdapterType);
+    PyModule_AddObject(pDispatchModule, "RouterAdapter", (PyObject*) &RouterAdapterType);
+
+    //
+    // Attempt to import the Python Router module
+    //
+    PyObject* pName;
+    PyObject* pId;
+    PyObject* pArea;
+    PyObject* pModule;
+    PyObject* pClass;
+    PyObject* pArgs;
+
+    pName   = PyString_FromString("router");
+    pModule = PyImport_Import(pName);
+    Py_DECREF(pName);
+    if (!pModule) {
+        dx_log(module, LOG_CRITICAL, "Can't Locate 'router' Python module");
+        return;
+    }
+
+    pClass = PyObject_GetAttrString(pModule, "RouterEngine");
+    if (!pClass || !PyClass_Check(pClass)) {
+        dx_log(module, LOG_CRITICAL, "Can't Locate 'RouterEngine' class in the 'router' module");
+        return;
+    }
+
+    PyObject *adapterType     = PyObject_GetAttrString(pDispatchModule, "RouterAdapter");
+    PyObject *adapterInstance = PyObject_CallObject(adapterType, 0);
+    assert(adapterInstance);
+
+    ((RouterAdapter*) adapterInstance)->router = router;
+
+    //
+    // Constructor Arguments for RouterEngine
+    //
+    pArgs = PyTuple_New(3);
+
+    // arg 0: adapter instance
+    PyTuple_SetItem(pArgs, 0, adapterInstance);
+
+    // arg 1: router_id
+    pId = PyString_FromString(router->router_id);
+    PyTuple_SetItem(pArgs, 1, pId);
+
+    // arg 2: area id
+    pArea = PyString_FromString(router->router_area);
+    PyTuple_SetItem(pArgs, 2, pArea);
+
+    //
+    // Instantiate the router
+    //
+    router->pyRouter = PyInstance_New(pClass, pArgs, 0);
+    Py_DECREF(pArgs);
+    Py_DECREF(adapterType);
+
+    if (!router->pyRouter) {
+        PyErr_Print();
+        dx_log(module, LOG_CRITICAL, "'RouterEngine' class cannot be instantiated");
+        return;
+    }
+
+    router->pyTick = PyObject_GetAttrString(router->pyRouter, "handleTimerTick");
+    if (!router->pyTick || !PyCallable_Check(router->pyTick)) {
+        dx_log(module, LOG_CRITICAL, "'RouterEngine' class has no handleTimerTick method");
+        return;
+    }
+}
+
+
+static void dx_pyrouter_tick(dx_router_t *router)
+{
+    PyObject *pArgs;
+    PyObject *pValue;
+
+    pArgs  = PyTuple_New(0);
+    pValue = PyObject_CallObject(router->pyTick, pArgs);
+    if (PyErr_Occurred()) {
+        PyErr_Print();
+    }
+    Py_DECREF(pArgs);
+    if (pValue) {
+        Py_DECREF(pValue);
+    }
+}
+

Modified: qpid/trunk/qpid/extras/dispatch/tests/router_engine_test.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/extras/dispatch/tests/router_engine_test.py?rev=1500977&r1=1500976&r2=1500977&view=diff
==============================================================================
--- qpid/trunk/qpid/extras/dispatch/tests/router_engine_test.py (original)
+++ qpid/trunk/qpid/extras/dispatch/tests/router_engine_test.py Mon Jul  8 21:43:48 2013
@@ -30,19 +30,12 @@ class Adapter(object):
 
   def send(self, dest, opcode, body):
     print "Adapter.send: domain=%s, dest=%s, opcode=%s, body=%s" % (self._domain, dest, opcode, body)
-
-  def local_bind(self, key):
-    print "Adapter.local_bind: key=%s" % key
-
   def remote_bind(self, subject, peer):
     print "Adapter.remote_bind: subject=%s, peer=%s" % (subject, peer)
 
   def remote_unbind(self, subject, peer):
     print "Adapter.remote_unbind: subject=%s, peer=%s" % (subject, peer)
 
-  def remote_rebind(self, subject, old_peer, new_peer):
-    print "Adapter.remote_rebind: subject=%s, old_peer=%s, new_peer=%s" % (subject, old_peer, new_peer)
-
 
 class DataTest(unittest.TestCase):
   def test_link_state(self):
@@ -122,7 +115,7 @@ class NeighborTest(unittest.TestCase):
     self.engine.tick(1.5)
     self.assertEqual(len(self.sent), 1)
     dest, msg = self.sent.pop(0)
-    self.assertEqual(dest, "_peer")
+    self.assertEqual(dest, "_local/qdxrouter")
     self.assertEqual(msg.get_opcode(), "HELLO")
     self.assertEqual(msg.id, self.id)
     self.assertEqual(msg.area, self.area)



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org