[rhmessaging-commits] rhmessaging commits: r3209 - in mgmt/trunk: mint/python/mint and 2 other directories.

rhmessaging-commits at lists.jboss.org rhmessaging-commits at lists.jboss.org
Wed Mar 25 13:38:56 EDT 2009


Author: justi9
Date: 2009-03-25 13:38:55 -0400 (Wed, 25 Mar 2009)
New Revision: 3209

Added:
   mgmt/trunk/cumin/python/cumin/managementserver.py
   mgmt/trunk/cumin/python/cumin/managementserver.strings
Modified:
   mgmt/trunk/cumin/python/cumin/binding.py
   mgmt/trunk/cumin/python/cumin/broker.py
   mgmt/trunk/cumin/python/cumin/broker.strings
   mgmt/trunk/cumin/python/cumin/brokergroup.py
   mgmt/trunk/cumin/python/cumin/brokerlink.py
   mgmt/trunk/cumin/python/cumin/brokerprofile.py
   mgmt/trunk/cumin/python/cumin/client.py
   mgmt/trunk/cumin/python/cumin/exchange.py
   mgmt/trunk/cumin/python/cumin/model.py
   mgmt/trunk/cumin/python/cumin/page.py
   mgmt/trunk/cumin/python/cumin/page.strings
   mgmt/trunk/cumin/python/cumin/parameters.py
   mgmt/trunk/cumin/python/cumin/queue.py
   mgmt/trunk/cumin/python/cumin/queue.strings
   mgmt/trunk/cumin/python/cumin/test.py
   mgmt/trunk/cumin/python/cumin/tools.py
   mgmt/trunk/cumin/python/cumin/virtualhost.py
   mgmt/trunk/cumin/python/cumin/widgets.py
   mgmt/trunk/mint/python/mint/__init__.py
   mgmt/trunk/mint/sql/schema.sql
   mgmt/trunk/wooly/python/wooly/tables.py
Log:
Separates brokers from management servers.  These were fused in an
awkward way before, but now they are independent.  As a result, the
"broker" frame no longer tries to merge data from broker registrations
and brokers, and the broker list under messaging is a list of brokers,
not registrations.

This change also makes an effort to avoid using *args in widget
process and render methods.  That's a failed approach that I'm trying
to move away from incrementally.  This change also endeavors to use
parameters by passed-down reference rather than having code search in
parent widgets or frames.

In order to support broker status, introduces heartbeat handling in
mint.

Deletes virtualhost.py, which was unused.

Refactors constraint gathering in SqlItemTable.



Modified: mgmt/trunk/cumin/python/cumin/binding.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/binding.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/binding.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -251,9 +251,13 @@
         return self.get(session) == "c"
 
 class ExchangeKeysField(FormField):
-    def __init__(self, app, name, title="Initial bindings:"):
+    def __init__(self, app, name, vhost, title="Initial bindings:"):
         super(ExchangeKeysField, self).__init__(app, name)
 
+        assert vhost
+
+        self.vhost = vhost
+
         self.dict_param = DictParameter(app, "exchange")
         self.add_parameter(self.dict_param)
 
@@ -280,18 +284,15 @@
         self.state = ExchangeState(app, "phase")
         self.add_child(self.state)
 
-    def get_args(self, session):
-        reg = self.frame.get_ancestor("broker").get_object(session)
-        return (reg.getDefaultVhost(),)
-
     class Errors(Attribute):
         def get_default(self, session):
             return dict()
 
-    def render_title(self, session, vhost):
+    def render_title(self, session):
         return self.title
 
-    def render_exchanges(self, session, vhost):
+    def render_exchanges(self, session):
+        vhost = self.vhost.get(session)
         sortedExchanges = sorted_by(vhost.exchanges)
 
         # render each exchange we support
@@ -324,7 +325,6 @@
         return writer.to_string()
 
     def get_binding_errors(self, session, queue_name):
-
         form_binding_info = self.process_binding_info(session, queue_name)
         binding_info = self.dict_param.get(session)
         berrs = self.binding_errors.get(session)

Modified: mgmt/trunk/cumin/python/cumin/broker.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/broker.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/broker.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -5,11 +5,11 @@
 from psycopg2 import IntegrityError
 
 from configproperty import *
-from virtualhost import *
 from queue import *
 from exchange import *
 from brokerlink import *
 from client import *
+from modelwidgets import *
 from widgets import *
 from parameters import *
 from formats import *
@@ -17,112 +17,75 @@
 
 strings = StringCatalog(__file__)
 
-class BrokerSet(CuminTable, Form):
+class NewBrokerSet(CuminClassTable):
     def __init__(self, app, name):
-        super(BrokerSet, self).__init__(app, name)
+        super(NewBrokerSet, self).__init__(app, name, app.model.broker)
 
-        self.ids = CheckboxIdColumn(app, "id")
-        self.add_column(self.ids)
+        self.group = BrokerGroupParameter(app, "group")
+        self.add_parameter(self.group)
 
         col = self.NameColumn(app, "name")
         self.add_column(col)
         self.set_default_column(col)
 
-        col = self.GroupsColumn(app, "groups")
+        col = self.StatusColumn(app, "status")
         self.add_column(col)
 
         col = self.ClusterColumn(app, "cluster")
         self.add_column(col)
 
-        self.groups = self.BrokerSetGroupInput(app, "groups")
-        self.add_child(self.groups)
-
-        self.__unregister = self.Unregister(app, "unregister")
-        self.add_child(self.__unregister)
-
-        self.groupify = self.Groupify(app, "groupify")
-        self.add_child(self.groupify)
-
-    def render_title(self, session, *args):
-        count = BrokerRegistration.select().count()
+    def render_title(self, session):
+        count = self.get_item_count(session)
         return "Brokers %s" % fmt_count(count)
 
-    class Unregister(FormButton):
-        def render_content(self, session):
-            return "Unregister"
+    def render_sql_where(self, session):
+        constraints = self.get_sql_where_constraints(session)
 
-        def render_class(self, session):
-            return "unregister"
+        if constraints:
+            return "where %s" % " and ".join(constraints)
 
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
+    def get_sql_where_constraints(self, session):
+        constraints = list()
+        group = self.group.get(session)
 
-            branch = session.branch()
-            frame = self.page.main.brokers_remove.show(branch)
-            frame.ids.set(branch, ids)
-            frame.origin.set(branch, session.marshal())
-            self.page.set_redirect_url(session, branch.marshal())
+        if group:
+            subquery = \
+                "select 1 from broker_group_mapping " + \
+                "where broker_group_id = %(group_id)r " + \
+                "and broker_id = b.id"
 
-    class BrokerSetGroupInput(BrokerGroupInput):
-        def render_submit_id(self, session):
-            return self.parent.groupify.path
+            constraints.append("exists (%s)" % subquery)
 
-    class Groupify(FormButton):
-        def render_content(self, session):
-            return "Add"
+        return constraints
 
-        def process_submit(self, session):
-            group = self.parent.groups.get(session)
+    def get_sql_values(self, session):
+        group = self.group.get(session)
 
-            if group:
-                ids = self.parent.ids.get(session)
-                self.parent.ids.clear(session)
+        if group:
+            return {"group_id": group.id}
 
-                for id in ids:
-                    try:
-                        broker = BrokerRegistration.get(id)
-                        broker.addBrokerGroup(group)
-                    except IntegrityError:
-                        pass
-
-            self.page.set_redirect_url(session, session.marshal())
-
     class NameColumn(SqlTableColumn):
         def render_title(self, session, data):
             return "Name"
 
         def render_content(self, session, data):
-            reg = Identifiable(data["id"])
-            href = self.page.main.broker.get_href(session, reg)
-            return fmt_link(href, fmt_shorten(data["name"]))
+            broker = Identifiable(data["id"])
+            href = self.page.main.broker.get_href(session, broker)
+            return fmt_link(href, fmt_shorten(data["name"], 32, 8))
 
-    class GroupsColumn(SqlTableColumn):
+    class StatusColumn(SqlTableColumn):
         def render_title(self, session, data):
-            return "Groups"
+            return "Status"
 
-        def get_order_by_sql(self, session):
-            return None
-
         def render_content(self, session, data):
-            broker = BrokerRegistration.get(data["id"])
-            count = broker.groups.count()
+            scopeId = data["qmf_scope_id"]
+            dt = self.app.model.data.getLatestHeartbeat(scopeId)
 
-            if count == 0:
-                link = fmt_none()
-            elif count < 3:
-                links = list()
-
-                for group in broker.groups[:2]:
-                    href = self.page.main.broker_group.get_href(session, group)
-                    links.append(fmt_link(href, group.name))
-
-                link = ", ".join(links)
+            if dt is None:
+                return fmt_none()
             else:
-                link = "%i groups" % count
+                return fmt_datetime(dt)
 
-            return link
-
     class ClusterColumn(SqlTableColumn):
         def render_title(self, session, data):
             return "Cluster"
@@ -151,10 +114,13 @@
     def __init__(self, app, name):
         super(BrokerFrame, self).__init__(app, name)
 
-        self.object = BrokerRegistrationParameter(app, "id")
+        self.object = BrokerParameter(app, "id")
         self.add_parameter(self.object)
 
-        self.view = BrokerView(app, "view")
+        self.vhost = self.VhostAttribute(app, "vhost")
+        self.add_attribute(self.vhost)
+
+        self.view = BrokerView(app, "view", self.vhost)
         self.add_mode(self.view)
         self.set_view_mode(self.view)
 
@@ -171,13 +137,13 @@
         self.queues_remove = QueueSetRemove(app, "queuesremove")
         self.add_mode(self.queues_remove)
 
-        self.queue_add = QueueAdd(app, "queueadd")
+        self.queue_add = QueueAdd(app, "queueadd", self.vhost)
         self.add_mode(self.queue_add)
 
         self.exchange = ExchangeFrame(app, "exchange")
         self.add_mode(self.exchange)
 
-        self.exchange_add = ExchangeAdd(app, "exchangeadd")
+        self.exchange_add = ExchangeAdd(app, "exchangeadd", self.vhost)
         self.add_mode(self.exchange_add)
 
         self.exchanges_remove = ExchangeSetRemove(app, "exchangesremove")
@@ -189,7 +155,7 @@
         self.link = PeerFrame(app, "link")
         self.add_mode(self.link)
 
-        self.link_add = BrokerLinkAdd(app, "linkadd")
+        self.link_add = BrokerLinkAdd(app, "linkadd", self.vhost)
         self.add_mode(self.link_add)
 
         self.links_close = BrokerSetClose(app, "linksclose")
@@ -201,20 +167,29 @@
         self.connections_close = ConnectionSetClose(app, "connsclose")
         self.add_mode(self.connections_close)
 
+    class VhostAttribute(Attribute):
+        def get_default(self, session):
+            broker = self.widget.object.get(session)
+
+            for vhost in Vhost.selectBy(broker=broker, name="/"):
+                return vhost
+
 class BrokerStatus(CuminStatus):
-    def __init__(self, app, name):
+    def __init__(self, app, name, vhost):
         super(BrokerStatus, self).__init__(app, name)
 
+        self.vhost = vhost
+
         self.connected = self.ConnectedAttribute(app, "conn")
         self.add_attribute(self.connected)
 
-    def render_status(self, session, reg):
+    def render_status(self, session, object):
         if self.connected.get(session):
             return "Connected"
         else:
             return "Disconnected"
 
-    def render_color(self, session, reg):
+    def render_color(self, session, object):
         if self.connected.get(session):
             return "green"
         else:
@@ -222,6 +197,9 @@
 
     class ConnectedAttribute(Attribute):
         def get_default(self, session):
+            # XXXX this should be done with heartbeats instead?
+            return False
+
             reg = self.widget.frame.get_object(session)
             connected = False
 
@@ -235,57 +213,34 @@
             return connected
 
 class BrokerView(CuminView):
-    """
-    Despite the name, this is actually a view of two objects, usually
-    coupled: a BrokerRegistration and a Broker.
-    """
-
-    def __init__(self, app, name):
+    def __init__(self, app, name, vhost):
         super(BrokerView, self).__init__(app, name)
 
-        status = BrokerStatus(app, "status")
+        self.vhost = vhost
+
+        status = BrokerStatus(app, "status", vhost)
         self.add_child(status)
 
-        self.__body = ModeSet(app, "body")
-        self.add_child(self.__body)
+        tabs = TabbedModeSet(app, "tabs")
+        self.add_child(tabs)
 
-        self.__tabs = TabbedModeSet(app, "tabs")
-        self.__body.add_mode(self.__tabs)
+        #tabs.add_tab(BrokerStats(app, "stats"))
+        tabs.add_tab(self.BrokerQueueTab(app, "queues", self.vhost))
+        tabs.add_tab(ExchangeSet(app, "exchanges", self.vhost))
+        tabs.add_tab(ConnectionSet(app, "conns", self.vhost))
+        tabs.add_tab(PeerSet(app, "peers", self.vhost))
+        tabs.add_tab(BrokerAccessControl(app, "access", self.vhost))
+        tabs.add_tab(BrokerClustering(app, "cluster", self.vhost))
+        tabs.add_tab(self.BrokerDetailsTab(app, "details", self.vhost))
 
-        #self.__tabs.add_tab(BrokerStats(app, "stats"))
-        self.__tabs.add_tab(self.BrokerQueueTab(app, "queues"))
-        self.__tabs.add_tab(ExchangeSet(app, "exchanges"))
-        self.__tabs.add_tab(ConnectionSet(app, "conns"))
-        self.__tabs.add_tab(PeerSet(app, "peers"))
-        self.__tabs.add_tab(BrokerAccessControl(app, "access"))
-        self.__tabs.add_tab(BrokerClustering(app, "cluster"))
-        self.__tabs.add_tab(self.BrokerDetailsTab(app, "details"))
+    def render_script(self, session, object):
+        broker = self.vhost.get(session).broker
+        data = "model.xml?class=broker;id=%i" % broker.id
+        return "wooly.setIntervalUpdate('%s', updateBroker, 3000)" % data
 
-        self.__missing = self.BrokerMissing(app, "missing")
-        self.__body.add_mode(self.__missing)
+    def render_group_links(self, session, object):
+        return "XXX"
 
-        self.__vhost = Attribute(app, "vhost")
-        self.add_attribute(self.__vhost)
-
-    class BrokerMissing(Widget):
-        pass
-
-    def do_process(self, session, reg):
-        reg.sync()
-
-        if reg.broker:
-            self.__vhost.set(session, reg.getDefaultVhost())
-        else:
-            self.__body.show_mode(session, self.__missing)
-
-        super(BrokerView, self).do_process(session, reg)
-
-    def render_script(self, session, reg):
-        if reg.broker:
-            data = "model.xml?class=broker;id=%i" % reg.broker.id
-            return "wooly.setIntervalUpdate('%s', updateBroker, 3000)" % data
-
-    def render_group_links(self, session, reg):
         links = list()
 
         for group in reg.groups:
@@ -296,36 +251,33 @@
 
         return ", ".join(links)
 
+    # XXX see if we can't get rid of this
     class BrokerQueueTab(Widget):
-        def __init__(self, app, name):
+        def __init__(self, app, name, vhost):
             super(BrokerView.BrokerQueueTab, self).__init__(app, name)
 
-            self.__queues = QueueSet(app, "items")
+            self.__queues = QueueSet(app, "items", vhost)
             self.add_child(self.__queues)
 
-        def get_args(self, session):
-            return self.frame.get_args(session)
-
-        def render_title(self, session, reg):
-            vhost = reg.getDefaultVhost()
+        def render_title(self, session):
+            vhost = self.frame.vhost.get(session)
             return "Queues %s" % fmt_count(vhost.queues.count())
 
-        def render_add_queue_href(self, session, reg):
+        def render_add_queue_href(self, session):
             branch = session.branch()
             self.frame.queue.add.show(branch, None)
             return branch.marshal()
 
     class BrokerLogTab(Widget):
-        def get_args(self, session):
-            return self.frame.get_args(session)
-
-        def render_title(self, session, reg):
+        def render_title(self, session):
             return "Log Messages"
 
     class BrokerDetailsTab(Widget):
-        def __init__(self, app, name):
+        def __init__(self, app, name, vhost):
             super(BrokerView.BrokerDetailsTab, self).__init__(app, name)
 
+            self.vhost = vhost
+
             props = self.Properties(app, "properties")
             self.add_child(props)
 
@@ -336,30 +288,26 @@
             return "Details"
 
         class Properties(CuminProperties):
-            def do_get_items(self, session, reg):
-                cls = self.app.model.get_class_by_object(reg)
-                props = [(x.get_title(session), x.value(session, reg))
+            def do_get_items(self, session, object):
+                broker = self.parent.vhost.get(session).broker
+
+                cls = self.app.model.get_class_by_object(broker)
+                props = [(x.get_title(session),
+                          x.value(session, broker))
                          for x in cls.properties]
 
-                if reg.broker:
-                    cls = self.app.model.get_class_by_object(reg.broker)
-                    props.extend([(x.get_title(session),
-                                   x.value(session, reg.broker))
-                                  for x in cls.properties])
-
                 return props
 
         class Actions(CuminActions):
-            def do_get_items(self, session, reg):
-                cls = self.app.model.get_class_by_object(reg)
-                acts = [(x.get_href(session, reg), x.get_title(session), x.get_enabled(session, reg))
-                         for x in cls.actions if x.navigable]
+            def do_get_items(self, session, object):
+                broker = self.parent.vhost.get(session).broker
 
-                if reg.broker:
-                    cls = self.app.model.get_class_by_object(reg.broker)
-                    acts.extend([(x.get_href(session, reg.broker),
-                                  x.get_title(session), x.get_enabled(session, reg.broker))
-                                 for x in cls.actions if x.navigable])
+                cls = self.app.model.get_class_by_object(broker)
+                acts = [(x.get_href(session, broker),
+                         x.get_title(session),
+                         x.get_enabled(session, broker))
+                        for x in cls.actions 
+                        if x.navigable and not x.aggregate]
 
                 return acts
 
@@ -368,83 +316,90 @@
         return "This module is not enabled"
 
 class BrokerAccessControl(ModeSet):
-    def __init__(self, app, name):
+    def __init__(self, app, name, vhost):
         super(BrokerAccessControl, self).__init__(app, name)
 
+        self.vhost = vhost
+
+        self.acl = self.AclModuleAttribute(self, "acl")
+        self.add_attribute(self.acl)
+
         mode = ModuleNotEnabled(app, "notenabled")
         self.add_mode(mode)
 
-        self.__view = BrokerAccessControlView(app, "view")
+        self.__view = BrokerAccessControlView(app, "view", self.acl)
         self.add_mode(self.__view)
 
-    def get_args(self, session):
-        broker = self.frame.get_object(session).broker
-        acl = None
+    class AclModuleAttribute(Attribute):
+        def get_default(self, session):
+            broker = self.widget.vhost.get(session).broker
 
-        try:
-            acl = Acl.selectBy(broker=broker)[0]
-        except IndexError:
-            pass
+            for acl in Acl.selectBy(broker=broker):
+                return acl
 
-        return (acl,)
-
-    def do_process(self, session, acl):
-        if acl:
+    def do_process(self, session):
+        if self.acl.get(session):
             self.show_mode(session, self.__view)
 
-    def render_title(self, session, acl):
+    def render_title(self, session):
         return "Access Control"
 
 class BrokerAccessControlView(Widget):
-    def __init__(self, app, name):
+    def __init__(self, app, name, acl):
         super(BrokerAccessControlView, self).__init__(app, name)
 
+        self.acl = acl
+
         props = self.Properties(app, "props")
         self.add_child(props)
 
         stats = self.Stats(app, "stats", "general")
         self.add_child(stats)
 
+    # XXX don't do this this way
     class Properties(CuminProperties):
         def get_args(self, session):
-            return self.parent.parent.get_args(session)
+            return (self.parent.acl.get(session),)
 
     class Stats(StatSet):
         def get_args(self, session):
-            return self.parent.parent.get_args(session)
+            return (self.parent.acl.get(session),)
 
 class BrokerClustering(ModeSet):
-    def __init__(self, app, name):
+    def __init__(self, app, name, vhost):
         super(BrokerClustering, self).__init__(app, name)
 
+        self.vhost = vhost
+
+        self.cluster = self.ClusteringModuleAttribute(self, "cluster")
+        self.add_attribute(self.cluster)
+
         mode = ModuleNotEnabled(app, "notenabled")
         self.add_mode(mode)
 
-        self.__view = BrokerClusteringView(app, "view")
+        self.__view = BrokerClusteringView(app, "view", self.cluster)
         self.add_mode(self.__view)
 
-    def get_args(self, session):
-        broker = self.frame.get_object(session).broker
-        cluster = None
+    class ClusteringModuleAttribute(Attribute):
+        def get_default(self, session):
+            broker = self.widget.vhost.get(session).broker
 
-        try:
-            cluster = Cluster.selectBy(broker=broker)[0]
-        except IndexError:
-            pass
+            for cluster in Cluster.selectBy(broker=broker):
+                return cluster
 
-        return (cluster,)
-
-    def do_process(self, session, cluster):
-        if cluster:
+    def do_process(self, session):
+        if self.cluster.get(session):
             self.show_mode(session, self.__view)
 
-    def render_title(self, session, cluster):
+    def render_title(self, session):
         return "Clustering"
 
 class BrokerClusteringView(Widget):
-    def __init__(self, app, name):
+    def __init__(self, app, name, cluster):
         super(BrokerClusteringView, self).__init__(app, name)
 
+        self.cluster = cluster
+
         props = self.Properties(app, "props")
         self.add_child(props)
 
@@ -453,20 +408,17 @@
 
     class Properties(CuminProperties):
         def get_args(self, session):
-            return self.parent.parent.get_args(session)
+            return (self.parent.cluster.get(session),)
 
     class Stats(StatSet):
         def get_args(self, session):
-            return self.parent.parent.get_args(session)
+            return (self.parent.cluster.get(session),)
 
 class BrokerStats(Widget):
     def __init__(self, app, name):
         super(BrokerStats, self).__init__(app, name)
 
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, reg):
+    def render_title(self, session):
         return "Statistics"
 
 class BrokerBrowser(Widget):
@@ -477,49 +429,15 @@
         self.profile_tmpl = Template(self, "profile_html")
         self.cluster_tmpl = Template(self, "cluster_html")
 
-        self.group = BrokerGroupParameter(app, "group")
-        self.add_parameter(self.group)
-
-        self.profile = BrokerProfileParameter(app, "profile")
-        self.add_parameter(self.profile)
-
-        self.cluster = BrokerClusterParameter(app, "cluster")
-        self.add_parameter(self.cluster)
-
-        self.brokers = self.BrowserBrokers(app, "brokers")
+        self.brokers = NewBrokerSet(app, "brokers")
         self.add_child(self.brokers)
 
     def render_title(self, session, *args):
-        return "Brokers %s" % fmt_count(BrokerRegistration.select().count())
+        return "Brokers %s" % fmt_count(Broker.select().count())
 
-    class BrowserBrokers(BrokerSet):
-        def render_sql_where(self, session):
-            elems = list()
-            group = self.parent.group.get(session)
-            #profile = self.parent.profile.get(session)
-            #cluster = self.parent.cluster.get(session)
-
-            if group:
-                subquery = \
-                    "select 1 from broker_group_mapping " + \
-                    "where broker_group_id = %i "  % group.id + \
-                    "and broker_registration_id = br.id"
-
-                elems.append("exists (%s)" % subquery)
-
-            if elems:
-                return "where %s" % " and ".join(elems)
-
-    def render_add_broker_href(self, session):
-        branch = session.branch()
-        self.frame.brokers_add.show(branch)
-        return branch.marshal()
-
     def render_clear_filters_href(self, session):
         branch = session.branch()
-        self.group.set(branch, None)
-        self.profile.set(branch, None)
-        self.cluster.set(branch, None)
+        self.brokers.group.set(branch, None)
         return branch.marshal()
 
     def render_group_filters(self, session):
@@ -527,7 +445,7 @@
         return self._render_filters(session, groups, self.group_tmpl)
 
     def render_group_link(self, session, group):
-        return self._render_filter_link(session, group, self.group)
+        return self._render_filter_link(session, group, self.brokers.group)
 
     def render_profile_filters(self, session):
         profiles = BrokerProfile.select()
@@ -783,7 +701,7 @@
         if errors:
             pass
         else:
-            action = self.app.model.broker_registration.edit
+            action = self.app.model.management_server.edit
             args = {"name": self.broker_name.get(session)}
             action.invoke(reg, args)
 
@@ -805,16 +723,11 @@
         for group in reg.groups:
             self.groups.get(session).append(group)
 
-class BrokerSetRemove(CuminBulkActionForm, Frame):
-    def process_item(self, session, id):
-        action = self.app.model.broker_registration.remove
-        # XXX need to handle object not found case
-        action.invoke(BrokerRegistration.get(id))
+class BrokerSetEngroup(CuminSetActionForm):
+    def __init__(self, app, name):
+        param = BrokerParameter(app, "item")
 
-    def render_title(self, session):
-        return "Unregister Brokers"
+        super(BrokerSetEngroup, self).__init__ \
+            (app, name, app.model.broker.engroup_set, param)
 
-    def render_item_content(self, session, id):
-        return "Unregister Broker '%s'" % BrokerRegistration.get(id).name
-
 from brokergroup import BrokerGroupCheckboxField

Modified: mgmt/trunk/cumin/python/cumin/broker.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/broker.strings	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/broker.strings	2009-03-25 17:38:55 UTC (rev 3209)
@@ -44,6 +44,24 @@
   <div>{hidden_inputs}</div>
 </form>
 
+[NewBrokerSet.sql]
+select
+  b.id,
+  b.qmf_scope_id,
+  s.node_name || ':' || b.port as name,
+  c.cluster_name as cluster
+from broker as b
+left outer join system as s on b.system_id = s.id
+left outer join cluster as c on c.broker_id = b.id
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[NewBrokerSet.count_sql]
+select count(*)
+from broker as b
+{sql_where}
+
 [BrokerView.javascript]
 function updateBroker(data) {
     var model = data.objectify();
@@ -62,19 +80,6 @@
 }
 
 
-[BrokerView.html]
-<script type="text/javascript">
-//<![CDATA[
-{script}
-//]]>
-</script>
-
-{status}
-
-{summary}
-
-{body}
-
 [BrokerMissing.html]
 <div class="notice">
   The broker at this address is currently unavailable.  This page will
@@ -191,13 +196,7 @@
       <h2>Filter by Group</h2>
       <ul class="slist">{group_filters}</ul>
     </td>
-    <td class="view">
-      <ul class="actions">
-        <li><a class="nav" href="{add_broker_href}">Register New Brokers</a></li>
-      </ul>
-
-      {brokers}
-    </td>
+    <td class="view">{brokers}</td>
   </tr>
 </table>
 
@@ -221,76 +220,6 @@
   font-style: italic;
 }
 
-[BrokerSetForm.html]
-<form id="{id}" class="mform" method="post" action="?">
-  <div class="head">
-    <h1>{title}</h1>
-  </div>
-  <div class="body">
-    <fieldset>
-      <table class="BrokerSetForm">
-        <tr>
-          <th>Name</th>
-          <th>
-            Address
-            <br/>
-            <span class="example">Examples: example.net, example.net:5672, 172.16.82.10</span>
-          </th>
-          <th>Initial Group</th>
-        </tr>
-
-        {fields}
-      </table>
-
-      {more}
-    </fieldset>
-
-    {hidden_inputs}
-  </div>
-  <div class="foot">
-    {help}
-    {submit}
-    {cancel}
-  </div>
-</form>
-<script type="text/javascript" defer="defer">
-function click_more(id, value) {
-    click_button(id, value);
-	document.forms[0].submit(); 
-	return true;
-}
-(function() {
-    var elem = wooly.doc().elembyid("{id}").node.elements[1];
-    elem.focus();
-    elem.select();
-}())
-</script>
-
-[MoreEntries.html]
-<input type="hidden" name="{name}" value="" />
-<button class="more" type="button" tabindex="{tab_index}" {disabled_attr} onclick="return click_more('{name}', '{value}')">{content}</button>
-
-[BrokerSetForm.field_html]
-<tr>
-  <td>
-    <input type="text" name="{field_name_name}" value="{field_name_value}" size="15" tabindex="100"/>
-    {field_name_errors}
-  </td>
-  <td>
-    <input type="text" name="{field_address_name}" value="{field_address_value}" size="35" tabindex="100"/>
-    {field_address_errors}
-  </td>
-  <td>
-    <select name="{field_group_name}" tabindex="100">
-      <option value="__none__">None</option>
-      {groups}
-    </select>
-  </td>
-</tr>
-
-[BrokerSetForm.group_html]
-<option value="{group_value}" {group_selected_attr}>{group_name}</option>
-
 [BrokerGroupInputSet.item_html]
 <div class="field">
   <input type="checkbox" id="{id}" name="{name}" value="{item_value}" tabindex="{tab_index}" {item_checked_attr}/>

Modified: mgmt/trunk/cumin/python/cumin/brokergroup.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/brokergroup.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/brokergroup.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -3,7 +3,7 @@
 from wooly.widgets import *
 from wooly.forms import *
 
-from broker import BrokerSet
+from broker import NewBrokerSet
 from model import *
 from widgets import *
 from modelwidgets import *
@@ -63,7 +63,7 @@
         self.object = BrokerGroupParameter(app, "id")
         self.add_parameter(self.object)
 
-        self.view = BrokerGroupView(app, "view")
+        self.view = BrokerGroupView(app, "view", self.object)
         self.add_child(self.view)
         self.set_view_mode(self.view)
 
@@ -93,34 +93,23 @@
     pass
 
 class BrokerGroupView(CuminView):
-    def __init__(self, app, name):
+    def __init__(self, app, name, group):
         super(BrokerGroupView, self).__init__(app, name)
 
+        self.group = group
+
         status = BrokerGroupStatus(app, "status")
         self.add_child(status)
 
         self.__tabs = TabbedModeSet(app, "tabs")
         self.add_child(self.__tabs)
 
-        self.__tabs.add_tab(self.GroupBrokerTab(app, "brokers"))
+        brokers = NewBrokerSet(app, "brokers")
+        brokers.group = self.group
+        self.__tabs.add_tab(brokers)
+
         self.__tabs.add_tab(CuminDetails(app, "details"))
 
-    class GroupBrokerTab(BrokerSet):
-        def get_args(self, session):
-            return self.frame.get_args(session)
-
-        def render_title(self, session, group):
-            return "Brokers %s" % \
-                fmt_count(self.get_item_count(session, group))
-
-        def render_sql_where(self, session, group):
-            subquery = \
-                "select 1 from broker_group_mapping " + \
-                "where broker_group_id = %i " % group.id + \
-                "and broker_registration_id = br.id"
-
-            return "where exists (%s)" % subquery
-
 class BrokerGroupForm(CuminFieldForm):
     def __init__(self, app, name):
         super(BrokerGroupForm, self).__init__(app, name)

Modified: mgmt/trunk/cumin/python/cumin/brokerlink.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/brokerlink.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/brokerlink.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -12,9 +12,11 @@
 strings = StringCatalog(__file__)
 
 class PeerSet(CuminTable, Form):
-    def __init__(self, app, name):
+    def __init__(self, app, name, vhost):
         super(PeerSet, self).__init__(app, name)
 
+        self.vhost = vhost
+
         self.ids = FilteredCheckboxIdColumn(app, "id", self, callback=self.disable_closed)
         self.add_column(self.ids)
 
@@ -43,23 +45,22 @@
         self.__close = self.Close(app, "close")
         self.add_child(self.__close)
 
-    def render_add_broker_link_url(self, session, vhost):
+    def render_add_broker_link_url(self, session):
         branch = session.branch()
         self.frame.link_add.show(branch)
         return branch.marshal()
 
-    def get_args(self, session):
-        reg = self.frame.get_object(session)
-        return (reg.getDefaultVhost(),)
-
-    def render_title(self, session, vhost):
-        count = self.get_item_count(session, vhost)
+    def render_title(self, session):
+        count = self.get_item_count(session)
         return "Broker Links %s" % fmt_count(count)
 
-    def render_sql_where(self, session, vhost):
-        return "where v.id = %(vhost_id)r"
+    def get_sql_where_constraints(self, session):
+        constraints = super(PeerSet, self).get_sql_where_constraints(session)
+        constraints.append("v.id = %(vhost_id)r")
+        return constraints
 
-    def get_sql_values(self, session, vhost):
+    def get_sql_values(self, session):
+        vhost = self.vhost.get(session)
         return {"vhost_id": vhost.id}
 
     def disable_closed(self, session, data):
@@ -501,10 +502,12 @@
 
             self.process_cancel(session, link)
             
-class BrokerLinkAddForm(CuminFieldForm):
-    def __init__(self, app, name):
-        super(BrokerLinkAddForm, self).__init__(app, name)
+class BrokerLinkAdd(CuminFieldForm):
+    def __init__(self, app, name, vhost):
+        super(BrokerLinkAdd, self).__init__(app, name)
 
+        self.vhost = vhost
+
         self.host = self.Host(app, "host")
         self.add_field(self.host)
 
@@ -526,15 +529,16 @@
         self.transport = self.TransportField(app, "transport")
         self.more.add_field(self.transport)
                 
-    def render_title(self, session, *args):
-        reg = self.frame.get_object(session)
-        return "Add Broker Link to '%s'" % reg.name
+    def render_title(self, session):
+        vhost = self.vhost.get(session)
+        name = self.app.model.broker.get_object_name(vhost.broker)
+        return "Add Broker Link to '%s'" % name
 
     class ShowButton(MoreFieldSet):
-        def render_more_text(self, session, *args):
+        def render_more_text(self, session):
             return "Show Optional Inputs..."
         
-        def render_less_text(self, session, *args):
+        def render_less_text(self, session):
             return "Hide Optional Inputs..."
     
     class Host(NameField):
@@ -543,7 +547,7 @@
 
     class PortField(StringField):
         def __init__(self, app, name):
-            super(BrokerLinkAddForm.PortField, self).__init__(app, name)
+            super(BrokerLinkAdd.PortField, self).__init__(app, name)
             
             self.input.size = 5
             self.css_class = "compact first"
@@ -575,7 +579,7 @@
         
     class TransportField(RadioField):
         def __init__(self, app, name):
-            super(BrokerLinkAddForm.TransportField, self).__init__(app, name, None)
+            super(BrokerLinkAdd.TransportField, self).__init__(app, name, None)
     
             self.param = Parameter(app, "param")
             self.param.default = "tcp"
@@ -621,16 +625,12 @@
         def render_title_2(self, session):
             return "No, do not restore if broker restarts"
 
-class BrokerLinkAdd(BrokerLinkAddForm):
-    def get_args(self, session):
-        return (self.frame.get_object(session), )
-
-    def process_cancel(self, session, *args):
+    def process_cancel(self, session):
         branch = session.branch()
         self.frame.show_view(branch)
         self.page.set_redirect_url(session, branch.marshal())
 
-    def process_submit(self, session, reg):
+    def process_submit(self, session):
         if self.validate(session):
             pass
         else:
@@ -642,22 +642,21 @@
             password = self.password.get(session)
             durable = self.durable.get(session)
             transport = self.transport.get(session)
-            
-            link = Link()
-            link.host = host
-            link.port = port
-            link.durable = (durable == "yes")
 
-            args = {"reg": reg,
-                    "username": username,
-                    "password": password,
-                    "transport": transport}
-            
+            args = {
+                "host": host,
+                "port": port,
+                "durable": durable == "yes",
+                "username": username,
+                "password": password,
+                "transport": transport
+                }
+
             action = self.app.model.broker.add_link
-            action.invoke(link, args)
-            
+            action.invoke(self.vhost.get(session).broker, args)
+
             # navigate back to main queue frame
-            self.process_cancel(session, (reg,))
+            self.process_cancel(session)
 
 class BrokerSetClose(CuminBulkActionForm):
     def process_return(self, session):

Modified: mgmt/trunk/cumin/python/cumin/brokerprofile.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/brokerprofile.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/brokerprofile.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -1,171 +0,0 @@
-from mint import *
-from wooly import *
-from wooly.widgets import *
-
-from configproperty import *
-from broker import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-
-strings = StringCatalog(__file__)
-
-class BrokerProfileSet(object):
-    def render_profile_add_href(self, session, *args):
-        branch = session.branch()
-        self.page.show_broker_profile_add(branch)
-        return branch.marshal()
-
-    def render_title(self, session, *args):
-        return "Broker Profiles %s" % fmt_count(BrokerProfile.select().count())
-
-    def do_get_items(self, session, *args):
-        return BrokerProfile.select()
-
-    def render_item_link(self, session, profile):
-        branch = session.branch()
-        self.page.show_broker_profile(branch, profile).show_view(branch)
-        return fmt_olink(branch, profile)
-
-class BrokerProfileFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(BrokerProfileFrame, self).__init__(app, name)
-
-        self.object = BrokerProfileParameter(app, "id")
-        self.add_parameter(self.object)
-
-        view = BrokerProfileView(app, "view")
-        self.add_mode(view)
-        self.set_view_mode(view)
-
-        edit = BrokerProfileEdit(app, "edit")
-        self.add_mode(edit)
-        self.set_edit_mode(edit)
-
-        remove = BrokerProfileRemove(app, "remove")
-        self.add_mode(remove)
-        self.set_remove_mode(remove)
-        
-class BrokerProfileView(CuminView):
-    def __init__(self, app, name):
-        super(BrokerProfileView, self).__init__(app, name)
-
-        self.tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.tabs)
-        
-        self.tabs.add_tab(self.ProfileConfigTab(app, "config"))
-        self.tabs.add_tab(self.ProfileBrokerTab(app, "brokers"))
-
-    class ProfileConfigTab(ConfigPropertySet):
-        def get_args(self, session):
-            return self.frame.get_args(session)
-
-        def do_get_items(self, session, profile):
-            return sorted_by(profile.properties)
-        
-        def render_title(self, session, profile):
-            return "Configuration"
-
-    class ProfileBrokerTab(BrokerSet):
-        def __init__(self, app, name):
-            super(BrokerProfileView.ProfileBrokerTab, self).__init__(app, name)
-
-        def get_args(self, session):
-            return self.frame.get_args(session)
-
-        def render_title(self, session, profile):
-            return "Brokers %s" % fmt_count(len(profile.brokers))
-
-        def do_get_items(self, session, profile):
-            return profile.brokers
-
-        def render_item_config_href(self, session, broker):
-            branch = session.branch()
-            frame = self.page.show_broker(branch, broker)
-            frame.show_view(branch).show_config(branch)
-            return branch.marshal()
-
-        def render_item_config_status(self, session, broker):
-            return "0 differences" #XXX
-
-            diffs = 0
-
-            for prop in broker.profile.properties:
-                # XXX need to add assoc for this
-                for iprop in broker.config_property_items():
-                    if iprop.name == prop.name:
-                        if iprop.value != prop.value:
-                            diffs += 1
-                            
-            return "%i difference(s)" % diffs
-
-class BrokerProfileForm(CuminForm):
-    def __init__(self, app, name):
-        super(BrokerProfileForm, self).__init__(app, name)
-
-        self.profile_name = StringInput(app, "name")
-        self.add_child(self.profile_name)
-
-    def process_profile(self, session, profile):
-        profile.name = self.profile_name.get(session)
-
-        branch = session.branch()
-        self.page.show_broker_profile(branch, profile).show_view(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-
-class BrokerProfileAdd(BrokerProfileForm, Frame):
-    def render_title(self, session):
-        return "Add Profile"
-
-    def process_cancel(self, session):
-        branch = session.branch()
-        self.page.main.show(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-    
-    def process_submit(self, session):
-        profile = BrokerProfile()
-        self.process_profile(session, profile)
-    
-class BrokerProfileEdit(BrokerProfileForm, Frame):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def process_cancel(self, session, profile):
-        branch = session.branch()
-        self.parent.show_view(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_submit(self, session, profile):
-        self.process_profile(session, profile)
-
-    def process_display(self, session, profile):
-        self.profile_name.set(session, profile.name)
-
-    def render_title(self, session, profile):
-        return "Edit Profile '%s'" % profile.name
-
-class BrokerProfileRemove(CuminConfirmForm):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def process_cancel(self, session, profile):
-        branch = session.branch()
-        self.page.show_broker_profile(branch, profile).show_view(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_submit(self, session, profile):
-        profile.destroySelf()
-
-        branch = session.branch()
-        self.page.main.show(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def render_title(self, session, profile):
-        return "Remove Broker Profile '%s'" % profile.name
-
-    def render_submit_content(self, session, profile):
-        return "Yes, Remove Broker Profile '%s'" % profile.name
-
-    def render_cancel_content(self, session, profile):
-        return "No, Cancel"

Modified: mgmt/trunk/cumin/python/cumin/client.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/client.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/client.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -12,9 +12,11 @@
 strings = StringCatalog(__file__)
 
 class ConnectionSet(CuminTable, Form):
-    def __init__(self, app, name):
+    def __init__(self, app, name, vhost):
         super(ConnectionSet, self).__init__(app, name)
 
+        self.vhost = vhost
+
         self.ids = CheckboxIdColumn(app, "id")
         self.add_column(self.ids)
 
@@ -51,23 +53,24 @@
         self.__close = self.Close(app, "close")
         self.add_child(self.__close)
 
-    def get_args(self, session):
-        reg = self.frame.get_object(session)
-        return (reg.getDefaultVhost(),)
-
     def get_unit_plural(self, session):
         return self.unit.get(session) == "b" and "Bytes" or "Frames"
 
-    def render_title(self, session, vhost):
+    def render_title(self, session):
+        vhost = self.vhost.get(session)
         return "Connections %s" % fmt_count(vhost.clientConnections.count())
 
-    def render_sql_where(self, session, vhost):
-        elems = list()
-        elems.append("l.vhost_id = %(id)r")
-        elems.append(self.__phase.get_sql_constraint(session, vhost))
-        return "where %s" % " and ".join(elems)
+    def render_sql_where(self, session):
+        vhost = self.vhost.get(session)
 
-    def get_sql_values(self, session, vhost):
+        constraints = list()
+        constraints.append("l.vhost_id = %(id)r")
+        constraints.append(self.__phase.get_sql_constraint(session, vhost))
+
+        return "where %s" % " and ".join(constraints)
+
+    def get_sql_values(self, session):
+        vhost = self.vhost.get(session)
         return {"id": vhost.id}
 
     class Close(FormButton):
@@ -147,7 +150,7 @@
         self.add_mode(view)
         self.set_view_mode(view)
 
-        self.__close = ConnectionClose(app, "close")
+        self.__close = ConnectionClose(app, "close", self.object)
         self.add_mode(self.__close)
 
         self.__sessions_detach = SessionSetDetach(app, "sessionsdetach")
@@ -178,27 +181,31 @@
     #print "did it!"
 
 class ConnectionClose(CuminConfirmForm):
-    def get_args(self, session):
-        return self.frame.get_args(session)
+    def __init__(self, app, name, conn):
+        super(ConnectionClose, self).__init__(app, name)
 
-    def process_cancel(self, session, conn):
+        self.conn = conn
+
+    def process_cancel(self, session):
         branch = session.branch()
         self.frame.show_view(branch)
         self.page.set_redirect_url(session, branch.marshal())
 
-    def process_submit(self, session, conn):
+    def process_submit(self, session):
+        conn = self.conn.get(session)
+
         action = self.app.model.connection.close
         action.invoke(conn)
 
         self.process_cancel(session, conn)
 
-    def render_title(self, session, conn):
-        return "Close Connection '%s'" % conn.address
+    def render_title(self, session):
+        return "Close Connection '%s'" % self.conn.get(session).address
 
-    def render_submit_content(self, session, conn):
-        return "Yes, Close Connection '%s'" % conn.address
+    def render_submit_content(self, session):
+        return "Yes, Close Connection '%s'" % self.conn.get(session).address
 
-    def render_cancel_content(self, session, conn):
+    def render_cancel_content(self, session):
         return "No, Cancel"
 
 class ConnectionSetClose(CuminBulkActionForm):

Modified: mgmt/trunk/cumin/python/cumin/exchange.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/exchange.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/exchange.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -33,9 +33,11 @@
         return exchange is self.param.get(session) and "checked=\"checked\""
 
 class ExchangeSet(CuminTable, Form):
-    def __init__(self, app, name):
+    def __init__(self, app, name, vhost):
         super(ExchangeSet, self).__init__(app, name)
 
+        self.vhost = vhost
+
         self.ids = FilteredCheckboxIdColumn(app, "id", self, callback=self.disable_exchange)
         self.add_column(self.ids)
 
@@ -72,28 +74,29 @@
         self.__remove = self.Remove(app, "remove")
         self.add_child(self.__remove)
 
-    def get_args(self, session):
-        reg = self.frame.get_object(session)
-        return (reg.getDefaultVhost(),)
-    
     def disable_exchange(self, session, data):
         return data["name"] in ExchangeInfo.get_builtins()
         
-    def render_add_exchange_url(self, session, vhost):
+    def render_add_exchange_url(self, session):
         branch = session.branch()
         self.frame.exchange_add.show(branch)
         return branch.marshal()
 
-    def render_title(self, session, vhost):
+    def render_title(self, session):
+        vhost = self.vhost.get(session)
         return "Exchanges %s" % fmt_count(vhost.exchanges.count())
     
-    def render_sql_where(self, session, vhost):
+    def render_sql_where(self, session):
+        vhost = self.vhost.get(session)
+
         elems = list()
         elems.append("e.vhost_id = %(id)r")
         elems.append(self.phase.get_sql_constraint(session, vhost))
+
         return "where %s" % " and ".join(elems)
 
-    def get_sql_values(self, session, vhost):
+    def get_sql_values(self, session):
+        vhost = self.vhost.get(session)
         return {"id": vhost.id}
 
     class Remove(FormButton):
@@ -175,7 +178,7 @@
         exchange = Exchange.get(id)
         reg = self.frame.get_object(session)
         action = self.app.model.exchange.remove
-        action.invoke(exchange, reg)
+        action.invoke(exchange)
  
     def render_title(self, session):
         return "Remove Exchanges"
@@ -227,7 +230,7 @@
     def process_submit(self, session, exchange):
         reg = self.frame.frame.get_object(session)
         action = self.app.model.exchange.remove
-        action.invoke(exchange, reg)
+        action.invoke(exchange)
 
         branch = session.branch()
         self.frame.frame.show_view(branch)
@@ -337,9 +340,13 @@
         return "Exchange: %s <i>and</i> Queue: %s" % (ename, qname)
 
 class ExchangeForm(CuminFieldForm):
-    def __init__(self, app, name):
+    def __init__(self, app, name, vhost):
         super(ExchangeForm, self).__init__(app, name)
 
+        assert vhost
+
+        self.vhost = vhost
+
         self.exchange_name = ExchangeNameField(app, "exchange_name")
         self.add_field(self.exchange_name)
  
@@ -462,38 +469,39 @@
                 return "<em>XML:</em> Route message to queues based on XML content of the message"
     
 class ExchangeAdd(ExchangeForm):
-    def get_args(self, session):
-        return (self.frame.get_object(session), )
-
-    def process_cancel(self, session, *args):
+    def process_cancel(self, session):
         branch = session.branch()
         self.frame.show_view(branch)
         self.page.set_redirect_url(session, branch.marshal())
 
-    def process_submit(self, session, *args):
+    def process_submit(self, session):
         errors = self.validate(session)
 
         if errors:
             pass
         else:
-            reg = self.frame.get_object(session)
+            reg = self.vhost.get(session).broker.registration
+
             exchange = Exchange()
             exchange.name = self.exchange_name.get(session)
             exchange.type = self.exchange_type.get(session)
-            exchange.durable = self.durable.get(session) == "yes" 
+            exchange.durable = self.durable.get(session) == "yes"
+
             args = {}
             args["reg"] = reg
             args["sequence"] = self.sequence.get(session) == "yes"
             args["ive"] = self.ive.get(session) == "yes"
-            
+
             action = self.app.model.broker.add_exchange
             action.invoke(exchange, args)
 
             self.process_cancel(session)
-            
-    def render_title(self, session, reg):
-        return "Add Exchange to the Broker '%s'" % reg.name
-        
+
+    def render_title(self, session):
+        broker = self.vhost.get(session).broker
+        title = self.app.model.broker.get_object_title(session, broker)
+        return "Add Exchange to %s" % title
+
 class ExchangeStats(TabbedModeSet):
     def __init__(self, app, name):
         super(ExchangeStats, self).__init__(app, name)

Added: mgmt/trunk/cumin/python/cumin/managementserver.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/managementserver.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/managementserver.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -0,0 +1,466 @@
+from mint import *
+from wooly import *
+from wooly.widgets import *
+
+from widgets import *
+from modelwidgets import *
+from parameters import *
+from formats import *
+from util import *
+
+strings = StringCatalog(__file__)
+
+class ManagementServerSet(CuminClassTable):
+    def __init__(self, app, name):
+        cls = app.model.management_server
+
+        super(ManagementServerSet, self).__init__(app, name, cls)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+
+        col = self.UrlColumn(app, "url")
+        self.add_column(col)
+
+        col = self.StatusColumn(app, "status")
+        self.add_column(col)
+
+    class NameColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+    class UrlColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "URL"
+
+    class StatusColumn(ItemTableColumn):
+        def render_title(self, session, data):
+            return "Status"
+
+        def render_content(self, session, data):
+            url = data["url"]
+
+            try:
+                server = self.app.model.data.mintBrokersByUrl[url]
+
+                if server.connected:
+                    html = "Connected"
+                else:
+                    html = "Disconnected"
+            except KeyError:
+                html = "Unreachable"
+
+            return html
+
+class ManagementServerSetAdd(CuminForm, Frame):
+    def __init__(self, app, name):
+        super(ManagementServerSetAdd, self).__init__(app, name)
+
+        self.name_param = Parameter(app, "name_param");
+        self.add_parameter(self.name_param)
+
+        self.names = ListParameter(app, "name", self.name_param)
+        self.add_parameter(self.names)
+
+        self.name_errors = self.Errors(self, "name_errors")
+        self.add_attribute(self.name_errors)
+
+        self.addr_param = Parameter(app, "addr_param")
+        self.add_parameter(self.addr_param)
+
+        self.addrs = ListParameter(app, "address", self.addr_param)
+        self.add_parameter(self.addrs)
+
+        self.addr_errors = self.Errors(self, "addr_errors")
+        self.add_attribute(self.addr_errors)
+
+        self.fields = IntegerParameter(app, "fields")
+        self.fields.default = 3
+        self.add_parameter(self.fields)
+
+        self.field_tmpl = Template(self, "field_html")
+
+        self.more_button = self.MoreEntries(app, "more_button")
+        self.add_child(self.more_button)
+
+        self.more = self.More(app, "more")
+        self.add_parameter(self.more)
+
+    def process_cancel(self, session):
+        branch = session.branch()
+        self.page.pop_current_frame(branch)
+        self.page.get_current_frame(branch).show_view(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_submit(self, session):
+        action = self.app.model.management_server.add
+
+        addrs = self.addrs.get(session)
+        names = self.names.get(session)
+        fields = self.fields.get(session)
+
+        if self.validate(session, addrs, names):
+            for i in range(0, fields):
+                try:
+                    addr = addrs[i]
+                except:
+                    addr = None
+
+                if addr:
+                    name = names[i]
+                    url = "amqp://%s:%i" % parse_broker_addr(addr)
+
+                    args = {"name": name, "url": url}
+                    reg = action.invoke(None, args)
+
+            self.process_cancel(session)
+
+    def validate(self, session, addrs, names):
+        nerrs = self.name_errors.get(session)
+        aerrs = self.addr_errors.get(session)
+        fields = self.fields.get(session)
+
+        for i in range(0, fields):
+            try:
+                addr, name = addrs[i], names[i]
+            except:
+                addr = name = None
+
+            if not addr and not name:
+                pass # It's just an empty row
+            else:
+                if not name:
+                    errs = nerrs.setdefault(i, list())
+                    errs.append("The name field is empty; it is required")
+                elif BrokerRegistration.selectBy(name=name).count():
+                    errs = nerrs.setdefault(i, list())
+                    errs.append("A broker called '%s' already exists" % name)
+
+                if not addr:
+                    errs = aerrs.setdefault(i, list())
+                    errs.append("The address field is empty; it is required")
+                else:
+                    try:
+                        parse_broker_addr(addr)
+                    except:
+                        errs = aerrs.setdefault(i, list())
+                        errs.append("The address is malformed")
+                        break
+
+                    count = BrokerRegistration.selectBy \
+                        (url=addr).count()
+
+                    if count:
+                        errs = aerrs.setdefault(i, list())
+                        errs.append("The broker at %s " % (url) +
+                                    "is already registered")
+
+        return not len(nerrs) and not len(aerrs)
+
+    def render_title(self, session):
+        return "Register New Brokers"
+
+    class Errors(Attribute):
+        def get_default(self, session):
+            return dict()
+
+    class More(Parameter):
+        def get_default(self, session):
+            return ""
+
+    def process_display(self, session):
+        if self.more.get(session):
+            self.fields.set(session, self.fields.get(session) + 3)
+
+    def render_fields(self, session):
+        writer = Writer()
+
+        for i in range(self.fields.get(session)):
+            self.field_tmpl.render(writer, session, i)
+
+        return writer.to_string()
+
+    def render_field_name_name(self, session, index):
+        return self.names.path
+
+    def render_field_name_value(self, session, index):
+        names = self.names.get(session)
+        if len(names) > index:
+            return names[index]
+
+    def render_field_name_errors(self, session, index):
+        errors = self.name_errors.get(session)
+        if index in errors:
+            return "<ul class=\"errors\"><li>%s</li></ul>" % \
+                "</li><li>".join(errors[index])
+
+    def render_field_address_name(self, session, index):
+        return self.addrs.path
+
+    def render_field_address_value(self, session, index):
+        addrs = self.addrs.get(session)
+        if len(addrs) > index:
+            return addrs[index]
+
+    def render_field_address_errors(self, session, index):
+        errors = self.addr_errors.get(session)
+        if index in errors:
+            return "<ul class=\"errors\"><li>%s</li></ul>" % \
+                "</li><li>".join(errors[index])
+
+    def render_more_id(self, session):
+        return self.more_button.path
+
+    def render_more_name(self, session):
+        return self.more.path
+
+    class MoreEntries(FormButton):
+        def render_content(self, session):
+            return "More Entries"
+
+        def render_class(self, session):
+            return "more"
+
+        def render_type(self, session):
+            return "button"
+
+class ManagementServerSetRemove(CuminSetActionForm, Frame):
+    def __init__(self, app, name):
+        action = app.model.management_server.remove_set
+        object = BrokerRegistrationParameter(app, "item")
+
+        super(ManagementServerSetRemove, self).__init__ \
+            (app, name, action, object)
+from mint import *
+from wooly import *
+from wooly.widgets import *
+
+from widgets import *
+from modelwidgets import *
+from parameters import *
+from formats import *
+from util import *
+
+strings = StringCatalog(__file__)
+
+class ManagementServerSet(CuminClassTable):
+    def __init__(self, app, name):
+        cls = app.model.management_server
+
+        super(ManagementServerSet, self).__init__(app, name, cls)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+
+        col = self.UrlColumn(app, "url")
+        self.add_column(col)
+
+        col = self.StatusColumn(app, "status")
+        self.add_column(col)
+
+    class NameColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+    class UrlColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "URL"
+
+    class StatusColumn(ItemTableColumn):
+        def render_title(self, session, data):
+            return "Status"
+
+        def render_content(self, session, data):
+            url = data["url"]
+
+            try:
+                server = self.app.model.data.mintBrokersByUrl[url]
+
+                if server.connected:
+                    html = "Connected"
+                else:
+                    html = "Disconnected"
+            except KeyError:
+                html = "Unreachable"
+
+            return html
+
+class ManagementServerSetAdd(CuminForm, Frame):
+    def __init__(self, app, name):
+        super(ManagementServerSetAdd, self).__init__(app, name)
+
+        self.name_param = Parameter(app, "name_param");
+        self.add_parameter(self.name_param)
+
+        self.names = ListParameter(app, "name", self.name_param)
+        self.add_parameter(self.names)
+
+        self.name_errors = self.Errors(self, "name_errors")
+        self.add_attribute(self.name_errors)
+
+        self.addr_param = Parameter(app, "addr_param")
+        self.add_parameter(self.addr_param)
+
+        self.addrs = ListParameter(app, "address", self.addr_param)
+        self.add_parameter(self.addrs)
+
+        self.addr_errors = self.Errors(self, "addr_errors")
+        self.add_attribute(self.addr_errors)
+
+        self.fields = IntegerParameter(app, "fields")
+        self.fields.default = 3
+        self.add_parameter(self.fields)
+
+        self.field_tmpl = Template(self, "field_html")
+
+        self.more_button = self.MoreEntries(app, "more_button")
+        self.add_child(self.more_button)
+
+        self.more = self.More(app, "more")
+        self.add_parameter(self.more)
+
+    def process_cancel(self, session):
+        branch = session.branch()
+        self.page.pop_frame(branch)
+        self.page.get_frame(branch).show_view(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_submit(self, session):
+        action = self.app.model.management_server.add
+
+        addrs = self.addrs.get(session)
+        names = self.names.get(session)
+        fields = self.fields.get(session)
+
+        if self.validate(session, addrs, names):
+            for i in range(0, fields):
+                try:
+                    addr = addrs[i]
+                except:
+                    addr = None
+
+                if addr:
+                    name = names[i]
+                    url = "amqp://%s:%i" % parse_broker_addr(addr)
+
+                    args = {"name": name, "url": url}
+                    reg = action.invoke(None, args)
+
+            self.process_cancel(session)
+
+    def validate(self, session, addrs, names):
+        nerrs = self.name_errors.get(session)
+        aerrs = self.addr_errors.get(session)
+        fields = self.fields.get(session)
+
+        for i in range(0, fields):
+            try:
+                addr, name = addrs[i], names[i]
+            except:
+                addr = name = None
+
+            if not addr and not name:
+                pass # It's just an empty row
+            else:
+                if not name:
+                    errs = nerrs.setdefault(i, list())
+                    errs.append("The name field is empty; it is required")
+                elif BrokerRegistration.selectBy(name=name).count():
+                    errs = nerrs.setdefault(i, list())
+                    errs.append("A broker called '%s' already exists" % name)
+
+                if not addr:
+                    errs = aerrs.setdefault(i, list())
+                    errs.append("The address field is empty; it is required")
+                else:
+                    try:
+                        parse_broker_addr(addr)
+                    except:
+                        errs = aerrs.setdefault(i, list())
+                        errs.append("The address is malformed")
+                        break
+
+                    count = BrokerRegistration.selectBy \
+                        (url=addr).count()
+
+                    if count:
+                        errs = aerrs.setdefault(i, list())
+                        errs.append("The broker at %s " % (url) +
+                                    "is already registered")
+
+        return not len(nerrs) and not len(aerrs)
+
+    def render_title(self, session):
+        return "Register New Brokers"
+
+    class Errors(Attribute):
+        def get_default(self, session):
+            return dict()
+
+    class More(Parameter):
+        def get_default(self, session):
+            return ""
+
+    def process_display(self, session):
+        if self.more.get(session):
+            self.fields.set(session, self.fields.get(session) + 3)
+
+    def render_fields(self, session):
+        writer = Writer()
+
+        for i in range(self.fields.get(session)):
+            self.field_tmpl.render(writer, session, i)
+
+        return writer.to_string()
+
+    def render_field_name_name(self, session, index):
+        return self.names.path
+
+    def render_field_name_value(self, session, index):
+        names = self.names.get(session)
+        if len(names) > index:
+            return names[index]
+
+    def render_field_name_errors(self, session, index):
+        errors = self.name_errors.get(session)
+        if index in errors:
+            return "<ul class=\"errors\"><li>%s</li></ul>" % \
+                "</li><li>".join(errors[index])
+
+    def render_field_address_name(self, session, index):
+        return self.addrs.path
+
+    def render_field_address_value(self, session, index):
+        addrs = self.addrs.get(session)
+        if len(addrs) > index:
+            return addrs[index]
+
+    def render_field_address_errors(self, session, index):
+        errors = self.addr_errors.get(session)
+        if index in errors:
+            return "<ul class=\"errors\"><li>%s</li></ul>" % \
+                "</li><li>".join(errors[index])
+
+    def render_more_id(self, session):
+        return self.more_button.path
+
+    def render_more_name(self, session):
+        return self.more.path
+
+    class MoreEntries(FormButton):
+        def render_content(self, session):
+            return "More Entries"
+
+        def render_class(self, session):
+            return "more"
+
+        def render_type(self, session):
+            return "button"
+
+class ManagementServerSetRemove(CuminSetActionForm, Frame):
+    def __init__(self, app, name):
+        action = app.model.management_server.remove_set
+        object = BrokerRegistrationParameter(app, "item")
+
+        super(ManagementServerSetRemove, self).__init__ \
+            (app, name, action, object)

Added: mgmt/trunk/cumin/python/cumin/managementserver.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/managementserver.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/managementserver.strings	2009-03-25 17:38:55 UTC (rev 3209)
@@ -0,0 +1,178 @@
+[ManagementServerSet.sql]
+select br.id, br.name, br.url
+from broker_registration as br
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[ManagementServerSet.count_sql]
+select count(*)
+from broker_registration as br
+{sql_where}
+
+[ManagementServerSetAdd.css]
+table.ManagementServerSetAdd td, table.ManagementServerSetAdd th {
+  padding: 0.25em;
+}
+
+table.ManagementServerSetAdd span.example {
+  font-weight: normal;
+  font-size: 0.8em;
+  font-style: italic;
+}
+
+[ManagementServerSetAdd.html]
+<form id="{id}" class="mform" method="post" action="?">
+  <div class="head">
+    <h1>{title}</h1>
+  </div>
+  <div class="body">
+    <fieldset>
+      <table class="ManagementServerSetAdd">
+        <tr>
+          <th>Name</th>
+          <th>
+            Address
+            <br/>
+            <span class="example">Examples: example.net, example.net:5672, 172.16.82.10</span>
+          </th>
+        </tr>
+
+        {fields}
+      </table>
+
+      {more_button}<input type="hidden" name="{more_name}" value="" />
+    </fieldset>
+
+    {hidden_inputs}
+  </div>
+  <div class="foot">
+    {help}
+    {submit}
+    {cancel}
+  </div>
+</form>
+<script type="text/javascript" defer="defer">
+<![CDATA[
+(function() {
+    var elem = wooly.doc().elembyid("{id}").node.elements[1];
+    elem.focus();
+    elem.select();
+
+    function attach_more_id() {
+        var oMore = document.getElementById("{more_id}");
+        if (oMore) {
+            oMore.onclick = function() {
+                document.forms[0].elements["{more_name}"].value = "t";
+                document.forms[0].submit();
+            }
+        }
+    }
+
+    addEvent(window, "load", attach_more_id);
+}())
+]]>
+</script>
+
+[ManagementServerSetAdd.field_html]
+<tr>
+  <td>
+    <input type="text" name="{field_name_name}" value="{field_name_value}"
+           size="15" tabindex="100"/>
+    {field_name_errors}
+  </td>
+  <td>
+    <input type="text" name="{field_address_name}" value="{field_address_value}"
+           size="35" tabindex="100"/>
+    {field_address_errors}
+  </td>
+</tr>
+[ManagementServerSet.sql]
+select br.id, br.name, br.url
+from broker_registration as br
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[ManagementServerSet.count_sql]
+select count(*)
+from broker_registration as br
+{sql_where}
+
+[ManagementServerSetAdd.css]
+table.ManagementServerSetAdd td, table.ManagementServerSetAdd th {
+  padding: 0.25em;
+}
+
+table.ManagementServerSetAdd span.example {
+  font-weight: normal;
+  font-size: 0.8em;
+  font-style: italic;
+}
+
+[ManagementServerSetAdd.html]
+<form id="{id}" class="mform" method="post" action="?">
+  <div class="head">
+    <h1>{title}</h1>
+  </div>
+  <div class="body">
+    <fieldset>
+      <table class="ManagementServerSetAdd">
+        <tr>
+          <th>Name</th>
+          <th>
+            Address
+            <br/>
+            <span class="example">Examples: example.net, example.net:5672, 172.16.82.10</span>
+          </th>
+        </tr>
+
+        {fields}
+      </table>
+
+      {more_button}<input type="hidden" name="{more_name}" value="" />
+    </fieldset>
+
+    {hidden_inputs}
+  </div>
+  <div class="foot">
+    {help}
+    {submit}
+    {cancel}
+  </div>
+</form>
+<script type="text/javascript" defer="defer">
+<![CDATA[
+(function() {
+    var elem = wooly.doc().elembyid("{id}").node.elements[1];
+    elem.focus();
+    elem.select();
+
+    function attach_more_id() {
+        var oMore = document.getElementById("{more_id}");
+        if (oMore) {
+            oMore.onclick = function() {
+                document.forms[0].elements["{more_name}"].value = "t";
+                document.forms[0].submit();
+            }
+        }
+    }
+
+    addEvent(window, "load", attach_more_id);
+}())
+]]>
+</script>
+
+[ManagementServerSetAdd.field_html]
+<tr>
+  <td>
+    <input type="text" name="{field_name_name}" value="{field_name_value}"
+           size="15" tabindex="100"/>
+    {field_name_errors}
+  </td>
+  <td>
+    <input type="text" name="{field_address_name}" value="{field_address_value}"
+           size="35" tabindex="100"/>
+    {field_address_errors}
+  </td>
+</tr>

Modified: mgmt/trunk/cumin/python/cumin/model.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/model.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/model.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -49,7 +49,7 @@
         CuminBrokerAclModule(self)
         CuminBrokerClusterModule(self)
 
-        CuminBrokerRegistration(self)
+        CuminManagementServer(self)
         CuminBrokerGroup(self)
 
         # Grid
@@ -247,9 +247,39 @@
     
     def get_verb(self, session):
         return None
-    
+
+    def get_description(self, session, object):
+        verb  = self.get_verb(session)
+
+        if not verb:
+            verb = self.get_title(session)
+
+        cls = self.cumin_class
+
+        if cls and object:
+            obj = None
+
+            if type(object) is list:
+                if len(object) == 1:
+                    obj = object[0]
+            else:
+                obj = object
+
+            if obj is None:
+                sobject = "%i %s" % \
+                    (len(object), cls.get_plural_title(session))
+            else:
+                sobject = cls.get_object_title(session, obj)
+        elif cls:
+            sobject = cls.get_title(session)
+        else:
+            # XXX lame
+            sobject = str(object)
+
+        return "%s %s" % (verb, sobject)
+
     def invoke(self, object, args={}):
-        invoc = CuminActionInvocation(self, object)
+        invoc = self.begin(object)
 
         def completion(status, args=None):
             invoc.status = status
@@ -257,28 +287,30 @@
             #invoc.prt()
 
         try:
-            try:
-                return self.do_invoke(object, args, completion)
-            except Exception, e:
-                invoc.status = "failed"
-                invoc.exception = e
+            return self.do_invoke(object, args, completion)
+        except Exception, e:
+            invoc.status = "failed"
+            invoc.exception = e
 
-                log.exception(e)
-        finally:
-            self.model.invocations.add(invoc)
+            log.exception(e)
 
         #invoc.prt()
 
         return invoc
 
     def do_invoke(self, object, args, completion):
-        pass
+        raise Exception("Not implemented")
 
-    def get_session_by_registration(self, reg):
-        assert reg.broker
-        assert reg.broker.qmfBrokerId in self.model.data.mintBrokersById
+    def begin(self, object):
+        invoc = CuminActionInvocation(self, object)
+        self.model.invocations.add(invoc)
+        return invoc
 
-        broker = self.model.data.mintBrokersById[reg.broker.qmfBrokerId]
+    def get_session_by_object(self, object):
+        assert object
+
+        broker = self.model.data.mintBrokersById[object.qmfBrokerId]
+
         return broker.getAmqpSession()
 
 class CuminActionInvocation(object):
@@ -291,24 +323,8 @@
         self.exception = None
 
     def get_description(self, session):
-        verb = self.action.get_verb(session)
+        return self.action.get_description(session, self.object)
 
-        if not verb:
-            verb = self.action.get_title(session)
-
-        if self.object:
-            if type(self.object) is list:
-                count = len(self.object)
-                name = self.action.cumin_class.get_title(session)
-                sobject = "%i %s%s" % (count, name, ess(count))
-            else:
-                cls = self.action.model.get_class_by_object(self.object)
-                sobject = cls.get_object_title(session, self.object)
-        else:
-            sobject = self.action.cumin_class.get_title(session)
-
-        return "%s %s" % (verb, sobject)
-
     def prt(self):
         print "action", self.action.name, self.object, self.when, \
             self.status, self.args, self.exception
@@ -762,6 +778,7 @@
 
         prop = CuminProperty(self, "version")
         prop.title = "Version"
+        prop.summary = True
 
         prop = CuminProperty(self, "dataDir")
         prop.title = "Data Directory"
@@ -769,6 +786,8 @@
         stat = self.StatusStat(self, "connection")
         stat.category = "status"
 
+        action = self.EngroupSet(self, "engroup_set")
+
         action = self.AddExchange(self, "add_exchange")
         action.summary = True
 
@@ -784,12 +803,16 @@
     def get_icon_href(self, session):
         return "resource?name=broker-36.png"
 
-    def show_object(self, session, broker):
-        reg = broker.registration
-        return super(CuminBroker, self).show_object(session, reg)
+    def get_title(self, session):
+        return "Broker"
 
+#    def show_object(self, session, broker):
+#        reg = broker.registration
+#        return super(CuminBroker, self).show_object(session, reg)
+
     def get_object_name(self, broker):
-        return broker.id
+        host, port = broker.system.nodeName, broker.port
+        return "%s:%i" % (host, port)
 
     class StatusStat(CuminStat):
         def value_text(self, broker):
@@ -809,6 +832,15 @@
         def rate_text(self, record):
             return ""
 
+    class EngroupSet(CuminSetAction):
+        def show(self, session, brokers):
+            frame = self.model.frame.brokers_group
+            frame.objects.set(session, brokers)
+            return frame.show(session)
+
+        def get_title(self, session):
+            return "Add to Group"
+
     class AddExchange(CuminAction):
         MSG_SEQUENCE = "qpid.msg_sequence"
         IVE = "qpid.ive"
@@ -825,21 +857,22 @@
             return frame.exchange_add.show(session)
         
         def do_invoke(self, exchange, args, completion):
-
-            reg = args["reg"]
             declArgs = {}
+
             if args["sequence"]:
                 declArgs[self.MSG_SEQUENCE] = 1
             if args["ive"]:
                 declArgs[self.IVE] = 1
-            
-            session = self.get_session_by_registration(reg)
-            session.exchange_declare(exchange=exchange.name, 
-                                     type=exchange.type, 
-                                     durable=exchange.durable, 
+
+            session = self.get_session_by_object(exchange)
+            session.exchange_declare(exchange=exchange.name,
+                                     type=exchange.type,
+                                     durable=exchange.durable,
                                      arguments=declArgs)
+
             # if the above call fails, an exception is
             # raised and we won't get here
+
             completion("OK")
 
     class AddLink(CuminAction):
@@ -853,85 +886,49 @@
             frame = self.cumin_class.show_object(session, reg)
             frame.set_object(session, reg)
             return frame.link_add.show(session)
-        
-        def do_invoke(self, link, args, completion):
-            reg = args["reg"]
+
+        def do_invoke(self, broker, args, completion):
+            host = args["host"]
+            port = args["port"]
+            durable = args["durable"]
             username = args["username"]
             password = args["password"]
             transport = args["transport"]
+
             if username == "anonymous":
                 authMechanism = "ANONYMOUS"
             else:
                 authMechanism = "PLAIN"
 
-            broker = reg._get_broker()
-            broker.connect(self.model.data, completion, 
-                        link.host, link.port, link.durable,
-                        authMechanism, username, password, transport)
-            
-    class AddQueue(CuminAction):
-        FILECOUNT = "qpid.file_count"
-        FILESIZE  = "qpid.file_size"
-        MAX_QUEUE_SIZE  = "qpid.max_size"
-        MAX_QUEUE_COUNT  = "qpid.max_count"
-        POLICY_TYPE  = "qpid.policy_type"
-        CLUSTER_DURABLE = "qpid.persist_last_node"
-        LVQ = "qpid.last_value_queue"
-        OPTIMISTIC_CONSUME = "qpid.optimistic_consume"
+            broker.connect(self.model.data, completion, host, port, durable,
+                           authMechanism, username, password, transport)
 
+    class AddQueue(CuminAction):
         def get_title(self, session):
             return "Add Queue"
-        
+
         def get_verb(self, session):
             return "Add"
-        
+
+        def get_description(self, session, vhost):
+            host = vhost.broker.system.nodeName
+            port = vhost.broker.port
+            return "Add Queue to %s:%i" % (host, port)
+
         def show(self, session, reg):
             frame = self.cumin_class.show_object(session, reg)
             frame.set_object(session, reg)
             return frame.queue_add.show(session)
-        
-        def do_invoke(self, queue, args, completion):
 
-            reg = args["reg"]
-            declArgs = {}
-            if queue.durable:
-                if args["file_count"]:
-                    declArgs[self.FILECOUNT] = args["file_count"]
-                if args["file_size"]:
-                    declArgs[self.FILESIZE] = args["file_size"]
-
-            if args["policy"]:
-                declArgs[self.POLICY_TYPE] = args["policy"]
-                if args["q_size"]:
-                    declArgs[self.MAX_QUEUE_SIZE] = args["q_size"]
-                if args["q_count"]:
-                    declArgs[self.MAX_QUEUE_COUNT] = args["q_count"]
-
-            if args["cluster_durable"]:
-                declArgs[self.CLUSTER_DURABLE] = 1
-            if args["lvq"]:
-                declArgs[self.LVQ] = 1
-            if args["optimistic"]:
-                declArgs[self.OPTIMISTIC_CONSUME] = 1
-                
-            session = self.get_session_by_registration(reg)
-            session.queue_declare(queue=queue.name, 
-                        durable=queue.durable, 
-                        arguments=declArgs)
-
-            # optionally bind to exchanges
-            binding_info = args['exchange_keys']
-            do_bind(session, queue, binding_info)
-            completion("OK")
-
-def do_bind(session, queue, binding_info):
+# XXX "do_" on this doesn't make sense
+def do_bind(session, queue_name, binding_info):
         for exchange in binding_info:
             if "key" in binding_info[exchange]:
                 binding_key = binding_info[exchange]["key"] 
             else:
                 binding_key = None
 
-            session.exchange_bind(queue=queue.name,
+            session.exchange_bind(queue=queue_name,
                 exchange=binding_info[exchange]["name"],
                 binding_key=binding_key,
                 arguments=binding_info[exchange]["arguments"])
@@ -939,7 +936,7 @@
 class CuminQueue(RemoteClass):
     def __init__(self, model):
         super(CuminQueue, self).__init__(model, "queue", Queue, QueueStats)
-        
+
         prop = CuminProperty(self, "name")
         prop.title = "Name"
 
@@ -1149,10 +1146,9 @@
             return "Remove"
 
         def do_invoke(self, queue, args, completion):
-            reg = queue.vhost.broker.registration
-            session = self.get_session_by_registration(reg)
+            session = self.get_session_by_object(queue)
             session.queue_delete(queue=queue.name)
-                
+
             completion("OK")
 
     class Bind(CuminAction):
@@ -1165,10 +1161,9 @@
             return "Bind"
 
         def do_invoke(self, queue, args, completion):
-            reg = queue.vhost.broker.registration
-            session = self.get_session_by_registration(reg)
+            session = self.get_session_by_object(queue)
             binding_info = args['exchange_keys']
-            do_bind(session, queue, binding_info)
+            do_bind(session, queue.name, binding_info)
 
             completion("OK")
 
@@ -1273,8 +1268,8 @@
             frame = self.cumin_class.show_object(session, exchange)
             return frame.remove.show(session)
         
-        def do_invoke(self, exchange, reg, completion):
-            session = self.get_session_by_registration(reg)
+        def do_invoke(self, exchange, args, completion):
+            session = self.get_session_by_object(exchange)
             session.exchange_delete(exchange=exchange.name)
             
             completion("OK")
@@ -1312,12 +1307,11 @@
             return frame.remove.show(session)
         
         def do_invoke(self, binding, args, completion):
-            reg = binding.exchange.vhost.broker.registration
-            session = self.get_session_by_registration(reg)
-            session.exchange_unbind(queue=binding.queue.name, 
-                                    exchange=binding.exchange.name, 
+            session = self.get_session_by_object(binding)
+            session.exchange_unbind(queue=binding.queue.name,
+                                    exchange=binding.exchange.name,
                                     binding_key=binding.bindingKey)
- 
+
             completion("OK")
 
 
@@ -1730,40 +1724,38 @@
         prop = CuminProperty(self, "members")
         prop.title = "Members"
 
-class CuminBrokerRegistration(CuminClass):
+class CuminManagementServer(CuminClass):
     def __init__(self, model):
-        super(CuminBrokerRegistration, self).__init__ \
-            (model, "broker_registration", BrokerRegistration)
+        super(CuminManagementServer, self).__init__ \
+            (model, "management_server", BrokerRegistration)
 
         prop = CuminProperty(self, "url")
         prop.title = "URL"
         prop.summary = True
 
-        action = self.Add(self, "add")
-        action.title = "Add"
+        action = self.AddSet(self, "add")
         action.navigable = False
 
-        action = self.Edit(self, "edit")
-        action.title = "Edit"
-        action.summary = True
+        action = self.RemoveSet(self, "remove_set")
 
-        action = self.Remove(self, "remove")
-        action.title = "Unregister"
-        action.summary = True
-
     def init(self):
         self.frame = self.model.frame.broker
 
     def get_title(self, session):
-        return "Broker"
+        return "Management Server"
 
     def get_icon_href(self, session):
         return "resource?name=broker-36.png"
 
-    class Add(CuminAction):
-        def do_invoke(self, object, args, completion):
-            assert object is None
+    class AddSet(CuminAction):
+        def get_title(self, session):
+            return "Add Management Servers"
 
+        def show(self, session, object):
+            frame = self.model.frame.mservers_add
+            frame.show(session)
+
+        def do_invoke(self, object, args, completion):
             try:
                 object = self.cumin_class.mint_class(**args)
 
@@ -1774,38 +1766,22 @@
                 log.exception("Action failed")
                 completion(e.message or "failed")
 
-    class Edit(CuminAction):
-        def show(self, session, object):
-            frame = self.cumin_class.show_object(session, object)
-            return frame.show_edit(session)
+    class RemoveSet(CuminSetAction):
+        def get_title(self, session):
+            return "Remove"
 
-        def do_invoke(self, object, args, completion):
-            try:
-                object.set(**args)
-                object.syncUpdate()
-                completion("OK")
-            except Exception, e:
-                completion(e.message or "failed")
-
-    class Remove(CuminAction):
-        def show(self, session, object):
-            frame = self.model.frame.brokers_remove
-            frame.ids.set(session, [object.id])
-
-            branch = session.branch()
-            self.model.frame.view.show(branch)
-            frame.origin.set(session, branch.marshal())
-
+        def show(self, session, objects):
+            frame = self.model.frame.mservers_remove
+            frame.objects.set(session, objects)
             return frame.show(session)
 
-        def do_invoke(self, object, args, completion):
-            try:
-                object.destroySelf();
-                object.syncUpdate()
-                completion("OK")
-            except Exception, e:
-                completion(e.message or "failed")
+        def do_invoke(self, servers, args, completion):
+            for server in servers:
+                server.destroySelf()
+                server.syncUpdate()
 
+            completion("OK")
+
 class CuminBrokerGroup(CuminClass):
     def __init__(self, model):
         super(CuminBrokerGroup, self).__init__ \

Modified: mgmt/trunk/cumin/python/cumin/page.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/page.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/page.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -5,8 +5,7 @@
 
 from broker import *
 from brokergroup import *
-from brokerprofile import *
-from brokercluster import *
+from managementserver import *
 from pool import *
 from job import *
 from system import *
@@ -66,12 +65,15 @@
         self.change_password = ChangePasswordForm(app, "password")
         self.add_mode(self.change_password)
 
-        self.brokers_add = BrokerSetAdd(app, "brokersadd")
-        self.add_mode(self.brokers_add)
+        self.mservers_add = ManagementServerSetAdd(app, "mserversadd")
+        self.add_mode(self.mservers_add)
 
-        self.brokers_remove = BrokerSetRemove(app, "brokersremove")
-        self.add_mode(self.brokers_remove)
+        self.mservers_remove = ManagementServerSetRemove(app, "mserversremove")
+        self.add_mode(self.mservers_remove)
 
+        self.brokers_group = BrokerSetEngroup(app, "brokersengroup")
+        self.add_mode(self.brokers_group)
+
         self.jobs_hold = JobSetHold(app, "jobshold")
         self.add_mode(self.jobs_hold)
 
@@ -255,6 +257,7 @@
         self.add_tab(self.OverviewTab(app, "over"))
         self.add_tab(self.MyGridJobs(app, "jobs"))
         self.add_tab(self.AccountTab(app, "acct"))
+        self.add_tab(ManagementServerSet(app, "servers"))
 
     def render_change_password_href(self, session):
         branch = session.branch()
@@ -275,6 +278,9 @@
         def __init__(self, app, name):
             super(HomeView.OverviewTab, self).__init__(app, name)
 
+            notice = self.ManagementServerNotice(app, "notice")
+            self.add_child(notice)
+
             queues = TopQueueSet(app, "queues")
             self.add_child(queues)
 
@@ -287,11 +293,14 @@
         def render_title(self, session):
             return "Overview"
 
-        def render_add_qmf_source_href(self, session):
-            branch = session.branch()
-            self.page.main.brokers_add.show(branch)
-            return branch.marshal()
+        class ManagementServerNotice(Widget):
+            def do_render(self, session):
+                count = BrokerRegistration.select().count()
 
+                if count == 0:
+                    return super(HomeView.OverviewTab.ManagementServerNotice,
+                                 self).do_render(session)
+
     class AccountTab(ActionSet):
         def render_title(self, session):
             return "Your Account"

Modified: mgmt/trunk/cumin/python/cumin/page.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/page.strings	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/page.strings	2009-03-25 17:38:55 UTC (rev 3209)
@@ -203,9 +203,7 @@
 }
 
 [OverviewTab.html]
-<ul class="actions">
-  <li><a class="nav" href="{add_qmf_source_href}">Add Management Data Source</a></li>
-</ul>
+{notice}
 
 <table class="OverviewTab">
   <tbody>
@@ -232,6 +230,27 @@
   </tbody>
 </table>
 
+[ManagementServerNotice.css]
+div.ManagementServerNotice {
+  margin: 0 0 1em 0;
+  border: 1px dotted #cec;
+  padding: 1em;
+  background-color: #dfd;
+}
+
+div.ManagementServerNotice img {
+  vertical-align: top;
+  float: left;
+  margin: 0 0.5em 0.5em 0;
+}
+
+[ManagementServerNotice.html]
+<div class="ManagementServerNotice">
+  <img src="resource?name=notice-36.png"/> This console is not
+  registered with any management servers.  Go to the 'Management Servers'
+  tab above to add a new server.
+</div>
+
 [AccountTab.html]
 <ul class="actions">
   <a class="nav" href="{change_password_href}">Change Password</a>

Modified: mgmt/trunk/cumin/python/cumin/parameters.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/parameters.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/parameters.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -41,6 +41,13 @@
     def do_marshal(self, group):
         return str(group.id)
 
+class BrokerParameter(Parameter):
+    def do_unmarshal(self, string):
+        return Broker.get(int(string))
+
+    def do_marshal(self, broker):
+        return str(broker.id)
+
 class BrokerRegistrationParameter(Parameter):
     def do_unmarshal(self, string):
         return BrokerRegistration.get(int(string))

Modified: mgmt/trunk/cumin/python/cumin/queue.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/queue.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/queue.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -21,9 +21,11 @@
 log = logging.getLogger("cumin.queue")
 
 class QueueSet(CuminTable, Form):
-    def __init__(self, app, name):
+    def __init__(self, app, name, vhost):
         super(QueueSet, self).__init__(app, name)
 
+        self.vhost = vhost
+
         self.ids = CheckboxIdColumn(app, "id")
         self.add_column(self.ids)
 
@@ -64,25 +66,25 @@
         self.__remove = self.Remove(app, "remove")
         self.add_child(self.__remove)
 
-    def render_add_queue_url(self, session, vhost):
+    def render_add_queue_url(self, session):
         branch = session.branch()
         self.frame.queue_add.show(branch)
         return branch.marshal()
-    
-    def get_args(self, session):
-        reg = self.frame.get_object(session)
-        return (reg.getDefaultVhost(),)
 
-    def render_title(self, session, vhost):
+    def render_title(self, session):
         return "Queues %s" % fmt_count(Queue.select().count())
 
-    def render_sql_where(self, session, vhost):
-        elems = list()
-        elems.append("q.vhost_id = %(id)r")
-        elems.append(self.phase.get_sql_constraint(session, vhost))
-        return "where %s" % " and ".join(elems)
+    def render_sql_where(self, session):
+        vhost = self.vhost.get(session)
 
-    def get_sql_values(self, session, vhost):
+        constraints = list()
+        constraints.append("q.vhost_id = %(id)r")
+        constraints.append(self.phase.get_sql_constraint(session, vhost))
+
+        return "where %s" % " and ".join(constraints)
+
+    def get_sql_values(self, session):
+        vhost = self.vhost.get(session)
         return {"id": vhost.id}
 
     class Purge(FormButton):
@@ -115,7 +117,7 @@
 
         def render_content(self, session, data):
             queue = Identifiable(data["id"])
-            href = self.frame.queue.get_href(session, queue)
+            href = self.page.main.broker.queue.get_href(session, queue)
             return fmt_link(href, fmt_shorten(data["name"]))
 
     class ConsumersColumn(SqlTableColumn):
@@ -193,13 +195,13 @@
             return "Name"
 
         def render_content(self, session, data):
-            reg = Identifiable(data["registration_id"])
+            broker = Identifiable(data["broker_id"])
             queue = Identifiable(data["id"])
 
             branch = session.branch()
-            self.page.main.broker.object.set(session, reg)
-            self.page.main.broker.queue.object.set(session, queue)
-            self.page.main.broker.queue.show(session)
+            self.page.main.broker.object.set(branch, broker)
+            self.page.main.broker.queue.object.set(branch, queue)
+            self.page.main.broker.queue.show(branch)
             return fmt_link(branch.marshal(), fmt_shorten(data["name"]))
 
     class EnqueuesColumn(TopTableColumn):
@@ -219,8 +221,8 @@
 
         self.purge = QueuePurge(app, "purge")
         self.add_mode(self.purge)
-        
-        self.binding_add = QueueBindingAdd(app, "bindingadd")
+
+        self.binding_add = QueueBindingAdd(app, "bindingadd", self.object)
         self.add_mode(self.binding_add)
 
         self.remove = QueueRemove(app, "remove")
@@ -231,9 +233,7 @@
         self.add_mode(self.move_messages)
 
     def show_object(self, session, queue):
-        reg = queue.vhost.broker.registration
-        self.page.main.broker.set_object(session, reg)
-
+        self.page.main.broker.object.set(session, queue.vhost.broker)
         return super(QueueFrame, self).show_object(session, queue)
 
     def render_href(self, session, queue):
@@ -342,9 +342,13 @@
             return "Remove"
 
 class QueueForm(CuminFieldForm):
-    def __init__(self, app, name):
+    def __init__(self, app, name, vhost):
         super(QueueForm, self).__init__(app, name)
 
+        assert vhost
+        
+        self.vhost = vhost
+
         self.namef = NameField(app, "name")
         self.add_field(self.namef)
 
@@ -380,14 +384,14 @@
         self.q_count = self.QCountField(app, "q_count")
         self.more.add_field(self.q_count)
         
-        self.bindings = ExchangeKeysField(app, "bindings")
+        self.bindings = ExchangeKeysField(app, "bindings", self.vhost)
         self.add_field(self.bindings)
         
     def validate(self, session, queue_name):
         super_error = super(QueueForm, self).validate(session)
         (errors, form_binding_info) = self.bindings.get_binding_errors(session, queue_name)
         return (errors or super_error, form_binding_info)
-        
+
     class QCountField(IntegerField):
         def render_title(self, session):
             return "<div style=\"padding-left: 1em;\">Max Queue Count</div>"
@@ -533,60 +537,81 @@
                 return "Ring Strict"
 
 class QueueAdd(QueueForm):
-    def get_args(self, session):
-        return (self.frame.get_object(session), )
+    def __init__(self, app, name, vhost):
+        super(QueueAdd, self).__init__(app, name, vhost)
 
-    def process_cancel(self, session, *args):
+    def process_cancel(self, session):
         branch = session.branch()
         self.frame.show_view(branch)
         self.page.set_redirect_url(session, branch.marshal())
 
-    def process_submit(self, session, reg):
-        queue_name = self.namef.get(session)
+    def process_submit(self, session):
+        vhost = self.vhost.get(session)
+        name = self.namef.get(session)
         durable = self.durable.get(session)
+        policy = self.policy.get(session)
 
-        (errors, form_binding_info) = self.validate(session, queue_name)
-        if errors:
-            pass
-        else:
-            # since we are adding a queue, we don't have
-            # an existing queue to pass, so create a
-            # blank one
-            queue = Queue()
-            queue.name = queue_name
-            queue.durable = (durable == "yes")
+        errors, binding_info = self.validate(session, name)
 
-            args = {}
-            args["reg"] = reg
-            args["exchange_keys"] = form_binding_info
-            args["cluster_durable"] = self.cluster_durable.get(session) == "yes"
-            args["lvq"] = self.lvq.get(session) == "enable"
-            args["optimistic"] = self.optimistic.get(session) == "yes"
-            policy = self.policy.get(session)
-            if policy == "none":
-                policy = None
-            args["policy"] = policy
-            
-            file_count = self.file_count.get(session)
-            file_size = self.file_size.get(session)
-            if file_count == self.file_count.input.param.default:
-                file_count = None
-            if file_size == self.file_size.input.param.default:
-                file_size = None
-            args["file_count"] = file_count
-            args["file_size"] = file_size
+        if not errors:
+            action = self.app.model.broker.add_queue
+            invoc = action.begin(vhost)
 
-            args["q_count"] = self.q_count.get(session)
-            args["q_size"] = self.q_size.get(session)
-            
-            action = self.app.model.broker.add_queue
-            action.invoke(queue, args)
-            
+            try:
+                args = dict()
+
+                if durable:
+                    args["qpid.file_count"] = self.file_count.get(session)
+                    args["qpid.file_size"] = self.file_size.get(session)
+
+                if policy != "none":
+                    args["qpid.policy_type"] = policy
+                    args["qpid.max_size"] = self.q_size.get(session)
+                    args["qpid.max_count"] = self.q_count.get(session)
+
+                args["qpid.persist_last_node"] = \
+                    self.cluster_durable.get(session) == "yes"
+
+                args["qpid.last_value_queue"] = \
+                    self.lvq.get(session) == "enable"
+
+                args["qpid.optimistic_consume"] = \
+                    self.optimistic.get(session) == "yes"
+
+                qsession = action.get_session_by_object(vhost)
+
+                qsession.queue_declare(queue=name,
+                                       durable=durable,
+                                       arguments=args)
+
+                for exchange in binding_info:
+                    if "key" in binding_info[exchange]:
+                        binding_key = binding_info[exchange]["key"]
+                    else:
+                        binding_key = None
+
+                    ename = binding_info[exchange]["name"]
+                    eargs = binding_info[exchange]["arguments"]
+
+                    qsession.exchange_bind(queue=name,
+                                           exchange=ename,
+                                           binding_key=binding_key,
+                                           arguments=eargs)
+
+                invoc.status = "OK"
+            except Exception, e:
+                invoc.status = "failed"
+                invoc.exception = e
+
+                log.exception(e)
+
             # navigate back to main queue frame
             self.process_cancel(session)
 
-    def render_title(self, session, reg):
-        return "Add Queue to the Broker '%s'" % reg.name
+    def render_title(self, session):
+        broker = self.vhost.get(session).broker
+        title = self.app.model.broker.get_object_title(session, broker)
+        return "Add Queue to %s" % title
 
 class QueueRemove(CuminConfirmForm):
     def get_args(self, session):
@@ -713,33 +738,41 @@
         return (self.frame.frame.get_object(session),)
 
 class QueueBindingAdd(CuminFieldForm):
-    def __init__(self, app, name):
+    def __init__(self, app, name, queue):
         super(QueueBindingAdd, self).__init__(app, name)
 
+        self.queue = queue
+
+        self.vhost = self.VhostAttribute(self, "vhost")
+        self.add_attribute(self.vhost)
+
         self.props = BindSummaryPropertiesField(app, "props")
         self.add_field(self.props)
 
-        self.bindings = ExchangeKeysField(app, "bindings", title="Bind to Exchange:")
+        self.bindings = ExchangeKeysField(app, "bindings", self.vhost,
+                                          title="Bind to Exchange:")
         self.add_field(self.bindings)
         
         self.errors = self.Errors(self, "errors")
         self.add_attribute(self.errors)
 
-    def get_args(self, session):
-        return self.frame.get_args(session)
+    class VhostAttribute(Attribute):
+        def get_default(self, session):
+            return self.widget.queue.get(session).vhost
 
-    def render_form_error(self, session, *args):
+    def render_form_error(self, session):
         errors = self.errors.get(session)
         if "no_exchanges" in errors:
             return "<ul class=\"errors\" style=\"margin:0; float:left;\"><li>%s</li></ul>" % \
                 "</li><li>".join(errors["no_exchanges"])
         
-    def process_cancel(self, session, *args):
+    def process_cancel(self, session):
         branch = session.branch()
         self.frame.show_view(branch)
         self.page.set_redirect_url(session, branch.marshal())
 
-    def process_submit(self, session, queue):
+    def process_submit(self, session):
+        queue = self.queue.get(session)
         (errors, form_binding_info) = self.bindings.get_binding_errors(session, queue.name)
 
         if not len(form_binding_info):
@@ -765,8 +798,9 @@
             self.process_cancel(session)
 
     def render_title(self, session, *args):
-        queue = self.frame.get_object(session)
-        return "Add Binding to the Queue '%s'" % queue.name
+        queue = self.queue.get(session)
+        title = self.app.model.queue.get_object_title(session, queue)
+        return "Add Binding to %s" % title
 
     class Errors(Attribute):
         def get_default(self, session):

Modified: mgmt/trunk/cumin/python/cumin/queue.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/queue.strings	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/queue.strings	2009-03-25 17:38:55 UTC (rev 3209)
@@ -67,11 +67,10 @@
 select
   q.id,
   q.name,
-  b.registration_id,
+  v.broker_id,
   (c.msg_total_enqueues - p.msg_total_enqueues) as enqueues
 from queue as q
 join vhost as v on v.id = q.vhost_id
-join broker as b on b.id = v.broker_id
 join queue_stats as c on c.id = q.stats_curr_id
 join queue_stats as p on p.id = q.stats_prev_id
 where p.qmf_update_time > now() - interval '60 seconds'

Modified: mgmt/trunk/cumin/python/cumin/test.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/test.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/test.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -55,13 +55,16 @@
 class TestEnvironment(object):
     def __init__(self, app, broker_host, broker_port, spec_path):
         self.app = app
+        self.broker_host = broker_host
+        self.broker_port = broker_port
 
-        self.broker_conn = quirk.Connection(broker_host, broker_port,
-                                            spec_path)
+        broker = TestBroker("qpidd", self.broker_port)
+
+        self.broker_conn = quirk.Connection \
+            (self.broker_host, self.broker_port, spec_path)
         self.broker_queue = quirk.Queue("cumin.queue")
         self.broker_exchange = quirk.Exchange("cumin.exchange")
 
-        self.broker_registration = None
         self.broker = None
         self.vhost = None
         self.queue = None
@@ -69,7 +72,30 @@
         self.broker_group = None
 
     def init(self):
+        name = "test-%s-%s" % (self.broker_host, self.broker_port)
+        url = "amqp://%s:%s" % (self.broker_host, self.broker_port)
+
+        print "Connecting to qmf server at %s" % url
+
+        if not BrokerRegistration.selectBy(name=name, url=url).count():
+            reg = BrokerRegistration(name=name, url=url)
+
+        ready = False
+
+        print "Waiting for the broker to show up...",
+
+        while not ready:
+            time.sleep(1)
+
+            for broker in Broker.select():
+                print "got it."
+                ready = True
+                break
+
+            print ".", 
+
         self.broker_conn.open()
+
         session = quirk.Session(self.broker_conn, "test")
         session.open()
 
@@ -246,8 +272,8 @@
     def __init__(self, env):
         super(MainTest, self).__init__(env, None)
 
+        BrokerTest(env, self)
         BrokerGroupTest(env, self)
-        BrokerRegistrationTest(env, self)
 
 class BrokerLinkTest(Test):
     def __init__(self, env, parent):
@@ -259,7 +285,7 @@
     def do_run(self, session):
         p, s = self.env.page_and_session()
 
-        p.main.broker.set_object(s, self.env.broker_registration)
+        p.main.broker.set_object(s, self.env.broker)
 
         form = p.main.broker.link_add
         form.show(s)
@@ -287,7 +313,7 @@
         def do_run(self, session):
             p, s = self.env.page_and_session()
 
-            p.main.broker.set_object(s, self.env.broker_registration)
+            p.main.broker.set_object(s, self.env.broker)
 
             form = p.main.broker.links_close
             form.show(s)
@@ -317,7 +343,7 @@
         def do_run(self, session):
             p, s = self.env.page_and_session()
     
-            p.main.broker.set_object(s, self.env.broker_registration)
+            p.main.broker.set_object(s, self.env.broker)
             p.main.broker.link.set_object(s, self.env.link)
 
             form = p.main.broker.link.bridge_add
@@ -348,7 +374,7 @@
         def do_run(self, session):
             p, s = self.env.page_and_session()
 
-            p.main.broker.set_object(s, self.env.broker_registration)
+            p.main.broker.set_object(s, self.env.broker)
             p.main.broker.link.set_object(s, self.evn.link)
 
             form = p.main.broker.link.routes_close
@@ -365,67 +391,6 @@
 
             wait(predicate)
 
-class BrokerRegistrationTest(Test):
-    def __init__(self, env, parent):
-        super(BrokerRegistrationTest, self).__init__(env, parent)
-
-        BrokerTest(env, self)
-        self.AddToGroup(env, self)
-        self.Remove(env, self)
-
-    def do_run(self, session):
-        p, s = self.env.page_and_session()
-
-        form = p.main.brokers_add
-        form.show(s)
-
-        form.names.get(s).append(session.id)
-        addr = "%s:%s" % \
-            (self.env.broker_conn.host, self.env.broker_conn.port)
-        form.addrs.get(s).append(addr)
-        form.groups.get(s).append(None)
-        form.submit(s)
- 
-        p.process(s)
-
-        self.env.check_redirect(p, s)
-
-        try:
-            self.env.broker_registration = BrokerRegistration.selectBy \
-                (name=session.id)[0]
-        except IndexError:
-            raise Exception("Registration not created")
-            
-        self.run_children(session)
-
-    class AddToGroup(Test):
-        def do_run(self, session):
-            raise Exception("Not implemented")
-
-    class Remove(Test):
-        def do_run(self, session):
-            try:
-                reg = BrokerRegistration.selectBy(name=session.id)[0]
-            except IndexError:
-                raise Exception("Broker missing")
-
-            p, s = self.env.page_and_session()
-
-            form = p.main.brokers_remove
-            form.show(s)
-            form.ids.set(s, [reg.id])
-            form.submit(s)
-
-            p.process(s)
-
-            self.env.check_redirect(p, s)
-
-            try:
-                reg = BrokerRegistration.selectBy(name=session.id)[0]
-                raise Exception("Registration not deleted")
-            except IndexError:
-                pass
-
 class BrokerGroupTest(Test):
     def __init__(self, env, parent):
         super(BrokerGroupTest, self).__init__(env, parent)
@@ -488,12 +453,12 @@
         VhostTest(env, self)
 
     def do_run(self, session):
-        reg = self.env.broker_registration
+        try:
+            time.sleep(10)
+            self.env.broker = Broker.select()[0]
+        except IndexError:
+            raise Exception("Broker not found")
 
-        wait(lambda: reg.broker)
-
-        self.env.broker = reg.broker
-
         self.run_children(session)
 
 class VhostTest(Test):
@@ -573,7 +538,7 @@
             def do_run(self, session):
                 p, s = self.env.page_and_session()
 
-                p.main.broker.set_object(s, self.env.broker_registration)
+                p.main.broker.set_object(s, self.env.broker)
 
                 form = p.main.broker.bindings_remove.show(s)
                 form.ids.set([self.env.binding_direct.id])
@@ -627,7 +592,7 @@
             def do_run(self, session):
                 p, s = self.env.page_and_session()
 
-                p.main.broker.set_object(s, self.env.broker_registration)
+                p.main.broker.set_object(s, self.env.broker)
 
                 form = p.main.broker.bindings_remove.show(s)
                 form.ids.set([self.env.binding_topic.id])
@@ -681,7 +646,7 @@
             def do_run(self, session):
                 p, s = self.env.page_and_session()
 
-                p.main.broker.set_object(s, self.env.broker_registration)
+                p.main.broker.set_object(s, self.env.broker)
 
                 form = p.main.broker.bindings_remove.show(s)
                 form.ids.set([self.env.binding_fanout.id])
@@ -744,8 +709,7 @@
         name = "cumin.queue.%s" % session.id
         p, s = self.env.page_and_session()
 
-        reg = self.env.broker_registration
-        p.main.broker.set_object(s, reg)
+        p.main.broker.set_object(s, self.env.broker)
 
         form = p.main.broker.queue_add
         form.show(s)
@@ -798,8 +762,7 @@
         def do_run(self, session):
             p, s = self.env.page_and_session()
 
-            reg = self.env.broker_registration
-            p.main.broker.set_object(s, reg)
+            p.main.broker.set_object(s, self.env.broker)
 
             form = p.main.broker.queues_remove
             form.show(s)
@@ -821,8 +784,7 @@
         name = "cumin.exchange.%s" % session.id
         p, s = self.env.page_and_session()
 
-        reg = self.env.broker_registration
-        p.main.broker.set_object(s, reg)
+        p.main.broker.set_object(s, self.env.broker)
 
         form = p.main.broker.exchange_add
         form.show(s)
@@ -869,8 +831,7 @@
             # try to delete it
             p, s = self.env.page_and_session()
 
-            reg = self.env.broker_registration
-            p.main.broker.set_object(s, reg)
+            p.main.broker.set_object(s, self.env.broker)
 
             form = p.main.broker.exchanges_remove
             form.show(s)

Modified: mgmt/trunk/cumin/python/cumin/tools.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/tools.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/tools.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -57,8 +57,9 @@
     def init(self):
         super(BaseCuminTool, self).init()
 
+        # Drop privileges
+
         if os.getuid() == 0:
-            # Drop privileges
             os.setuid(os.stat(__file__).st_uid)
 
         self.config.init()

Modified: mgmt/trunk/cumin/python/cumin/virtualhost.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/virtualhost.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/virtualhost.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -1,76 +0,0 @@
-from wooly import *
-from wooly.widgets import *
-
-from queue import *
-from exchange import *
-from client import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-
-strings = StringCatalog(__file__)
-
-class VirtualHostSet(ItemSet):
-    def render_title(self, session, *args):
-        return "Functional Hosts %s" % \
-               fmt_count(len(model.get_virtual_hosts()))
-
-    def do_get_items(self, session, *args):
-        return sorted_by(model.get_virtual_hosts())
-
-    def render_item_link(self, session, vhost):
-        branch = session.branch()
-        self.page.show_virtual_host(branch, vhost).show_view(branch)
-        return fmt_olink(branch, vhost)
-
-class VirtualHostFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(VirtualHostFrame, self).__init__(app, name)
-
-        self.object = VirtualHostParameter(app, "id")
-        self.add_parameter(self.object)
-
-        self.view = VirtualHostView(app, "view")
-        self.add_mode(self.view)
-        self.set_view_mode(self.view)
-
-        self.queue = QueueFrame(app, "queue")
-        self.add_mode(self.queue)
-
-        self.__exchange = ExchangeFrame(app, "exchange")
-        self.add_mode(self.exchange)
-
-        self.conn = ConnectionFrame(app, "conn")
-        self.add_mode(self.conn)
-
-class VirtualHostView(CuminView):
-    def __init__(self, app, name):
-        super(VirtualHostView, self).__init__(app, name)
-
-        self.tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.tabs)
-
-        self.tabs.add_tab(QueueSet(app, "queues"))
-        self.tabs.add_tab(ExchangeSet(app, "exchanges"))
-        self.tabs.add_tab(ConnectionSet(app, "conns"))
-
-    def render_broker_link(self, session, vhost):
-        broker = vhost.get_broker()
-
-        if broker:
-            branch = session.branch()
-            self.page.show_broker(branch, broker).show_view(branch)
-            return fmt_olink(branch, broker)
-        else:
-            return fmt_none()
-
-    def render_cluster_link(self, session, vhost):
-        cluster = vhost.get_broker_cluster()
-
-        if cluster:
-            branch = session.branch()
-            self.page.show_broker_cluster(branch, cluster).show_view(branch)
-            return fmt_olink(branch, cluster)
-        else:
-            return fmt_none()

Modified: mgmt/trunk/cumin/python/cumin/widgets.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/widgets.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/cumin/python/cumin/widgets.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -716,8 +716,9 @@
         if self.filters.children:
             return self.filters.render(session, *args)
 
-    def render_sql_where(self, session, *args):
-        constraints = list()
+    def get_sql_where_constraints(self, session, *args):
+        constraints = super(CuminTableWithControls, self) \
+            .get_sql_where_constraints(session, *args)
 
         for filter in self.filters.children:
             if filter:
@@ -728,7 +729,7 @@
         if constraint:
             constraints.append(constraint)
 
-        return "where %s" % " and ".join(constraints)
+        return constraints
 
 class NullSortColumn(SqlTableColumn):
     def get_order_by_sql(self, session):

Modified: mgmt/trunk/mint/python/mint/__init__.py
===================================================================
--- mgmt/trunk/mint/python/mint/__init__.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/mint/python/mint/__init__.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -245,9 +245,6 @@
   name = StringCol(length=1000, default=None, unique=True, notNone=True)
   url = StringCol(length=1000, default=None)
   broker = ForeignKey("Broker", cascade="null", default=None)
-  groups = SQLRelatedJoin("BrokerGroup",
-                          intermediateTable="broker_group_mapping",
-                          createRelatedTable=False)
   cluster = ForeignKey("BrokerCluster", cascade="null", default=None)
   profile = ForeignKey("BrokerProfile", cascade="null", default=None)
 
@@ -268,7 +265,7 @@
     lazyUpdate = True
 
   name = StringCol(length=1000, default=None, unique=True, notNone=True)
-  brokers = SQLRelatedJoin("BrokerRegistration",
+  brokers = SQLRelatedJoin("Broker",
                            intermediateTable="broker_group_mapping",
                            createRelatedTable=False)
 
@@ -276,10 +273,9 @@
   class sqlmeta:
     lazyUpdate = True
 
-  brokerRegistration = ForeignKey("BrokerRegistration", notNull=True,
-                                  cascade=True)
+  broker = ForeignKey("Broker", notNull=True, cascade=True)
   brokerGroup = ForeignKey("BrokerGroup", notNull=True, cascade=True)
-  unique = DatabaseIndex(brokerRegistration, brokerGroup, unique=True)
+  unique = DatabaseIndex(broker, brokerGroup, unique=True)
 
 class BrokerCluster(SQLObject):
   class sqlmeta:
@@ -341,6 +337,11 @@
     self.mintBrokersById = dict()
     self.mintBrokersByUrl = dict()
 
+    # Agent heartbeats
+    # (broker bank, agent bank) => latest heartbeat timestamp
+
+    self.heartbeatsByAgentId = dict()
+
     self.__lock = RLock()
 
     self.dbConn = None
@@ -450,8 +451,10 @@
       self.qmfSession.delBroker(mbroker.qmfBroker)
 
       del self.mintBrokersByQmfBroker[mbroker.qmfBroker]
-      del self.mintBrokersById[mbroker.qmfId]
       del self.mintBrokersByUrl[mbroker.url]
+
+      if mbroker.qmfId:
+        del self.mintBrokersById[mbroker.qmfId]
     finally:
       self.unlock()
 
@@ -548,8 +551,18 @@
     pass
 
   def heartbeat(self, agent, timestamp):
-    pass
+    key = (agent.getBrokerBank(), agent.getAgentBank())
+    timestamp = timestamp / 1000000000
+    self.heartbeatsByAgentId[key] = datetime.fromtimestamp(timestamp)
 
+  def getLatestHeartbeat(self, scopeId):
+    scope = int(scopeId)
+    broker = (scope & 0x0000FFFFF0000000) >> 28
+    agent = scope & 0x000000000FFFFFFF
+    key = (broker, agent)
+
+    return self.heartbeatsByAgentId.get(key)
+
   def methodResponse(self, broker, seq, response):
     mbroker = self.getMintBrokerByQmfBroker(broker)
     up = update.MethodUpdate(self, mbroker, seq, response)

Modified: mgmt/trunk/mint/sql/schema.sql
===================================================================
--- mgmt/trunk/mint/sql/schema.sql	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/mint/sql/schema.sql	2009-03-25 17:38:55 UTC (rev 3209)
@@ -10,10 +10,10 @@
 
 CREATE TABLE broker_group_mapping (
     id SERIAL PRIMARY KEY,
-    broker_registration_id INT NOT NULL,
+    broker_id INT NOT NULL,
     broker_group_id INT NOT NULL
 );
-CREATE UNIQUE INDEX broker_group_mapping_unique ON broker_group_mapping (broker_registration_id, broker_group_id);
+CREATE UNIQUE INDEX broker_group_mapping_unique ON broker_group_mapping (broker_id, broker_group_id);
 
 CREATE TABLE broker_profile (
     id SERIAL PRIMARY KEY,
@@ -969,7 +969,7 @@
     vhost_id INT
 );
 
-ALTER TABLE broker_group_mapping ADD CONSTRAINT broker_registration_id_exists FOREIGN KEY (broker_registration_id) REFERENCES broker_registration (id) ON DELETE CASCADE;
+ALTER TABLE broker_group_mapping ADD CONSTRAINT broker_id_exists FOREIGN KEY (broker_id) REFERENCES broker (id) ON DELETE CASCADE;
 
 ALTER TABLE broker_group_mapping ADD CONSTRAINT broker_group_id_exists FOREIGN KEY (broker_group_id) REFERENCES broker_group (id) ON DELETE CASCADE;
 

Modified: mgmt/trunk/wooly/python/wooly/tables.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/tables.py	2009-03-24 18:55:40 UTC (rev 3208)
+++ mgmt/trunk/wooly/python/wooly/tables.py	2009-03-25 17:38:55 UTC (rev 3209)
@@ -185,8 +185,11 @@
         return writer.to_string()
 
     def render_sql_where(self, session, *args):
-        pass
+        constraints = self.get_sql_where_constraints(session)
 
+        if constraints:
+            return "where %s" % " and ".join(constraints)
+
     def render_find_sql_where(self, session, *args):
         pass
 
@@ -218,6 +221,9 @@
 
         return writer.to_string()
 
+    def get_sql_where_constraints(self, session, *args):
+        return list()
+
     def get_sql_values(self, session, *args):
         return None
 




More information about the rhmessaging-commits mailing list