[rhmessaging-commits] rhmessaging commits: r3274 - in mgmt/trunk/cumin/python/cumin: grid and 2 other directories.

rhmessaging-commits at lists.jboss.org rhmessaging-commits at lists.jboss.org
Thu Apr 9 11:40:24 EDT 2009


Author: justi9
Date: 2009-04-09 11:40:23 -0400 (Thu, 09 Apr 2009)
New Revision: 3274

Added:
   mgmt/trunk/cumin/python/cumin/grid/
   mgmt/trunk/cumin/python/cumin/grid/__init__.py
   mgmt/trunk/cumin/python/cumin/grid/collector.py
   mgmt/trunk/cumin/python/cumin/grid/collector.strings
   mgmt/trunk/cumin/python/cumin/grid/job.py
   mgmt/trunk/cumin/python/cumin/grid/job.strings
   mgmt/trunk/cumin/python/cumin/grid/limit.py
   mgmt/trunk/cumin/python/cumin/grid/limit.strings
   mgmt/trunk/cumin/python/cumin/grid/main.py
   mgmt/trunk/cumin/python/cumin/grid/main.strings
   mgmt/trunk/cumin/python/cumin/grid/negotiator.py
   mgmt/trunk/cumin/python/cumin/grid/negotiator.strings
   mgmt/trunk/cumin/python/cumin/grid/pool.py
   mgmt/trunk/cumin/python/cumin/grid/pool.strings
   mgmt/trunk/cumin/python/cumin/grid/scheduler.py
   mgmt/trunk/cumin/python/cumin/grid/scheduler.strings
   mgmt/trunk/cumin/python/cumin/grid/slot.py
   mgmt/trunk/cumin/python/cumin/grid/slot.strings
   mgmt/trunk/cumin/python/cumin/grid/submitter.py
   mgmt/trunk/cumin/python/cumin/grid/submitter.strings
   mgmt/trunk/cumin/python/cumin/inventory/
   mgmt/trunk/cumin/python/cumin/inventory/__init__.py
   mgmt/trunk/cumin/python/cumin/inventory/main.py
   mgmt/trunk/cumin/python/cumin/inventory/main.strings
   mgmt/trunk/cumin/python/cumin/inventory/system.py
   mgmt/trunk/cumin/python/cumin/inventory/system.strings
   mgmt/trunk/cumin/python/cumin/messaging/
   mgmt/trunk/cumin/python/cumin/messaging/__init__.py
   mgmt/trunk/cumin/python/cumin/messaging/binding.py
   mgmt/trunk/cumin/python/cumin/messaging/binding.strings
   mgmt/trunk/cumin/python/cumin/messaging/broker.py
   mgmt/trunk/cumin/python/cumin/messaging/broker.strings
   mgmt/trunk/cumin/python/cumin/messaging/brokergroup.py
   mgmt/trunk/cumin/python/cumin/messaging/brokergroup.strings
   mgmt/trunk/cumin/python/cumin/messaging/brokerlink.py
   mgmt/trunk/cumin/python/cumin/messaging/brokerlink.strings
   mgmt/trunk/cumin/python/cumin/messaging/client.py
   mgmt/trunk/cumin/python/cumin/messaging/client.strings
   mgmt/trunk/cumin/python/cumin/messaging/exchange.py
   mgmt/trunk/cumin/python/cumin/messaging/exchange.strings
   mgmt/trunk/cumin/python/cumin/messaging/main.py
   mgmt/trunk/cumin/python/cumin/messaging/main.strings
   mgmt/trunk/cumin/python/cumin/messaging/queue.py
   mgmt/trunk/cumin/python/cumin/messaging/queue.strings
Removed:
   mgmt/trunk/cumin/python/cumin/binding.py
   mgmt/trunk/cumin/python/cumin/binding.strings
   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/brokergroup.strings
   mgmt/trunk/cumin/python/cumin/brokerlink.py
   mgmt/trunk/cumin/python/cumin/brokerlink.strings
   mgmt/trunk/cumin/python/cumin/client.py
   mgmt/trunk/cumin/python/cumin/client.strings
   mgmt/trunk/cumin/python/cumin/collector.py
   mgmt/trunk/cumin/python/cumin/collector.strings
   mgmt/trunk/cumin/python/cumin/exchange.py
   mgmt/trunk/cumin/python/cumin/exchange.strings
   mgmt/trunk/cumin/python/cumin/job.py
   mgmt/trunk/cumin/python/cumin/job.strings
   mgmt/trunk/cumin/python/cumin/limits.py
   mgmt/trunk/cumin/python/cumin/limits.strings
   mgmt/trunk/cumin/python/cumin/negotiator.py
   mgmt/trunk/cumin/python/cumin/negotiator.strings
   mgmt/trunk/cumin/python/cumin/pool.py
   mgmt/trunk/cumin/python/cumin/pool.strings
   mgmt/trunk/cumin/python/cumin/queue.py
   mgmt/trunk/cumin/python/cumin/queue.strings
   mgmt/trunk/cumin/python/cumin/scheduler.py
   mgmt/trunk/cumin/python/cumin/scheduler.strings
   mgmt/trunk/cumin/python/cumin/slot.py
   mgmt/trunk/cumin/python/cumin/slot.strings
   mgmt/trunk/cumin/python/cumin/submitter.py
   mgmt/trunk/cumin/python/cumin/submitter.strings
   mgmt/trunk/cumin/python/cumin/system.py
   mgmt/trunk/cumin/python/cumin/system.strings
Modified:
   mgmt/trunk/cumin/python/cumin/managementserver.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/user.py
   mgmt/trunk/cumin/python/cumin/visualizations.py
   mgmt/trunk/cumin/python/cumin/widgets.py
   mgmt/trunk/cumin/python/cumin/widgets.strings
Log:
Reorganize cumin code under category-specific modules.  This is part
one of an eventual move toward supporting loadable modules in cumin,
but it's useful by itself just to clean up the code's layout.

Revamp the top-level tabs in accordance with the design review.  The
details underneath are also a lot more straightforward than before.

Refactor TabbedModeSet to use the new show methods of widget.

Make tabs a little prettier.



Deleted: mgmt/trunk/cumin/python/cumin/binding.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/binding.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/binding.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,414 +0,0 @@
-from cumin.exchange import ExchangeInfo
-from cumin.util import sorted_by
-from cumin.widgets import SubmitSwitch
-from formats import *
-from wooly import Template, Writer, Attribute, Parameter, Widget
-from wooly.forms import FormInput, FormField, Form
-from wooly.parameters import DictParameter
-from wooly.resources import StringCatalog
-
-strings = StringCatalog(__file__)
-
-class ExchangeInput(Widget):
-    def __init__(self, app, name):
-        super(ExchangeInput, self).__init__(app, name)
-
-        self.exchange = None
-        self.instance_data = None
-
-        self.name_tmpl = Template(self, "name_html")
-        self.key_tmpl = Template(self, "key_html")
-
-        self.form = None
-
-    def init(self):
-        super(ExchangeInput, self).init()
-
-        for anc in self.ancestors:
-            if isinstance(anc, Form):
-                self.form = anc
-
-    def get_args(self, session):
-        return (self.exchange,)
-
-    def get_exchange_info(self, session, exchange):
-        binding_info = self.form.bindings.dict_param.get(session)
-        if str(exchange.id) in binding_info:
-            return binding_info[str(exchange.id)]
-
-    def get_exchange_info_for(self, session, exchange, key):
-        exchange_info = self.get_exchange_info(session, exchange)
-        if exchange_info:
-            if key in exchange_info:
-                return exchange_info[key]
-
-    def render_exchange_name(self, session, exchange):
-        return exchange.name
-
-    def render_exchange_fmt_name(self, session, exchange):
-        return fmt_shorten(exchange.name)
-
-    def render_name_path(self, session, *args):
-        return DictParameter.sep().join((self.instance_data, "name"))
-
-    def render_exchange_type(self, session, exchange):
-        return exchange.type
-
-    def render_exchange_type_path(self, session, exchange):
-        return DictParameter.sep().join((self.instance_data, "type"))
-
-    def render_exchange_id(self, session, exchange):
-        return exchange.id
-
-    def render_exchange_checked(self, session, exchange):
-        exchange_info = self.get_exchange_info(session, exchange)
-        if exchange_info:
-            if "name" in exchange_info:
-                return "checked=\"checked\""
-
-    def render_exchange_name_input(self, session, exchange):
-        writer = Writer()
-        self.name_tmpl.render(writer, session, exchange)
-        return writer.to_string()
-
-    def render_exchange_key_input(self, session, exchange):
-        writer = Writer()
-        self.key_tmpl.render(writer, session, exchange)
-        return writer.to_string()
-
-    def render_onclick(self, session, exchange):
-        pass
-
-    def render_list_error(self, session, exchange):
-        errors = self.parent.binding_errors.get(session)
-        if exchange.name in errors:
-            return "<ul class=\"errors\" style=\"margin:0; float:left;\"><li>%s</li></ul>" % \
-                "</li><li>".join(errors[exchange.name])
-
-    def render_dict_error(self, session, exchange, key):
-        errors = self.parent.binding_errors.get(session)
-        if exchange.name in errors:
-            exchange_errors = errors[exchange.name]
-            if key in exchange_errors:
-                return "<ul class=\"errors\" style=\"margin:0; float:left;\"><li>%s</li></ul>" % \
-                "</li><li>".join(exchange_errors[key])
-
-    def set_instance_data(self, exchange, dict_key):
-        self.exchange = exchange
-        self.instance_data = dict_key
-
-class FanoutExchangeInput(ExchangeInput):
-    pass
-
-class BindingKeyExchangeInput(ExchangeInput):
-    def __init__(self, app, name):
-        super(BindingKeyExchangeInput, self).__init__(app, name)
-
-    def render_key_path(self, session, exchange):
-        return DictParameter.sep().join((self.instance_data, "key"))
-
-    def render_key_error(self, session, exchange):
-        return self.render_list_error(session, exchange)
-
-    def render_key_value(self, session, exchange):
-        return self.get_exchange_info_for(session, exchange, "key")
-
-class DirectExchangeInput(BindingKeyExchangeInput):
-    pass
-
-class TopicExchangeInput(BindingKeyExchangeInput):
-    pass
-
-class XMLExchangeInput(BindingKeyExchangeInput):
-    def __init__(self, app, name):
-        super(XMLExchangeInput, self).__init__(app, name)
-
-    def render_xquery_path(self, session, exchange):
-        return DictParameter.sep().join((self.instance_data, "xquery"))
-
-    def render_headers_class(self, session, exchange):
-        exchange_info = self.get_exchange_info(session, exchange)
-        if not exchange_info or not "name" in exchange_info:
-            return "initial_header_state"
-
-    def render_key_error(self, session, exchange):
-        return self.render_dict_error(session, exchange, "key")
-
-    def render_onclick(self, session, exchange):
-        return "onclick=\"toggle_row(this, 'xml_extra.%s')\"" % str(exchange.id)
-
-    def render_xml_extra(self, session, exchange):
-        return "xml_extra.%s" % str(exchange.id)
-
-    def render_xquery_error(self, session, exchange):
-        return self.render_dict_error(session, exchange, "xquery")
-
-    def render_xquery_value(self, session, exchange):
-        return self.get_exchange_info_for(session, exchange, "xquery")
-
-    def process_input(self, this_exchange, arguments):
-        if "xquery" in this_exchange:
-            arguments["xquery"] = this_exchange["xquery"]
-
-class HeadersExchangeInput(BindingKeyExchangeInput):
-    def __init__(self, app, name):
-        super(HeadersExchangeInput, self).__init__(app, name)
-
-    def render_x_match_path(self, session, exchange):
-        return DictParameter.sep().join((self.instance_data, "x-match"))
-
-    def render_mkey_path(self, session, exchange):
-        return DictParameter.sep().join((self.instance_data, "mkey"))
-
-    def render_headers_class(self, session, exchange):
-        exchange_info = self.get_exchange_info(session, exchange)
-        if not exchange_info or not "name" in exchange_info:
-            return "initial_header_state"
-
-    def render_all_checked(self, session, exchange):
-        checked = self.render_any_checked(session, exchange)
-        if not checked:
-            return "checked=\"checked\""
-
-    def render_any_checked(self, session, exchange):
-        exchange_info = self.get_exchange_info(session, exchange)
-        if exchange_info:
-            if "x-match" in exchange_info:
-                if exchange_info["x-match"] == "any":
-                    return "checked=\"checked\""
-
-    def render_mkey1_value(self, session, exchange):
-        return self.get_exchange_info_for(session, exchange, "mkey.1")
-
-    def render_mkey2_value(self, session, exchange):
-        return self.get_exchange_info_for(session, exchange, "mkey.2")
-
-    def render_mkey3_value(self, session, exchange):
-        return self.get_exchange_info_for(session, exchange, "mkey.3")
-
-    def render_mnv1_value(self, session, exchange):
-        return self.get_exchange_info_for(session, exchange, "mkey.1.nv")
-
-    def render_mnv2_value(self, session, exchange):
-        return self.get_exchange_info_for(session, exchange, "mkey.2.nv")
-
-    def render_mnv3_value(self, session, exchange):
-        return self.get_exchange_info_for(session, exchange, "mkey.3.nv")
-
-    def render_key_error(self, session, exchange):
-        return self.render_dict_error(session, exchange, "key")
-
-    def render_mkey1_error(self, session, exchange):
-        return self.render_dict_error(session, exchange, "mkey.1")
-
-    def render_mkey2_error(self, session, exchange):
-        return self.render_dict_error(session, exchange, "mkey.2")
-
-    def render_mkey3_error(self, session, exchange):
-        return self.render_dict_error(session, exchange, "mkey.3")
-
-    def render_onclick(self, session, exchange):
-        return "onclick=\"toggle_row(this, 'headers_extra.%s')\"" % str(exchange.id)
-
-    def render_headers_extra(self, session, exchange):
-        return "headers_extra.%s" % str(exchange.id)
-
-    def process_input(self, this_exchange, arguments):
-        # x-match is a radio button, it must have a value
-        arguments["x-match"] = this_exchange["x-match"]
-        # Fill out the other arguments.
-        # The form has input boxes named mkey.* and mkey.*.nv
-        # We need to create an arguments dictionary entry
-        # of the form {mkey.*.value: mkey.*.nv.value}
-        for match_info in this_exchange:
-            if this_exchange[match_info]:
-                if match_info.startswith("mkey") \
-                    and not match_info.endswith("nv"):
-                    # find the value in the matching .nv field
-                    match_value = self._find_match_value(this_exchange, match_info)
-                    # it is valid for the value in the .nv field
-                    # to be empty
-                    arguments[this_exchange[match_info]] = \
-                        match_value or None
-
-    def _find_match_value(self, this_exchange, match_info):
-        for m_info in this_exchange:
-            if m_info.startswith(match_info):
-                if m_info.endswith("nv"):
-                    return this_exchange[m_info]
-
-class ExchangeState(SubmitSwitch):
-    def __init__(self, app, name):
-        super(ExchangeState, self).__init__(app, name)
-
-        self.add_state("c", "Active", bm="phase")
-        self.add_state("a", "All", bm="phase")
-
-    def is_all(self, session):
-        return self.get(session) == "a"
-
-    def is_active(self, session):
-        return self.get(session) == "c"
-
-class ExchangeKeysField(FormField):
-    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)
-
-        self.direct_input = DirectExchangeInput(app, "direct")
-        self.add_child(self.direct_input)
-
-        self.topic_input = TopicExchangeInput(app, "topic")
-        self.add_child(self.topic_input)
-
-        self.fanout_input = FanoutExchangeInput(app, "fanout")
-        self.add_child(self.fanout_input)
-
-        self.xml_input = XMLExchangeInput(app, "xml")
-        self.add_child(self.xml_input)
-
-        self.headers_input = HeadersExchangeInput(app, "headers")
-        self.add_child(self.headers_input)
-
-        self.title = title
-
-        self.binding_errors = self.Errors(self, "binding_errors")
-        self.add_attribute(self.binding_errors)
-
-        self.state = ExchangeState(app, "phase")
-        self.add_child(self.state)
-
-    class Errors(Attribute):
-        def get_default(self, session):
-            return dict()
-
-    def render_title(self, session):
-        return self.title
-
-    def render_exchanges(self, session):
-        vhost = self.vhost.get(session)
-        sortedExchanges = sorted_by(vhost.exchanges)
-
-        # render each exchange we support
-        writer = Writer()
-        for exchange in sortedExchanges:
-            if ExchangeInfo.is_builtin(exchange) or \
-                (not exchange._get_qmfDeleteTime() and \
-                 not (self.state.is_active(session) and not is_active(exchange))):
-                # instance_key gives us a unique path for each exchange
-                # we will be rendering
-                instance_key = self.dict_param.get_instance_key(str(exchange.id))
-                if exchange.type == "direct":
-                    if exchange.name:
-                        self.direct_input.set_instance_data(exchange, instance_key)
-                        writer.write(self.direct_input.render(session))
-                elif exchange.type == "topic":
-                    if not exchange.name == "qpid.management":
-                        self.topic_input.set_instance_data(exchange, instance_key)
-                        writer.write(self.topic_input.render(session))
-                elif exchange.type == "fanout":
-                    self.fanout_input.set_instance_data(exchange, instance_key)
-                    writer.write(self.fanout_input.render(session))
-                elif exchange.type == "xml":
-                    self.xml_input.set_instance_data(exchange, instance_key)
-                    writer.write(self.xml_input.render(session))
-                elif exchange.type == "headers":
-                    self.headers_input.set_instance_data(exchange, instance_key)
-                    writer.write(self.headers_input.render(session))
-
-        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)
-
-        for exchange in form_binding_info:
-            type = form_binding_info[exchange]["type"]
-            if (type == "topic") or (type == "direct"):
-                try:
-                    val = form_binding_info[exchange]["key"]
-                    if not val:
-                        raise KeyError
-                except KeyError:
-                    name = form_binding_info[exchange]["name"]
-                    errs = berrs.setdefault(name, list())
-                    errs.append("A binding key is required")
-            elif type == "headers":
-                try:
-                    val = form_binding_info[exchange]["key"]
-                    if not val:
-                        raise KeyError
-                except KeyError:
-                    name = form_binding_info[exchange]["name"]
-                    errs = berrs.setdefault(name, dict())
-                    errs["key"] = ["A binding key is required"]
-                for key_num in ("1", "2", "3"):
-                    mkey = "mkey."+key_num
-                    mkeynv = mkey+".nv"
-                    if mkeynv in binding_info[exchange] and binding_info[exchange][mkeynv]:
-                        try:
-                            val = binding_info[exchange][mkey]
-                            if not val:
-                                raise KeyError
-                        except KeyError:
-                            name = binding_info[exchange]["name"]
-                            if not name in berrs:
-                                berrs.setdefault(name, dict())
-                            berrs[name][mkey] = ["Missing key"]
-            elif type == "xml":
-                try:
-                    val = form_binding_info[exchange]["key"]
-                    if not val:
-                        raise KeyError
-                except KeyError:
-                    name = form_binding_info[exchange]["name"]
-                    errs = berrs.setdefault(name, dict())
-                    errs["key"] = ["A binding key is required"]
-                try:
-                    val = binding_info[exchange]["xquery"]
-                    if not val:
-                        raise KeyError
-                except KeyError:
-                    name = binding_info[exchange]["name"]
-                    if not name in berrs:
-                        berrs.setdefault(name, dict())
-                    berrs[name]["xquery"] = ["Missing xquery"]
-
-        return (len(berrs), form_binding_info)
-
-    def process_binding_info(self, session, queue_name):
-        """ Processes the raw binding_info from the DictParameter into
-        a "form_binding_info" dictionary that contains four keys:
-        name, key, arguments, and type
-        """
-        binding_info = self.dict_param.get(session)
-        form_binding_info = dict()
-        for this_exchange in binding_info:
-            # if the exchange checkbox is checked
-            if "name" in binding_info[this_exchange]:
-                type = binding_info[this_exchange]["type"]
-                #if type == "direct":
-                #    binding_info[this_exchange]["key"] = queue_name
-
-                form_binding_info[this_exchange] = dict()
-                form_binding_info[this_exchange]["name"] = binding_info[this_exchange]["name"]
-                if "key" in binding_info[this_exchange] and binding_info[this_exchange]["key"]:
-                    form_binding_info[this_exchange]["key"] = binding_info[this_exchange]["key"]
-                form_binding_info[this_exchange]["type"] = type
-
-                arguments = dict()
-                if type == "headers":
-                    self.headers_input.process_input(binding_info[this_exchange], arguments)
-                elif type == "xml":
-                    self.xml_input.process_input(binding_info[this_exchange], arguments)
-                #direct, topic and fanout exchanges don't have aditional arguments
-                form_binding_info[this_exchange]["arguments"] = arguments
-
-        return form_binding_info

Deleted: mgmt/trunk/cumin/python/cumin/binding.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/binding.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/binding.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,159 +0,0 @@
-[ExchangeInput.name_html]
-<td>
-  <input type="checkbox" id="{id}.{exchange_id}" name="{name_path}"
-         value="{exchange_name}" size="15" tabindex="100" {exchange_checked}
-         {onclick} />
-  <input type="hidden" name="{exchange_type_path}" value="{exchange_type}" />
-</td>
-<td><label class="exchange_name" for="{id}.{exchange_id}">{exchange_fmt_name}</label></td>
-<td class="exchange_type">{exchange_type}</td>
-
-[ExchangeInput.key_html]
-<td>
-  <input type="text" name="{key_path}" id="{exchange_name}"
-         value="{key_value}" size="32" maxlength="256" tabindex="100" />
-  {key_error}
-</td>
-
-[DirectExchangeInput.html]
-<tr>
-  {exchange_name_input}
-  {exchange_key_input}
-</tr>
-
-[TopicExchangeInput.html]
-<tr>
-  {exchange_name_input}
-  {exchange_key_input}
-</tr>
-
-[FanoutExchangeInput.html]
-<tr>
-  {exchange_name_input}
-  <td>&nbsp;</td>
-</tr>
-
-[XMLExchangeInput.html]
-<tr>
-  {exchange_name_input}
-  {exchange_key_input}
-</tr>
-<tr id="{xml_extra}" class="{headers_class}">
-  <td colspan="4"><table>
-    <tr>
-      <td>XQuery:</td>
-      <td colspan="3"><textarea name="{xquery_path}" id="{exchange_name}" tabindex="100" rows="4" cols="40">{xquery_value}</textarea>{xquery_error}</td>
-     </tr>
-  </table></td>
-</tr>
-
-[HeadersExchangeInput.html]
-<tr>
-  {exchange_name_input}
-  {exchange_key_input}
-</tr>
-<tr id="{headers_extra}" class="{headers_class}">
-  <td colspan="4"><table>
-    <tr>
-      <td>&nbsp;</td>
-      <td>x-match Type:</td>
-      <td colspan="2">
-        <input type="radio" id="headers.x-match.all" name="{x_match_path}" value="all" {all_checked}/>
-        <label for="headers.x-match.all">All</label>
-        <input type="radio" id="headers.x-match.any" name="{x_match_path}" value="any" {any_checked}/>
-        <label for="headers.x-match.any">Any</label>
-      </td>
-    </tr>
-    <tr>
-      <td>&nbsp;</td>
-      <td>Match Keys:</td>
-      <td colspan="2">
-        <table class="xmlExchange">
-          <thead>
-            <tr>
-              <th>Key</th><th>type, value</th>
-            </tr>
-          </thead>
-          <tbody>
-            <tr>
-              <td><input type="text" name="{mkey_path}.1" value="{mkey1_value}" tabindex="100" />{mkey1_error}</td>
-              <td><input type="text" name="{mkey_path}.1.nv" value="{mnv1_value}" tabindex="100" /></td>
-            </tr>
-            <tr>
-              <td><input type="text" name="{mkey_path}.2" value="{mkey2_value}" tabindex="100" />{mkey2_error}</td>
-              <td><input type="text" name="{mkey_path}.2.nv" value="{mnv2_value}" tabindex="100" /></td>
-            </tr>
-            <tr>
-              <td><input type="text" name="{mkey_path}.3" value="{mkey3_value}" tabindex="100" />{mkey3_error}</td>
-              <td><input type="text" name="{mkey_path}.3.nv" value="{mnv3_value}" tabindex="100" /></td>
-            </tr>
-          </tbody>
-        </table>
-      </td>
-    </tr>
-</table></td></tr>
-
-[ExchangeKeysField.css]
-td.exchange_type {
-    font-style: italic;
-}
-
-table.mobjects tr#headers_extra {
-    border-top: 0px;
-}
-
-table.mobjects tr.initial_header_state {
-    display:none;
-}
-
-table.xmlExchange {
-    border-collapse: collapse;
-    border: 1px dotted #ccc;
-    margin: 0;
-}
-
-table.xmlExchange tr {
-    border-top: 0px solid #fff;
-}
-
-table.mobjects label.exchange_name {
-    font-weight: bold;
-}
-
-table.mobjects td.exchange_type, table.mobjects th.exchange_type {
-    font-style: italic;
-}
-
-[ExchangeKeysField.javascript]
-function toggle_row(chk, row_id) {
-    var display = "none";
-    var headers_extra = document.getElementById(row_id);
-
-    if (chk.checked) {
-        display = "table-row";
-    }
-
-    headers_extra.style.display = display;
-}
-
-[ExchangeKeysField.html]
-<div class="field">
-  <div class="rfloat">{phase}</div>
-  <div class="title">{title}</div>
-  <div class="rclear">&nbsp;</div>
-
-  <div class="inputs">
-    <table class="mobjects" id="exchange_types">
-      <thead>
-        <tr>
-          <th colspan="2"><label class="exchange_name">Exchange Name</label></th>
-          <th class="exchange_type">Exchange Type</th>
-          <th>Binding Key</th>
-        </tr>
-      </thead>
-      <tbody>
-        {exchanges}
-      </tbody>
-    </table>
-  </div>
-</div>

Deleted: mgmt/trunk/cumin/python/cumin/broker.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/broker.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/broker.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,708 +0,0 @@
-from mint import *
-from wooly import *
-from wooly.widgets import *
-from random import random
-from psycopg2 import IntegrityError
-
-from queue import *
-from exchange import *
-from brokerlink import *
-from client import *
-from modelwidgets import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-
-strings = StringCatalog(__file__)
-
-class NewBrokerSet(CuminClassTable):
-    def __init__(self, app, name):
-        super(NewBrokerSet, self).__init__(app, name, app.model.broker)
-
-        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.StatusColumn(app, "status")
-        self.add_column(col)
-
-        col = self.ClusterColumn(app, "cluster")
-        self.add_column(col)
-
-    def render_title(self, session):
-        count = self.get_item_count(session)
-        return "Brokers %s" % fmt_count(count)
-
-    def render_sql_where(self, session):
-        constraints = self.get_sql_where_constraints(session)
-
-        if constraints:
-            return "where %s" % " and ".join(constraints)
-
-    def get_sql_where_constraints(self, session):
-        constraints = list()
-        group = self.group.get(session)
-
-        if group:
-            subquery = \
-                "select 1 from broker_group_mapping " + \
-                "where broker_group_id = %(group_id)r " + \
-                "and broker_id = b.id"
-
-            constraints.append("exists (%s)" % subquery)
-
-        return constraints
-
-    def get_sql_values(self, session):
-        group = self.group.get(session)
-
-        if group:
-            return {"group_id": group.id}
-
-    class NameColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-        def render_content(self, session, data):
-            broker = Identifiable(data["id"])
-            href = self.page.main.broker.get_href(session, broker)
-            return fmt_link(href, fmt_shorten(data["name"], 32, 8))
-
-    class StatusColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Status"
-
-        def render_content(self, session, data):
-            scopeId = data["qmf_scope_id"]
-            dt = self.app.model.mint.model.getLatestHeartbeat(scopeId)
-
-            if dt is None:
-                return fmt_none()
-            else:
-                return fmt_datetime(dt)
-
-    class ClusterColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Cluster"
-
-        def render_content(self, session, data):
-            return data["cluster"] or fmt_none()
-
-class TopBrokerSet(CuminTable):
-    def __init__(self, app, name):
-        super(TopBrokerSet, self).__init__(app, name)
-
-        col = self.NameColumn(app, "name")
-        self.add_column(col)
-        self.set_default_column(col)
-
-    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"]))
-
-class BrokerFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(BrokerFrame, self).__init__(app, name)
-
-        self.object = BrokerParameter(app, "id")
-        self.add_parameter(self.object)
-
-        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)
-
-        self.edit = BrokerEdit(app, "edit")
-        self.add_mode(self.edit)
-        self.set_edit_mode(self.edit)
-
-        self.queue = QueueFrame(app, "queue")
-        self.add_mode(self.queue)
-
-        self.queues_purge = QueueSetPurge(app, "queuespurge")
-        self.add_mode(self.queues_purge)
-
-        self.queues_remove = QueueSetRemove(app, "queuesremove")
-        self.add_mode(self.queues_remove)
-
-        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.vhost)
-        self.add_mode(self.exchange_add)
-
-        self.exchanges_remove = ExchangeSetRemove(app, "exchangesremove")
-        self.add_mode(self.exchanges_remove)
-
-        self.bindings_remove = BindingSetRemove(app, "bindingsremove")
-        self.add_mode(self.bindings_remove)
-
-        self.link = PeerFrame(app, "link")
-        self.add_mode(self.link)
-
-        self.link_add = BrokerLinkAdd(app, "linkadd", self.vhost)
-        self.add_mode(self.link_add)
-
-        self.links_close = BrokerSetClose(app, "linksclose")
-        self.add_mode(self.links_close)
-
-        self.connection = ConnectionFrame(app, "conn")
-        self.add_mode(self.connection)
-
-        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, 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, object):
-        if self.connected.get(session):
-            return "Connected"
-        else:
-            return "Disconnected"
-
-    def render_color(self, session, object):
-        if self.connected.get(session):
-            return "green"
-        else:
-            return "yellow"
-
-    class ConnectedAttribute(Attribute):
-        def get_default(self, session):
-            connected = False
-            broker = self.widget.frame.get_object(session)
-
-            try:
-                id = broker.qmfBrokerId
-                mbroker = self.app.model.mint.model.mintBrokersById[id]
-                connected = mbroker.connected
-            except KeyError:
-                pass
-
-            return connected
-
-class BrokerView(CuminView):
-    def __init__(self, app, name, vhost):
-        super(BrokerView, self).__init__(app, name)
-
-        self.vhost = vhost
-
-        status = BrokerStatus(app, "status", vhost)
-        self.add_child(status)
-
-        tabs = TabbedModeSet(app, "tabs")
-        self.add_child(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))
-
-    def render_group_links(self, session, object):
-        return "XXX"
-
-        links = list()
-
-        for group in reg.groups:
-            branch = session.branch()
-            self.frame.frame.show_broker_group(branch, group).show_view \
-                (branch)
-            links.append(fmt_olink(branch, group))
-
-        return ", ".join(links)
-
-    # XXX see if we can't get rid of this
-    class BrokerQueueTab(Widget):
-        def __init__(self, app, name, vhost):
-            super(BrokerView.BrokerQueueTab, self).__init__(app, name)
-
-            self.__queues = QueueSet(app, "items", vhost)
-            self.add_child(self.__queues)
-
-        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):
-            branch = session.branch()
-            self.frame.queue.add.show(branch, None)
-            return branch.marshal()
-
-    class BrokerLogTab(Widget):
-        def render_title(self, session):
-            return "Log Messages"
-
-    class BrokerDetailsTab(Widget):
-        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)
-
-            actions = self.Actions(app, "actions")
-            self.add_child(actions)
-
-        def render_title(self, session):
-            return "Details"
-
-        class Properties(CuminProperties):
-            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]
-
-                return props
-
-        class Actions(CuminActions):
-            def do_get_items(self, session, object):
-                broker = self.parent.vhost.get(session).broker
-
-                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
-
-class ModuleNotEnabled(Widget):
-    def do_render(self, session):
-        return "This module is not enabled"
-
-class BrokerAccessControl(ModeSet):
-    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.acl)
-        self.add_mode(self.__view)
-
-    class AclModuleAttribute(Attribute):
-        def get_default(self, session):
-            broker = self.widget.vhost.get(session).broker
-
-            for acl in Acl.selectBy(broker=broker):
-                return acl
-
-    def do_process(self, session):
-        if self.acl.get(session):
-            self.show_mode(session, self.__view)
-
-    def render_title(self, session):
-        return "Access Control"
-
-class BrokerAccessControlView(Widget):
-    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.acl.get(session),)
-
-    class Stats(StatSet):
-        def get_args(self, session):
-            return (self.parent.acl.get(session),)
-
-class BrokerClustering(ModeSet):
-    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.cluster)
-        self.add_mode(self.__view)
-
-    class ClusteringModuleAttribute(Attribute):
-        def get_default(self, session):
-            broker = self.widget.vhost.get(session).broker
-
-            for cluster in Cluster.selectBy(broker=broker):
-                return cluster
-
-    def do_process(self, session):
-        if self.cluster.get(session):
-            self.show_mode(session, self.__view)
-
-    def render_title(self, session):
-        return "Clustering"
-
-class BrokerClusteringView(Widget):
-    def __init__(self, app, name, cluster):
-        super(BrokerClusteringView, self).__init__(app, name)
-
-        self.cluster = cluster
-
-        props = self.Properties(app, "props")
-        self.add_child(props)
-
-        stats = self.Stats(app, "stats", "general")
-        self.add_child(stats)
-
-    class Properties(CuminProperties):
-        def get_args(self, session):
-            return (self.parent.cluster.get(session),)
-
-    class Stats(StatSet):
-        def get_args(self, session):
-            return (self.parent.cluster.get(session),)
-
-class BrokerStats(Widget):
-    def __init__(self, app, name):
-        super(BrokerStats, self).__init__(app, name)
-
-    def render_title(self, session):
-        return "Statistics"
-
-class BrokerBrowser(Widget):
-    def __init__(self, app, name):
-        super(BrokerBrowser, self).__init__(app, name)
-
-        self.group_tmpl = Template(self, "group_html")
-
-        self.brokers = NewBrokerSet(app, "brokers")
-        self.add_child(self.brokers)
-
-    def render_title(self, session, *args):
-        return "Brokers %s" % fmt_count(Broker.select().count())
-
-    def render_clear_filters_href(self, session):
-        branch = session.branch()
-        self.brokers.group.set(branch, None)
-        return branch.marshal()
-
-    def render_group_filters(self, session):
-        groups = BrokerGroup.select()
-        return self._render_filters(session, groups, self.group_tmpl)
-
-    def render_group_link(self, session, group):
-        return self._render_filter_link(session, group, self.brokers.group)
-
-    def _render_filters(self, session, collection, template):
-        writer = Writer()
-
-        for object in collection:
-            template.render(writer, session, object)
-
-        template.render(writer, session, None)
-
-        return writer.to_string()
-
-    def _render_filter_link(self, session, object, param):
-        branch = session.branch()
-        param.set(branch, object)
-        href = branch.marshal()
-
-        name = object and object.name or "Any"
-
-        class_ = param.get(session) is object and "selected"
-
-        return fmt_link(href, name, class_)
-
-class BrokerSetForm(CuminForm, Frame):
-    def __init__(self, app, name):
-        super(BrokerSetForm, 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.group_param = BrokerGroupParameter(app, "group_param")
-        self.group_param.default = None
-        self.add_parameter(self.group_param)
-
-        self.groups = ListParameter(app, "group", self.group_param)
-        self.add_parameter(self.groups)
-
-        self.fields = IntegerParameter(app, "fields")
-        self.fields.default = 3
-        self.add_parameter(self.fields)
-
-        self.field_tmpl = Template(self, "field_html")
-        self.group_tmpl = Template(self, "group_html")
-
-        self.more = self.MoreEntries(app, "more")
-        self.add_child(self.more)
-
-    class Errors(Attribute):
-        def get_default(self, session):
-            return dict()
-
-    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 escape_entity(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 escape_entity(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_field_group_name(self, session, index):
-        return self.groups.path
-
-    def render_groups(self, session, index):
-        writer = Writer()
-
-        for group in BrokerGroup.select():
-            self.group_tmpl.render(writer, session, index, group)
-
-        return writer.to_string()
-
-    def render_group_value(self, session, index, group):
-        return group.id
-
-    def render_group_name(self, session, index, group):
-        return group.name
-
-    def render_group_selected_attr(self, session, index, group):
-        groups = self.groups.get(session)
-        if len(groups) > index:
-            if groups[index] and group.id == groups[index].id:
-                return "selected=\"selected\""
-
-    class MoreEntries(FormButton):
-        def render_content(self, session):
-            return "More Entries"
-
-class BrokerSetAdd(BrokerSetForm):
-    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.broker_registration.add
-
-        addrs = self.addrs.get(session)
-        names = self.names.get(session)
-        groups = self.groups.get(session)
-        fields = self.fields.get(session)
-
-        if self.validate(session, addrs, names, groups):
-            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)
-
-                    if len(groups) > i:
-                        group = groups[i]
-
-                        if group:
-                            reg.addBrokerGroup(group)
-
-            self.process_cancel(session)
-
-    def validate(self, session, addrs, names, groups):
-        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:
-                    #host, port = parse_broker_addr(addr)
-                    count = BrokerRegistration.selectBy \
-                        (url=addr).count()
-
-                    if count:
-                        errs = aerrs.setdefault(i, list())
-                        errs.append("The broker at %s " % (addr) +
-                                    "is already registered")
-
-        return not len(nerrs) and not len(aerrs)
-
-    def render_title(self, session):
-        return "Register New Brokers"
-
-class BrokerEdit(CuminFieldForm):
-    def __init__(self, app, name):
-        super(BrokerEdit, self).__init__(app, name)
-
-        self.broker_name = UniqueNameField(app, "name", BrokerRegistration)
-        self.add_field(self.broker_name)
-
-        self.groups = BrokerGroupCheckboxField(app, "groups")
-        self.add_field(self.groups)
-
-    def init(self):
-        super(BrokerEdit, self).init()
-
-        self.broker_name.set_object_attr(self.frame.object)
-
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, reg):
-        return "Edit Broker '%s'" % reg.name
-
-    def process_cancel(self, session, reg):
-        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, reg):
-        errors = self.validate(session)
-
-        if errors:
-            pass
-        else:
-            action = self.app.model.management_server.edit
-            args = {"name": self.broker_name.get(session)}
-            action.invoke(reg, args)
-
-            for group in self.groups.get(session):
-                if group not in reg.groups:
-                    reg.addBrokerGroup(group)
-
-            for group in reg.groups:
-                if group not in self.groups.get(session):
-                    reg.removeBrokerGroup(group)
-
-            reg.syncUpdate()
-
-            self.process_cancel(session, reg)
-
-    def process_display(self, session, reg):
-        self.broker_name.set(session, reg.name)
-
-        for group in reg.groups:
-            self.groups.get(session).append(group)
-
-class BrokerSetEngroup(CuminSetActionForm):
-    def __init__(self, app, name):
-        param = BrokerParameter(app, "item")
-
-        super(BrokerSetEngroup, self).__init__ \
-            (app, name, app.model.broker.engroup_set, param)
-
-from brokergroup import BrokerGroupCheckboxField

Deleted: mgmt/trunk/cumin/python/cumin/broker.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/broker.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/broker.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,200 +0,0 @@
-[BrokerSet.sql]
-select br.id, br.name, c.cluster_name as cluster
-from broker_registration as br
-left outer join broker as b on b.registration_id = br.id
-left outer join cluster as c on c.broker_id = b.id
-{sql_where}
-{sql_orderby}
-{sql_limit}
-
-[BrokerSet.count_sql]
-select count(*)
-from broker_registration as br
-{sql_where}
-
-[BrokerSet.css]
-div.sactions button.unregister {
-	margin-right: 2em;
-}
-
-[BrokerSet.html]
-<form id="{id}" method="post" action="?">
-  <!-- <select onchange="document.getElementById('{id}.submit').submit()"> -->
-
-  <div class="sactions">
-    <h2>Act on Selection:</h2>
-    {unregister}
-
-    <h2>Add to Group:</h2>
-    {groups} {groupify}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-        <th class="setnav" colspan="{column_count}">
-          <div class="rfloat">{page}</div>
-          {count}
-        </th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <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}
-
-[BrokerQueueTab.html]
-{items}
-
-[BrokerDetailsTab.html]
-<table class="CuminDetails">
-  <tbody>
-  <tr>
-    <td>
-      <h2>Properties</h2>
-      {properties}
-    </td>
-    <td>
-      <h2>Actions</h2>
-      {actions}
-    </td>
-  </tr>
-  </tbody>
-</table>
-
-[BrokerStatus.html]
-<div id="{id}" class="CuminStatus {color}">
-  <h2>Broker Status</h2>
-
-  <div>{status}</div>
-</div>
-
-[BrokerStats.html]
-<table class="twocol">
-  <tbody>
-  <tr>
-    <td>
-      <h2>Access Control</h2>
-      {acl}
-    </td>
-    <td>
-<!-- -->
-    </td>
-  </tr>
-  </tbody>
-</table>
-
-[BrokerBrowser.css]
-table.BrokerBrowser {
-  width: 100%;
-}
-
-table.BrokerBrowser td {
-  vertical-align: top;
-}
-
-table.BrokerBrowser td.nav {
-  width: 20%;
-  vertical-align: top;
-}
-
-table.BrokerBrowser td.nav h2 {
-  font-weight: normal;
-  font-size: 0.9em;
-}
-
-table.BrokerBrowser td.nav ul.slist {
-  margin: 0.5em 0 1em 0;
-}
-
-table.BrokerBrowser td.view {
-  width: 80%;
-}
-
-[BrokerBrowser.html]
-<table class="BrokerBrowser">
-  <tr>
-    <td class="nav">
-      <ul class="actions">
-        <li><a href="{clear_filters_href}">Clear Filters</a></li>
-      </ul>
-
-      <h2>Filter by Group</h2>
-      <ul class="slist">{group_filters}</ul>
-    </td>
-    <td class="view">{brokers}</td>
-  </tr>
-</table>
-
-[BrokerBrowser.group_html]
-<li>{group_link}</li>
-
-[BrokerSetForm.css]
-table.BrokerSetForm td, table.BrokerSetForm th {
-  padding: 0.25em;
-}
-
-table.BrokerSetForm span.example {
-  font-weight: normal;
-  font-size: 0.8em;
-  font-style: italic;
-}
-
-[BrokerGroupInputSet.item_html]
-<div class="field">
-  <input type="checkbox" id="{id}" name="{name}" value="{item_value}" tabindex="{tab_index}" {item_checked_attr}/>
-  <label for="{id}">{item_content}</label>
-</div>
-
-[BrokerAccessControlView.html]
-<table class="twocol">
-  <tbody>
-    <tr>
-      <td>
-        <h2>Properties</h2>
-        {props}
-
-        <h2>Statistics</h2>
-        {stats}
-      </td>
-      <td>
-      </td>
-    </tr>
-  </tbody>
-</table>
-
-[BrokerClusteringView.html]
-<table class="twocol">
-  <tbody>
-    <tr>
-      <td>
-        <h2>Properties</h2>
-        {props}
-
-        <h2>Statistics</h2>
-        {stats}
-      </td>
-      <td>
-      </td>
-    </tr>
-  </tbody>
-</table>

Deleted: mgmt/trunk/cumin/python/cumin/brokergroup.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/brokergroup.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/brokergroup.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,200 +0,0 @@
-from mint import *
-from wooly import *
-from wooly.widgets import *
-from wooly.forms import *
-
-from broker import NewBrokerSet
-from model import *
-from widgets import *
-from modelwidgets import *
-from parameters import *
-from formats import *
-from util import *
-
-strings = StringCatalog(__file__)
-
-class BrokerGroupSet(CuminClassTable):
-    def __init__(self, app, name):
-        cls = app.model.broker_group
-
-        super(BrokerGroupSet, self).__init__(app, name, cls)
-
-        col = CuminClassNameColumn(app, "name", cls)
-        self.add_column(col)
-
-class BrokerGroupInputSet(CheckboxInputSet):
-    def __init__(self, app, name):
-        super(BrokerGroupInputSet, self).__init__(app, name, None)
-
-        item = BrokerGroupParameter(app, "item")
-        self.param = ListParameter(app, "param", item)
-        self.add_parameter(self.param)
-
-    def do_get_items(self, session, *args):
-        return BrokerGroup.select()
-
-    def render_item_value(self, session, group):
-        return group.id
-
-    def render_item_content(self, session, group):
-        return group.name
-
-    def render_item_checked_attr(self, session, group):
-        if group in self.param.get(session):
-            return "checked=\"checked\""
-
-class BrokerGroupCheckboxField(FormField):
-    def __init__(self, app, name):
-        super(BrokerGroupCheckboxField, self).__init__(app, name)
-
-        self.__groups = BrokerGroupInputSet(app, "inputs")
-        self.add_child(self.__groups)
-
-    def get(self, session):
-        return self.__groups.get(session)
-
-    def render_title(self, session):
-        return "Broker Groups"
-
-class BrokerGroupFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(BrokerGroupFrame, self).__init__(app, name)
-
-        self.object = BrokerGroupParameter(app, "id")
-        self.add_parameter(self.object)
-
-        self.view = BrokerGroupView(app, "view", self.object)
-        self.add_child(self.view)
-        self.set_view_mode(self.view)
-
-        self.add = BrokerGroupAdd(app, "add")
-        self.add_child(self.add)
-        self.set_add_mode(self.add)
-
-        self.edit = BrokerGroupEdit(app, "edit")
-        self.add_child(self.edit)
-        self.set_edit_mode(self.edit)
-
-        self.remove = BrokerGroupRemove(app, "remove")
-        self.add_child(self.remove)
-        self.set_remove_mode(self.remove)
-
-    def render_title(self, session, group):
-        if group:
-            return super(BrokerGroupFrame, self).render_title(session, group)
-        else:
-            return "Broker Group"
-
-    def render_href(self, session, group):
-        if group:
-            return super(BrokerGroupFrame, self).render_href(session, group)
-
-class BrokerGroupStatus(CuminStatus):
-    pass
-
-class BrokerGroupView(CuminView):
-    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)
-
-        brokers = NewBrokerSet(app, "brokers")
-        brokers.group = self.group
-        self.__tabs.add_tab(brokers)
-
-        self.__tabs.add_tab(CuminDetails(app, "details"))
-
-class BrokerGroupForm(CuminFieldForm):
-    def __init__(self, app, name):
-        super(BrokerGroupForm, self).__init__(app, name)
-
-        self.group_name = UniqueNameField(app, "name", BrokerGroup)
-        self.add_field(self.group_name)
-
-    def init(self):
-        super(BrokerGroupForm, self).init()
-
-        self.group_name.set_object_attr(self.frame.object)
-
-class BrokerGroupAdd(BrokerGroupForm):
-    def process_cancel(self, session):
-        branch = session.branch()
-        self.page.main.view.show(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_submit(self, session):
-        errors = self.validate(session)
-
-        if errors:
-            pass
-        else:
-            args = {"name": self.group_name.get(session)}
-            method = self.app.model.broker_group.add
-            method.invoke(None, args)
-
-            self.process_cancel(session)
-
-    def render_title(self, session):
-        return "Add Group"
-
-class BrokerGroupEdit(BrokerGroupForm):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def process_cancel(self, session, group):
-        branch = session.branch()
-        self.frame.show_view(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_submit(self, session, group):
-        errors = self.validate(session)
-
-        if errors:
-            pass
-        else:
-            args = {"name": self.group_name.get(session)}
-            method = self.app.model.broker_group.edit
-            method.invoke(group, args)
-
-            self.process_cancel(session, group)
-
-    def process_display(self, session, group):
-        self.group_name.set(session, group.name)
-
-    def render_title(self, session, group):
-        return "Edit Group '%s'" % group.name
-
-class BrokerGroupRemove(CuminConfirmForm, Frame):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def process_cancel(self, session, group):
-        branch = session.branch()
-        self.frame.show_view(branch)
-        self.page.pop_frame(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_submit(self, session, group):
-        method = self.app.model.broker_group.remove
-        method.invoke(group)
-
-        branch = session.branch()
-        self.frame.frame.show_view(branch)
-        self.page.pop_frame(branch)
-        self.page.pop_frame(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def render_title(self, session, group):
-        return "Remove Broker Group '%s'" % group.name
-
-    def render_submit_content(self, session, group):
-        return "Yes, Remove Broker Group '%s'" % group.name
-
-    def render_cancel_content(self, session, group):
-        return "No, Cancel"

Deleted: mgmt/trunk/cumin/python/cumin/brokergroup.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/brokergroup.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/brokergroup.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,8 +0,0 @@
-[BrokerGroupSet.sql]
-select bg.id, bg.name
-from broker_group as bg
-{sql_orderby}
-{sql_limit}
-
-[BrokerGroupSet.count_sql]
-select count(*) from broker_group

Deleted: mgmt/trunk/cumin/python/cumin/brokerlink.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/brokerlink.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/brokerlink.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,698 +0,0 @@
-from mint import *
-from wooly import *
-from wooly.widgets import *
-
-from queue import *
-from exchange import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-
-strings = StringCatalog(__file__)
-
-class PeerSet(CuminTable, Form):
-    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)
-
-        #self.ids = CheckboxIdColumn(app, "id")
-        #self.add_column(self.ids)
-
-        col = self.AddressColumn(app, "addr")
-        self.add_column(col)
-        self.set_default_column(col)
-
-        col = self.DurableColumn(app, "durable")
-        self.add_column(col)
-
-        col = self.StateColumn(app, "state")
-        self.add_column(col)
-
-        col = self.LastErrorColumn(app, "last_error")
-        self.add_column(col)
-
-        #col = self.FromPeerColumn(app, "from_peer")
-        #self.add_column(col)
-
-        #col = self.ToPeerColumn(app, "to_peer")
-        #self.add_column(col)
-
-        self.__close = self.Close(app, "close")
-        self.add_child(self.__close)
-
-    def render_add_broker_link_url(self, session):
-        branch = session.branch()
-        self.frame.link_add.show(branch)
-        return branch.marshal()
-
-    def render_title(self, session):
-        count = self.get_item_count(session)
-        return "Broker Links %s" % fmt_count(count)
-
-    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 = self.vhost.get(session)
-        return {"vhost_id": vhost.id}
-
-    def disable_closed(self, session, data):
-        return data["state"] == "Closed"
-
-    class AddressColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Address"
-
-        def render_content(self, session, data):
-            peer = Identifiable(data["id"])
-            href = self.frame.link.get_href(session, peer)
-            name = "%s:%i" % (data["host"], data["port"])
-            return fmt_link(href, fmt_shorten(name))
-
-        def get_order_by_sql(self, session):
-            dir = self.parent.is_reversed(session) and "desc" or "asc"
-            return "order by host, port %s" % dir
-
-    class StateColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "State"
-
-    class LastErrorColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Last Error"
-
-    class DurableColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Durable"
-
-    class FromPeerColumn(NullSortColumn, FreshDataOnlyColumn):
-        def render_title(self, session, data):
-            return "Bytes from Broker"
-
-        def render_value(self, session, value):
-            return fmt_rate(value)
-
-    class ToPeerColumn(NullSortColumn, FreshDataOnlyColumn):
-        def render_title(self, session, data):
-            return "Bytes to Broker"
-
-        def render_value(self, session, value):
-            return fmt_rate(value)
-
-    class Close(FormButton):
-        def render_content(self, session):
-            return "Close"
-
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            href = self.frame.links_close.get_href(session, ids)
-            self.page.set_redirect_url(session, href)
-
-class PeerRouteSet(CuminTable, Form):
-    def __init__(self, app, name):
-        super(PeerRouteSet, self).__init__(app, name)
-
-        self.ids = CheckboxIdColumn(app, "id")
-        self.add_column(self.ids)
-
-        #col = self.SourceColumn(app, "source")
-        #self.add_column(col)
-
-        #col = self.DestinationColumn(app, "managed_broker")
-        #self.add_column(col)
-
-        col = self.ExchangeColumn(app, "exchange")
-        self.add_column(col)
-        self.set_default_column(col)
-
-        col = self.KeyColumn(app, "key")
-        self.add_column(col)
-
-        col = self.TagColumn(app, "tag")
-        self.add_column(col)
-
-        col = self.ExcludesColumn(app, "excludes")
-        self.add_column(col)
-
-        self.__remove = self.Remove(app, "remove")
-        self.add_child(self.__remove)
-
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, link):
-        count = self.get_item_count(session, link)
-        return "Link Routes %s" % fmt_count(count)
-
-    def render_sql_where(self, session, link):
-        return "where l.id = %(link_id)r and b.qmf_delete_time is null"
-
-    def get_sql_values(self, session, link):
-        return {"link_id": link.id}
-
-    def render_add_bridge_url(self, session, route):
-        branch = session.branch()
-        self.frame.show_bridge_add(branch)
-        return branch.marshal()
-
-    class SourceColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Source"
-
-        def render_content(self, session, data):
-            return "%s:%i" % (data["host"], data["port"])
-
-        def get_order_by_sql(self, session):
-            dir = self.parent.is_reversed(session) and "desc" or "asc"
-            return "order by l.host, l.port %s" % dir
-
-    class DestinationColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Destination"
-
-    class ExchangeColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Exchange"
-
-    class KeyColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Routing Key"
-
-    class TagColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Tag"
-
-    class ExcludesColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Excludes"
-
-    class Remove(FormButton):
-        def render_content(self, session):
-            return "Remove"
-
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            branch = session.branch()
-            frame = self.frame.show_routes_close(branch)
-            frame.ids.set(branch, ids)
-            self.page.set_redirect_url(session, branch.marshal())
-
-class PeerFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(PeerFrame, self).__init__(app, name)
-
-        self.object = PeerParameter(app, "id")
-        self.add_parameter(self.object)
-
-        self.view = PeerView(app, "view")
-        self.add_mode(self.view)
-        self.set_view_mode(self.view)
-
-        remove = LinkRemove(app, "remove")
-        self.add_mode(remove)
-        self.set_remove_mode(remove)
-
-        self.__bridge_add = BridgeAdd(app, "bridgeadd")
-        self.add_mode(self.__bridge_add)
-
-        self.__routes_close = PeerRouteSetClose(app, "routesclose")
-        self.add_mode(self.__routes_close)
-
-    def render_title(self, session, peer):
-        return super(PeerFrame, self).render_title(session, peer)
-
-    def show_object(self, session, peer):
-        reg = peer.vhost.broker.registration
-        self.page.main.broker.set_object(session, reg)
-
-        return super(PeerFrame, self).show_object(session, peer)
-
-    def show_bridge_add(self, session):
-        self.page.set_frame(session, self.__bridge_add)
-        return self.show_mode(session, self.__bridge_add)
-
-    def show_routes_close(self, session):
-        self.page.set_frame(session, self.__routes_close)
-        return self.show_mode(session, self.__routes_close)
-
-class LinkRemove(CuminConfirmForm):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def process_cancel(self, session, link):
-        branch = session.branch()
-        self.frame.show_view(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_submit(self, session, link):
-        action = self.app.model.link.close
-        action.invoke(link)
-
-        branch = session.branch()
-        self.frame.frame.show_view(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def render_title(self, session, link):
-        return "Close Broker Link '%s:%d'" % (link.host, link.port)
-
-    def render_submit_content(self, session, link):
-        return "Yes, Close Broker Link"
-
-    def render_cancel_content(self, session, link):
-        return "No, Cancel"
-
-class PeerStatus(CuminStatus):
-    def render_color(self, session, link):
-        if link.statsCurr:
-            return link.statsCurr.lastError and "red" or "green"
-
-    def render_peer_state(self, session, peer):
-        if peer.statsCurr:
-            return peer.statsCurr.state
-
-    def render_peer_error(self, session, peer):
-        if peer.statsCurr:
-            return peer.statsCurr.lastError
-
-class PeerView(CuminView):
-    def __init__(self, app, name):
-        super(PeerView, self).__init__(app, name)
-
-        status = PeerStatus(app, "status")
-        self.add_child(status)
-
-        self.__tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.__tabs)
-
-        #self.__tabs.add_tab(PeerStats(app, "stats"))
-
-        self.__routes = PeerRouteSet(app, "routes")
-        self.__tabs.add_tab(self.__routes)
-
-        self.__tabs.add_tab(CuminDetails(app, "details"))
-
-    def show_routes(self, session):
-        return self.__tabs.show_mode(session, self.__routes);
-
-class PeerStats(TabbedModeSet):
-    def __init__(self, app, name):
-        super(PeerStats, self).__init__(app, name)
-
-        self.add_child(StatSet(app, "io", "io"))
-        self.add_child(StatSet(app, "general", "general"))
-
-        chart = self.ReceiveRouteDropRateChart(app, "recvroutedrop")
-        self.add_child(chart)
-
-        chart = StatValueChart(app, "producers")
-        chart.stats = ("producerCount",)
-        self.add_child(chart)
-
-    def render_title(self, session):
-        return "Statistics"
-
-    class ReceiveRouteDropRateChart(StatValueChart):
-        def __init__(self, app, name):
-            super(PeerStats.ReceiveRouteDropRateChart, self).__init__ \
-                (app, name)
-
-            self.stats = ("msgReceives", "msgRoutes", "msgDrops")
-            self.mode = "rate"
-
-        def render_title(self, session, exchange):
-            return "Messages Received, Routed, and Dropped"
-
-class ExchangeInputSet(RadioInputSet):
-    def __init__(self, app, name, state):
-        super(ExchangeInputSet, self).__init__(app, name, None)
-
-        self.param = IntegerParameter(app, "param")
-        self.add_parameter(self.param)
-
-        self.state = state
-
-    def do_get_items(self, session, *args):
-        exchanges = list()
-
-        link = self.frame.frame.get_object(session)
-        vhost = link.vhost
-        sortedExchanges = sorted_by(vhost.exchanges)
-
-        for exchange in sortedExchanges:
-            if ExchangeInfo.is_builtin(exchange) or \
-               (not exchange._get_qmfDeleteTime() and \
-                not (self.state.is_active(session) and not is_active(exchange))):
-                if not exchange.name in ["qpid.management", ""]:
-                    if not self.param.get(session):
-                        self.param.set(session, exchange.id)
-                    exchanges.append(exchange)
-
-        return exchanges
-
-    def render_item_value(self, session, exchange):
-        return exchange.id
-
-    def render_item_content(self, session, exchange):
-        return exchange.name
-
-    def render_item_checked_attr(self, session, exchange):
-        if self.param.get(session) == exchange.id:
-            return "checked=\"checked\""
-
-class ExchangeRadioField(FormField):
-    def __init__(self, app, name):
-        super(ExchangeRadioField, self).__init__(app, name)
-
-        self.state = ExchangeState(app, "phase")
-        self.add_child(self.state)
-
-        self.__exchanges = ExchangeInputSet(app, "inputs", self.state)
-        self.add_child(self.__exchanges)
-
-    def get(self, session):
-        return self.__exchanges.get(session)
-
-    def render_title(self, session):
-        return "Choose an Exchange"
-
-class BridgeAddForm(CuminFieldForm):
-    def __init__(self, app, name):
-        super(BridgeAddForm, self).__init__(app, name)
-
-        self.exchange = ExchangeRadioField(app, "exchange")
-        self.add_field(self.exchange)
-
-        self.key = TextField(app, "key")
-        self.key.set_title("Routing Key")
-        self.add_field(self.key)
-
-        self.more = MoreFieldSet(app, "more")
-        self.add_field(self.more)
-
-        self.help = self.BridgeAddHelpField(app, "help")
-        self.more.add_field(self.help)
-
-        self.tag = TextField(app, "tag")
-        self.tag.set_required(False)
-        self.tag.set_title("Tag")
-        self.more.add_field(self.tag)
-
-        self.excludes = TextField(app, "excludes")
-        self.excludes.set_required(False)
-        self.excludes.set_title("Excludes")
-        self.more.add_field(self.excludes)
-
-        self.dynamic = self.DynamicField(app, "dynamic")
-        self.more.add_field(self.dynamic)
-
-        self.sync = self.SyncField(app, "sync")
-        self.more.add_field(self.sync)
-
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, link):
-        return "Add Route to '%s:%d'" % (link.host, link.port)
-
-    def process_display(self, session, *args):
-        if not self.tag.get(session):
-            self.tag.set(session, args[0].qmfBrokerId)
-
-        if not self.excludes.get(session):
-            self.excludes.set(session, "%s:%s" % (args[0].host, args[0].port))
-
-        if not self.sync.get(session):
-            self.sync.set(session, self.sync.get_default(session))
-
-    class SyncField(IntegerField):
-        def render_title(self, session):
-            return "Ack"
-
-        def render_field_help(self, session):
-             return "Acknowledge transfers over the bridge in batches of N"
-
-        def get_default(self, session):
-            return 0
-
-    class DynamicField(TwoOptionRadioField):
-        def render_title(self, session):
-            return "Dynamic Route?"
-
-        def render_field_help(self, session):
-            return "(Should the added route be dynamic)"
-
-        def render_title_1(self, session):
-            return "Dynamic"
-
-        def render_title_2(self, session):
-            return "Not dynamic"
-
-
-    class BridgeAddHelpField(FormField):
-        pass
-
-class BridgeAdd(BridgeAddForm):
-    def process_cancel(self, session, *args):
-        branch = session.branch()
-        self.frame.show_view(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_submit(self, session, link):
-        errors = self.validate(session)
-        if errors:
-            pass
-        else:
-            key = self.key.get(session)
-            tag = self.tag.get(session)
-            excludes = self.excludes.get(session)
-            exchange_id = self.exchange.get(session)
-            exchange = Exchange.get(int(exchange_id))
-            durable = link.durable
-            dynamic = self.dynamic.get(session) == "yes"
-            sync = self.sync.get(session)
-
-            args = {"durable": durable,
-                    "exchange": exchange.name,
-                    "key": key,
-                    "tag": tag,
-                    "excludes": excludes,
-                    "dynamic": dynamic,
-                    "sync": sync
-                    }
-
-            action = self.app.model.link.bridge
-            action.invoke(link, args)
-
-            self.process_cancel(session, link)
-
-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)
-
-        self.more = self.ShowButton(app, "more")
-        self.add_field(self.more)
-
-        self.port = self.PortField(app, "port")
-        self.more.add_field(self.port)
-
-        self.username = self.UsernameField(app, "username")
-        self.more.add_field(self.username)
-
-        self.password = self.PassField(app, "password")
-        self.more.add_field(self.password)
-
-        self.durable = self.DurableField(app, "durable")
-        self.more.add_field(self.durable)
-
-        self.transport = self.TransportField(app, "transport")
-        self.more.add_field(self.transport)
-
-    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):
-            return "Show Optional Inputs..."
-
-        def render_less_text(self, session):
-            return "Hide Optional Inputs..."
-
-    class Host(NameField):
-        def render_title(self, session):
-            return "Address"
-
-    class PortField(StringField):
-        def __init__(self, app, name):
-            super(BrokerLinkAdd.PortField, self).__init__(app, name)
-
-            self.input.size = 5
-            self.css_class = "compact first"
-
-        def render_title(self, session):
-            return "Port"
-
-        def do_validate(self, session, errors):
-            try:
-                port = self.get(session)
-                if port:
-                    int(port)
-            except:
-                errors.append(FormError("Port must be a number"))
-
-    class UsernameField(StringField):
-        def render_title(self, session):
-            return "Username"
-
-        def render_form_field_class(self, session):
-            return "compact"
-
-    class PassField(PasswordField):
-        def render_title(self, session):
-            return "Password"
-
-        def render_form_field_class(self, session):
-            return "compact last"
-
-    class TransportField(RadioField):
-        def __init__(self, app, name):
-            super(BrokerLinkAdd.TransportField, self).__init__(app, name, None)
-
-            self.param = Parameter(app, "param")
-            self.param.default = "tcp"
-            self.add_parameter(self.param)
-
-            option = self.TCP(app, "tcp", self.param)
-            self.add_option(option)
-
-            option = self.SSL(app, "ssl", self.param)
-            self.add_option(option)
-
-            option = self.RDMA(app, "rdma", self.param)
-            self.add_option(option)
-
-        def render_title(self, session):
-            return "Transport-type"
-
-        def render_field_help(self, session):
-            return "(Transport to use)"
-
-        class TCP(RadioFieldOption):
-            def render_title(self, session):
-                return "tcp"
-
-        class SSL(RadioFieldOption):
-            def render_title(self, session):
-                return "ssl"
-
-        class RDMA(RadioFieldOption):
-            def render_title(self, session):
-                return "rdma"
-
-    class DurableField(TwoOptionRadioField):
-        def render_title(self, session):
-            return "Restore if broker restarts?"
-
-        def render_field_help(self, session):
-            return "(Should the added configuration be durable)"
-
-        def render_title_1(self, session):
-            return "Yes, restore if broker restarts"
-
-        def render_title_2(self, session):
-            return "No, do not restore if broker restarts"
-
-    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):
-        if self.validate(session):
-            pass
-        else:
-            host = self.host.get(session)
-            port = self.port.get(session) or 5672
-            if port:
-                port = int(port)
-            username = self.username.get(session) or "anonymous"
-            password = self.password.get(session)
-            durable = self.durable.get(session)
-            transport = self.transport.get(session)
-
-            args = {
-                "host": host,
-                "port": port,
-                "durable": durable == "yes",
-                "username": username,
-                "password": password,
-                "transport": transport
-                }
-
-            action = self.app.model.broker.add_link
-            action.invoke(self.vhost.get(session).broker, args)
-
-            # navigate back to main queue frame
-            self.process_cancel(session)
-
-class BrokerSetClose(CuminBulkActionForm):
-    def process_return(self, session):
-        branch = session.branch()
-        self.frame.show_view(branch)
-        self.page.set_frame(branch, self.frame)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_item(self, session, id):
-        link = Link.get(id)
-        action = self.app.model.link.close
-        action.invoke(link)
-
-    def render_title(self, session):
-        return "Close Broker Link"
-
-    def render_form_heading(self, session, *args):
-        return "Close Link to"
-
-    def render_item_content(self, session, id):
-        link = Link.get(id)
-        return "Broker: %s:%d" % (link.host, link.port)
-
-class PeerRouteSetClose(CuminBulkActionForm):
-    def process_return(self, session):
-        branch = session.branch()
-        self.frame.show_view(branch)
-        self.page.set_frame(branch, self.frame)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_item(self, session, id):
-        bridge = Bridge.get(id)
-        action = self.app.model.route.remove
-        action.invoke(bridge)
-
-    def render_title(self, session):
-        link = self.parent.get_object(session)
-        return "Remove Route from %s:%i" % (link.host, link.port)
-
-    def render_form_heading(self, session, *args):
-        return "Remove Route"
-
-    def render_item_content(self, session, id):
-        bridge = Bridge.get(id)
-        return "<td>%s</td><td>%s</td>" % (bridge.dest, bridge.key)

Deleted: mgmt/trunk/cumin/python/cumin/brokerlink.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/brokerlink.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/brokerlink.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,176 +0,0 @@
-[PeerSet.sql]
-select
-  l.id,
-  l.host,
-  l.port,
-  l.durable,
-  c.state,
-  c.last_error
-from link as l
-join vhost as v on v.id = l.vhost_id
-left outer join link_stats as c on c.id = l.stats_curr_id
-left outer join link_stats as p on p.id = l.stats_prev_id
-{sql_where}
-{sql_orderby}
-{sql_limit}
-
-[PeerSet.count_sql]
-select count(*)
-from link as l
-join vhost as v on v.id = l.vhost_id
-{sql_where}
-
-[PeerSet.html]
-<form id="{id}" method="post" action="?">
-  <ul class="actions">
-    <li><a class="nav" href="{add_broker_link_url}">Add Broker Link</a></li>
-  </ul>
-
-  <div class="sactions">
-    <h2>Act on Selected Broker Links:</h2>
-    {close}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-        <th class="setnav" colspan="{column_count}">
-          <div class="rfloat">{page}</div>
-          {count}
-        </th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>
-
-[PeerRouteSet.sql]
-select
-  b.id,
-  b.src,
-  b.dest as exchange,
-  b.key,
-  b.tag,
-  b.excludes,
-  l.host,
-  l.port,
-  l.qmf_broker_id
-from bridge as b
-join link as l on l.id = b.link_id
-left outer join bridge_stats as c on c.id = b.stats_curr_id
-left outer join bridge_stats as p on p.id = b.stats_prev_id
-{sql_where}
-{sql_orderby}
-{sql_limit}
-
-[PeerRouteSet.count_sql]
-select count(*)
-from bridge as b
-join link as l on l.id = b.link_id
-{sql_where}
-
-[PeerRouteSet.html]
-<form id="{id}" method="post" action="?">
-  <ul class="actions">
-    <li><a class="nav" href="{add_bridge_url}">Add Route</a></li>
-  </ul>
-
-  <div class="sactions">
-    <h2>Act on Selected Routes:</h2>
-    {remove}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-        <th class="setnav" colspan="{column_count}">
-          <div class="rfloat">{page}</div>
-          {count}
-        </th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>
-
-[ExchangeRadioField.html]
-<div class="{form_field_class}">
-  <div class="rfloat">{phase}</div>
-  <div class="title">{title}</div> <div class="field_help">{field_help}</div><div class="clear_left"></div>
-  {errors}
-  <div class="inputs">{inputs}</div><div style="clear:left;"><!-- --></div>
-</div>
-
-[PeerRouteSetClose.html]
-<form id="{id}" class="mform" method="post" action="?">
-  <div class="head">
-    <h1>{title}</h1>
-  </div>
-  <div class="body">
-    <span class="legend">{form_heading}</span>
-          <table class="mobjects">
-            <thead>
-              <tr>
-                <th>Exchange</th>
-                <th>Key</th>
-              </tr>
-            </thead>
-            <tbody>{items}</tbody>
-          </table>
-    {hidden_inputs}
-  </div>
-  <div class="foot">
-    {help}
-    {submit}
-    {cancel}
-  </div>
-</form>
-<script type="text/javascript">
-  wooly.doc().elembyid("{id}").node.elements[0].focus();
-</script>
-
-[PeerRouteSetClose.item_html]
-<tr>{item_content}</tr>
-
-[BridgeAddHelpField.css]
-div#bridge_add_help span.tag1 {
-        color:red;
-}
-div#bridge_add_help span.tag2 {
-        color:green;
-}
-div#bridge_add_help p.example {
-        font-size: 0.9em;
-        color: #444444;
-}
-
-
-[BridgeAddHelpField.html]
-<div id="bridge_add_help">
-  <p>The <strong>Tag</strong> and <strong>Excludes</strong> are used to prevent a message from routing back
-    to the source broker and causing an infinite loop.</p>
-  <p>Enter a short <strong>tag</strong> that will be associated with the source exchange.
-    Then <strong>exclude</strong> any tags that were used for the destination exchanges.</p>
-  <p class="example">
-    <em>broker1</em> &lt;==&gt; <em>broker2</em> tag: <span class="tag2">tag2</span> excludes: <span class="tag1">tag1</span><br/>
-    <em>broker2</em> &lt;==&gt; <em>broker1</em> tag: <span class="tag1">tag1</span> excludes: <span class="tag2">tag2</span>
-  </p>
-</div>
-
-[PeerStatus.html]
-<div id="{id}" class="CuminStatus {color}">
-  <table>
-    <tr>
-      <th><strong>State</strong></th>
-      <td>{peer_state}</td>
-    </tr>
-    <tr>
-      <th><strong>Last Error</strong></th>
-      <td>{peer_error}</td>
-    </tr>
-  </table>
-</div>

Deleted: mgmt/trunk/cumin/python/cumin/client.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/client.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/client.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,407 +0,0 @@
-from wooly import *
-from wooly.widgets import *
-from wooly.tables import *
-from datetime import datetime
-
-from stat import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-
-strings = StringCatalog(__file__)
-
-class ConnectionSet(CuminTable, Form):
-    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)
-
-        col = self.AddressColumn(app, "addr")
-        self.add_column(col)
-
-        self.set_default_column(col)
-
-        col = self.SystemConnectionColumn(app, "sysconn")
-        self.add_column(col)
-
-        col = self.AuthIdentityColumn(app, "authid")
-        self.add_column(col)
-
-        col = self.FedLinkColumn(app, "fedlink")
-        self.add_column(col)
-
-        col = self.SentColumn(app, "sent")
-        col.alignment = "right"
-        self.add_column(col)
-
-        col = self.ReceivedColumn(app, "received")
-        col.alignment = "right"
-        self.add_column(col)
-
-        self.unit = StateSwitch(app, "unit")
-        self.unit.add_state("b", "Bytes")
-        self.unit.add_state("f", "Frames")
-        self.add_child(self.unit)
-
-        self.__phase = PhaseSwitch(app, "phase")
-        self.add_child(self.__phase)
-
-        self.__close = self.Close(app, "close")
-        self.add_child(self.__close)
-
-    def get_unit_plural(self, session):
-        return self.unit.get(session) == "b" and "Bytes" or "Frames"
-
-    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 = self.vhost.get(session)
-
-        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):
-        def render_content(self, session):
-            return "Close"
-
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            # XXX Make table a frame to elim this
-            self.parent.ids.clear(session)
-            href = self.frame.connections_close.get_href(session, ids)
-            self.page.set_redirect_url(session, href)
-
-    class AddressColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Address"
-
-        def render_content(self, session, data):
-            conn = Identifiable(data["id"])
-            href = self.frame.connection.get_href(session, conn)
-            return fmt_link(href, fmt_shorten(data["addr"]))
-
-    class SystemConnectionColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Connect Type"
-
-        def render_content(self, session, data):
-            if data['sysconn']:
-                return "System"
-            else:
-                return "Client"
-
-    class AuthIdentityColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Auth Id"
-
-    class FedLinkColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Fed Link"
-
-        def render_content(self, session, data):
-            if data['fedlink']:
-                return "Yes"
-            else:
-                return "No"
-
-    class SentColumn(NullSortColumn, FreshDataOnlyColumn):
-        def render_title(self, session, data):
-            return "%s Sent" % self.parent.get_unit_plural(session)
-
-        def get_column_key(self, session):
-            unit = self.parent.unit.get(session)
-            return unit == "b" and "bs" or "fs"
-
-        def render_value(self, session, value):
-            return fmt_rate(value, "", "sec")
-
-    class ReceivedColumn(NullSortColumn, FreshDataOnlyColumn):
-        def render_title(self, session, data):
-            return "%s Received" % self.parent.get_unit_plural(session)
-
-        def get_column_key(self, session):
-            unit = self.parent.unit.get(session)
-            return unit == "b" and "br" or "fr"
-
-        def render_value(self, session, value):
-            return fmt_rate(value, "", "sec")
-
-class ConnectionFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(ConnectionFrame, self).__init__(app, name)
-
-        self.object = ConnectionParameter(app, "id")
-        self.add_parameter(self.object)
-
-        view = ConnectionView(app, "view")
-        self.add_mode(view)
-        self.set_view_mode(view)
-
-        self.__close = ConnectionClose(app, "close", self.object)
-        self.add_mode(self.__close)
-
-        self.__sessions_detach = SessionSetDetach(app, "sessionsdetach")
-        self.add_mode(self.__sessions_detach)
-
-        self.__sessions_close = SessionSetClose(app, "sessionsclose")
-        self.add_mode(self.__sessions_close)
-
-    def show_object(self, session, conn):
-        reg = conn.vhost.broker.registration
-        self.page.main.broker.set_object(session, reg)
-
-        return super(ConnectionFrame, self).show_object(session, conn)
-
-    def show_close(self, session):
-        return self.show_mode(session, self.__close)
-
-    def show_sessions_detach(self, session):
-        return self.show_mode(session, self.__sessions_detach)
-
-    def show_sessions_close(self, session):
-        return self.show_mode(session, self.__sessions_close)
-
-# XXX get rid of this
-def doit(error, args):
-    pass
-    #print error, args
-    #print "did it!"
-
-class ConnectionClose(CuminConfirmForm):
-    def __init__(self, app, name, conn):
-        super(ConnectionClose, self).__init__(app, name)
-
-        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 = self.conn.get(session)
-
-        action = self.app.model.connection.close
-        action.invoke(conn)
-
-        self.process_cancel(session, conn)
-
-    def render_title(self, session):
-        return "Close Connection '%s'" % self.conn.get(session).address
-
-    def render_submit_content(self, session):
-        return "Yes, Close Connection '%s'" % self.conn.get(session).address
-
-    def render_cancel_content(self, session):
-        return "No, Cancel"
-
-class ConnectionSetClose(CuminBulkActionForm):
-    def process_return(self, session):
-        branch = session.branch()
-        self.frame.show_view(branch)
-        self.page.set_frame(branch, self.frame)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_item(self, session, id):
-        conn = ClientConnection.get(id)
-        action = self.app.model.connection.close
-        action.invoke(conn)
-
-    def render_title(self, session):
-        return "Close Connections"
-
-    def render_item_content(self, session, id):
-        return "Close Connection %s" % ClientConnection.get(id).address
-
-class ConnectionStatus(CuminStatus):
-    def render_frames_from(self, session, conn):
-        return self.app.model.connection.framesFromClient.rate_html(conn)
-
-    def render_frames_to(self, session, conn):
-        return self.app.model.connection.framesToClient.rate_html(conn)
-
-    def render_bytes_from(self, session, conn):
-        return self.app.model.connection.bytesFromClient.rate_html(conn)
-
-    def render_bytes_to(self, session, conn):
-        return self.app.model.connection.bytesToClient.rate_html(conn)
-
-class ConnectionView(CuminView):
-    def __init__(self, app, name):
-        super(ConnectionView, self).__init__(app, name)
-
-        status = ConnectionStatus(app, "status")
-        self.add_child(status)
-
-        self.__tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.__tabs)
-
-        self.__tabs.add_tab(ConnectionStats(app, "stats"))
-
-        self.__sessions = SessionSet(app, "sessions")
-        self.__tabs.add_tab(self.__sessions)
-
-        self.__tabs.add_tab(CuminDetails(app, "details"))
-
-    def show_sessions(self, session):
-        return self.__tabs.show_mode(session, self.__sessions)
-
-class ConnectionStats(Widget):
-    def __init__(self, app, name):
-        super(ConnectionStats, self).__init__(app, name)
-
-        self.add_child(StatSet(app, "io", "io"))
-        self.add_child(StatSet(app, "general", "general"))
-
-        chart = self.SendReceiveRateChart(app, "sendrecv")
-        self.add_child(chart)
-
-    def render_title(self, session):
-        return "Statistics"
-
-    class SendReceiveRateChart(StatValueChart):
-        def __init__(self, app, name):
-            super(ConnectionStats.SendReceiveRateChart, self).__init__(app, name)
-
-            self.stats = ("bytesFromClient", "bytesToClient")
-            self.mode = "rate"
-
-        def render_title(self, session, conn):
-            return "Bytes Sent and Received"
-
-class SessionSetDetach(CuminBulkActionForm, Frame):
-    def process_return(self, session):
-        branch = session.branch()
-        self.frame.show_view(branch).show_sessions(branch)
-        self.page.set_frame(branch, self.frame)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_item(self, session, id):
-        session_ = Session.get(id)
-        action = self.app.model.session.detach
-        action.invoke(session_)
-
-    def render_title(self, session):
-        return "Detach Sessions"
-
-    def render_item_content(self, session, id):
-        return "Detach Session '%s'" % Session.get(id).name
-
-class SessionSetClose(CuminBulkActionForm, Frame):
-    def process_return(self, session):
-        branch = session.branch()
-        self.frame.show_view(branch).show_sessions(branch)
-        self.page.set_frame(branch, self.frame)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_item(self, session, id):
-        session_ = Session.get(id)
-        action = self.app.model.session.close
-        action.invoke(session_)
-
-    def render_title(self, session):
-        return "Close Sessions"
-
-    def render_item_content(self, session, id):
-        return "Close Session '%s'" % Session.get(id).name
-
-class SessionSet(CuminTable, Form):
-    def __init__(self, app, name):
-        super(SessionSet, self).__init__(app, name)
-
-        self.ids = CheckboxIdColumn(app, "id")
-        self.add_column(self.ids)
-
-        col = self.NameColumn(app, "name")
-        self.add_column(col)
-
-        self.set_default_column(col)
-
-        col = self.ExpiresColumn(app, "expires")
-        self.add_column(col)
-
-        col = self.StatusColumn(app, "status")
-        self.add_column(col)
-
-        self.__phase = PhaseSwitch(app, "phase")
-        self.add_child(self.__phase)
-
-        self.__detach = self.Detach(app, "detach")
-        self.add_child(self.__detach)
-
-        self.__close = self.Close(app, "close")
-        self.add_child(self.__close)
-
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, conn):
-        return "Sessions %s" % fmt_count(conn.sessions.count())
-
-    def render_sql_where(self, session, conn):
-        elems = list()
-        elems.append("s.client_connection_id = %(id)r")
-        elems.append(self.__phase.get_sql_constraint(session, conn))
-        return "where %s" % " and ".join(elems)
-
-    def get_sql_values(self, session, conn):
-        return {"id": conn.id}
-
-    class Detach(FormButton):
-        def render_content(self, session):
-            return "Detach"
-
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            branch = session.branch()
-            frame = self.frame.show_sessions_detach(branch)
-            frame.ids.set(branch, ids)
-            self.page.set_frame(branch, frame)
-            self.page.set_redirect_url(session, branch.marshal())
-
-    class Close(FormButton):
-        def render_content(self, session):
-            return "Close"
-
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            branch = session.branch()
-            frame = self.frame.show_sessions_close(branch)
-            frame.ids.set(branch, ids)
-            self.page.set_frame(branch, frame)
-            self.page.set_redirect_url(session, branch.marshal())
-
-    class NameColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-    class ExpiresColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Expires"
-
-        def render_value(self, session, value):
-            return fmt_datetime(value)
-
-    class StatusColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Attached?"
-
-        def render_content(self, session, data):
-            return fmt_predicate(data["attached"])

Deleted: mgmt/trunk/cumin/python/cumin/client.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/client.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/client.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,138 +0,0 @@
-[ConnectionSet.sql]
-select
-  l.id,
-  l.system_connection as sysconn,
-  l.auth_identity as authid,
-  l.federation_link as fedlink,
-  l.address as addr,
-  (c.bytes_from_client - p.bytes_from_client)
-   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as bs,
-  case when p.bytes_from_client is null then true else false end as bs_is_null,
-  (c.frames_from_client - p.frames_from_client)
-   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as fs,
-  case when p.frames_from_client is null then true else false end as fs_is_null,
-  (c.bytes_to_client - p.bytes_to_client)
-   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as br,
-  case when p.bytes_to_client is null then true else false end as br_is_null,
-  (c.frames_to_client - p.frames_to_client)
-   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as fr,
-  case when p.frames_to_client is null then true else false end as fr_is_null,
-  c.qmf_update_time
-from client_connection as l
-left outer join client_connection_stats as c on c.id = l.stats_curr_id
-left outer join client_connection_stats as p on p.id = l.stats_prev_id
-{sql_where}
-{sql_orderby}
-{sql_limit}
-
-[ConnectionSet.count_sql]
-select count(*)
-from client_connection as l
-left outer join client_connection_stats as c on c.id = l.stats_curr_id
-{sql_where}
-
-[ConnectionSet.html]
-<form id="{id}" method="post" action="?">
-  <div class="rfloat">{phase}</div>
-
-  {unit}
-
-  <div class="sactions">
-    <h2>Act on Selected Connections:</h2>
-    {close}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-        <th class="setnav" colspan="{column_count}">
-          <div class="rfloat">{page}</div>
-          {count}
-        </th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>
-
-[ConnectionStatus.html]
-<div id="{id}" class="CuminStatus {color}">
-  <table>
-    <tr>
-      <th></th>
-      <th style="width: 35%;" class="ralign">Frames</th>
-      <th style="width: 35%;" class="ralign">Bytes</th>
-    </tr>
-    <tr>
-      <th>Sent</th>
-      <td class="ralign">{frames_from}</td>
-      <td class="ralign">{bytes_from}</td>
-    </tr>
-    <tr>
-      <th>Received</th>
-      <td class="ralign">{frames_to}</td>
-      <td class="ralign">{bytes_to}</td>
-    </tr>
-  </table>
-</div>
-
-[ConnectionStats.html]
-<table class="twocol">
-  <tbody>
-  <tr>
-    <td>
-      <h2>Input/Output</h2>
-      {io}
-
-      <h2>General</h2>
-      {general}
-    </td>
-    <td>
-      {sendrecv}
-    </td>
-  </tr>
-  </tbody>
-</table>
-
-[SessionSet.sql]
-select s.id, s.name, s.expire_time as expires, s.attached
-from session as s
-left outer join session_stats as c on c.id = s.stats_curr_id
-left outer join session_stats as p on p.id = s.stats_prev_id
-{sql_where}
-{sql_orderby}
-{sql_limit}
-
-[SessionSet.count_sql]
-select count(*)
-from session as s
-left outer join session_stats as c on c.id = s.stats_curr_id
-{sql_where}
-
-[SessionSet.html]
-<form id="{id}" method="post" action="?">
-  <div class="rfloat">{phase}</div>
-
-  <ul class="radiotabs"><li>&nbsp;</li></ul>
-
-  <div class="sactions">
-    <h2>Act on Selected Sessions:</h2>
-    {close}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-        <th class="setnav" colspan="{column_count}">
-          <div class="rfloat">{page}</div>
-          {count}
-        </th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>

Deleted: mgmt/trunk/cumin/python/cumin/collector.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/collector.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/collector.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,178 +0,0 @@
-import logging
-
-from wooly import *
-from wooly.widgets import *
-from wooly.forms import *
-from wooly.resources import *
-from wooly.tables import *
-
-from stat import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-from job import *
-
-strings = StringCatalog(__file__)
-log = logging.getLogger("cumin.collector")
-
-class CollectorSet(CuminTable, Form):
-    def __init__(self, app, name):
-        super(CollectorSet, self).__init__(app, name)
-
-        self.ids = CheckboxIdColumn(app, "id")
-        self.add_column(self.ids)
-
-        col = self.NameColumn(app, "name")
-        self.add_column(col)
-        self.set_default_column(col)
-
-        col = self.SystemColumn(app, "system")
-        self.add_column(col)
-
-        self.__start = self.StartButton(app, "start")
-        self.add_child(self.__start)
-
-        self.__stop = self.StopButton(app, "stop")
-        self.add_child(self.__stop)
-
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, collector):
-        count = self.get_item_count(session, collector)
-        return "Collectors %s" % fmt_count(count)
-
-    def render_sql_where(self, session, collector):
-        sql = "qmf_delete_time is null"
-        #sql = "((cs.qmf_update_time is null and c.qmf_update_time > now() - interval '10 minutes') or " + \
-        #    "(cs.qmf_update_time > now() - interval '10 minutes')" + \
-        #    " and qmf_delete_time is null)"
-        return "where %s" % sql
-
-    class NameColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-        def render_content(self, session, data):
-            coll = Identifiable(data["id"])
-            href = self.page.main.pool.collector.get_href(session, coll)
-            return fmt_link(href, data["name"])
-
-    class SystemColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "System"
-
-        def render_content(self, session, data):
-            id = data["system_id"]
-
-            if id:
-                sys = Identifiable(id)
-                href = self.page.main.system.get_href(session, sys)
-                return fmt_link(href, data["system_name"])
-
-    class StartButton(FormButton):
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            branch = session.branch()
-            frame = self.frame.show_colls_start(branch)
-            frame.ids.set(branch, ids)
-            self.page.set_redirect_url(session, branch.marshal())
-
-        def render_content(self, session):
-            return "Start"
-
-    class StopButton(FormButton):
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            branch = session.branch()
-            frame = self.frame.show_colls_stop(branch)
-            frame.ids.set(branch, ids)
-            self.page.set_redirect_url(session, branch.marshal())
-
-        def render_content(self, session):
-            return "Stop"
-
-class CollectorFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(CollectorFrame, self).__init__(app, name)
-
-        self.object = CollectorParameter(app, "id")
-        self.add_parameter(self.object)
-
-        view = CollectorView(app, "view")
-        self.add_mode(view)
-        self.set_view_mode(view)
-
-class CollectorStats(Widget):
-    def __init__(self, app, name):
-        super(CollectorStats, self).__init__(app, name)
-
-        self.add_child(StatSet(app, "stats", "general"))
-
-        chart = self.StackedChart(app, "utilization")
-        chart.stats = ("HostsIdle", "HostsClaimed", "HostsUnclaimed")
-        self.add_child(chart)
-
-    def render_title(self, session):
-        return "Statistics"
-
-    class StackedChart(StatStackedChart):
-        def render_title(self, session, *args):
-            return "Slot Utilization"
-
-class CollectorView(CuminView):
-    def __init__(self, app, name):
-        super(CollectorView, self).__init__(app, name)
-
-        status = self.CollectorStatus(app, "status")
-        self.add_child(status)
-
-        self.__tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.__tabs)
-
-        stats = CollectorStats(app, "stats")
-        self.__tabs.add_tab(stats)
-
-        details = CuminDetails(app, "details")
-        self.__tabs.add_tab(details)
-
-    class CollectorStatus(CuminStatus):
-        def render_title(self, session, object):
-            return "Collector Status"
-
-class CollectorStart(CuminBulkActionForm):
-    def render_title(self, session, *args):
-        return "Start Collector"
-
-    def render_form_heading(self, session, *args):
-        return ""
-
-    def render_item_content(self, session, id):
-        return "Start Collector '%s'" % Collector.get(id).Name
-
-    def process_item(self, session, item):
-        collector = Collector.get(item)
-        action = self.app.model.master.start
-        action.invoke(collector, {"subsystem": "COLLECTOR"})
-        self.process_cancel(session)
-
-class CollectorStop(CuminBulkActionForm):
-    def render_title(self, session, *args):
-        return "Stop Collector"
-
-    def render_form_heading(self, session, *args):
-        return ""
-
-    def render_item_content(self, session, id):
-        return "Stop Collector '%s'" % Collector.get(id).Name
-
-    def process_item(self, session, item):
-        collector = Collector.get(item)
-        action = self.app.model.master.stop
-        action.invoke(collector, {"subsystem": "COLLECTOR"})
-        self.process_cancel(session)

Deleted: mgmt/trunk/cumin/python/cumin/collector.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/collector.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/collector.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,55 +0,0 @@
-[CollectorSet.sql]
-select
-  c.id,
-  c.name,
-  y.id as system_id,
-  y.node_name as system_name
-from collector as c
-left outer join sysimage as y on c.system = y.node_name
-left outer join collector_stats as cs on cs.id = c.stats_curr_id
-{sql_where}
-{sql_orderby}
-{sql_limit}
-
-[CollectorSet.count_sql]
-select count(1) from collector as c
-left outer join collector_stats as cs on cs.id = c.stats_curr_id
-{sql_where}
-
-[CollectorSet.html]
-<form id="{id}" method="post" action="?">
-  <div class="sactions">
-    <h2>Act on Selected Collectors:</h2>
-    {start} {stop}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-	<th class="setnav" colspan="{column_count}">
-	  <div class="rfloat">{page}</div>
-	  {count}
-	</th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-
-  <div>{hidden_inputs}</div>
-</form>
-
-[CollectorStats.html]
-<table class="twocol">
-  <tbody>
-    <tr>
-      <td>
-        <h2>Collector Stats</h2>
-        {stats}
-      </td>
-      <td>
-    {utilization}
-      </td>
-    </tr>
-  </tbody>
-</table>

Deleted: mgmt/trunk/cumin/python/cumin/exchange.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/exchange.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/exchange.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,553 +0,0 @@
-from wooly import *
-from wooly.widgets import *
-from wooly.forms import *
-from wooly.resources import *
-
-from stat import *
-from model import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-
-strings = StringCatalog(__file__)
-
-class ExchangeInputSet(RadioInputSet):
-    def __init__(self, app, name):
-        super(ExchangeInputSet, self).__init__(app, name)
-
-        param = ExchangeParameter(app, "param")
-        self.add_parameter(param)
-        self.set_parameter(param)
-
-    def do_get_items(self, session, vhost):
-        return sorted_by(vhost.exchanges)
-
-    def render_item_value(self, session, exchange):
-        return exchange.id
-
-    def render_item_content(self, session, exchange):
-        return exchange.name or "<em>Default</em>"
-
-    def render_item_checked_attr(self, session, exchange):
-        return exchange is self.param.get(session) and "checked=\"checked\""
-
-class ExchangeSet(CuminTable, Form):
-    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)
-
-        col = self.NameColumn(app, "name")
-        self.add_column(col)
-        self.set_default_column(col)
-
-        col = self.ProducersColumn(app, "name")
-        col.alignment = "right"
-        self.add_column(col)
-
-        col = self.BindingsColumn(app, "bindings")
-        col.alignment = "right"
-        self.add_column(col)
-
-        col = self.ReceivedColumn(app, "received")
-        col.alignment = "right"
-        self.add_column(col)
-
-        col = self.RoutedColumn(app, "routed")
-        col.alignment = "right"
-        self.add_column(col)
-
-        col = self.DroppedColumn(app, "dropped")
-        col.alignment = "right"
-        self.add_column(col)
-
-        self.unit = UnitSwitch(app, "unit")
-        self.add_child(self.unit)
-
-        self.phase = PhaseSwitch(app, "phase")
-        self.add_child(self.phase)
-
-        self.__remove = self.Remove(app, "remove")
-        self.add_child(self.__remove)
-
-    def disable_exchange(self, session, data):
-        return data["name"] in ExchangeInfo.get_builtins()
-
-    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 = self.vhost.get(session)
-        return "Exchanges %s" % fmt_count(vhost.exchanges.count())
-
-    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 = self.vhost.get(session)
-        return {"id": vhost.id}
-
-    class Remove(FormButton):
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            branch = session.branch()
-            self.frame.exchanges_remove.show(branch).ids.set(branch, ids)
-            self.page.set_redirect_url(session, branch.marshal())
-
-        def render_content(self, session):
-            return "Remove"
-
-    class NameColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-        def render_content(self, session, data):
-            exchange = Identifiable(data["id"])
-            href = self.frame.exchange.get_href(session, exchange)
-            name = data["name"] or "<em>Default</em>"
-            return fmt_link(href, fmt_shorten(name))
-
-    class ProducersColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Producers"
-
-        def render_content(self, session, data):
-            return data["producers"]
-
-    class BindingsColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Bindings"
-
-        def render_content(self, session, data):
-            exchange = Identifiable(data["id"])
-            href = self.frame.exchange.get_href(session, exchange)
-            return fmt_link(href, data["bindings"])
-
-    class ReceivedColumn(NullSortColumn, FreshDataOnlyColumn):
-        def render_title(self, session, data):
-            return "%s Received" % self.parent.unit.get_brief_plural(session)
-
-        def get_column_key(self, session):
-            unit = self.parent.unit.get(session)
-            return unit == "b" and "breceived" or "mreceived"
-
-        def render_value(self, session, value):
-            return fmt_rate(value, "", "sec")
-
-    class RoutedColumn(NullSortColumn, FreshDataOnlyColumn):
-        def render_title(self, session, data):
-            return "%s Routed" % self.parent.unit.get_brief_plural(session)
-
-        def get_column_key(self, session):
-            unit = self.parent.unit.get(session)
-            return unit == "b" and "brouted" or "mrouted"
-
-        def render_value(self, session, value):
-            return fmt_rate(value, "", "sec")
-
-    class DroppedColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "%s Dropped" % self.parent.unit.get_brief_plural(session)
-
-        def get_column_key(self, session):
-            unit = self.parent.unit.get(session)
-            return unit == "b" and "bdropped" or "mdropped"
-
-class ExchangeSetRemove(CuminBulkActionForm):
-    def process_return(self, session):
-        branch = session.branch()
-        self.frame.show_view(branch)
-        self.page.set_frame(branch, self.frame)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_item(self, session, id):
-        exchange = Exchange.get(id)
-        reg = self.frame.get_object(session)
-        action = self.app.model.exchange.remove
-        action.invoke(exchange)
-
-    def render_title(self, session):
-        return "Remove Exchanges"
-
-    def render_item_content(self, session, id):
-        return "Remove Exchange '%s'" % Exchange.get(id).name
-
-class ExchangeFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(ExchangeFrame, self).__init__(app, name)
-
-        self.object = ExchangeParameter(app, "id")
-        self.add_parameter(self.object)
-
-        self.view = ExchangeView(app, "view")
-        self.add_mode(self.view)
-        self.set_view_mode(self.view)
-
-        self.remove = ExchangeRemove(app, "remove")
-        self.add_mode(self.remove)
-        self.set_remove_mode(self.remove)
-
-    def show_object(self, session, exchange):
-        reg = exchange.vhost.broker.registration
-        self.page.main.broker.set_object(session, reg)
-
-        return super(ExchangeFrame, self).show_object(session, exchange)
-
-    def render_title(self, session, exchange):
-        if exchange.name:
-            return super(ExchangeFrame, self).render_title(session, exchange)
-        else:
-            return "Default Exchange"
-
-    def render_href(self, session, exchange):
-        if exchange:
-            return super(ExchangeFrame, self).render_href(session, exchange)
-
-
-class ExchangeRemove(CuminConfirmForm):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def process_cancel(self, session, exchange):
-        branch = session.branch()
-        self.frame.show_view(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_submit(self, session, exchange):
-        reg = self.frame.frame.get_object(session)
-        action = self.app.model.exchange.remove
-        action.invoke(exchange)
-
-        branch = session.branch()
-        self.frame.frame.show_view(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def render_title(self, session, exchange):
-        return "Remove Exchange '%s'" % exchange.name
-
-    def render_submit_content(self, session, exchange):
-        return "Yes, Remove Exchange '%s'" % exchange.name
-
-    def render_cancel_content(self, session, exchange):
-        return "No, Cancel"
-
-class ExchangeStatus(CuminStatus):
-    def render_messages_received(self, session, exchange):
-        return self.app.model.exchange.msgReceives.rate_html(exchange)
-
-    def render_messages_routed(self, session, exchange):
-        return self.app.model.exchange.msgRoutes.rate_html(exchange)
-
-    def render_messages_dropped(self, session, exchange):
-        return self.app.model.exchange.msgDrops.value(exchange)
-
-    def render_bytes_received(self, session, exchange):
-        return self.app.model.exchange.byteReceives.rate_html(exchange)
-
-    def render_bytes_routed(self, session, exchange):
-        return self.app.model.exchange.byteRoutes.rate_html(exchange)
-
-    def render_bytes_dropped(self, session, exchange):
-        return self.app.model.exchange.byteDrops.value(exchange)
-
-class ExchangeView(CuminView):
-    def __init__(self, app, name):
-        super(ExchangeView, self).__init__(app, name)
-
-        status = ExchangeStatus(app, "status")
-        self.add_child(status)
-
-        self.__tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.__tabs)
-
-        self.__tabs.add_tab(ExchangeStats(app, "stats"))
-
-        self.__bindings = ExchangeBindingSet(app, "bindings")
-        self.__tabs.add_tab(self.__bindings)
-
-        self.__tabs.add_tab(CuminDetails(app, "details"))
-
-    def show_bindings(self, session):
-        return self.__tabs.show_mode(session, self.__bindings);
-
-class ExchangeBindingSet(BindingSet, Form):
-    def __init__(self, app, name):
-        super(ExchangeBindingSet, self).__init__(app, name)
-
-        self.__remove = self.Remove(app, "remove")
-        self.add_child(self.__remove)
-
-        self.set_default_column_name("q_id")
-
-    def get_visible_columns(self, session):
-        return self.get_request_visible_columns(session, ["q_id"])
-
-    def render_title(self, session, exchange):
-        return "Queue Bindings %s" % \
-            fmt_count(exchange.bindings.count())
-
-    def render_sql_where(self, session, exchange):
-        elems = list()
-        elems.append("b.exchange_id = %(id)r")
-        elems.append(self.phase.get_sql_constraint(session, exchange))
-        return "where %s" % " and ".join(elems)
-
-    class Remove(FormButton):
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            href = self.page.main.broker.bindings_remove.get_href(session, ids)
-            self.page.set_redirect_url(session, href)
-
-        def render_content(self, session):
-            return "Remove"
-
-class BindingSetRemove(CuminBulkActionForm):
-    def process_item(self, session, id):
-        binding = Binding.get(id)
-        action = self.app.model.binding.remove
-        action.invoke(binding)
-
-    def render_title(self, session):
-        return "Remove Binding"
-
-    def render_form_heading(self, session, *args):
-        return "Remove Binding between:"
-
-    def render_item_content(self, session, id):
-        binding = Binding.get(id)
-        ename = binding.exchange.name or "Default"
-        qname = binding.queue.name
-        return "Exchange: %s <i>and</i> Queue: %s" % (ename, qname)
-
-class ExchangeForm(CuminFieldForm):
-    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)
-
-        self.exchange_type = self.ExchangeTypeField(app, "exchange_type")
-        self.add_field(self.exchange_type)
-
-        self.more = MoreFieldSet(app, "more")
-        self.add_field(self.more)
-
-        self.durable = self.ExchangeDurabilityField(app, "durable")
-        self.more.add_field(self.durable)
-
-        self.sequence = self.SequenceField(app, "sequence")
-        self.more.add_field(self.sequence)
-
-        self.ive = self.IVEField(app, "ive")
-        self.more.add_field(self.ive)
-
-    class SequenceField(TwoOptionRadioField):
-        def render_title(self, session):
-            return "Insert Sequence?"
-
-        def render_field_help(self, session):
-            return "(Exchange will insert a 'qpid.msg_sequence' field in the message header)"
-
-        def render_title_1(self, session):
-            return "Insert Sequence"
-
-        def render_title_2(self, session):
-            return "No Sequence"
-
-    class IVEField(TwoOptionRadioField):
-        def render_title(self, session):
-            return "Initial Value Exchange?"
-
-        def render_field_help(self, session):
-            return "(Exchange will behave as an 'initial-value-exchange', keeping a reference to the last message forwarded and enqueuing that message to newly bound queues)"
-
-        def render_title_1(self, session):
-            return "Initial-Value-Exchange"
-
-        def render_title_2(self, session):
-            return "No IVE"
-
-    class ExchangeDurabilityField(TwoOptionRadioField):
-        def render_title(self, session):
-            return "Durable?"
-
-        def render_field_help(self, session):
-            return "(Queue is durable)"
-
-        def render_title_1(self, session):
-            return "Durable"
-
-        def render_title_2(self, session):
-            return "Transient"
-
-    class ExchangeTypeField(RadioField):
-        def __init__(self, app, name):
-            super(ExchangeForm.ExchangeTypeField, self).__init__(app, name, None)
-
-            self.param = Parameter(app, "param")
-            self.param.default = "direct"
-            self.add_parameter(self.param)
-
-            option = self.Direct(app, "direct", self.param)
-            self.add_option(option)
-
-            option = self.Topic(app, "topic", self.param)
-            self.add_option(option)
-
-            option = self.Fanout(app, "fanout", self.param)
-            self.add_option(option)
-
-            option = self.Headers(app, "headers", self.param)
-            self.add_option(option)
-
-            option = self.XML(app, "xml", self.param)
-            self.add_option(option)
-
-        def render_title(self, session):
-            return "Exchange Type"
-
-        def render_field_help(self, session):
-            return "(Type of exchange to add)"
-
-        class Direct(RadioFieldOption):
-            def render_value(self, session):
-                return "direct"
-
-            def render_title(self, session):
-                return "<em>Direct:</em> Route messages to queues by queue name"
-
-        class Topic(RadioFieldOption):
-            def render_value(self, session):
-                return "topic"
-
-            def render_title(self, session):
-                return "<em>Topic:</em> Route messages to queues by topic keyword match"
-
-        class Fanout(RadioFieldOption):
-            def render_value(self, session):
-                return "fanout"
-
-            def render_title(self, session):
-                return "<em>Fan Out:</em> Route message to all queues attached to this exchange"
-
-        class Headers(RadioFieldOption):
-            def render_value(self, session):
-                return "headers"
-
-            def render_title(self, session):
-                return "<em>Headers:</em> Route message to queues based on content of the message header"
-
-        class XML(RadioFieldOption):
-            def render_value(self, session):
-                return "xml"
-
-            def render_title(self, session):
-                return "<em>XML:</em> Route message to queues based on XML content of the message"
-
-class ExchangeAdd(ExchangeForm):
-    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):
-        errors = self.validate(session)
-
-        if errors:
-            pass
-        else:
-            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"
-
-            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):
-        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)
-
-        self.add_child(StatSet(app, "io", "io"))
-        self.add_child(StatSet(app, "general", "general"))
-
-        chart = self.ReceiveRouteDropRateChart(app, "recvroutedrop")
-        self.add_child(chart)
-
-        chart = StatValueChart(app, "producers")
-        chart.stats = ("producerCount",)
-        self.add_child(chart)
-
-    def render_title(self, session):
-        return "Statistics"
-
-    class ReceiveRouteDropRateChart(StatValueChart):
-        def __init__(self, app, name):
-            super(ExchangeStats.ReceiveRouteDropRateChart, self).__init__ \
-                (app, name)
-
-            self.stats = ("msgReceives", "msgRoutes", "msgDrops")
-            self.mode = "rate"
-
-        def render_title(self, session, exchange):
-            return "Messages Received, Routed, and Dropped"
-
-class ExchangeProducerSet(ItemSet):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, exchange):
-        return "Producers %s" % \
-            fmt_count(self.get_item_count(session, exchange))
-
-    def get_item_count(self, session, exchange):
-        return exchange.producers.count()
-
-    def do_get_items(self, session, exchange):
-        return exchange.producers
-
-    def render_item_name(self, session, producer):
-        return producer.name
-
-class ExchangeInfo(object):
-    @classmethod
-    def is_builtin(cls, exchange):
-        return exchange.name in ExchangeInfo.get_builtins()
-
-    @classmethod
-    def get_builtins(cls):
-        return ["", "amq.direct", "amq.topic", "amq.match", "amq.fanout", "qpid.management"]

Deleted: mgmt/trunk/cumin/python/cumin/exchange.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/exchange.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/exchange.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,183 +0,0 @@
-[ExchangeInputSet.item_html]
-<div class="field">
-  <input type="radio" name="{name}" value="{item_value}" tabindex="{tab_index}" {item_checked_attr}/>
-  {item_content}
-</div>
-
-[ExchangeSet.sql]
-select
-  e.id,
-  e.name,
-  c.producer_count as producers,
-  c.binding_count as bindings,
-  (c.msg_receives - p.msg_receives)
-   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as mreceived,
-  case when p.msg_receives is null then true else false end as mreceived_is_null,
-  (c.byte_receives - p.byte_receives)
-   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as breceived,
-  case when p.byte_receives is null then true else false end as breceived_is_null,
-  (c.msg_routes - p.msg_routes)
-   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as mrouted,
-  case when p.msg_routes is null then true else false end as mrouted_is_null,
-  (c.byte_routes - p.byte_routes)
-   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as brouted,
-  case when p.byte_routes is null then true else false end as brouted_is_null,
-  c.msg_drops as mdropped,
-  c.byte_drops as bdropped,
-  c.qmf_update_time
-from exchange as e
-left outer join exchange_stats as c on c.id = e.stats_curr_id
-left outer join exchange_stats as p on p.id = e.stats_prev_id
-{sql_where}
-{sql_orderby}
-{sql_limit}
-
-
-[ExchangeSet.count_sql]
-select count(*)
-from exchange as e
-left outer join exchange_stats as c on c.id = e.stats_curr_id
-{sql_where}
-
-[ExchangeSet.css]
-ul.ExchangeSet li:before {
-  content: url(resource?name=exchange-20.png);
-  vertical-align: -30%;
-  padding: 0 0.25em;
-}
-
-[ExchangeSet.html]
-<form id="{id}" method="post" action="?">
-  <ul class="actions">
-    <li><a class="nav" href="{add_exchange_url}">Add New Exchange</a></li>
-  </ul>
-
-  <div class="rfloat">{phase}</div>
-  {unit}
-
-    <div class="sactions">
-      <h2>Act on Selected Exchanges:</h2>
-      {remove}
-    </div>
-
-    <table class="mobjects">
-      <thead>
-        <tr>
-          <th class="setnav" colspan="{column_count}">
-            <div class="rfloat">{page}</div>
-            {count}
-          </th>
-        </tr>
-        <tr>{headers}</tr>
-      </thead>
-      <tbody>{items}</tbody>
-    </table>
-
-  <div>{hidden_inputs}</div>
-</form>
-
-[ExchangeSet.item_html]
-<tr>{cells}</tr>
-
-[ExchangeStatus.html]
-<div id="{id}" class="CuminStatus {color}">
-  <table>
-    <tr>
-      <th></th>
-      <th style="width: 35%;" class="ralign">Messages</th>
-      <th style="width: 35%;" class="ralign">Bytes</th>
-    </tr>
-    <tr>
-      <th>Received</th>
-      <td class="ralign">{messages_received}</td>
-      <td class="ralign">{bytes_received}</td>
-    </tr>
-    <tr>
-      <th>Routed</th>
-      <td class="ralign">{messages_routed}</td>
-      <td class="ralign">{bytes_routed}</td>
-    </tr>
-    <tr>
-      <th>Dropped</th>
-      <td class="ralign">{messages_dropped}</td>
-      <td class="ralign">{bytes_dropped}</td>
-    </tr>
-  </table>
-</div>
-
-[ExchangeBindingSet.html]
-<form id="{id}" method="post" action="?">
-
-  <div class="rfloat">{phase}</div>
-  <ul class="radiotabs"><li>&nbsp;</li></ul>
-
-  <div class="sactions">
-    <h2>Act on Selected Bindings:</h2>
-    {remove}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-        <th class="setnav" colspan="{column_count}">
-          <div class="rfloat">{page}</div>
-          {count}
-        </th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>
-
-[ExchangeBindingSet.item_html]
-<tr>{cells}</tr>
-
-[ExchangeStats.html]
-<table class="twocol">
-  <tbody>
-  <tr>
-    <td>
-      <h2>Input/Output</h2>
-      {io}
-
-      <h2>General</h2>
-      {general}
-    </td>
-    <td>
-      {recvroutedrop}
-      {producers}
-    </td>
-  </tr>
-  </tbody>
-</table>
-
-[ExchangeProducerSet.html]
-<div class="sactions">
-  <h2>Act on Selected Producers:</h2>
-  <button>Start</button>
-  <button>Stop</button>
-  <button>Throttle</button>
-</div>
-
-<table class="mobjects">
-  <tr>
-    <th><input type="checkbox"/></th>
-    <th>Name</th>
-    <th class="ralign" colspan="2">Msgs. Produced</th>
-    <th class="ralign" colspan="2">Bytes Produced</th>
-  </tr>
-
-  {items}
-</table>
-
-[ExchangeProducerSet.item_html]
-<tr>
-  <td><input type="checkbox"/></td>
-  <td>{item_name}</td>
-  <td class="ralign">{item_messages_produced_rate}</td>
-  <td class="ralign">{item_messages_produced}</td>
-  <td class="ralign">{item_bytes_produced_rate}</td>
-  <td class="ralign">{item_bytes_produced}</td>
-</tr>

Added: mgmt/trunk/cumin/python/cumin/grid/__init__.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/__init__.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/__init__.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1 @@
+from main import *

Copied: mgmt/trunk/cumin/python/cumin/grid/collector.py (from rev 3256, mgmt/trunk/cumin/python/cumin/collector.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/collector.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/collector.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,177 @@
+import logging
+
+from wooly import *
+from wooly.widgets import *
+from wooly.forms import *
+from wooly.resources import *
+from wooly.tables import *
+from cumin.stat import *
+from cumin.widgets import *
+from cumin.parameters import *
+from cumin.formats import *
+from cumin.util import *
+
+from job import *
+
+strings = StringCatalog(__file__)
+log = logging.getLogger("cumin.grid.collector")
+
+class CollectorSet(CuminTable, Form):
+    def __init__(self, app, name):
+        super(CollectorSet, self).__init__(app, name)
+
+        self.ids = CheckboxIdColumn(app, "id")
+        self.add_column(self.ids)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+        self.set_default_column(col)
+
+        col = self.SystemColumn(app, "system")
+        self.add_column(col)
+
+        self.__start = self.StartButton(app, "start")
+        self.add_child(self.__start)
+
+        self.__stop = self.StopButton(app, "stop")
+        self.add_child(self.__stop)
+
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, collector):
+        count = self.get_item_count(session, collector)
+        return "Collectors %s" % fmt_count(count)
+
+    def render_sql_where(self, session, collector):
+        sql = "qmf_delete_time is null"
+        #sql = "((cs.qmf_update_time is null and c.qmf_update_time > now() - interval '10 minutes') or " + \
+        #    "(cs.qmf_update_time > now() - interval '10 minutes')" + \
+        #    " and qmf_delete_time is null)"
+        return "where %s" % sql
+
+    class NameColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+        def render_content(self, session, data):
+            coll = Identifiable(data["id"])
+            href = self.page.main.grid.pool.collector.get_href(session, coll)
+            return fmt_link(href, data["name"])
+
+    class SystemColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "System"
+
+        def render_content(self, session, data):
+            id = data["system_id"]
+
+            if id:
+                sys = Identifiable(id)
+                href = self.page.main.inventory.system.get_href(session, sys)
+                return fmt_link(href, data["system_name"])
+
+    class StartButton(FormButton):
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            branch = session.branch()
+            frame = self.frame.show_colls_start(branch)
+            frame.ids.set(branch, ids)
+            self.page.set_redirect_url(session, branch.marshal())
+
+        def render_content(self, session):
+            return "Start"
+
+    class StopButton(FormButton):
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            branch = session.branch()
+            frame = self.frame.show_colls_stop(branch)
+            frame.ids.set(branch, ids)
+            self.page.set_redirect_url(session, branch.marshal())
+
+        def render_content(self, session):
+            return "Stop"
+
+class CollectorFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(CollectorFrame, self).__init__(app, name)
+
+        self.object = CollectorParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.view = CollectorView(app, "view")
+        self.add_mode(self.view)
+
+class CollectorStats(Widget):
+    def __init__(self, app, name):
+        super(CollectorStats, self).__init__(app, name)
+
+        self.add_child(StatSet(app, "stats", "general"))
+
+        chart = self.StackedChart(app, "utilization")
+        chart.stats = ("HostsIdle", "HostsClaimed", "HostsUnclaimed")
+        self.add_child(chart)
+
+    def render_title(self, session):
+        return "Statistics"
+
+    class StackedChart(StatStackedChart):
+        def render_title(self, session, *args):
+            return "Slot Utilization"
+
+class CollectorView(CuminView):
+    def __init__(self, app, name):
+        super(CollectorView, self).__init__(app, name)
+
+        status = self.CollectorStatus(app, "status")
+        self.add_child(status)
+
+        self.__tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.__tabs)
+
+        stats = CollectorStats(app, "stats")
+        self.__tabs.add_tab(stats)
+
+        details = CuminDetails(app, "details")
+        self.__tabs.add_tab(details)
+
+    class CollectorStatus(CuminStatus):
+        def render_title(self, session, object):
+            return "Collector Status"
+
+class CollectorStart(CuminBulkActionForm):
+    def render_title(self, session, *args):
+        return "Start Collector"
+
+    def render_form_heading(self, session, *args):
+        return ""
+
+    def render_item_content(self, session, id):
+        return "Start Collector '%s'" % Collector.get(id).Name
+
+    def process_item(self, session, item):
+        collector = Collector.get(item)
+        action = self.app.model.master.start
+        action.invoke(collector, {"subsystem": "COLLECTOR"})
+        self.process_cancel(session)
+
+class CollectorStop(CuminBulkActionForm):
+    def render_title(self, session, *args):
+        return "Stop Collector"
+
+    def render_form_heading(self, session, *args):
+        return ""
+
+    def render_item_content(self, session, id):
+        return "Stop Collector '%s'" % Collector.get(id).Name
+
+    def process_item(self, session, item):
+        collector = Collector.get(item)
+        action = self.app.model.master.stop
+        action.invoke(collector, {"subsystem": "COLLECTOR"})
+        self.process_cancel(session)


Property changes on: mgmt/trunk/cumin/python/cumin/grid/collector.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/grid/collector.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/collector.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/collector.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/collector.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,53 @@
+[CollectorSet.sql]
+select
+  c.id,
+  c.name,
+  y.id as system_id,
+  y.node_name as system_name
+from collector as c
+left outer join sysimage as y on c.system = y.node_name
+left outer join collector_stats as cs on cs.id = c.stats_curr_id
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[CollectorSet.count_sql]
+select count(1) from collector as c
+left outer join collector_stats as cs on cs.id = c.stats_curr_id
+{sql_where}
+
+[CollectorSet.html]
+<form id="{id}" method="post" action="?">
+  <div class="sactions">
+    <h2>Act on Selected Collectors:</h2>
+    {start} {stop}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+	<th class="setnav" colspan="{column_count}">
+	  <div class="rfloat">{page}</div>
+	  {count}
+	</th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+
+  <div>{hidden_inputs}</div>
+</form>
+
+[CollectorStats.html]
+<table class="twocol">
+  <tbody>
+    <tr>
+      <td>
+        <h2>Collector Stats</h2>
+        {stats}
+      </td>
+      <td>{utilization}</td>
+    </tr>
+  </tbody>
+</table>


Property changes on: mgmt/trunk/cumin/python/cumin/grid/collector.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/grid/job.py (from rev 3256, mgmt/trunk/cumin/python/cumin/job.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/job.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/job.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,1403 @@
+import logging
+from wooly import *
+from wooly.widgets import *
+from wooly.forms import *
+from wooly.resources import *
+from wooly.tables import *
+from time import time
+from cumin.widgets import *
+from cumin.parameters import *
+from cumin.stat import *
+from cumin.formats import *
+from cumin.util import *
+
+strings = StringCatalog(__file__)
+log = logging.getLogger("cumin.job")
+
+class JobSet(CuminTable, Form):
+    def __init__(self, app, name):
+        super(JobSet, self).__init__(app, name)
+
+        self.ids = CheckboxIdColumn(app, "id")
+        self.add_column(self.ids)
+
+        col = self.CustomIdColumn(app, "custom_id")
+        self.add_column(col)
+        self.set_default_column(col)
+
+        col = self.GlobalJobIdColumn(app, "global_job_id")
+        col.visible = False
+        self.add_column(col)
+
+        col = self.CommandColumn(app, "cmd")
+        self.add_column(col)
+
+        col = self.AccountingGroupColumn(app, "agroup")
+        col.visible = False
+        self.add_column(col)
+
+        col = self.SchedulerColumn(app, "scheduler")
+        col.visible = False
+        self.add_column(col)
+
+        col = self.SubmitterColumn(app, "submitter")
+        col.visible = False
+        self.add_column(col)
+
+        col = self.ClusterIdColumn(app, "cluster_id")
+        col.alignment = "right"
+        col.visible = False
+        self.add_column(col)
+
+        col = self.ConcurrencyLimitsColumn(app, "concurrency_limits")
+        #col.visible = False
+        self.add_column(col)
+
+        col = self.CustomGroupColumn(app, "custom_group")
+        col.visible = False
+        self.add_column(col)
+
+        col = self.CustomPriorityColumn(app, "custom_priority")
+        col.visible = False
+        self.add_column(col)
+
+        col = self.StatusColumn(app, "job_status")
+        self.add_column(col)
+
+        col = self.TitleColumn(app, "title")
+        col.visible = False
+        self.add_column(col)
+
+        col = self.ArgsColumn(app, "args")
+        col.alignment = "right"
+        col.visible = False
+        self.add_column(col)
+
+        self.phase = JobStatusSwitch(app, "phase")
+        self.add_child(self.phase)
+
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def get_phase_sql(self, session, phase=None):
+        return self.phase.get_sql_constraint(session, phase)
+
+    def get_phase_title(self, session):
+        state = self.phase.get(session)
+        return self.phase.get_title(state)
+
+    def render_sql_where(self, session, *args):
+        phase = len(args) > 1 and args[1] or None
+        elems = list()
+        elems.append(self.get_phase_sql(session, phase))
+        elems.append("s.pool = %(pool)s")
+        return "where %s" % " and ".join(elems)
+
+    def get_sql_values(self, session, *args):
+        pool = args[0]
+        return {"pool": pool.id}
+
+    class ArgsColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Arguments"
+
+    class ClusterIdColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Cluster Id"
+
+    class ConcurrencyLimitsColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Limits"
+
+    class CustomGroupColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Job Group"
+
+        def render_content(self, session, data):
+            name = data[self.name]
+
+            if name:
+                group = Identifiable(name)
+                href = self.page.main.grid.pool.job_group.get_href \
+                    (session, group)
+                return fmt_link(href, fmt_shorten(name, 12, 3))
+
+    class CustomIdColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "ID"
+
+        def render_content(self, session, data):
+            id = data[self.name]
+
+            if id:
+                job = Identifiable(data["id"])
+                href = self.page.main.grid.pool.job.get_href(session, job)
+                return fmt_link(href, fmt_shorten(id, 12, 3))
+
+    class CustomPriorityColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Custom Priority"
+
+    class GlobalJobIdColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Global Job Id"
+
+        def render_content(self, session, data):
+            id = data["id"]
+
+            if id:
+                job = Identifiable(data["id"])
+                href = self.frame.job.get_href(session, job)
+                content = fmt_shorten(data[self.name], 12, 3)
+                return fmt_link(href, content)
+
+    class StatusColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Status"
+
+        def render_content(self, session, data):
+            stat = data["job_status"]
+            return JobStatusInfo.get_status_string(stat)
+
+    class AccountingGroupColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Accounting Group"
+
+    class SubmitterColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Submitter"
+
+        def render_content(self, session, data):
+            name = data["submitter"]
+
+            if name:
+                sub = Identifiable(data["submitter_id"])
+                href = self.page.main.grid.pool.submitter.get_href \
+                    (session, sub)
+                return fmt_link(href, fmt_shorten(name))
+
+    class SchedulerColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Scheduler"
+
+        def render_content(self, session, data):
+            name = data["scheduler"]
+
+            if name:
+                sched = Identifiable(data["scheduler_id"])
+                href = self.page.main.grid.pool.scheduler.get_href \
+                    (session, sched)
+                return fmt_link(href, fmt_shorten(name))
+
+    class CommandColumn(ItemTableColumn):
+        def render_title(self, session, data):
+            return "Command"
+
+        def render_content(self, session, data):
+            return fmt_shorten(data[self.name], 0, 16)
+
+    class TitleColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Title"
+
+class TopJobSet(TopTable):
+    def __init__(self, app, name):
+        super(TopJobSet, self).__init__(app, name)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+
+        self.set_default_column(col)
+
+        col = self.DurationColumn(app, "name")
+        col.alignment = "right"
+        self.add_column(col)
+
+    class NameColumn(TopTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+        def render_content(self, session, data):
+            pool = Identifiable(data["pool"])
+            job = Identifiable(data["id"])
+
+            branch = session.branch()
+            self.page.main.grid.pool.object.set(session, pool)
+            self.page.main.grid.pool.job.object.set(session, job)
+            self.page.main.grid.pool.job.show(session)
+            return fmt_link(branch.marshal(), fmt_shorten(data["name"]))
+
+    class DurationColumn(TopTableColumn):
+        def render_title(self, session, data):
+            return "Duration"
+
+        def render_content(self, session, data):
+            since = data["q_date"]
+            return fmt_duration(time() - secs(since))
+
+class JobTab(JobSet):
+    def __init__(self, app, name):
+        super(JobTab, self).__init__(app, name)
+
+        self.__remove = JobRemoveButton(app, "remove")
+        self.add_child(self.__remove)
+
+        self.__hold = JobHoldButton(app, "hold")
+        self.add_child(self.__hold)
+
+        self.__release = JobReleaseButton(app, "release")
+        self.add_child(self.__release)
+
+        self.job_search = self.JobSearch(app, "job_search")
+        self.add_child(self.job_search)
+
+    def find_job(self, session):
+        search_term = self.job_search.get(session)
+
+        if search_term:
+            object = self.frame.get_object(session)
+            rows = self.find_item(session, object)
+
+            if rows:
+                try:
+                    first = rows[0]
+                    job = Identifiable(first["id"])
+                    href = self.page.main.grid.pool.job.get_href(session, job)
+                    self.page.set_redirect_url(session, href)
+                except:
+                    self.job_search.set_not_found(session, search_term)
+            else:
+                self.job_search.set_not_found(session, search_term)
+
+            self.job_search.set(session, None)
+
+    def render_find_sql_where(self, session, *args):
+        return "j.custom_id = %(custom_id)s"
+
+    def get_find_sql_values(self, session, pool):
+        return {"custom_id": self.job_search.get(session)}
+        #return {"custom_id": self.job_search.get(session), "pool": pool.id}
+
+    def get_full_item_count(self, session, *args):
+        # request item count will phase=="a"
+        new_args = (args[0], "a")
+        return self.get_item_count(session, *new_args)
+
+    def get_visible_columns(self, session):
+        return self.get_request_visible_columns(session, ["custom_group", "scheduler", "submitter"])
+
+    def render_count(self, session, *args):
+        count = self.get_item_count(session, *args)
+        phase = self.get_phase_title(session)
+        if phase == "All":
+            phase = ""
+        return "%i %s %s" % (count, phase, count == 1 and "Job" or "Jobs")
+
+    class JobSearch(StringInput):
+        """ displays the input box and button used to search for job id """
+
+        def __init__(self, app, name):
+            super(JobTab.JobSearch, self).__init__(app, name)
+
+            self.__go = self.JobSearchButton(app, "go")
+            self.add_child(self.__go)
+
+            self.not_found = Attribute(app, "error")
+            self.add_attribute(self.not_found)
+
+        def set_not_found(self, session, value):
+            self.not_found.set(session, value)
+
+        def render_search_prompt(self, session):
+            not_found = self.not_found.get(session)
+            return not_found and "%s Not Found" % escape_entity(not_found) or self.render_search_default_prompt(session)
+
+        def render_search_default_prompt(self, session):
+            return "Enter Job ID"
+
+        def render_search_class(self, session):
+            return self.not_found.get(session) and "search_error" or " "
+
+        def find_job(self, session):
+            self.parent.find_job(session)
+
+        class JobSearchButton(FormButton):
+            def process_submit(self, session):
+                self.parent.find_job(session)
+
+            def render_content(self, session):
+                return "Go"
+
+from cumin.inventory.system import SystemFrame, SystemSet
+
+class JobGroupFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(JobGroupFrame, self).__init__(app, name)
+
+        self.object = JobGroupParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.view = JobGroupView(app, "view")
+        self.add_mode(self.view)
+
+        self.jobs_hold = JobSetHold(app, "jobshold")
+        self.add_mode(self.jobs_hold)
+
+        self.jobs_release = JobSetRelease(app, "jobsrelease")
+        self.add_mode(self.jobs_release)
+
+        self.jobs_remove = JobSetRemove(app, "jobsremove")
+        self.add_mode(self.jobs_remove)
+
+        self.system = SystemFrame(app, "system")
+        self.add_mode(self.system)
+
+class JobGroupView(CuminView):
+    def __init__(self, app, name):
+        super(JobGroupView, self).__init__(app, name)
+
+        summary = CuminSummary(app, "summary")
+        self.add_child(summary)
+
+        status = JobGroupStatus(app, "status")
+        self.add_child(status)
+
+        self.__tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.__tabs)
+
+        self.__tabs.add_tab(JobGroupStats(app, "stats"))
+        self.__tabs.add_tab(JobGroupJobSet(app, "jobs"))
+        self.__tabs.add_tab(JobGroupSystemSet(app, "systems"))
+        #self.__tabs.add_tab(CuminDetails(app, "details"))
+
+class JobGroupStats(Widget):
+    def __init__(self, app, name):
+        super(JobGroupStats, self).__init__(app, name)
+
+        stats = JobGroupStatSet(app, "general", "general")
+        self.add_child(stats)
+
+    def render_title(self, session):
+        return "Statistics"
+
+class JobGroupStatSet(StatSet):
+    def __init__(self, app, name, category):
+        super(JobGroupStatSet, self).__init__(app, name, category)
+
+        self.jobs = Attribute(app, "jobs")
+        self.add_attribute(self.jobs)
+
+    def process(self, session):
+        group = self.frame.get_args(session)[0]
+        if group:
+            where_group = "custom_group = '%s'" % group.get_id()
+            value = Job.select(where_group).count()
+            self.jobs.set(session, value)
+        super(JobGroupStatSet, self).process(session)
+
+    def render_rate_text(self, session, args):
+        return "Percentage"
+
+    def render_item_name(self, session, args):
+        stat, object = args
+        return stat.name
+
+    def render_item_value(self, session, args):
+        stat, group = args
+        if stat.name == "Jobs":
+            return self.jobs.get(session)
+        else:
+            state = stat.name
+            value = self.get_value(group, state)
+        return value
+
+    def get_value(self, group, state):
+        where_group = "custom_group = '%s' \
+            and job_status = %i" % (group.get_id(),
+                                    JobStatusInfo.get_status_int(state))
+        return Job.select(where_group).count()
+
+    def render_item_rate(self, session, args):
+        stat, group = args
+        jobs = self.jobs.get(session)
+        state = stat.name
+        if stat.name == "Jobs":
+            value = jobs
+        else:
+            value = self.get_value(group, state)
+        percent = (value*1.0) / (jobs*1.0) * 100.0
+        return jobs and "%2.1f" % percent or "-"
+
+class JobRemoveButton(FormButton):
+    def process_submit(self, session):
+        ids = self.parent.ids.get(session)
+        self.parent.ids.clear(session)
+
+        href = self.frame.jobs_remove.get_href(session, ids)
+        self.page.set_redirect_url(session, href)
+
+    def render_content(self, session):
+        return "Remove"
+
+    def render_disabled_attr(self, session, *args):
+        phase = self.parent.phase.get(session)
+        return phase == "d" and "disabled=\"disabled\"" or None
+
+    def render_class(self, session, *args):
+        phase = self.parent.phase.get(session)
+        return phase == "d" and "disabled" or "enabled"
+
+class JobHoldButton(FormButton):
+    def process_submit(self, session):
+        ids = self.parent.ids.get(session)
+        self.parent.ids.clear(session)
+
+        href = self.frame.jobs_hold.get_href(session, ids)
+        self.page.set_redirect_url(session, href)
+
+    def render_content(self, session):
+        return "Hold"
+
+    def render_disabled_attr(self, session, *args):
+        phase = self.parent.phase.get(session)
+        return (phase == "h" or phase == "d") and "disabled=\"disabled\"" or None
+
+    def render_class(self, session, *args):
+        phase = self.parent.phase.get(session)
+        return (phase == "h" or phase == "d") and "disabled" or "enabled"
+
+class JobReleaseButton(FormButton):
+    def process_submit(self, session):
+        ids = self.parent.ids.get(session)
+        self.parent.ids.clear(session)
+
+        href = self.frame.jobs_release.get_href(session, ids)
+        self.page.set_redirect_url(session, href)
+
+    def render_content(self, session):
+        return "Release"
+
+    def render_disabled_attr(self, session, *args):
+        phase = self.parent.phase.get(session)
+        return (phase == "r" or phase == "d") and "disabled=\"disabled\"" or None
+
+    def render_class(self, session, *args):
+        phase = self.parent.phase.get(session)
+        return (phase == "r" or phase == "d") and "disabled" or "enabled"
+
+class JobGroupJobSet(JobTab):
+    def __init__(self, app, name):
+        super(JobGroupJobSet, self).__init__(app, name)
+
+        self.__remove = JobRemoveButton(app, "remove")
+        self.add_child(self.__remove)
+
+        self.__hold = JobHoldButton(app, "hold")
+        self.add_child(self.__hold)
+
+        self.__release = JobReleaseButton(app, "release")
+        self.add_child(self.__release)
+
+    def get_visible_columns(self, session):
+        return self.get_request_visible_columns(session, ["scheduler", "submitter"])
+
+    def render_title(self, session, group):
+        where_group = "custom_group = '%s'" % group.get_id()
+        return "Jobs %s" % fmt_count(Job.select(where_group).count())
+
+    def render_sql_where(self, session, group):
+        phase_sql = self.get_phase_sql(session)
+        group_sql = "j.custom_group = '%s'" % group.get_id()
+        return "where %s" % " and ".join([phase_sql, group_sql])
+
+    def render_count(self, session, *args):
+        str = super(JobGroupJobSet, self).render_count(session, *args)
+        return "%s in Job Group '%s'" % (str, args[0].id)
+
+class JobGroupStatus(CuminStatus):
+    def render_color(self, session, job_group):
+        #return JobStatusInfo.get_status_color(job.JobStatus)
+        return "green"
+
+    def render_job_status(self, session, job_group):
+        #return JobStatusInfo.get_status_string(job.JobStatus)
+        return "Status"
+
+class JobGroupSystemSet(SystemSet):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_sql_where(self, session, group):
+        subquery = """
+            select 1
+            from slot as l
+            join job as j on j.custom_id = l.job_id
+            where j.custom_group = %(id)s and l.system = s.node_name
+        """
+
+        return "where exists (%s)" % subquery
+
+    def get_sql_values(self, session, group):
+        return {"id": group.id}
+
+class JobFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(JobFrame, self).__init__(app, name)
+
+        self.object = JobParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.view = JobView(app, "view")
+        self.add_mode(self.view)
+
+        self.__edit_ads = JobAdsEditor(app, "editads")
+        self.add_mode(self.__edit_ads)
+
+        self.__system = SystemFrame(app, "system")
+        self.add_mode(self.__system)
+
+    def show_ads_edit(self, session):
+        self.page.set_frame(session, self.__edit_ads)
+        return self.__edit_ads.show(session)
+
+    def show_job_group(self, session, jobgroup):
+        self.__job.set_object(session, jobgroup)
+        self.page.set_frame(session, self.__job)
+        self.__job.set_switch(session, "group")
+        return self.__job.show(session)
+
+    def show_system(self, session, system):
+        frame = self.__system.show(session)
+        frame.set_object(session, system)
+        return self.page.set_frame(session, frame)
+
+
+class JobView(CuminView):
+    def __init__(self, app, name):
+        super(JobView, self).__init__(app, name)
+
+        summary = CuminSummary(app, "summary")
+        self.add_child(summary)
+
+        status = JobStatus(app, "status")
+        self.add_child(status)
+
+        self.__tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.__tabs)
+
+        self.__tabs.add_tab(JobAdsViewer(app, "jobads"))
+        self.__tabs.add_tab(JobOutput(app, "output"))
+        self.__tabs.add_tab(JobSystemSet(app, "systems"))
+        self.__tabs.add_tab(CuminDetails(app, "details"))
+
+class JobSystemSet(SystemSet):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_sql_where(self, session, job):
+        return """
+            where exists
+              (select 1
+               from slot
+               where system = s.node_name and job_id = %(id)s)
+        """
+
+    def get_sql_values(self, session, job):
+        return {"id": "%i.%i" % (job.ClusterId, job.ProcId)}
+
+class JobAdsSet(PropertySet):
+    def __init__(self, app, name):
+        super(JobAdsSet, self).__init__(app, name, )
+
+        self.types = {0: "expression",
+                      1: "integer",
+                      2: "float",
+                      3: "string"}
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def do_get_items(self, session, job):
+        items = self.items.get(session)
+        if not items:
+            items = self.gen_items(session, job)
+            # cache the items
+            self.items.set(session, items)
+
+        return items
+
+    def get_raw_ads(self, session, job):
+        action = self.app.model.job.getad
+        return action.do_invoke(job)
+
+    def gen_items(self, session, job):
+        job_ads = self.get_raw_ads(session, job)
+
+        cls = self.app.model.get_class_by_object(job)
+        return [self.gen_item(x, job_ads[x]["VALUE"], cls, dtype=self.types[job_ads[x]["TYPE"]]) for x in job_ads]
+        # list of dictionaries
+        # each disctionary has:
+        # name:, value:, type: [, error:] [, property:] [,path:]
+        #return [self.gen_item(x, job_ads[x], cls) for x in job_ads]
+#
+
+    def gen_item(self, name, value, cls, path=None, dtype=None, error=None, orig=None):
+        """ Generate a dict with name, value, type, error, path, property, orig
+
+            This is called with raw GetAd data and with processed data from
+            a form submit. With raw data, only the name and value will be present.
+            With form data, we might have a path, dtype, or error. dtype is the
+            data type that was remembered from the raw data.
+        """
+
+        idict = dict()
+        idict["name"] = name
+        idict["value"] = value
+        idict["orig"] = value
+        idict["type"] = dtype
+        if dtype == "string":
+            idict["value"] = self.strip_string_quotes(value)
+        if orig:
+            idict["orig"] = orig
+        if error:
+            if "error" in error:
+                idict["error"] = error["error"]
+
+        if name in cls.ad_properties_by_name:
+            idict["property"] = cls.ad_properties_by_name[name]
+        if path:
+            idict["path"] = path
+        return idict
+
+    def strip_string_quotes(self, value):
+        dvalue = value
+        if value:
+            if value[:1] == "\"" and value[-1:] ==  "\"":
+                dvalue = value[1:-1]
+        return dvalue
+
+class JobPropertyRenderer(TemplateRenderer):
+    def render_title(self, session, item):
+        title = item["name"]
+        if "property" in item:
+            property = item["property"]
+            if property.title:
+                title = property.get_title(session)
+        return escape_amp(title)
+
+    def render_value(self, session, item):
+        value = item["value"]
+        if "property" in item:
+            property = item["property"]
+            if property.renderer:
+                value = property.renderer(session, value)
+        ret = escape_entity(str(value))
+        return self.insert_breaks(ret)
+
+    def insert_breaks(self, value):
+        subwords = list()
+        snippets = parse(value, begin_delim="&", end_delim=";")
+        for snippet in snippets:
+            while len(snippet) > 40:
+                subwords.append(snippet[:40])
+                snippet = snippet[40:]
+            subwords.append(snippet)
+
+        return "&#8203;".join(subwords)
+
+    def render_inline_help(self, session, item):
+        if "property" in item:
+            property = item["property"]
+            return property.description
+
+class JobAdsViewer(JobAdsSet):
+    def __init__(self, app, name):
+        super(JobAdsViewer, self).__init__(app, name)
+
+        self.group_tmpl = Template(self, "group_html")
+        self.item_renderer = JobPropertyRenderer(self, "property_html")
+
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, job):
+        return "Attributes"
+
+    def do_get_items(self, session, args):
+        job = args[0]
+        group = args[1]
+        group_items = list()
+        if job:
+            all_items = super(JobAdsViewer, self).do_get_items(session, job)
+            for item in all_items:
+                if "property" in item:
+                    property = item["property"]
+                    item_group = property.group
+                else:
+                    item_group = "Other"
+                if item_group == group:
+                    group_items.append(item)
+
+        return group_items
+
+    def render_properties(self, session, *args):
+        items = self.do_get_items(session, *args)
+        writer = Writer()
+
+        for item in items:
+            self.item_renderer.render(writer, session, item)
+
+        return writer.to_string()
+
+    def render_edit_ads_url(self, session, job):
+        branch = session.branch()
+        self.frame.show_ads_edit(branch)
+        return branch.marshal()
+
+    def render_groups(self, session, job):
+        groups = self.app.model.get_ad_groups()
+        writer = Writer()
+        for group in groups:
+            self.group_tmpl.render(writer, session, (job, group,))
+        return writer.to_string()
+
+    def render_group_name(self, session, args):
+        return args[1]
+
+class JobAdsEditor(CuminForm, JobAdsViewer):
+    def __init__(self, app, name):
+        super(JobAdsEditor, self).__init__(app, name)
+
+        # the parameter that will hold all the field values
+        self.ads = DictParameter(app, "params")
+        self.add_parameter(self.ads)
+
+        self.item_renderer = EditablePropertyRenderer(self, "property_html")
+
+    def do_get_items(self, session, args):
+        job = args[0]
+        group = args[1]
+        cls = self.app.model.get_class_by_object(job)
+        ads = self.ads.get(session)
+        if len(ads):
+            return [self.gen_item(x, ads[x]["value"], cls, path=self.ads.path,
+                                  dtype=ads[x]["type"], error=ads[x], orig=ads[x]["orig"]) for x in ads
+                                  if self.is_group(x, cls, group)]
+        else:
+            items = super(JobAdsEditor, self).do_get_items(session, args)
+            for item in items:
+                item["path"] = self.ads.path
+            return items
+
+    def is_group(self, name, cls, group):
+        if name in cls.ad_properties_by_name:
+            property = cls.ad_properties_by_name[name]
+            item_group = property.group
+        else:
+            item_group = "Other"
+        return item_group == group
+
+    def process_cancel(self, session, job):
+        branch = session.branch()
+        self.ads.set(branch, None) # otherwise url is too long
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_submit(self, session, job):
+        ads = self.ads.get(session)
+        errors = False
+
+        just_ads = dict()
+        for field in ads:
+            try:
+                fval = ads[field]["value"]
+            except KeyError:
+                ads[field]["value"] = ""
+                fval = ""
+            ftype = ads[field]["type"]
+            if ftype == "integer":
+                try:
+                    fval = int(fval)
+                except:
+                    ads[field]["error"] = "Integer value expected"
+                    errors = True
+            elif ftype == "float":
+                try:
+                    fval = float(fval)
+                except:
+                    ads[field]["error"] = "Floating point value expected"
+                    errors = True
+            elif ftype == "string":
+                fval = "\"%s\"" % fval
+            else:
+                fval = unicode(fval)
+            if "orig" in ads[field]:
+                orig = ads[field]["orig"]
+                if ftype == "integer":
+                    orig = int(orig)
+                elif ftype == "float":
+                    orig = float(orig)
+                if fval != orig:
+                    just_ads[unicode(field)] = fval
+
+        if not errors:
+            for field in just_ads:
+                action = self.app.model.job.setattribute
+                action.invoke(job, [field, just_ads[field]])
+            self.process_cancel(session, job)
+
+class JobOutput(Form):
+    def __init__(self, app, name):
+        super(JobOutput, self).__init__(app, name)
+
+        self.which_file = self.FileSwitch(app, "file")
+        self.add_child(self.which_file)
+
+        self.first_last = self.FLSwitch(app, "first_last")
+        self.add_child(self.first_last)
+
+        self.__fetch = self.FetchButton(app, "refresh")
+        self.add_child(self.__fetch)
+
+        self.ads = JobAdsSet(app, "ads")
+        self.add_child(self.ads)
+
+        self.out_file = Parameter(app, "out")
+        self.add_parameter(self.out_file)
+
+        self.err_file = Parameter(app, "err")
+        self.add_parameter(self.err_file)
+
+        self.user_file = Parameter(app, "user")
+        self.add_parameter(self.user_file)
+
+        self.output = self.OutputFile(app, "job_output")
+        self.add_child(self.output)
+
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, *args):
+        return "Output"
+
+    def render(self, session, *args):
+        out_file = self.out_file.get(session)
+        err_file = self.err_file.get(session)
+        user_file = self.user_file.get(session)
+        if not out_file:
+            job = self.frame.get_args(session)[0]
+            items = self.ads.get_raw_ads(session, job)
+            out_file = err_file = user_file = None
+            if "Out" in items:
+                out_file = items["Out"]["VALUE"]
+            if "Err" in items:
+                err_file = items["Err"]["VALUE"]
+            if "UserLog" in items:
+                user_file = items["UserLog"]["VALUE"]
+
+            # strip any double quotes surrounding file names
+            out_file = self.ads.strip_string_quotes(out_file)
+            err_file = self.ads.strip_string_quotes(err_file)
+            user_file = self.ads.strip_string_quotes(user_file)
+
+            # remember the file names so we don't need to reget them
+            self.out_file.set(session, out_file)
+            self.err_file.set(session, err_file)
+            self.user_file.set(session, user_file)
+
+        # set title for radiotab so mouseover will display file name
+        self.which_file.set_file_name(session, "o", out_file)
+        self.which_file.set_file_name(session,"e", err_file)
+        self.which_file.set_file_name(session,"u", user_file)
+
+        if self.which_file.is_bad(out_file):
+            self.which_file.disable(session, "o")
+        if self.which_file.is_bad(err_file):
+            self.which_file.disable(session, "e")
+        if self.which_file.is_bad(user_file):
+            self.which_file.disable(session, "u")
+
+        return super(JobOutput, self).render(session, *args)
+
+    def render_loading(self, session, *args):
+        file = self.which_file.get_current_file_name(session)
+        return file and "loading..." or "Output, Error, and UserLog file names are invalid."
+
+    def get_file_args(self, session):
+        first_last = self.first_last.get(session)
+        if first_last == "t":
+            start = -2048
+            end = 0
+        else:
+            start = 0
+            end = 2048
+        file = self.which_file.get_current_file_name(session)
+        return (file, start, end)
+
+    class OutputFile(AjaxField):
+        def get_url(self, session):
+            job = self.parent.frame.get_args(session)[0]
+            if job:
+                file, start, end = self.parent.get_file_args(session)
+                if file:
+                    fl = self.parent.first_last.get(session)
+                    args = "%s&%i&%i&%s" % (file, start, end, fl)
+                    args = escape_amp(args)
+                    return "call.xml?class=job;id=%i;method=fetch;xargs=%s" % (job.id, args)
+
+        def do_render(self, session):
+            return self.render_script(session)
+
+    class FetchButton(FormButton):
+        def render_content(self, session):
+            return "Refresh"
+
+    class FileSwitch(StateSwitch):
+        def __init__(self, app, name):
+            super(JobOutput.FileSwitch, self).__init__(app, name)
+
+            self.add_state("o", "Output")
+            self.add_state("e", "Error")
+            self.add_state("u", "UserLog")
+
+            self.disabled = self.DisabledList(app, "disabled")
+            self.add_attribute(self.disabled)
+
+            self.link_titles = self.Titles(app, "link_titles")
+            self.add_attribute(self.link_titles)
+
+        class DisabledList(Attribute):
+            def get_default(self, session):
+                return list()
+
+        class Titles(Attribute):
+            def get_default(self, session):
+                return dict()
+
+        def disable(self, session, state):
+            disabled = self.disabled.get(session)
+            disabled.append(state)
+            self.disabled.set(session, disabled)
+            if state == self.get(session):
+                self.select_first_enabled(session)
+
+        def set_file_name(self, session, state, link_title):
+            link_titles = self.link_titles.get(session)
+            link_titles[state] = link_title
+            self.link_titles.set(session, link_titles)
+
+        def get_file_name(self, session, state):
+            link_titles = self.link_titles.get(session)
+            return state in link_titles and link_titles[state] or ""
+
+        def get_current_file_name(self, session):
+            state = self.get(session)
+            return self.get_file_name(session, state)
+
+        def select_first_enabled(self, session):
+            states = self.get_items(session)
+            disabled = self.disabled.get(session)
+            for state in states:
+                if not state in disabled:
+                    self.set(session, state)
+                    break
+
+        def render_item_link(self, session, state):
+            branch = session.branch()
+            self.set(branch, state)
+
+            title = self.get_title(state)
+            link_titles = self.link_titles.get(session)
+            link_title = state in link_titles and link_titles[state] or ""
+            disabled = self.disabled.get(session)
+            if state in disabled:
+                class_ = "disabled"
+                href = "javascript:void(0)"
+            else:
+                class_ = self.get(session) == state and "selected"
+                href = branch.marshal()
+            return fmt_link(href, title, class_, link_title=link_title)
+
+        def is_bad(self, file):
+            bad = False
+            if not file:
+                bad = True
+            elif "/dev/null" in file.lower():
+                bad = True
+            return bad
+
+
+    class FLSwitch(StateSwitch):
+        def __init__(self, app, name):
+            super(JobOutput.FLSwitch, self).__init__(app, name)
+
+            self.add_state("t", "Tail", "Display end of file")
+            self.add_state("h", "Head", "Display beginning of file")
+
+class JobStatus(CuminStatus):
+    def render_color(self, session, job):
+        if job:
+            return JobStatusInfo.get_status_color(job.JobStatus)
+
+    def render_job_status(self, session, job):
+        if job:
+            return JobStatusInfo.get_status_string(job.JobStatus)
+
+class JobGroupSet(CuminTable):
+    def __init__(self, app, name):
+        super(JobGroupSet, self).__init__(app, name)
+
+        self.ids = CheckboxStringIdColumn(app, "id")
+        self.add_column(self.ids)
+
+        col = self.GroupColumn(app, "job_group")
+        self.add_column(col)
+
+        col = self.JobsCountColumn(app, "jobs")
+        col.alignment = "right"
+        self.add_column(col)
+
+    class GroupColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Job Group"
+
+        def render_content(self, session, data):
+            name = data[self.name]
+
+            if name:
+                group = Identifiable(name)
+                href = self.page.main.grid.pool.job_group.get_href \
+                    (session, group)
+                return fmt_link(href, fmt_shorten(name))
+
+    class JobsCountColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Jobs"
+
+class JobsAndGroupsTab(Widget):
+    def __init__(self, app, name):
+        super(JobsAndGroupsTab, self).__init__(app, name)
+
+        self.is_group = GroupSwitch(app, "group")
+        self.add_child(self.is_group)
+
+        self.job_tab = JobTab(app, "jobtab")
+        self.add_child(self.job_tab)
+
+        self.job_group_tab = JobGroupTab(app, "jobgrouptab")
+        self.add_child(self.job_group_tab)
+
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, *args):
+        return "Jobs %s" % fmt_count(self.job_tab.get_full_item_count(session, *args))
+
+    def show_status_switch(self, session):
+        is_group = self.is_group.get(session)
+        return is_group == "j"
+
+    def set_switch(self, session, switch):
+        if switch == "group":
+            self.is_group.set(session, "g")
+        else:
+            self.is_group.set(session, "j")
+
+    def render_phase(self, session, *args):
+        is_group = self.is_group.get(session)
+        if is_group == "j":
+            return self.job_tab.phase.render(session)
+
+    def render_jobs(self, session, *args):
+        is_group = self.is_group.get(session)
+        if is_group == "j":
+            return self.job_tab.render(session)
+
+    def render_job_groups(self, session, *args):
+        is_group = self.is_group.get(session)
+        if is_group == "g":
+            return self.job_group_tab.render(session)
+
+class JobGroupTab(JobGroupSet, Form):
+    def __init__(self, app, name):
+        super(JobGroupTab, self).__init__(app, name)
+
+        self.__remove = self.Remove(app, "remove")
+        self.add_child(self.__remove)
+
+        self.__hold = self.Hold(app, "hold")
+        self.add_child(self.__hold)
+
+        self.__release = self.Release(app, "release")
+        self.add_child(self.__release)
+
+        self.set_default_column_name("job_group")
+
+    class Remove(FormButton):
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            href = self.frame.job_group_remove.get_href(session, ids)
+            self.page.set_redirect_url(session, href)
+
+        def render_content(self, session):
+            return "Remove"
+
+    class Hold(FormButton):
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            href = self.frame.job_group_hold.get_href(session, ids)
+            self.page.set_redirect_url(session, href)
+
+        def render_content(self, session):
+            return "Hold"
+
+    class Release(FormButton):
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            href = self.frame.job_group_release.get_href(session, ids)
+            self.page.set_redirect_url(session, href)
+
+        def render_content(self, session):
+            return "Release"
+
+class JobReasonBulkActionForm(CuminBulk):
+    def __init__(self, app, name):
+        super(JobReasonBulkActionForm, self).__init__(app, name)
+
+        self.reason = Parameter(app, "reason")
+        self.add_parameter(self.reason)
+
+        self.error = Attribute(app, "error")
+        self.add_attribute(self.error)
+
+        self.error_tmpl = Template(self, "reason_html")
+
+    def render_reason_text(self, session, *args):
+        return "Reason"
+
+    def render_reason_path(self, session, *args):
+        return self.reason.path
+
+    def render_reason_value(self, session, *args):
+        return escape_entity(self.reason.get(session))
+
+    def render_reason_error(self, session, *args):
+        if self.error.get(session):
+            writer = Writer()
+            self.error_tmpl.render(writer, session, *args)
+            return writer.to_string()
+
+    def render_reason_error_text(self, session, *args):
+        return self.error.get(session)
+
+    def render_form_heading(self, session, *args):
+        pass
+
+    def process_submit(self, session, *args):
+        reason = self.reason.get(session)
+        if not reason:
+            self.error.set(session, "Reason is required")
+        else:
+            super(JobReasonBulkActionForm, self).process_submit(session, *args)
+
+    def process_return(self, session, *args):
+        self.reason.set(session, "")
+
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def get_reason(self, session, verb):
+        """ returns <verb> by username[: <user input reason>] """
+        reason = [self.reason.get(session)]
+        verb_by = "%s by %s" % (verb, session.user_session.subject.name)
+        reason.insert(0, verb_by)
+        return ": ".join(reason)
+
+class JobReasonIntBulkActionForm(JobReasonBulkActionForm, CuminIntIdList):
+    def get_items(self, session, *args):
+        return self.ids.get(session)
+
+class JobSetHold(JobReasonIntBulkActionForm):
+    def process_item(self, session, id):
+        job = Job.get(id)
+        action = self.app.model.job.hold
+        reason = self.get_reason(session, "held")
+        action.invoke(job, reason)
+
+    def render_title(self, session):
+        ids = self.ids.get(session)
+        return len(ids) > 1 and "Hold Jobs" or "Hold Job"
+
+    def render_item_content(self, session, id):
+        return "Hold Job '%s'" % Job.get(id).CustomId
+
+    def render_reason_text(self, session, *args):
+        return "Hold Reason"
+
+class JobSetRelease(JobReasonIntBulkActionForm):
+    def process_item(self, session, id):
+        job = Job.get(id)
+        action = self.app.model.job.release
+        reason = self.get_reason(session, "released")
+        action.invoke(job, reason)
+
+    def render_title(self, session):
+        ids = self.ids.get(session)
+        return len(ids) > 1 and "Release Jobs" or "Release Job"
+
+    def render_item_content(self, session, id):
+        return "Release Job '%s'" % Job.get(id).CustomId
+
+    def render_reason_text(self, session, *args):
+        return "Release Reason"
+
+class JobSetRemove(JobReasonIntBulkActionForm):
+    def process_item(self, session, id):
+        job = Job.get(id)
+        action = self.app.model.job.remove
+        reason = self.get_reason(session, "removed")
+        action.invoke(job, reason)
+
+    def render_title(self, session):
+        ids = self.ids.get(session)
+        return len(ids) > 1 and "Remove Jobs" or "Remove Job"
+
+    def render_item_content(self, session, id):
+        return "Remove Job '%s'" % Job.get(id).CustomId
+
+    def render_reason_text(self, session, *args):
+        return "Remove Reason"
+
+class JobReasonStringBulkActionForm(JobReasonBulkActionForm, CuminStringIdList):
+    def get_items(self, session, *args):
+        return self.ids.get(session)
+
+class JobGroupHold(JobReasonStringBulkActionForm):
+    def process_item(self, session, id):
+        sel = "custom_group='%s'" % id
+        action = self.app.model.job.hold
+        reason = self.get_reason(session, "held")
+        for job in Job.select(sel):
+            action.invoke(job, reason)
+
+    def render_title(self, session):
+        ids = self.ids.get(session)
+        return len(ids) > 1 and "Hold Job Groups" or "Hold Job Group"
+
+    def render_item_content(self, session, group):
+        return group
+
+    def render_reason_text(self, session, *args):
+        return "Hold Reason"
+
+class JobGroupRelease(JobReasonStringBulkActionForm):
+    def process_item(self, session, id):
+        sel = "custom_group='%s'" % id
+        action = self.app.model.job.release
+        reason = self.get_reason(session, "released")
+        for job in Job.select(sel):
+            action.invoke(job, reason)
+
+    def render_title(self, session):
+        ids = self.ids.get(session)
+        return len(ids) > 1 and "Release Job Groups" or "Release Job Group"
+
+    def render_item_content(self, session, group):
+        return group
+
+    def render_reason_text(self, session, *args):
+        return "Release Reason"
+
+class JobGroupRemove(JobReasonStringBulkActionForm):
+    def process_item(self, session, id):
+        sel = "custom_group='%s'" % id
+        action = self.app.model.job.remove
+        reason = self.get_reason(session, "removed")
+        for job in Job.select(sel):
+            action.invoke(job, reason)
+
+    def render_title(self, session):
+        ids = self.ids.get(session)
+        return len(ids) > 1 and "Remove Job Groups" or "Remove Job Group"
+
+    def render_item_content(self, session, group):
+        return group
+
+    def render_reason_text(self, session, *args):
+        return "Remove Reason"
+
+class JobStatusSwitch(StateSwitch):
+    def __init__(self, app, name):
+        super(JobStatusSwitch, self).__init__(app, name)
+
+        self.add_state("a", "All")
+        self.add_state("r", "Running")
+        self.add_state("i", "Idle")
+        self.add_state("h", "Held")
+        self.add_state("c", "Completed")
+        self.add_state("d", "Removed")
+
+    def get_sql_constraint(self, session, phase=None):
+        if not phase:
+            phase = self.get(session)
+
+        alive = "((c.qmf_update_time is null or " + \
+            "c.qmf_update_time <= now() - interval '10 minutes')" + \
+            " and j.qmf_delete_time is null and j.job_status != %i)" % JobStatusInfo.get_status_int("Removed")
+
+        if phase == "a":
+            sql = alive
+        elif phase == "r":
+            sql = "(j.job_status = %i" % JobStatusInfo.get_status_int("Running") + \
+                    " and %s)" % alive
+        elif phase == "i":
+            sql = "(j.job_status = %i" % JobStatusInfo.get_status_int("Idle") + \
+                    " and %s)" % alive
+        elif phase == "h":
+            sql = "(j.job_status = %i" % JobStatusInfo.get_status_int("Held") + \
+                    " and %s)" % alive
+        elif phase == "c":
+            comotose = "(c.qmf_update_time is null or " + \
+                "c.qmf_update_time <= now() - interval '10 minutes')"
+            sql = "(j.job_status = %i" % JobStatusInfo.get_status_int("Completed") + \
+                    " and %s)" % comotose
+        else:
+            not_completed = "(j.qmf_delete_time is not null and j.job_status <> %i )" % JobStatusInfo.get_status_int("Completed")
+            is_removed = "j.job_status = %i" % JobStatusInfo.get_status_int("Removed")
+            sql = " or ".join((not_completed, is_removed))
+
+        return sql
+
+class JobStatusInfo(object):
+    stat_strings = ["Unexpanded", "Idle", "Running", "Removed", "Completed", "Held", "Submission Error"]
+    stat_colors = ["red", "clear", "green", "black", "blue", "yellow", "red"]
+    @classmethod
+    def get_status_string(cls, stat):
+        try:
+            return cls.stat_strings[stat]
+        except:
+            return ""
+
+    @classmethod
+    def get_status_color(cls, stat):
+        try:
+            return cls.stat_colors[stat]
+        except:
+            return "red"
+
+    @classmethod
+    def get_status_int(cls, stat):
+        try:
+            return cls.stat_strings.index(stat)
+        except:
+            return -1
+
+    @classmethod
+    def get_zipped_colors(cls):
+        return zip(cls.stat_strings, cls.stat_colors)


Property changes on: mgmt/trunk/cumin/python/cumin/grid/job.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/grid/job.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/job.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/job.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/job.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,438 @@
+[JobSet.sql]
+select
+  j.id,
+  j.accounting_group as agroup,
+  j.args,
+  j.cluster_id,
+  j.concurrency_limits,
+  j.custom_group,
+  j.custom_id,
+  j.custom_priority,
+  j.job_status,
+  j.title,
+  s.name as scheduler,
+  b.name as submitter,
+  j.scheduler_id,
+  j.submitter_id,
+  j.cmd,
+  j.qmf_delete_time
+from job as j
+left outer join job_stats as c on c.id = j.stats_curr_id
+left outer join job_stats as p on p.id = j.stats_prev_id
+inner join scheduler as s on s.id = j.scheduler_id
+inner join submitter as b on b.id = j.submitter_id
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[JobSet.find_sql]
+select
+        j.id,
+        j.custom_id
+from job as j
+left outer join job_stats as c on c.id = j.stats_curr_id
+left outer join job_stats as p on p.id = j.stats_prev_id
+inner join scheduler as s on s.id = j.scheduler_id
+inner join submitter as b on b.id = j.submitter_id
+
+[JobSet.count_sql]
+select count(1)
+from job as j
+left outer join job_stats as c on c.id = j.stats_curr_id
+left outer join job_stats as p on p.id = j.stats_prev_id
+inner join scheduler as s on s.id = j.scheduler_id
+inner join submitter as b on b.id = j.submitter_id
+{sql_where}
+
+[TopJobSet.sql]
+select
+  j.id,
+  j.custom_id as name,
+  j.q_date,
+  s.pool
+from job as j
+join scheduler s on s.id = j.scheduler_id
+where j.job_status = 2
+  and j.qmf_update_time > now() - interval '60 seconds'
+order by j.q_date asc
+limit 5
+
+[TopJobSet.count_sql]
+--
+
+[JobTab.css]
+input.search_input {
+    color: #555;
+    border: 1px solid #333;
+    font-size: 0.9em;
+    font-weight: normal;
+    padding-left: 0.25em;
+}
+
+input.search_error {
+    color: #CC0000 !important;
+}
+
+div.searchbox {
+    padding-top: 2px;
+}
+
+
+[JobTab.javascript]
+function JobSearchFocus() {
+    var val = this.value;
+
+    if (val == job_search_prompt) {
+        this.value = "";
+        this.style.color = "#000";
+        this.className = "search_input"; // remove search_error class
+    }
+}
+
+function JobSearchBlur() {
+    var val = this.value;
+
+    if (val == "") {
+        this.style.color = "#555";
+        job_search_prompt = job_search_default_prompt;
+        this.value = job_search_prompt;
+    }
+}
+
+window.addEvent('domready', function () {
+    var oInput = document.getElementById("job_search");
+
+    if (oInput) {
+        oInput.onfocus = JobSearchFocus;
+        oInput.onblur = JobSearchBlur;
+    }
+});
+
+[JobTab.html]
+<form id="{id}" method="post" action="?">
+  <div class="sactions">
+    {job_search}
+    <h2>Act on Selected Jobs:</h2>
+    {hold} {release} {remove}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+        <th class="setnav" colspan="{column_count}">
+          <div class="rfloat">{page}</div>
+          {count}
+        </th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>
+
+[JobSearch.html]
+<div class="rfloat searchbox">
+  <h2><label for="job_search">Go To Job:</label></h2>
+  <input class="search_input {search_class}" type="text" name="{name}" id="job_search" value="{search_prompt}" />
+  {go}
+</div>
+<script type="text/javascript">
+  var job_search_default_prompt = "{search_default_prompt}"
+  var job_search_prompt = "{search_prompt}"
+</script>
+
+[JobGroupSet.sql]
+select
+  j.custom_group as id,
+  j.custom_group as job_group,
+  count(*) as jobs
+from job as j
+inner join scheduler as s on s.id = j.scheduler_id
+{sql_where}
+group by j.custom_group
+{sql_orderby}
+{sql_limit}
+
+[JobGroupSet.count_sql]
+select count(distinct j.custom_group)
+from job as j
+{sql_where}
+
+[JobGroupStats.html]
+  <h2>General</h2>
+  <div style="width:50%;">
+  {general}
+  </div>
+
+
+[JobsAndGroupsTab.html]
+  <div class="rfloat">{phase}</div>
+{group}
+
+{jobs}{job_groups}
+
+
+[JobGroupTab.html]
+<form id="{id}" method="post" action="?">
+  <div class="sactions">
+    <h2>Act on Selected Groups:</h2>
+    {hold} {release} {remove}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+        <th class="setnav" colspan="{column_count}">
+          <div class="rfloat">{page}</div>
+          {count}
+        </th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>
+
+[JobGroupJobSet.html]
+<div class="rfloat">{phase}</div>
+<form id="{id}" style="clear:right;" method="post" action="?">
+
+  <div class="sactions">
+    {job_search}
+    <h2>Act on Selected Jobs:</h2>
+    {hold} {release} {remove}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+        <th class="setnav" colspan="{column_count}">
+          <div class="rfloat">{page}</div>
+          {count}
+        </th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>
+
+[JobStatus.html]
+<div id="{id}" class="CuminStatus {color}">
+  <h2>Job Status</h2>
+  {job_status}
+</div>
+
+
+[JobAdsViewer.html]
+<ul class="actions">
+  <li><a class="nav" href="{edit_ads_url}">Edit Attributes</a></li>
+</ul>
+<table class="CuminDetails">
+  <tbody>
+    <tr>
+      <td>
+        {groups}
+      </td>
+    </tr>
+  </tbody>
+</table>
+<ul class="actions">
+  <li><a class="nav" href="{edit_ads_url}">Edit Attributes</a></li>
+</ul>
+
+[JobAdsViewer.group_html]
+<div class="sactions">
+    <h2>{group_name}</h2>
+</div>
+<table class="PropertySet">
+  <thead>
+    <tr>
+      <th style="width: 33%;">Name</th>
+      <th style="width: 33%;">Value</th>
+      <th style="width: 33%;">&nbsp;</th>
+    </tr>
+  </thead>
+  <tbody>
+  {properties}
+  </tbody>
+</table>
+
+
+[JobAdsViewer.property_html]
+<tr>
+  <th>{title}</th><td>{value}</td><td>{inline_help}</td>
+</tr>
+
+[JobAdsEditor.css]
+div.inline_help {
+        float: right;
+}
+
+div.inline_help h2 {
+        display: inline;
+}
+
+[JobAdsEditor.html]
+<form id="{id}" class="mform editform" method="post" action="?">
+  <div class="inline_help">
+    <h2>Legend</h2>
+    <span class="edit_number">Numeric input expected</span>
+    <span class="edit_string">String input expected</span>
+  </div>
+  {help} {submit} {cancel}
+  <table class="CuminDetails Editable">
+    <tbody>
+      <tr>
+        <td>
+          {groups}
+        </td>
+      </tr>
+    </tbody>
+  </table>
+  {help} {submit} {cancel}
+  <div>{hidden_inputs}</div>
+</form>
+
+[JobReasonBulkActionForm.css]
+div.action_reason {
+    margin: 1em;
+}
+
+div.action_reason label {
+    font-weight: bold;
+    margin-right: 0.5em;
+}
+
+div.action_reason input {
+    width: 20em;
+}
+
+div.action_reason div.reason_error {
+    float: right;
+    border: 1px solid red;
+    color: red;
+    padding: 0.5em;
+}
+
+[JobReasonBulkActionForm.reason_html]
+        <div class="reason_error">{reason_error_text}</div>
+
+[JobReasonBulkActionForm.html]
+<form id="{id}" class="mform" method="post" action="?">
+  <div class="head">
+    <h1>{title}</h1>
+  </div>
+  <div class="body">
+    <span class="legend">{form_heading}</span>
+    <div class="action_reason">
+      {reason_error}
+      <label for="reason">{reason_text}</label> <input type="text" name="{reason_path}" id="reason" value="{reason_value}" maxlength="4000" />
+    </div>
+    <fieldset>
+      <ul>{items}</ul>
+    </fieldset>
+
+    {hidden_inputs}
+  </div>
+  <div class="foot">
+    {help}
+    {submit}
+    {cancel}
+  </div>
+</form>
+<script type="text/javascript">
+//<![CDATA[
+  wooly.doc().elembyid("{id}").node.elements[0].focus();
+//]]>
+</script>
+
+[JobOutput.css]
+textarea#job_output {
+    height: 25em;
+    width: 100%;
+    border: 1px solid #EAEAEA;
+    font-family: Fixed, monospace;
+    line-height: 1.15em;
+    background-color: #FFF;
+    color: #333;
+}
+
+div.out_actions {
+    padding:1em 1em 0 1em;
+}
+
+div.refresh_info h2 {
+    position: relative;
+    top: -0.5em;
+}
+
+[JobOutput.javascript]
+function scrollToEnd (element) {
+    if (typeof element.scrollTop != 'undefined'
+        && typeof element.scrollHeight != 'undefined') {
+        element.scrollTop = element.scrollHeight;
+    }
+}
+
+function outputEnd() {
+    var tarea = document.getElementById("job_output");
+
+    if (tarea) {
+        scrollToEnd(tarea);
+        setTimeout("get_job_output()", 5000);
+    }
+}
+
+[JobOutput.html]
+<form id="{id}" style="width:100%; border:0px;" class="mform" method="post" action="?">
+  <div class="out_actions">
+    <div class="rfloat">{first_last}</div>
+
+    {file}
+  </div>
+
+  <div class="sactions refresh_info">{refresh} <h2>Last refresh was at <span id="out_time"></span></h2></div>
+
+  <div>
+    <textarea name="job_output" id="job_output" rows="20" cols="80">
+      {loading}{job_output}
+    </textarea>
+
+    {hidden_inputs}
+  </div>
+</form>
+
+[OutTime.javascript]
+function got_out_time(obj, id) {
+    var elem = document.getElementById(id);
+
+    if (elem) {
+        var str = obj.time.value;
+        elem.innerHTML = str;
+    }
+}
+
+[OutputFile.javascript]
+function got_job_output(obj, id) {
+    var elem = document.getElementById(id);
+
+    if (elem) {
+        var str = obj.fetch.output;
+        elem.value = str;
+
+        if (obj.fetch.tail == "t") {
+            outputEnd();
+        }
+
+        var d = new Date();
+        var out_time = document.getElementById("out_time");
+
+        if (out_time) {
+            out_time.innerHTML = d.toLocaleString();
+        }
+    }
+}


Property changes on: mgmt/trunk/cumin/python/cumin/grid/job.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/grid/limit.py (from rev 3256, mgmt/trunk/cumin/python/cumin/limits.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/limit.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/limit.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,275 @@
+import logging
+
+from wooly import *
+from wooly.widgets import *
+from wooly.forms import *
+from wooly.resources import *
+from wooly.tables import *
+from cumin.stat import *
+from cumin.widgets import *
+from cumin.parameters import *
+from cumin.formats import *
+from cumin.util import *
+
+from job import *
+
+strings = StringCatalog(__file__)
+log = logging.getLogger("cumin.Limits")
+
+class LimitActions(object):
+    def fetch_limits(self, session):
+        negotiator = self.get_negotiator(session)
+        if negotiator:
+            limits = self.get_raw_limits(session, negotiator)
+            if "timeout" in limits:
+                del limits["timeout"]
+            return limits
+        else:
+            return dict()
+
+    def get_negotiator(self, session):
+#TODO: find better way to get the negotiator. from pool perhaps?
+        pool = self.frame.get_args(session)[0]
+        most_recent = None
+        negotiators = Negotiator.select("pool='%s'" % pool.id)
+        for negotiator in negotiators:
+            if negotiator.qmfBrokerId:
+                if not most_recent:
+                    most_recent = negotiator
+                try:
+                    if negotiator.statsCurr.qmfUpdateTime > \
+                            most_recent.statsCurr.qmfUpdateTime:
+                        most_recent = negotiator
+                except:
+                    pass
+
+        return most_recent
+
+    def set_limit(self, session, limit):
+        negotiator = self.get_negotiator(session)
+        action = self.app.model.limit.setlimit
+        action.invoke(limit, negotiator)
+#TODO: this probably shouldn't be called until after the invoke completes
+        def completion():
+            pass
+        negotiator.Reconfig(self.app.model.mint.model, completion)
+
+    def get_raw_limits(self, session, negotiator):
+        action = self.app.model.negotiator.GetLimits
+        return action.do_invoke(negotiator)
+
+class LimitsSet(ItemTable, LimitActions):
+    def __init__(self, app, name):
+        super(LimitsSet, self).__init__(app, name)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+        self.set_default_column(col)
+
+        col = self.CurrentColumn(app, "curr")
+        col.alignment = "right"
+        self.add_column(col)
+
+        col = self.MaxColumn(app, "max")
+        col.alignment = "right"
+        self.add_column(col)
+
+        self.limits = self.Limits(self, "limits")
+        self.add_attribute(self.limits)
+
+        self.limit_count = self.LimitCount(app, "limit_count")
+        self.add_child(self.limit_count)
+
+    def do_get_items(self, session, *args):
+        limits = self.limits.get(session)
+        if not len(limits):
+            limits = self.fetch_limits(session)
+            self.limits.set(session, limits)
+        keys = limits.keys()
+        keys.sort()
+        return [{"name":x, "curr":limits[x]["CURRENT"], "max":limits[x]["MAX"]} for x in keys]
+
+    def render_title(self, session):
+        return self.limit_count.get_title(session, "Limits")
+
+    class LimitCount(AjaxField):
+        def get_url(self, session):
+            negotiator = self.parent.get_negotiator(session)
+            return negotiator and \
+                "call.xml?class=negotiator;id=%i;method=GetLimitCount" % negotiator.id
+
+        def get_title(self, session, title):
+            script = self.render_script(session)
+            count = script and "?" or "0"
+            return "%s <span id=\"%s\"><span class='count'>(%s)</span>%s</span>" % \
+                (title, self.name, count, script)
+
+    class NameColumn(ItemTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+        def render_content(self, session, data):
+            limit = Identifiable(data["name"])
+            href = self.frame.limit.get_href(session, limit)
+            return fmt_link(href, data["name"])
+
+    class CurrentColumn(ItemTableColumn):
+        def render_title(self, session, data):
+            return "Current Usage"
+
+    class MaxColumn(ItemTableColumn):
+        def render_title(self, session, data):
+            return "Max Allowance"
+
+    class Limits(Attribute):
+        def get_default(self, session):
+            return dict()
+
+class LimitsFrame(CuminFrame, LimitActions):
+    def __init__(self, app, name):
+        super(LimitsFrame, self).__init__(app, name)
+
+        self.object = LimitParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.view = LimitsView(app, "view")
+        self.add_mode(self.view)
+
+        self.edit = LimitEdit(app, "edit")
+        self.add_mode(self.edit)
+
+    def get_object(self, session):
+        obj = self.object.get(session)
+        if not getattr(obj, "name", None):
+            limits = self.fetch_limits(session)
+            obj.name = obj.id
+            obj.curr = limits[obj.id]["CURRENT"]
+            obj.max = limits[obj.id]["MAX"]
+            self.object.set(session, obj)
+
+        return obj
+
+
+class LimitEdit(CuminForm):
+    def __init__(self, app, name):
+        super(LimitEdit, self).__init__(app, name)
+
+        self.max = Parameter(app, "max")
+        self.add_parameter(self.max)
+
+        self.error = self.Errors(self, "error")
+        self.add_attribute(self.error)
+
+        self.error_tmpl = Template(self, "error_html")
+
+    class Errors(Attribute):
+        def get_default(self, session):
+            return dict()
+
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, *args):
+        return "Edit Concurrency Limit '%s'" % args[0].id
+
+    def render_input_id(self, session, *args):
+        return self.max.path
+
+    def render_label(self, session, *args):
+        return "Maximum Allowance"
+
+    def render_input_name(self, session, *args):
+        return self.max.path
+
+    def render_input_value(self, session, *args):
+        max = self.max.get(session)
+        if not max:
+            max = args[0].max
+        return str(max)
+
+    def render_inline_help(self, session, *args):
+        return "Set the maximum number of jobs that can run concurrently using this limiter."
+
+    def render_limit_error(self, session, *args):
+        error = self.error.get(session)
+        if "max" in error:
+            writer = Writer()
+            self.error_tmpl.render(writer, session, *args)
+            return writer.to_string()
+
+    def render_error(self, session, *args):
+        error = self.error.get(session)
+        if "max" in error:
+            return error["max"]
+
+    def render_original_value(self, session, *args):
+        error = self.error.get(session)
+        if "max" in error:
+            return "Original value was %s" % str(args[0].max)
+
+    def process_submit(self, session, *args):
+        max = self.max.get(session)
+        fmax = 0
+        errors = False
+        try:
+            fmax = float(max)
+            if fmax < 1.0 or fmax > 99999.0:
+                raise "out of bounds"
+        except:
+            errors = True
+            error = self.error.get(session)
+            error["max"] = "Numeric value between 1 and 99999 expected"
+            self.error.set(session, error)
+
+        if not errors:
+            limit = args[0]
+            limit.max = fmax
+            self.frame.set_limit(session, limit)
+            self.process_cancel(session, *args)
+
+class LimitsView(CuminView):
+    def __init__(self, app, name):
+        super(LimitsView, self).__init__(app, name)
+
+        status = LimitsStatus(app, "status")
+        self.add_child(status)
+
+        self.__tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.__tabs)
+
+        jobs = LimitsJobSet(app, "jobs")
+        self.__tabs.add_tab(jobs)
+
+        details = CuminDetails(app, "details")
+        self.__tabs.add_tab(details)
+
+class LimitsStatus(CuminStatus):
+    def render_title(self, session, *args):
+        return "Limits Status"
+
+class LimitsJobSet(JobTab):
+    def get_visible_columns(self, session):
+        return self.get_request_visible_columns(session,
+                                                ["custom_group",
+                                                 "scheduler",
+                                                 "submitter"])
+
+    def get_sql_values(self, session, *args):
+        pass
+
+    def render_sql_where(self, session, limit):
+        phase_sql = self.get_phase_sql(session)
+        limits_sql = self.get_limits_sql(session, limit)
+        return "where %s" % " and ".join([phase_sql, limits_sql])
+
+    def render_title(self, session, limit):
+        limits_sql = self.get_limits_sql(session, limit)
+        return "Jobs %s" % fmt_count(Job.select(limits_sql).count())
+
+    def render_count(self, session, *args):
+        str = super(LimitsJobSet, self).render_count(session, *args)
+        return "%s with Concurrency Limit '%s'" % (str, args[0].id)
+
+    def get_limits_sql(self, session, limit):
+        x = limit.id
+        return "concurrency_limits similar to '(%s|%s,%%|%%,%s|%%,%s,%%)'" % (x, x, x, x)


Property changes on: mgmt/trunk/cumin/python/cumin/grid/limit.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/grid/limit.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/limits.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/limit.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/limit.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,105 @@
+[LimitsSet.html]
+<table class="mobjects">
+  <thead>
+    <tr>
+      <th class="setnav" colspan="{column_count}">
+        {count}
+      </th>
+    </tr>
+    <tr>{headers}</tr>
+  </thead>
+  <tbody>{items}</tbody>
+</table>
+
+
+[LimitCount.javascript]
+function got_limit_count(obj, id) {
+    var elem = document.getElementById(id);
+
+    if (elem) {
+        var str = "<span class='count'>(" + obj.count.value + ")</span>";
+        elem.innerHTML = str;
+    }
+}
+
+[LimitEdit.css]
+form.limitform {
+    /* padding: 1em; */
+}
+
+form.limitform div.label, form.limitform div.input {
+    float: left;
+    height: 3em;
+    margin-left: 1em;
+}
+
+form.limitform div.input input {
+    position: relative;
+    top: -0.2em;
+    width: 4em;
+}
+
+form.limitform div.foot {
+    clear: left;
+}
+
+form.limitform div.help {
+    margin: 0.5em 1em 1em 0;
+}
+
+form.limitform div.original_value {
+    color: #333;
+    font-size: 0.9em;
+    font-style: italic;
+}
+
+[LimitEdit.html]
+<form id="{id}" class="mform limitform" method="post" action="?">
+  <div class="head">
+    <h1>{title}</h1>
+  </div>
+  <div class="body">
+    <div class="help">
+      {inline_help}
+    </div>
+    <div class="label">
+      <label for="{input_id}">{label}</label>
+    </div>
+    <div class="input">
+      <input id="{input_id}" type="text" name="{input_name}" value="{input_value}" />
+      <div class="original_value">{original_value}</div>
+    </div>{limit_error}
+    <div style="clear:both;"><!-- --></div>
+  </div>
+  <div class="foot">
+    {help} {submit} {cancel}
+  </div>
+  <div>{hidden_inputs}</div>
+</form>
+
+[LimitEdit.error_html]
+<ul class="errors"><li>{error}</li></ul>
+
+[LimitsJobSet.html]
+<div class="rfloat">{phase}</div>
+<form id="{id}" style="clear:right;" method="post" action="?">
+
+  <div class="sactions">
+    <h2>Act on Selected Jobs:</h2>
+    {hold} {release} {remove}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+	<th class="setnav" colspan="{column_count}">
+	  <div class="rfloat">{page}</div>
+	  {count}
+	</th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>


Property changes on: mgmt/trunk/cumin/python/cumin/grid/limit.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Added: mgmt/trunk/cumin/python/cumin/grid/main.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/main.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/main.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,57 @@
+from wooly import *
+from wooly.widgets import *
+from wooly.resources import *
+from cumin.widgets import *
+from cumin.util import *
+
+from pool import *
+
+strings = StringCatalog(__file__)
+
+class GridFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(GridFrame, self).__init__(app, name)
+
+        self.view = GridView(app, "view")
+        self.add_mode(self.view)
+
+        self.pool = PoolFrame(app, "pool")
+        self.add_mode(self.pool)
+
+        self.sticky_pool = Parameter(app, "last_pool")
+        self.add_parameter(self.sticky_pool)
+
+        self.jobs_hold = JobSetHold(app, "jobshold")
+        self.add_mode(self.jobs_hold)
+
+        self.jobs_release = JobSetRelease(app, "jobsrelease")
+        self.add_mode(self.jobs_release)
+
+        self.jobs_remove = JobSetRemove(app, "jobsremove")
+        self.add_mode(self.jobs_remove)
+
+    def set_last_pool(self, session, pool):
+        self.sticky_pool.set(session, pool)
+
+    def get_last_pool(self, session):
+        return self.sticky_pool.get(session)
+
+    def render_title(self, session):
+        return "Grid"
+
+class GridView(Widget):
+    def __init__(self, app, name):
+        super(GridView, self).__init__(app, name)
+
+        heading = self.Heading(app, "heading")
+        self.add_child(heading)
+
+        pools = PoolSet(app, "pools")
+        self.add_child(pools)
+
+    class Heading(CuminHeading):
+        def render_title(self, session):
+            return "Grid"
+
+        def render_icon_href(self, session):
+            return "resource?name=pool-36.png"

Added: mgmt/trunk/cumin/python/cumin/grid/main.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/main.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/main.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1 @@
+

Copied: mgmt/trunk/cumin/python/cumin/grid/negotiator.py (from rev 3256, mgmt/trunk/cumin/python/cumin/negotiator.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/negotiator.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/negotiator.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,162 @@
+import logging
+
+from wooly import *
+from wooly.widgets import *
+from wooly.forms import *
+from wooly.resources import *
+from wooly.tables import *
+from cumin.stat import *
+from cumin.widgets import *
+from cumin.parameters import *
+from cumin.formats import *
+from cumin.util import *
+
+strings = StringCatalog(__file__)
+log = logging.getLogger("cumin.negotiator")
+
+class NegotiatorSet(CuminTable, Form):
+    def __init__(self, app, name):
+        super(NegotiatorSet, self).__init__(app, name)
+
+        self.ids = CheckboxIdColumn(app, "id")
+        self.add_column(self.ids)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+        self.set_default_column(col)
+
+        col = self.SystemColumn(app, "system")
+        self.add_column(col)
+
+        self.__start = self.StartButton(app, "start")
+        self.add_child(self.__start)
+
+        self.__stop = self.StopButton(app, "stop")
+        self.add_child(self.__stop)
+
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, negotiator):
+        count = self.get_item_count(session, negotiator)
+        return "Negotiators %s" % fmt_count(count)
+
+    def render_sql_where(self, session, negotiator):
+        sql = "((c.qmf_update_time is not null and " + \
+            "c.qmf_update_time > now() - interval '10 minutes')" + \
+            " and qmf_delete_time is null)"
+        return "where %s" % sql
+
+    class NameColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+        def render_content(self, session, data):
+            branch = session.branch()
+
+            neg = Identifiable(data["id"])
+            self.app.model.negotiator.show_object(branch, neg)
+
+            return fmt_olink(branch, neg, name=data["name"])
+
+    class SystemColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "System"
+
+        def render_content(self, session, data):
+            id = data["system_id"]
+
+            if id:
+                sys = Identifiable(id)
+                href = self.page.main.inventory.system.get_href(session, sys)
+                return fmt_link(href, data["system_name"])
+
+    class StartButton(FormButton):
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            branch = session.branch()
+            frame = self.frame.show_negs_start(branch)
+            frame.ids.set(branch, ids)
+            self.page.set_redirect_url(session, branch.marshal())
+
+        def render_content(self, session):
+            return "Start"
+
+    class StopButton(FormButton):
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            branch = session.branch()
+            frame = self.frame.show_negs_stop(branch)
+            frame.ids.set(branch, ids)
+            self.page.set_redirect_url(session, branch.marshal())
+
+        def render_content(self, session):
+            return "Stop"
+
+class NegotiatorFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(NegotiatorFrame, self).__init__(app, name)
+
+        self.object = NegotiatorParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.view = NegotiatorView(app, "view")
+        self.add_mode(self.view)
+
+class NegotiatorView(CuminView):
+    def __init__(self, app, name):
+        super(NegotiatorView, self).__init__(app, name)
+
+        status = self.NegotiatorStatus(app, "status")
+        self.add_child(status)
+
+        self.__tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.__tabs)
+
+        details = CuminDetails(app, "details")
+        self.__tabs.add_tab(details)
+
+    class NegotiatorStatus(StartStopStatus):
+        def get_url(self, session):
+            negotiator = self.get_args(session)[0]
+            if negotiator:
+                return "call.xml?class=negotiator;id=%i;method=GetStarted" % negotiator.id
+
+        def render_title(self, session, *args):
+            return "Negotiator Status"
+
+class NegStart(CuminBulkActionForm):
+    def render_title(self, session, *args):
+        return "Start Negotiator"
+
+    def render_form_heading(self, session, *args):
+        return ""
+
+    def render_item_content(self, session, id):
+        return "Start Negotiator '%s'" % Negotiator.get(id).Name
+
+    def process_item(self, session, item):
+        negotiator = Negotiator.get(item)
+        action = self.app.model.master.start
+        action.invoke(negotiator, {"subsystem": "NEGOTIATOR"})
+        self.process_cancel(session)
+
+class NegStop(CuminBulkActionForm):
+    def render_title(self, session, *args):
+        return "Stop Negotiator"
+
+    def render_form_heading(self, session, *args):
+        return ""
+
+    def render_item_content(self, session, id):
+        return "Stop Negotiator '%s'" % Negotiator.get(id).Name
+
+    def process_item(self, session, item):
+        negotiator = Negotiator.get(item)
+        action = self.app.model.master.stop
+        action.invoke(negotiator, {"subsystem": "NEGOTIATOR"})
+        self.process_cancel(session)


Property changes on: mgmt/trunk/cumin/python/cumin/grid/negotiator.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/grid/negotiator.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/negotiator.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/negotiator.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/negotiator.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,40 @@
+[NegotiatorSet.sql]
+select
+  n.id,
+  n.name,
+  y.id as system_id,
+  y.node_name as system_name
+from negotiator as n
+left outer join negotiator_stats as c on c.id = n.stats_curr_id
+left outer join sysimage as y on n.system = y.node_name
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[NegotiatorSet.count_sql]
+select count(1) from negotiator as n
+left outer join negotiator_stats as c on c.id = n.stats_curr_id
+{sql_where}
+
+[NegotiatorSet.html]
+<form id="{id}" method="post" action="?">
+
+  <div class="sactions">
+    <h2>Act on Selected Negotiators:</h2>
+    {start} {stop}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+	<th class="setnav" colspan="{column_count}">
+	  <div class="rfloat">{page}</div>
+	  {count}
+	</th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>


Property changes on: mgmt/trunk/cumin/python/cumin/grid/negotiator.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/grid/pool.py (from rev 3256, mgmt/trunk/cumin/python/cumin/pool.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/pool.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/pool.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,355 @@
+import logging
+from wooly import *
+from wooly.widgets import *
+from wooly.forms import *
+from wooly.resources import *
+from wooly.tables import *
+from cumin.stat import *
+from cumin.widgets import *
+from cumin.parameters import *
+from cumin.formats import *
+from cumin.util import *
+from cumin.visualizations import SlotMap
+
+from job import *
+from scheduler import SchedulerSet, SchedulerFrame, SchedulerStart, SchedulerStop
+from submitter import SubmitterSet, SubmitterFrame
+from collector import CollectorSet, CollectorFrame, CollectorStart, CollectorStop
+from negotiator import NegotiatorSet, NegotiatorFrame, NegStart, NegStop
+from limit import LimitsSet, LimitsFrame
+from slot import SlotSet, SlotStatSet
+
+strings = StringCatalog(__file__)
+
+log = logging.getLogger("cumin.pool")
+
+class PoolSet(CuminTable):
+    def __init__(self, app, name):
+        super(PoolSet, self).__init__(app, name)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+
+        self.set_default_column(col)
+
+        col = self.JobsColumn(app, "jobs")
+        self.add_column(col)
+
+        col = self.StatusColumn(app, "status")
+        self.add_column(col)
+
+    def render_title(self, session):
+        count = self.get_item_count(session)
+        return "Pools %s" % fmt_count(count)
+
+    class NameColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+        def render_content(self, session, data):
+            pool = Identifiable(data["id"])
+            self.page.main.grid.set_last_pool(session, data["id"])
+            href = self.page.main.grid.pool.get_href(session, pool)
+
+            return fmt_link(href, data["name"])
+
+    class JobsColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Jobs"
+
+        def render_content(self, session, data):
+            return data["jobs"]
+
+    class StatusColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Status"
+
+        def render_content(self, session, data):
+            return "Active"
+
+class PoolFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(PoolFrame, self).__init__(app, name)
+
+        self.object = PoolParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.view = PoolView(app, "view")
+        self.add_mode(self.view)
+
+        self.job = JobFrame(app, "job")
+        self.add_mode(self.job)
+
+        self.job_group = JobGroupFrame(app, "jobgroup")
+        self.add_mode(self.job_group)
+
+        self.scheduler = SchedulerFrame(app, "sched")
+        self.add_mode(self.scheduler)
+
+        self.submitter = SubmitterFrame(app, "sub")
+        self.add_mode(self.submitter)
+
+        self.collector = CollectorFrame(app, "coll")
+        self.add_mode(self.collector)
+
+        self.limit = LimitsFrame(app, "limit")
+        self.add_mode(self.limit)
+
+        self.negotiator = NegotiatorFrame(app, "neg")
+        self.add_mode(self.negotiator)
+
+        self.__startneg = NegStart(app, "startneg")
+        self.add_mode(self.__startneg)
+
+        self.__stopneg = NegStop(app, "stopneg")
+        self.add_mode(self.__stopneg)
+
+        self.__startcoll = CollectorStart(app, "startcoll")
+        self.add_mode(self.__startcoll)
+
+        self.__stopcoll = CollectorStop(app, "stopcoll")
+        self.add_mode(self.__stopcoll)
+
+        self.__startsched = SchedulerStart(app, "startsched")
+        self.add_mode(self.__startsched)
+
+        self.__stopsched = SchedulerStop(app, "stopsched")
+        self.add_mode(self.__stopsched)
+
+        self.jobs_hold = JobSetHold(app, "jobshold")
+        self.add_mode(self.jobs_hold)
+
+        self.jobs_release = JobSetRelease(app, "jobsrelease")
+        self.add_mode(self.jobs_release)
+
+        self.jobs_remove = JobSetRemove(app, "jobsremove")
+        self.add_mode(self.jobs_remove)
+
+        self.job_group_hold = JobGroupHold(app, "jobgrouphold")
+        self.add_mode(self.job_group_hold)
+
+        self.job_group_release = JobGroupRelease(app, "jobgrouprelease")
+        self.add_mode(self.job_group_release)
+
+        self.job_group_remove = JobGroupRemove(app, "jobgroupremove")
+        self.add_mode(self.job_group_remove)
+
+    def show_job_frame(self, session):
+        self.page.set_frame(session, self.job)
+        return self.job.show(session)
+
+    def show_negs_start(self, session):
+        self.page.set_frame(session, self.__startneg)
+        return self.__startneg.show(session)
+
+    def show_negs_stop(self, session):
+        self.page.set_frame(session, self.__stopneg)
+        return self.__stopneg.show(session)
+
+    def show_scheds_start(self, session):
+        self.page.set_frame(session, self.__startsched)
+        return self.__startsched.show(session)
+
+    def show_scheds_stop(self, session):
+        self.page.set_frame(session, self.__stopsched)
+        return self.__stopsched.show(session)
+
+    def show_colls_start(self, session):
+        self.page.set_frame(session, self.__startcoll)
+        return self.__startcoll.show(session)
+
+    def show_colls_stop(self, session):
+        self.page.set_frame(session, self.__stopcoll)
+        return self.__stopcoll.show(session)
+
+class PoolView(CuminView):
+    def __init__(self, app, name):
+        super(PoolView, self).__init__(app, name)
+
+        status = PoolStatus(app, "status")
+        self.add_child(status)
+
+        self.__tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.__tabs)
+
+        stats = PoolStats(app, "stats")
+        self.__tabs.add_tab(stats)
+
+        self.jobs = JobsAndGroupsTab(app, "jobs")
+        self.__tabs.add_tab(self.jobs)
+
+        self.scheds = PoolSchedulerSet(app, "scheds")
+        self.__tabs.add_tab(self.scheds)
+
+        subs = PoolSubmitterSet(app, "subs")
+        self.__tabs.add_tab(subs)
+
+        self.colls = PoolCollectorSet(app, "colls")
+        self.__tabs.add_tab(self.colls)
+
+        self.negs = PoolNegotiatorSet(app, "negs")
+        self.__tabs.add_tab(self.negs)
+
+        limits = self.LimitsTab(app, "limits")
+        self.__tabs.add_tab(limits)
+
+    class LimitsTab(LimitsSet):
+        pass
+
+    def set_collector_tab(self, session):
+        self.colls.show(session)
+
+    def set_negotiator_tab(self, session):
+        self.negs.show(session)
+
+    def set_scheduler_tab(self, session):
+        self.scheds.show(session)
+
+class PoolSchedulerSet(SchedulerSet):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def get_sql_values(self, session, pool):
+        return {"pool": pool.id}
+
+    def render_title(self, session, pool):
+        count = self.get_item_count(session, pool)
+        return "Schedulers %s" % fmt_count(count)
+
+    def render_sql_where(self, session, pool):
+        return "where s.pool = %(pool)s"
+
+class PoolSubmitterSet(SubmitterSet):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def get_sql_values(self, session, pool):
+        return {"pool": pool.id}
+
+    def render_title(self, session, pool):
+        count = self.get_item_count(session, pool)
+        return "Submitters %s" % fmt_count(count)
+
+    def render_sql_where(self, session, pool):
+        return "where d.pool = %(pool)s"
+
+class PoolCollectorSet(CollectorSet):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def get_sql_values(self, session, pool):
+        return {"pool": pool.id}
+
+    def render_title(self, session, pool):
+        count = self.get_item_count(session, pool)
+        return "Collectors %s" % fmt_count(count)
+
+    def render_sql_where(self, session, pool):
+        return "where c.pool = %(pool)s"
+
+class PoolNegotiatorSet(NegotiatorSet):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def get_sql_values(self, session, pool):
+        return {"pool": pool.id}
+
+    def render_title(self, session, pool):
+        count = self.get_item_count(session, pool)
+        return "Negotiators %s" % fmt_count(count)
+
+    def render_sql_where(self, session, pool):
+        return "where n.pool = %(pool)s"
+
+class PoolSlotSet(SlotSet):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_sql_where(self, session, pool):
+        elems = list()
+        elems.append("s.pool = %(pool)s")
+        recent = self.get_recent_sql_where(session)
+        if recent:
+            elems.append(recent)
+
+        return "where %s" % " and ".join(elems)
+
+    def get_sql_values(self, session, pool):
+        return {"pool": pool.id}
+
+    def render_title(self, session, pool):
+        count = self.get_item_count(session, pool)
+        return "Slots %s" % fmt_count(count)
+
+    def filter(self, session, system, slots):
+        return slots
+
+class PoolStats(Widget):
+    def __init__(self, app, name):
+        super(PoolStats, self).__init__(app, name)
+
+        stats = PoolStatSet(app, "general", "general")
+        self.add_child(stats)
+
+        self.slot_map = self.PoolSlotMap(app, "pool_slot_map")
+        self.add_child(self.slot_map)
+
+    def render_title(self, session):
+        return "Statistics"
+
+    class PoolSlotMap(SlotMap):
+        def get_title_name(self, session, pool):
+            return pool.name
+
+        def render_slot_clip_size(self, session, *args):
+            return 400
+
+class PoolStatSet(StatSet):
+    def render_rate_text(self, session, args):
+        return "Percentage"
+
+    def do_get_items(self, session, pool):
+        stats = super(PoolStatSet, self).do_get_items(session, pool)
+
+        action = self.app.model.pool.fakestats
+        record = action.get_stat_record(session, pool)
+
+        fake_stats = list()
+        for stat in stats:
+            fake_stats.append((stat[0], record))
+
+        return fake_stats
+
+class PoolJobStats(CuminTable):
+    def render_sql_where(self, session, pool):
+        elems = list()
+        elems.append("s.pool = %(pool)s")
+        return "where %s" % " and ".join(elems)
+
+    def get_sql_values(self, session, pool):
+        values = {"pool": pool.id}
+        return values
+
+class PoolStatus(CuminStatus):
+    def __init__(self, app, name):
+        super(PoolStatus, self).__init__(app, name)
+
+        self.item_tmpl = Template(self, "status_html")
+
+    def render_title(self, session, pool):
+        return "Pool Status"
+
+    def render_status(self, session, pool):
+        action = self.app.model.pool.poolstatus
+        record = action.get_stat_record(session, pool)
+        if record and ("idl" in record) and ("all" in record):
+            if record["idl"] and record["all"]: # not None
+                writer = Writer()
+                self.item_tmpl.render(writer, session, record)
+                return writer.to_string()
+
+    def render_idle(self, session, record):
+        return record["idl"]
+
+    def render_total(self, session, record):
+        return record["all"]


Property changes on: mgmt/trunk/cumin/python/cumin/grid/pool.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/grid/pool.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/pool.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/pool.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/pool.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,58 @@
+[PoolSet.sql]
+select p.pool as id, p.name, j.jobs
+from
+  (select pool, name
+   from collector
+   group by pool, name) as p
+left outer join
+  (select s.pool, count(*) as jobs
+   from job j
+   left outer join scheduler as s on j.scheduler_id = s.id
+   group by s.pool) as j
+  on j.pool = p.pool
+
+[PoolSet.count_sql]
+select count(*)
+from
+  (select 1 from collector group by pool) as l
+
+[PoolJobStats.sql]
+select
+ sum(case when job_status=2 then 1 else 0 end) as running,
+ sum(case when job_status=4 then 1 else 0 end) as completed,
+ sum(case when job_status=5 then 1 else 0 end) as held,
+ sum(case when job_status=1 and j.qmf_delete_time is null then 1 else 0 end) as idle,
+ sum(case when job_status=3 or (job_status=1 and j.qmf_delete_time is not null) then 1 else 0 end) as removed,
+ sum(1) as total,
+ s.pool
+from job as j
+left outer join scheduler as s on s.id = j.scheduler_id
+{sql_where}
+group by s.pool
+
+[PoolJobStats.count_sql]
+1
+
+[PoolStatus.html]
+<div id="{id}" class="CuminStatus {color}">
+  <h2>{title}</h2>
+
+  {status}
+</div>
+
+[PoolStatus.status_html]
+<div>
+  <span>{idle}</span> of <span>{total}</span> slots idle
+</div>
+
+[PoolStats.html]
+<div style="width: 40%; float: left;">
+  <h2>General</h2>
+  <div>
+  {general}
+  </div>
+</div>
+<div style="float: left; margin-left: 4em;">
+  {pool_slot_map}
+</div>
+<div style="clear:left;"><!-- --></div>


Property changes on: mgmt/trunk/cumin/python/cumin/grid/pool.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/grid/scheduler.py (from rev 3256, mgmt/trunk/cumin/python/cumin/scheduler.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/scheduler.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/scheduler.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,234 @@
+import logging
+from wooly import *
+from wooly.widgets import *
+from wooly.forms import *
+from wooly.resources import *
+from wooly.tables import *
+from cumin.stat import *
+from cumin.widgets import *
+from cumin.parameters import *
+from cumin.formats import *
+from cumin.util import *
+
+from job import *
+
+strings = StringCatalog(__file__)
+
+log = logging.getLogger("cumin.scheduler")
+
+class SchedulerSet(CuminTable, Form):
+    def __init__(self, app, name):
+        super(SchedulerSet, self).__init__(app, name)
+
+        self.ids = CheckboxIdColumn(app, "id")
+        self.add_column(self.ids)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+        self.set_default_column(col)
+
+        col = self.SystemColumn(app, "system")
+        self.add_column(col)
+
+        col = self.UsersColumn(app, "users")
+        col.alignment = "right"
+        self.add_column(col)
+
+        col = self.RunningJobsColumn(app, "running")
+        col.alignment = "right"
+        self.add_column(col)
+
+        col = self.HeldJobsColumn(app, "held")
+        col.alignment = "right"
+        self.add_column(col)
+
+        self.__start = self.StartButton(app, "start")
+        self.add_child(self.__start)
+
+        self.__stop = self.StopButton(app, "stop")
+        self.add_child(self.__stop)
+
+    def render_title(self, session, *args):
+        return "Schedulers %s" % fmt_count(Scheduler.select().count())
+
+    class NameColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+        def render_content(self, session, data):
+            sched = Identifiable(data["id"])
+            href = self.page.main.grid.pool.scheduler.get_href(session, sched)
+            return fmt_link(href, data["name"])
+
+    class UsersColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Users"
+
+    class RunningJobsColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Running Jobs"
+
+    class HeldJobsColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Held Jobs"
+
+    class SystemColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "System"
+
+        def render_content(self, session, data):
+            id = data["system_id"]
+
+            if id:
+                sys = Identifiable(id)
+                href = self.page.main.inventory.system.get_href(session, sys)
+                return fmt_link(href, data["system_name"])
+
+    class StartButton(FormButton):
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            branch = session.branch()
+            frame = self.frame.show_scheds_start(branch)
+            frame.ids.set(branch, ids)
+            self.page.set_redirect_url(session, branch.marshal())
+
+        def render_content(self, session):
+            return "Start"
+
+    class StopButton(FormButton):
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            branch = session.branch()
+            frame = self.frame.show_scheds_stop(branch)
+            frame.ids.set(branch, ids)
+            self.page.set_redirect_url(session, branch.marshal())
+
+        def render_content(self, session):
+            return "Stop"
+
+class SchedulerFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(SchedulerFrame, self).__init__(app, name)
+
+        self.object = SchedulerParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.view = SchedulerView(app, "view")
+        self.add_mode(self.view)
+
+class SchedulerView(CuminView):
+    def __init__(self, app, name):
+        super(SchedulerView, self).__init__(app, name)
+
+        status = self.SchedulerStatus(app, "status")
+        self.add_child(status)
+
+        self.__tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.__tabs)
+
+        stats = SchedulerStats(app, "stats")
+        self.__tabs.add_tab(stats)
+
+        jobs = SchedulerJobSet(app, "jobs")
+        self.__tabs.add_tab(jobs)
+
+        details = CuminDetails(app, "details")
+        self.__tabs.add_tab(details)
+
+    class SchedulerStatus(StartStopStatus):
+        def get_url(self, session):
+            scheduler = self.get_args(session)[0]
+            if scheduler:
+                return "call.xml?class=scheduler;id=%i;method=GetStarted" % scheduler.id
+
+        def render_title(self, session, *args):
+            return "Scheduler Status"
+
+class SchedulerStats(Widget):
+    def __init__(self, app, name):
+        super(SchedulerStats, self).__init__(app, name)
+
+        stats = StatSet(app, "general", "general")
+        self.add_child(stats)
+
+        chart = self.UsersChart(app, "users")
+        chart.duration.param.default = "h"
+        self.add_child(chart)
+
+        chart = self.JobsChart(app, "jobs")
+        chart.duration.param.default = "h"
+        self.add_child(chart)
+
+    def render_title(self, session):
+        return "Statistics"
+
+    class UsersChart(StatValueChart):
+        def __init__(self, app, name):
+            super(SchedulerStats.UsersChart, self).__init__(app, name)
+
+            self.stats = ("NumUsers",)
+
+        def render_title(self, session, sched):
+            return "Users"
+
+    class JobsChart(StatValueChart):
+        def __init__(self, app, name):
+            super(SchedulerStats.JobsChart, self).__init__ \
+                (app, name)
+
+            self.stats = ("TotalRunningJobs", "TotalIdleJobs", "TotalHeldJobs")
+
+        def render_title(self, session, sched):
+            return "Jobs"
+
+class SchedulerJobSet(JobTab):
+    def __init__(self, app, name):
+        super(SchedulerJobSet, self).__init__(app, name)
+
+    def get_visible_columns(self, session):
+        return self.get_request_visible_columns(session, ["custom_group", "submitter"])
+
+    def render_sql_where(self, session, scheduler):
+        phase_sql = self.get_phase_sql(session)
+        scheduler_sql = "j.scheduler_id = %i" % scheduler.id
+        return "where %s" % " and ".join([phase_sql, scheduler_sql])
+
+    def render_title(self, session, scheduler):
+        where_scheduler = "scheduler_id = %i" % scheduler.id
+        return "Jobs %s" % fmt_count(Job.select(where_scheduler).count())
+
+class SchedulerStart(CuminBulkActionForm):
+    def render_title(self, session, *args):
+        return "Start Scheduler"
+
+    def render_form_heading(self, session, *args):
+        return ""
+
+    def render_item_content(self, session, id):
+        return "Start Scheduler '%s'" % Scheduler.get(id).Name
+
+    def process_item(self, session, item):
+        scheduler = Scheduler.get(item)
+        action = self.app.model.master.start
+        action.invoke(scheduler, {"subsystem": "SCHEDD"})
+        self.process_cancel(session)
+
+class SchedulerStop(CuminBulkActionForm):
+    def render_title(self, session, *args):
+        return "Stop Scheduler"
+
+    def render_form_heading(self, session, *args):
+        return ""
+
+    def render_item_content(self, session, id):
+        return "Stop Scheduler '%s'" % Scheduler.get(id).Name
+
+    def process_item(self, session, item):
+        scheduler = Scheduler.get(item)
+        action = self.app.model.master.stop
+        action.invoke(scheduler, {"subsystem": "SCHEDD"})
+        self.process_cancel(session)


Property changes on: mgmt/trunk/cumin/python/cumin/grid/scheduler.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/grid/scheduler.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/scheduler.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/scheduler.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/scheduler.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,82 @@
+[SchedulerSet.sql]
+select
+  s.id,
+  s.name,
+  y.id as system_id,
+  y.node_name as system_name,
+  c.num_users as users,
+  c.total_running_jobs as running,
+  c.total_held_jobs as held
+from scheduler as s
+left outer join scheduler_stats as c on c.id = s.stats_curr_id
+left outer join sysimage as y on s.system = y.node_name
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[SchedulerSet.count_sql]
+select count(1) from scheduler as s
+{sql_where}
+
+[SchedulerSet.html]
+<form id="{id}" method="post" action="?">
+  <div class="sactions">
+    <h2>Act on Selected Schedulers:</h2>
+    {start} {stop}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+	<th class="setnav" colspan="{column_count}">
+	  <div class="rfloat">{page}</div>
+	  {count}
+	</th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>
+
+[SchedulerStats.html]
+<table class="twocol">
+  <tbody>
+  <tr>
+    <td>
+      <h2>General</h2>
+      {general}
+    </td>
+    <td>
+      {users}
+      {jobs}
+    </td>
+  </tr>
+  </tbody>
+</table>
+
+[SchedulerJobSet.html]
+<div class="rfloat">{phase}</div>
+
+<form id="{id}" style="clear:right;" method="post" action="?">
+  <div class="sactions">
+    {job_search}
+    <h2>Act on Selected Jobs:</h2>
+    {hold} {release} {remove}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+	<th class="setnav" colspan="{column_count}">
+	  <div class="rfloat">{page}</div>
+	  {count}
+	</th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>


Property changes on: mgmt/trunk/cumin/python/cumin/grid/scheduler.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/grid/slot.py (from rev 3256, mgmt/trunk/cumin/python/cumin/slot.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/slot.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/slot.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,51 @@
+import logging
+
+from wooly import *
+from wooly.widgets import *
+from wooly.forms import *
+from wooly.resources import *
+from wooly.tables import *
+
+from cumin.widgets import *
+
+strings = StringCatalog(__file__)
+log = logging.getLogger("cumin.job")
+
+# XXX marked for death
+class UniqueSlot(CuminTable):
+    def get_recent_sql_where(self, session):
+        return """
+            s.qmf_update_time > now() - interval '60 minutes'
+            """
+
+    def do_get_items(self, session, *args):
+        cursor = super(UniqueSlot, self).do_get_items(session, *args)
+        items = self.cursor_to_rows(cursor)
+        self.items.set(session, items)
+        return items
+
+class SlotSet(UniqueSlot):
+    def __init__(self, app, name):
+        super(SlotSet, self).__init__(app, name)
+
+        col = self.Name(app, "name")
+        self.add_column(col)
+
+    class Name(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+    def render_items(self, session, *args):
+        """ overridden because a slotset query is expensive.
+            the rows are cached """
+
+        rows = self.get_items(session, *args)
+        writer = Writer()
+
+        for row in rows:
+            self.item_tmpl.render(writer, session, row)
+
+        return writer.to_string()
+
+class SlotStatSet(UniqueSlot):
+    pass


Property changes on: mgmt/trunk/cumin/python/cumin/grid/slot.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/grid/slot.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/slot.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/slot.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/slot.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,36 @@
+[SlotSet.sql]
+select
+  s.id,
+  s.name,
+  s.machine,
+  s.system,
+  s.job_id,
+  j.id as jid,
+  c.activity,
+  c.state
+from slot as s
+left outer join slot_stats as c on c.id = s.stats_curr_id
+left outer join job as j on j.custom_id = s.job_id
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[SlotSet.count_sql]
+select count(1)
+from (select distinct name from slot as s {sql_where}) as s
+
+[SlotStatSet.sql]
+select
+  sum(case activity when 'Idle' then 1 else 0 end) as idl,
+  sum(1) as all
+from (select
+  s.name,
+  s.pool,
+  s.qmf_update_time,
+  c.activity
+from slot as s
+left outer join slot_stats as c on c.id = s.stats_curr_id) as s
+{sql_where}
+
+[SlotStatSet.count_sql]
+1


Property changes on: mgmt/trunk/cumin/python/cumin/grid/slot.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/grid/submitter.py (from rev 3256, mgmt/trunk/cumin/python/cumin/submitter.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/submitter.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/submitter.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,110 @@
+import logging
+
+from wooly import *
+from wooly.widgets import *
+from wooly.forms import *
+from wooly.resources import *
+from wooly.tables import *
+from cumin.stat import *
+from cumin.widgets import *
+from cumin.parameters import *
+from cumin.formats import *
+from cumin.util import *
+
+from job import *
+
+strings = StringCatalog(__file__)
+log = logging.getLogger("cumin.grid.submitter")
+
+class SubmitterSet(CuminTable):
+    def __init__(self, app, name):
+        super(SubmitterSet, self).__init__(app, name)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+
+        self.set_default_column(col)
+
+    def render_title(self, session):
+        return "Submitters %s" % fmt_count(Submitter.select().count())
+
+    class NameColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+        def render_content(self, session, data):
+            sub = Identifiable(data["id"])
+            href = self.page.main.grid.pool.submitter.get_href(session, sub)
+            return fmt_link(href, data["name"])
+
+class SubmitterFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(SubmitterFrame, self).__init__(app, name)
+
+        self.object = SubmitterParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.view = SubmitterView(app, "view")
+        self.add_mode(self.view)
+
+class SubmitterView(CuminView):
+    def __init__(self, app, name):
+        super(SubmitterView, self).__init__(app, name)
+
+        status = SubmitterStatus(app, "status")
+        self.add_child(status)
+
+        self.__tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.__tabs)
+
+        stats = SubmitterStats(app, "stats")
+        self.__tabs.add_tab(stats)
+
+        jobs = SubmitterJobSet(app, "jobs")
+        self.__tabs.add_tab(jobs)
+
+        details = CuminDetails(app, "details")
+        self.__tabs.add_tab(details)
+
+class SubmitterStatus(CuminStatus):
+    def render_title(self, session, submitter):
+        return "Submitter Status"
+
+class SubmitterStats(Widget):
+    def __init__(self, app, name):
+        super(SubmitterStats, self).__init__(app, name)
+
+        stats = StatSet(app, "general", "general")
+        self.add_child(stats)
+
+        chart = self.JobsChart(app, "jobs")
+        self.add_child(chart)
+
+    def render_title(self, session):
+        return "Statistics"
+
+    class JobsChart(StatValueChart):
+        def __init__(self, app, name):
+            super(SubmitterStats.JobsChart, self).__init__ \
+                (app, name)
+
+            self.stats = ("RunningJobs", "IdleJobs", "HeldJobs")
+
+        def render_title(self, session, sched):
+            return "Jobs"
+
+class SubmitterJobSet(JobTab):
+    def __init__(self, app, name):
+        super(SubmitterJobSet, self).__init__(app, name)
+
+    def get_visible_columns(self, session):
+        return self.get_request_visible_columns(session, ["custom_group", "scheduler"])
+
+    def render_sql_where(self, session, submitter):
+        phase_sql = self.get_phase_sql(session)
+        submitter_sql = "j.submitter_id = %i" % submitter.id
+        return "where %s" % " and ".join([phase_sql, submitter_sql])
+
+    def render_title(self, session, submitter):
+        submitter_sql = "submitter_id = %i" % submitter.id
+        return "Jobs %s" % fmt_count(Job.select(submitter_sql).count())


Property changes on: mgmt/trunk/cumin/python/cumin/grid/submitter.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/grid/submitter.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/submitter.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/submitter.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/grid/submitter.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,54 @@
+[SubmitterSet.sql]
+select
+  s.id,
+  s.name
+from submitter as s
+inner join scheduler as d on s.scheduler_id = d.id
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[SubmitterSet.count_sql]
+select count(*) from submitter as s
+inner join scheduler as d on s.scheduler_id = d.id
+{sql_where}
+
+[SubmitterStats.html]
+<table class="twocol">
+  <tbody>
+  <tr>
+    <td>
+      <h2>General</h2>
+      {general}
+    </td>
+    <td>
+      {jobs}
+    </td>
+  </tr>
+  </tbody>
+</table>
+
+[SubmitterJobSet.html]
+<div class="rfloat">{phase}</div>
+<form id="{id}" style="clear:right;" method="post" action="?">
+
+  <div class="sactions">
+    {job_search}
+    <h2>Act on Selected Jobs:</h2>
+    {hold} {release} {remove}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+	<th class="setnav" colspan="{column_count}">
+	  <div class="rfloat">{page}</div>
+	  {count}
+	</th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>


Property changes on: mgmt/trunk/cumin/python/cumin/grid/submitter.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Added: mgmt/trunk/cumin/python/cumin/inventory/__init__.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/inventory/__init__.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/inventory/__init__.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1 @@
+from main import *

Added: mgmt/trunk/cumin/python/cumin/inventory/main.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/inventory/main.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/inventory/main.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,41 @@
+from wooly import *
+from wooly.widgets import *
+from wooly.resources import *
+from cumin.widgets import *
+from cumin.util import *
+
+from system import *
+
+strings = StringCatalog(__file__)
+
+class InventoryFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(InventoryFrame, self).__init__(app, name)
+
+        self.view = InventoryView(app, "view")
+        self.add_mode(self.view)
+
+        self.system = SystemFrame(app, "system")
+        self.add_mode(self.system)
+
+    def render_title(self, session):
+        return "Inventory"
+
+class InventoryView(Widget):
+    def __init__(self, app, name):
+        super(InventoryView, self).__init__(app, name)
+
+        heading = self.Heading(app, "heading")
+        self.add_child(heading)
+
+        self.tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.tabs)
+
+        self.tabs.add_tab(SystemSet(app, "systems"))
+
+    class Heading(CuminHeading):
+        def render_title(self, session):
+            return "Inventory"
+
+        def render_icon_href(self, session):
+            return "resource?name=system-36.png"

Added: mgmt/trunk/cumin/python/cumin/inventory/main.strings
===================================================================

Copied: mgmt/trunk/cumin/python/cumin/inventory/system.py (from rev 3256, mgmt/trunk/cumin/python/cumin/system.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/inventory/system.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/inventory/system.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,280 @@
+from mint import *
+from wooly import *
+from wooly.widgets import *
+from cumin.stat import *
+from cumin.widgets import *
+from cumin.parameters import *
+from cumin.formats import *
+from cumin.util import *
+
+strings = StringCatalog(__file__)
+
+class SystemSet(CuminTable, Form):
+    def __init__(self, app, name):
+        super(SystemSet, self).__init__(app, name)
+
+        self.ids = CheckboxIdColumn(app, "id")
+        self.add_column(self.ids)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+        self.set_default_column(col)
+
+        col = self.KernelColumn(app, "kernel")
+        self.add_column(col)
+
+        col = self.ArchColumn(app, "arch")
+        self.add_column(col)
+
+        col = self.FreeMemoryColumn(app, "mem_free")
+        col.alignment = "right"
+        self.add_column(col)
+
+        col = self.LoadColumn(app, "load")
+        col.alignment = "right"
+        self.add_column(col)
+
+    def render_title(self, session, *args):
+        return "Systems %s" % fmt_count(self.get_item_count(session, *args))
+
+    class NameColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+        def render_content(self, session, data):
+            system = Identifiable(data["id"])
+            href = self.page.main.inventory.system.get_href(session, system)
+            return fmt_link(href, fmt_shorten(data["name"]))
+
+    class KernelColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Kernel"
+
+    class ArchColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Arch"
+
+    class FreeMemoryColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Free Memory"
+
+        def render_content(self, session, data):
+            mem_free = data["mem_free"]
+
+            if mem_free:
+                return "%i KB" % mem_free
+            else:
+                return fmt_none_brief()
+
+    class LoadColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Load Average"
+
+        def render_content(self, session, data):
+            load = data["load"]
+
+            if load:
+                return "%0.3f" % load
+            else:
+                return fmt_none_brief()
+
+class TopSystemSet(TopTable):
+    def __init__(self, app, name):
+        super(TopSystemSet, self).__init__(app, name)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+
+        self.set_default_column(col)
+
+        col = self.LoadColumn(app, "load")
+        col.alignment = "right"
+        self.add_column(col)
+
+    class NameColumn(TopTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+        def render_content(self, session, data):
+            system = Identifiable(data["id"])
+            href = self.page.main.inventory.system.get_href(session, system)
+            return fmt_link(href, fmt_shorten(data["name"]))
+
+    class LoadColumn(TopTableColumn):
+        def render_title(self, session, data):
+            return "Load Average"
+
+        def render_content(self, session, data):
+            return "%0.3f" % data["load_avg"]
+
+class SystemFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(SystemFrame, self).__init__(app, name)
+
+        self.object = SystemParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.view = SystemView(app, "view")
+        self.add_mode(self.view)
+
+class SystemStatus(CuminStatus):
+    def render_mem_free(self, session, system):
+        return self.app.model.system.memFree.value_html(system)
+
+    def render_load_average(self, session, system):
+        return self.app.model.system.loadAverage1Min.value_html(system)
+
+from cumin.visualizations import SlotMap
+
+class SystemStats(Widget):
+    def __init__(self, app, name):
+        super(SystemStats, self).__init__(app, name)
+
+        self.add_child(StatSet(app, "stats", "general"))
+
+        chart = StatValueChart(app, "freemem")
+        chart.stats = ("memFree",)
+        self.add_child(chart)
+
+        chart = StatValueChart(app, "loadavg")
+        chart.stats = ("loadAverage1Min",)
+        self.add_child(chart)
+
+        vis = self.SystemSlotMap(app, "system_slot_map")
+        self.add_child(vis)
+
+    def render_title(self, session):
+        return "Statistics"
+
+    def render_slot_job_url(self, session):
+        job = Identifiable("XXX")
+        return self.page.main.grid.pool.job.get_href(session, job)
+
+    class SystemSlotMap(SlotMap):
+        def get_title_name(self, session, sysimage):
+            return sysimage.nodeName
+
+        def render_slot_clip_size(self, session, *args):
+            return 240
+
+class SystemView(CuminView):
+    def __init__(self, app, name):
+        super(SystemView, self).__init__(app, name)
+
+        summary = CuminSummary(app, "summary")
+        self.add_child(summary)
+
+        status = SystemStatus(app, "status")
+        self.add_child(status)
+
+        self.__tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.__tabs)
+
+        self.__tabs.add_tab(SystemStats(app, "stats"))
+        self.__tabs.add_tab(SystemJobSet(app, "jobs"))
+        self.__tabs.add_tab(SystemSlotSet(app, "slots"))
+        self.__tabs.add_tab(SystemServices(app, "services"))
+        self.__tabs.add_tab(CuminDetails(app, "details"))
+
+from cumin.grid.job import JobTab
+
+class SystemJobSet(JobTab):
+    def render_title(self, session, system):
+        return "Grid Jobs %s" % fmt_count(self.get_item_count(session, system))
+
+    def render_sql_where(self, session, system):
+        elems = list()
+        elems.append("s.system = %(nodeName)s")
+        elems.append(self.get_phase_sql(session))
+        return "where %s" % " and ".join(elems)
+
+    def get_sql_values(self, session, system):
+        return {"nodeName": system.nodeName}
+
+from cumin.grid.slot import SlotSet
+
+class SystemSlotSet(SlotSet):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, system):
+        # dont' use self.get_item_count because it will cause a costly sql query
+        # instead, use the systemslotset in model so it will be cached
+        count = self.app.model.system.slots.get_slot_count(session, system)
+        return "Grid Slots %s" % fmt_count(count)
+
+    def render_sql_where(self, session, system):
+        elems = list()
+        elems.append("system = %(nodeName)s")
+        recent = self.get_recent_sql_where(session)
+        if recent:
+            elems.append(recent)
+
+        return "where %s" % " and ".join(elems)
+
+    def get_sql_values(self, session, system):
+        return {"nodeName": system.nodeName}
+
+class SystemServices(ItemSet):
+    def render_title(self, session, *args):
+        return "Services"
+
+    def get_args(self, session):
+        return (self.frame.get_object(session),)
+
+    def do_get_items(self, session, system):
+        daemons = list()
+        daemon_types = [Scheduler, Collector, Negotiator]
+        sql = "system = '%s'" % system.nodeName
+
+        for daemon in daemon_types:
+            system_daemons = daemon.select(sql)
+            for devil in system_daemons:
+                try:
+                    daemons.append(devil)
+                except Exception, e:
+                    pass
+
+        # using a loop instead of an sql select with an outer join
+        brokers = Broker.select()
+        for broker in brokers:
+            if broker.system.nodeName == system.nodeName:
+                daemons.append(BrokerRegistration.get(broker.registrationID))
+
+        return daemons
+
+    def render_item_content(self, session, item):
+        if isinstance(item, BrokerRegistration):
+            reg = Identifiable(item.id)
+            href = self.page.main.messaging.broker.get_href(session, reg)
+            return fmt_link(href, item.url)
+        else:
+            pool = model.Pool.get(item.Pool)
+            self.page.main.grid.pool.object.set(session, pool)
+            self.page.main.show_grid_tab(session)
+            daemon = Identifiable(item.id)
+            if isinstance(item, Collector):
+                self.page.main.grid.pool.view.set_collector_tab(session)
+                href = self.page.main.grid.pool.collector.get_href \
+                    (session, daemon)
+            elif isinstance(item, Scheduler):
+                self.page.main.grid.pool.view.set_scheduler_tab(session)
+                href = self.page.main.grid.pool.scheduler.get_href \
+                    (session, daemon)
+            elif isinstance(item, Negotiator):
+                self.page.main.grid.pool.view.set_negotiator_tab(session)
+                href = self.page.main.grid.pool.negotiator.get_href \
+                    (session, daemon)
+            return fmt_link(href, item.Name)
+
+    def render_item_type(self, session, item):
+        if isinstance(item, Collector):
+            return "Collector"
+        elif isinstance(item, Scheduler):
+            return "Scheduler"
+        elif isinstance(item, Negotiator):
+            return "Negotiator"
+        elif isinstance(item, BrokerRegistration):
+            return "Broker"
+        else:
+            return "Daemon"


Property changes on: mgmt/trunk/cumin/python/cumin/inventory/system.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/inventory/system.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/system.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/inventory/system.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/inventory/system.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,111 @@
+[SystemSet.sql]
+select
+  s.id,
+  s.node_name as name,
+  (s.os_name || ' ' || s.release) as kernel,
+  s.machine as arch,
+  c.mem_free,
+  c.load_average1_min as load
+from sysimage as s
+left outer join sysimage_stats as c on c.id = s.stats_curr_id
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[SystemSet.count_sql]
+select count(*) from sysimage as s
+{sql_where}
+
+[SystemSet.html]
+<form id="{id}" method="post" action="?">
+  <table class="mobjects">
+    <thead>
+      <tr>
+        <th class="setnav" colspan="{column_count}">
+          <div class="rfloat">{page}</div>
+          {count}
+        </th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>
+
+[TopSystemSet.sql]
+select
+  s.id,
+  s.node_name as name,
+  c.load_average1_min as load_avg
+from sysimage s
+join sysimage_stats as c on s.stats_curr_id = c.id
+order by load_avg desc
+limit 5
+
+[TopSystemSet.count_sql]
+--
+
+[SystemStatus.html]
+<div id="{id}" class="CuminStatus {color}">
+  <table>
+    <tr>
+      <th>Free Memory</th>
+      <td class="ralign">{mem_free}</td>
+    </tr>
+    <tr>
+      <th>Load Average</th>
+      <td class="ralign">{load_average}</td>
+    </tr>
+  </table>
+</div>
+
+[SystemStats.html]
+<table class="twocol">
+  <tbody>
+    <tr>
+      <td>
+        <h2>Memory/Load</h2>
+        {stats}
+	{system_slot_map}
+      </td>
+      <td>
+	{freemem}
+	{loadavg}
+      </td>
+    </tr>
+  </tbody>
+</table>
+<script type="text/javascript">
+    // <![CDATA[
+    var show_slot_job_url = "{slot_job_url}";
+    // ]]>
+</script>
+
+[SystemJobSet.html]
+<div class="rfloat">{phase}</div>
+
+<form id="{id}" style="clear:right;" method="post" action="?">
+  <table class="mobjects">
+    <thead>
+      <tr>
+	<th class="setnav" colspan="{column_count}">
+	  <div class="rfloat">{page}</div>
+	  {count}
+	</th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>
+
+[SystemServices.html]
+<h2>Services</h2>
+<table class="PropertySet">
+  <tbody>{items}</tbody>
+</table>
+
+[SystemServices.item_html]
+<tr><th>{item_type}</th><td>{item_content}</td></tr>


Property changes on: mgmt/trunk/cumin/python/cumin/inventory/system.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Deleted: mgmt/trunk/cumin/python/cumin/job.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/job.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/job.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,1404 +0,0 @@
-import logging
-
-from wooly import *
-from wooly.widgets import *
-from wooly.forms import *
-from wooly.resources import *
-from wooly.tables import *
-from time import time
-
-from stat import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-
-strings = StringCatalog(__file__)
-log = logging.getLogger("cumin.job")
-
-class JobSet(CuminTable, Form):
-    def __init__(self, app, name):
-        super(JobSet, self).__init__(app, name)
-
-        self.ids = CheckboxIdColumn(app, "id")
-        self.add_column(self.ids)
-
-        col = self.CustomIdColumn(app, "custom_id")
-        self.add_column(col)
-        self.set_default_column(col)
-
-        col = self.GlobalJobIdColumn(app, "global_job_id")
-        col.visible = False
-        self.add_column(col)
-
-        col = self.CommandColumn(app, "cmd")
-        self.add_column(col)
-
-        col = self.AccountingGroupColumn(app, "agroup")
-        col.visible = False
-        self.add_column(col)
-
-        col = self.SchedulerColumn(app, "scheduler")
-        col.visible = False
-        self.add_column(col)
-
-        col = self.SubmitterColumn(app, "submitter")
-        col.visible = False
-        self.add_column(col)
-
-        col = self.ClusterIdColumn(app, "cluster_id")
-        col.alignment = "right"
-        col.visible = False
-        self.add_column(col)
-
-        col = self.ConcurrencyLimitsColumn(app, "concurrency_limits")
-        #col.visible = False
-        self.add_column(col)
-
-        col = self.CustomGroupColumn(app, "custom_group")
-        col.visible = False
-        self.add_column(col)
-
-        col = self.CustomPriorityColumn(app, "custom_priority")
-        col.visible = False
-        self.add_column(col)
-
-        col = self.StatusColumn(app, "job_status")
-        self.add_column(col)
-
-        col = self.TitleColumn(app, "title")
-        col.visible = False
-        self.add_column(col)
-
-        col = self.ArgsColumn(app, "args")
-        col.alignment = "right"
-        col.visible = False
-        self.add_column(col)
-
-        self.phase = JobStatusSwitch(app, "phase")
-        self.add_child(self.phase)
-
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def get_phase_sql(self, session, phase=None):
-        return self.phase.get_sql_constraint(session, phase)
-
-    def get_phase_title(self, session):
-        state = self.phase.get(session)
-        return self.phase.get_title(state)
-
-    def render_sql_where(self, session, *args):
-        phase = len(args) > 1 and args[1] or None
-        elems = list()
-        elems.append(self.get_phase_sql(session, phase))
-        elems.append("s.pool = %(pool)s")
-        return "where %s" % " and ".join(elems)
-
-    def get_sql_values(self, session, *args):
-        pool = args[0]
-        return {"pool": pool.id}
-
-    class ArgsColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Arguments"
-
-    class ClusterIdColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Cluster Id"
-
-    class ConcurrencyLimitsColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Limits"
-
-    class CustomGroupColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Job Group"
-
-        def render_content(self, session, data):
-            name = data[self.name]
-
-            if name:
-                group = Identifiable(name)
-                href = self.page.main.pool.job_group.get_href(session, group)
-                return fmt_link(href, fmt_shorten(name, 12, 3))
-
-    class CustomIdColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "ID"
-
-        def render_content(self, session, data):
-            id = data[self.name]
-
-            if id:
-                job = Identifiable(data["id"])
-                href = self.page.main.pool.job.get_href(session, job)
-                return fmt_link(href, fmt_shorten(id, 12, 3))
-
-    class CustomPriorityColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Custom Priority"
-
-    class GlobalJobIdColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Global Job Id"
-
-        def render_content(self, session, data):
-            id = data["id"]
-
-            if id:
-                job = Identifiable(data["id"])
-                href = self.frame.job.get_href(session, job)
-                content = fmt_shorten(data[self.name], 12, 3)
-                return fmt_link(href, content)
-
-    class StatusColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Status"
-
-        def render_content(self, session, data):
-            stat = data["job_status"]
-            return JobStatusInfo.get_status_string(stat)
-
-    class AccountingGroupColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Accounting Group"
-
-    class SubmitterColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Submitter"
-
-        def render_content(self, session, data):
-            name = data["submitter"]
-
-            if name:
-                sub = Identifiable(data["submitter_id"])
-                href = self.page.main.pool.submitter.get_href(session, sub)
-                return fmt_link(href, fmt_shorten(name))
-
-    class SchedulerColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Scheduler"
-
-        def render_content(self, session, data):
-            name = data["scheduler"]
-
-            if name:
-                sched = Identifiable(data["scheduler_id"])
-                href = self.page.main.pool.scheduler.get_href(session, sched)
-                return fmt_link(href, fmt_shorten(name))
-
-    class CommandColumn(ItemTableColumn):
-        def render_title(self, session, data):
-            return "Command"
-
-        def render_content(self, session, data):
-            return fmt_shorten(data[self.name], 0, 16)
-
-    class TitleColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Title"
-
-class TopJobSet(TopTable):
-    def __init__(self, app, name):
-        super(TopJobSet, self).__init__(app, name)
-
-        col = self.NameColumn(app, "name")
-        self.add_column(col)
-
-        self.set_default_column(col)
-
-        col = self.DurationColumn(app, "name")
-        col.alignment = "right"
-        self.add_column(col)
-
-    class NameColumn(TopTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-        def render_content(self, session, data):
-            pool = Identifiable(data["pool"])
-            job = Identifiable(data["id"])
-
-            branch = session.branch()
-            self.page.main.pool.object.set(session, pool)
-            self.page.main.pool.job.object.set(session, job)
-            self.page.main.pool.job.show(session)
-            return fmt_link(branch.marshal(), fmt_shorten(data["name"]))
-
-    class DurationColumn(TopTableColumn):
-        def render_title(self, session, data):
-            return "Duration"
-
-        def render_content(self, session, data):
-            since = data["q_date"]
-            return fmt_duration(time() - secs(since))
-
-class JobTab(JobSet):
-    def __init__(self, app, name):
-        super(JobTab, self).__init__(app, name)
-
-        self.__remove = JobRemoveButton(app, "remove")
-        self.add_child(self.__remove)
-
-        self.__hold = JobHoldButton(app, "hold")
-        self.add_child(self.__hold)
-
-        self.__release = JobReleaseButton(app, "release")
-        self.add_child(self.__release)
-
-        self.job_search = self.JobSearch(app, "job_search")
-        self.add_child(self.job_search)
-
-    def find_job(self, session):
-        search_term = self.job_search.get(session)
-
-        if search_term:
-            object = self.frame.get_object(session)
-            rows = self.find_item(session, object)
-
-            if rows:
-                try:
-                    first = rows[0]
-                    job = Identifiable(first["id"])
-                    href = self.app.main_page.main.pool.job.get_href(session, job)
-                    self.page.set_redirect_url(session, href)
-                except:
-                    self.job_search.set_not_found(session, search_term)
-            else:
-                self.job_search.set_not_found(session, search_term)
-
-            self.job_search.set(session, None)
-
-    def render_find_sql_where(self, session, *args):
-        return "j.custom_id = %(custom_id)s"
-
-    def get_find_sql_values(self, session, pool):
-        return {"custom_id": self.job_search.get(session)}
-        #return {"custom_id": self.job_search.get(session), "pool": pool.id}
-
-    def get_full_item_count(self, session, *args):
-        # request item count will phase=="a"
-        new_args = (args[0], "a")
-        return self.get_item_count(session, *new_args)
-
-    def get_visible_columns(self, session):
-        return self.get_request_visible_columns(session, ["custom_group", "scheduler", "submitter"])
-
-    def render_count(self, session, *args):
-        count = self.get_item_count(session, *args)
-        phase = self.get_phase_title(session)
-        if phase == "All":
-            phase = ""
-        return "%i %s %s" % (count, phase, count == 1 and "Job" or "Jobs")
-
-    class JobSearch(StringInput):
-        """ displays the input box and button used to search for job id """
-
-        def __init__(self, app, name):
-            super(JobTab.JobSearch, self).__init__(app, name)
-
-            self.__go = self.JobSearchButton(app, "go")
-            self.add_child(self.__go)
-
-            self.not_found = Attribute(app, "error")
-            self.add_attribute(self.not_found)
-
-        def set_not_found(self, session, value):
-            self.not_found.set(session, value)
-
-        def render_search_prompt(self, session):
-            not_found = self.not_found.get(session)
-            return not_found and "%s Not Found" % escape_entity(not_found) or self.render_search_default_prompt(session)
-
-        def render_search_default_prompt(self, session):
-            return "Enter Job ID"
-
-        def render_search_class(self, session):
-            return self.not_found.get(session) and "search_error" or " "
-
-        def find_job(self, session):
-            self.parent.find_job(session)
-
-        class JobSearchButton(FormButton):
-            def process_submit(self, session):
-                self.parent.find_job(session)
-
-            def render_content(self, session):
-                return "Go"
-
-from system import SystemFrame, SystemSet
-
-class JobGroupFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(JobGroupFrame, self).__init__(app, name)
-
-        self.object = JobGroupParameter(app, "id")
-        self.add_parameter(self.object)
-
-        self.view = JobGroupView(app, "view")
-        self.add_mode(self.view)
-        self.set_view_mode(self.view)
-
-        self.jobs_hold = JobSetHold(app, "jobshold")
-        self.add_mode(self.jobs_hold)
-
-        self.jobs_release = JobSetRelease(app, "jobsrelease")
-        self.add_mode(self.jobs_release)
-
-        self.jobs_remove = JobSetRemove(app, "jobsremove")
-        self.add_mode(self.jobs_remove)
-
-        self.system = SystemFrame(app, "system")
-        self.add_mode(self.system)
-
-class JobGroupView(CuminView):
-    def __init__(self, app, name):
-        super(JobGroupView, self).__init__(app, name)
-
-        summary = CuminSummary(app, "summary")
-        self.add_child(summary)
-
-        status = JobGroupStatus(app, "status")
-        self.add_child(status)
-
-        self.__tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.__tabs)
-
-        self.__tabs.add_tab(JobGroupStats(app, "stats"))
-        self.__tabs.add_tab(JobGroupJobSet(app, "jobs"))
-        self.__tabs.add_tab(JobGroupSystemSet(app, "systems"))
-        #self.__tabs.add_tab(CuminDetails(app, "details"))
-
-class JobGroupStats(Widget):
-    def __init__(self, app, name):
-        super(JobGroupStats, self).__init__(app, name)
-
-        stats = JobGroupStatSet(app, "general", "general")
-        self.add_child(stats)
-
-    def render_title(self, session):
-        return "Statistics"
-
-class JobGroupStatSet(StatSet):
-    def __init__(self, app, name, category):
-        super(JobGroupStatSet, self).__init__(app, name, category)
-
-        self.jobs = Attribute(app, "jobs")
-        self.add_attribute(self.jobs)
-
-    def process(self, session):
-        group = self.frame.get_args(session)[0]
-        if group:
-            where_group = "custom_group = '%s'" % group.get_id()
-            value = Job.select(where_group).count()
-            self.jobs.set(session, value)
-        super(JobGroupStatSet, self).process(session)
-
-    def render_rate_text(self, session, args):
-        return "Percentage"
-
-    def render_item_name(self, session, args):
-        stat, object = args
-        return stat.name
-
-    def render_item_value(self, session, args):
-        stat, group = args
-        if stat.name == "Jobs":
-            return self.jobs.get(session)
-        else:
-            state = stat.name
-            value = self.get_value(group, state)
-        return value
-
-    def get_value(self, group, state):
-        where_group = "custom_group = '%s' \
-            and job_status = %i" % (group.get_id(),
-                                    JobStatusInfo.get_status_int(state))
-        return Job.select(where_group).count()
-
-    def render_item_rate(self, session, args):
-        stat, group = args
-        jobs = self.jobs.get(session)
-        state = stat.name
-        if stat.name == "Jobs":
-            value = jobs
-        else:
-            value = self.get_value(group, state)
-        percent = (value*1.0) / (jobs*1.0) * 100.0
-        return jobs and "%2.1f" % percent or "-"
-
-class JobRemoveButton(FormButton):
-    def process_submit(self, session):
-        ids = self.parent.ids.get(session)
-        self.parent.ids.clear(session)
-
-        href = self.frame.jobs_remove.get_href(session, ids)
-        self.page.set_redirect_url(session, href)
-
-    def render_content(self, session):
-        return "Remove"
-
-    def render_disabled_attr(self, session, *args):
-        phase = self.parent.phase.get(session)
-        return phase == "d" and "disabled=\"disabled\"" or None
-
-    def render_class(self, session, *args):
-        phase = self.parent.phase.get(session)
-        return phase == "d" and "disabled" or "enabled"
-
-class JobHoldButton(FormButton):
-    def process_submit(self, session):
-        ids = self.parent.ids.get(session)
-        self.parent.ids.clear(session)
-
-        href = self.frame.jobs_hold.get_href(session, ids)
-        self.page.set_redirect_url(session, href)
-
-    def render_content(self, session):
-        return "Hold"
-
-    def render_disabled_attr(self, session, *args):
-        phase = self.parent.phase.get(session)
-        return (phase == "h" or phase == "d") and "disabled=\"disabled\"" or None
-
-    def render_class(self, session, *args):
-        phase = self.parent.phase.get(session)
-        return (phase == "h" or phase == "d") and "disabled" or "enabled"
-
-class JobReleaseButton(FormButton):
-    def process_submit(self, session):
-        ids = self.parent.ids.get(session)
-        self.parent.ids.clear(session)
-
-        href = self.frame.jobs_release.get_href(session, ids)
-        self.page.set_redirect_url(session, href)
-
-    def render_content(self, session):
-        return "Release"
-
-    def render_disabled_attr(self, session, *args):
-        phase = self.parent.phase.get(session)
-        return (phase == "r" or phase == "d") and "disabled=\"disabled\"" or None
-
-    def render_class(self, session, *args):
-        phase = self.parent.phase.get(session)
-        return (phase == "r" or phase == "d") and "disabled" or "enabled"
-
-class JobGroupJobSet(JobTab):
-    def __init__(self, app, name):
-        super(JobGroupJobSet, self).__init__(app, name)
-
-        self.__remove = JobRemoveButton(app, "remove")
-        self.add_child(self.__remove)
-
-        self.__hold = JobHoldButton(app, "hold")
-        self.add_child(self.__hold)
-
-        self.__release = JobReleaseButton(app, "release")
-        self.add_child(self.__release)
-
-    def get_visible_columns(self, session):
-        return self.get_request_visible_columns(session, ["scheduler", "submitter"])
-
-    def render_title(self, session, group):
-        where_group = "custom_group = '%s'" % group.get_id()
-        return "Jobs %s" % fmt_count(Job.select(where_group).count())
-
-    def render_sql_where(self, session, group):
-        phase_sql = self.get_phase_sql(session)
-        group_sql = "j.custom_group = '%s'" % group.get_id()
-        return "where %s" % " and ".join([phase_sql, group_sql])
-
-    def render_count(self, session, *args):
-        str = super(JobGroupJobSet, self).render_count(session, *args)
-        return "%s in Job Group '%s'" % (str, args[0].id)
-
-class JobGroupStatus(CuminStatus):
-    def render_color(self, session, job_group):
-        #return JobStatusInfo.get_status_color(job.JobStatus)
-        return "green"
-
-    def render_job_status(self, session, job_group):
-        #return JobStatusInfo.get_status_string(job.JobStatus)
-        return "Status"
-
-class JobGroupSystemSet(SystemSet):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_sql_where(self, session, group):
-        subquery = """
-            select 1
-            from slot as l
-            join job as j on j.custom_id = l.job_id
-            where j.custom_group = %(id)s and l.system = s.node_name
-        """
-
-        return "where exists (%s)" % subquery
-
-    def get_sql_values(self, session, group):
-        return {"id": group.id}
-
-class JobFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(JobFrame, self).__init__(app, name)
-
-        self.object = JobParameter(app, "id")
-        self.add_parameter(self.object)
-
-        view = JobView(app, "view")
-        self.add_mode(view)
-        self.set_view_mode(view)
-
-        self.__edit_ads = JobAdsEditor(app, "editads")
-        self.add_mode(self.__edit_ads)
-
-        self.__system = SystemFrame(app, "system")
-        self.add_mode(self.__system)
-
-    def show_ads_edit(self, session):
-        self.page.set_frame(session, self.__edit_ads)
-        return self.show_mode(session, self.__edit_ads)
-
-    def show_job_group(self, session, jobgroup):
-        self.__job.set_object(session, jobgroup)
-        self.page.set_frame(session, self.__job)
-        self.__job.set_switch(session, "group")
-        return self.show_mode(session, self.__job)
-
-    def show_system(self, session, system):
-        frame = self.show_mode(session, self.__system)
-        frame.set_object(session, system)
-        return self.page.set_frame(session, frame)
-
-
-class JobView(CuminView):
-    def __init__(self, app, name):
-        super(JobView, self).__init__(app, name)
-
-        summary = CuminSummary(app, "summary")
-        self.add_child(summary)
-
-        status = JobStatus(app, "status")
-        self.add_child(status)
-
-        self.__tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.__tabs)
-
-        self.__tabs.add_tab(JobAdsViewer(app, "jobads"))
-        self.__tabs.add_tab(JobOutput(app, "output"))
-        self.__tabs.add_tab(JobSystemSet(app, "systems"))
-        self.__tabs.add_tab(CuminDetails(app, "details"))
-
-class JobSystemSet(SystemSet):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_sql_where(self, session, job):
-        return """
-            where exists
-              (select 1
-               from slot
-               where system = s.node_name and job_id = %(id)s)
-        """
-
-    def get_sql_values(self, session, job):
-        return {"id": "%i.%i" % (job.ClusterId, job.ProcId)}
-
-class JobAdsSet(PropertySet):
-    def __init__(self, app, name):
-        super(JobAdsSet, self).__init__(app, name, )
-
-        self.types = {0: "expression",
-                      1: "integer",
-                      2: "float",
-                      3: "string"}
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def do_get_items(self, session, job):
-        items = self.items.get(session)
-        if not items:
-            items = self.gen_items(session, job)
-            # cache the items
-            self.items.set(session, items)
-
-        return items
-
-    def get_raw_ads(self, session, job):
-        action = self.app.model.job.getad
-        return action.do_invoke(job)
-
-    def gen_items(self, session, job):
-        job_ads = self.get_raw_ads(session, job)
-
-        cls = self.app.model.get_class_by_object(job)
-        return [self.gen_item(x, job_ads[x]["VALUE"], cls, dtype=self.types[job_ads[x]["TYPE"]]) for x in job_ads]
-        # list of dictionaries
-        # each disctionary has:
-        # name:, value:, type: [, error:] [, property:] [,path:]
-        #return [self.gen_item(x, job_ads[x], cls) for x in job_ads]
-#
-
-    def gen_item(self, name, value, cls, path=None, dtype=None, error=None, orig=None):
-        """ Generate a dict with name, value, type, error, path, property, orig
-
-            This is called with raw GetAd data and with processed data from
-            a form submit. With raw data, only the name and value will be present.
-            With form data, we might have a path, dtype, or error. dtype is the
-            data type that was remembered from the raw data.
-        """
-
-        idict = dict()
-        idict["name"] = name
-        idict["value"] = value
-        idict["orig"] = value
-        idict["type"] = dtype
-        if dtype == "string":
-            idict["value"] = self.strip_string_quotes(value)
-        if orig:
-            idict["orig"] = orig
-        if error:
-            if "error" in error:
-                idict["error"] = error["error"]
-
-        if name in cls.ad_properties_by_name:
-            idict["property"] = cls.ad_properties_by_name[name]
-        if path:
-            idict["path"] = path
-        return idict
-
-    def strip_string_quotes(self, value):
-        dvalue = value
-        if value:
-            if value[:1] == "\"" and value[-1:] ==  "\"":
-                dvalue = value[1:-1]
-        return dvalue
-
-class JobPropertyRenderer(TemplateRenderer):
-    def render_title(self, session, item):
-        title = item["name"]
-        if "property" in item:
-            property = item["property"]
-            if property.title:
-                title = property.get_title(session)
-        return escape_amp(title)
-
-    def render_value(self, session, item):
-        value = item["value"]
-        if "property" in item:
-            property = item["property"]
-            if property.renderer:
-                value = property.renderer(session, value)
-        ret = escape_entity(str(value))
-        return self.insert_breaks(ret)
-
-    def insert_breaks(self, value):
-        subwords = list()
-        snippets = parse(value, begin_delim="&", end_delim=";")
-        for snippet in snippets:
-            while len(snippet) > 40:
-                subwords.append(snippet[:40])
-                snippet = snippet[40:]
-            subwords.append(snippet)
-
-        return "&#8203;".join(subwords)
-
-    def render_inline_help(self, session, item):
-        if "property" in item:
-            property = item["property"]
-            return property.description
-
-class JobAdsViewer(JobAdsSet):
-    def __init__(self, app, name):
-        super(JobAdsViewer, self).__init__(app, name)
-
-        self.group_tmpl = Template(self, "group_html")
-        self.item_renderer = JobPropertyRenderer(self, "property_html")
-
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, job):
-        return "Attributes"
-
-    def do_get_items(self, session, args):
-        job = args[0]
-        group = args[1]
-        group_items = list()
-        if job:
-            all_items = super(JobAdsViewer, self).do_get_items(session, job)
-            for item in all_items:
-                if "property" in item:
-                    property = item["property"]
-                    item_group = property.group
-                else:
-                    item_group = "Other"
-                if item_group == group:
-                    group_items.append(item)
-
-        return group_items
-
-    def render_properties(self, session, *args):
-        items = self.do_get_items(session, *args)
-        writer = Writer()
-
-        for item in items:
-            self.item_renderer.render(writer, session, item)
-
-        return writer.to_string()
-
-    def render_edit_ads_url(self, session, job):
-        branch = session.branch()
-        self.frame.show_ads_edit(branch)
-        return branch.marshal()
-
-    def render_groups(self, session, job):
-        groups = self.app.model.get_ad_groups()
-        writer = Writer()
-        for group in groups:
-            self.group_tmpl.render(writer, session, (job, group,))
-        return writer.to_string()
-
-    def render_group_name(self, session, args):
-        return args[1]
-
-class JobAdsEditor(CuminForm, JobAdsViewer):
-    def __init__(self, app, name):
-        super(JobAdsEditor, self).__init__(app, name)
-
-        # the parameter that will hold all the field values
-        self.ads = DictParameter(app, "params")
-        self.add_parameter(self.ads)
-
-        self.item_renderer = EditablePropertyRenderer(self, "property_html")
-
-    def do_get_items(self, session, args):
-        job = args[0]
-        group = args[1]
-        cls = self.app.model.get_class_by_object(job)
-        ads = self.ads.get(session)
-        if len(ads):
-            return [self.gen_item(x, ads[x]["value"], cls, path=self.ads.path,
-                                  dtype=ads[x]["type"], error=ads[x], orig=ads[x]["orig"]) for x in ads
-                                  if self.is_group(x, cls, group)]
-        else:
-            items = super(JobAdsEditor, self).do_get_items(session, args)
-            for item in items:
-                item["path"] = self.ads.path
-            return items
-
-    def is_group(self, name, cls, group):
-        if name in cls.ad_properties_by_name:
-            property = cls.ad_properties_by_name[name]
-            item_group = property.group
-        else:
-            item_group = "Other"
-        return item_group == group
-
-    def process_cancel(self, session, job):
-        branch = session.branch()
-        self.ads.set(branch, None) # otherwise url is too long
-        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, job):
-        ads = self.ads.get(session)
-        errors = False
-
-        just_ads = dict()
-        for field in ads:
-            try:
-                fval = ads[field]["value"]
-            except KeyError:
-                ads[field]["value"] = ""
-                fval = ""
-            ftype = ads[field]["type"]
-            if ftype == "integer":
-                try:
-                    fval = int(fval)
-                except:
-                    ads[field]["error"] = "Integer value expected"
-                    errors = True
-            elif ftype == "float":
-                try:
-                    fval = float(fval)
-                except:
-                    ads[field]["error"] = "Floating point value expected"
-                    errors = True
-            elif ftype == "string":
-                fval = "\"%s\"" % fval
-            else:
-                fval = unicode(fval)
-            if "orig" in ads[field]:
-                orig = ads[field]["orig"]
-                if ftype == "integer":
-                    orig = int(orig)
-                elif ftype == "float":
-                    orig = float(orig)
-                if fval != orig:
-                    just_ads[unicode(field)] = fval
-
-        if not errors:
-            for field in just_ads:
-                action = self.app.model.job.setattribute
-                action.invoke(job, [field, just_ads[field]])
-            self.process_cancel(session, job)
-
-class JobOutput(Form):
-    def __init__(self, app, name):
-        super(JobOutput, self).__init__(app, name)
-
-        self.which_file = self.FileSwitch(app, "file")
-        self.add_child(self.which_file)
-
-        self.first_last = self.FLSwitch(app, "first_last")
-        self.add_child(self.first_last)
-
-        self.__fetch = self.FetchButton(app, "refresh")
-        self.add_child(self.__fetch)
-
-        self.ads = JobAdsSet(app, "ads")
-        self.add_child(self.ads)
-
-        self.out_file = Parameter(app, "out")
-        self.add_parameter(self.out_file)
-
-        self.err_file = Parameter(app, "err")
-        self.add_parameter(self.err_file)
-
-        self.user_file = Parameter(app, "user")
-        self.add_parameter(self.user_file)
-
-        self.output = self.OutputFile(app, "job_output")
-        self.add_child(self.output)
-
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, *args):
-        return "Output"
-
-    def render(self, session, *args):
-        out_file = self.out_file.get(session)
-        err_file = self.err_file.get(session)
-        user_file = self.user_file.get(session)
-        if not out_file:
-            job = self.frame.get_args(session)[0]
-            items = self.ads.get_raw_ads(session, job)
-            out_file = err_file = user_file = None
-            if "Out" in items:
-                out_file = items["Out"]["VALUE"]
-            if "Err" in items:
-                err_file = items["Err"]["VALUE"]
-            if "UserLog" in items:
-                user_file = items["UserLog"]["VALUE"]
-
-            # strip any double quotes surrounding file names
-            out_file = self.ads.strip_string_quotes(out_file)
-            err_file = self.ads.strip_string_quotes(err_file)
-            user_file = self.ads.strip_string_quotes(user_file)
-
-            # remember the file names so we don't need to reget them
-            self.out_file.set(session, out_file)
-            self.err_file.set(session, err_file)
-            self.user_file.set(session, user_file)
-
-        # set title for radiotab so mouseover will display file name
-        self.which_file.set_file_name(session, "o", out_file)
-        self.which_file.set_file_name(session,"e", err_file)
-        self.which_file.set_file_name(session,"u", user_file)
-
-        if self.which_file.is_bad(out_file):
-            self.which_file.disable(session, "o")
-        if self.which_file.is_bad(err_file):
-            self.which_file.disable(session, "e")
-        if self.which_file.is_bad(user_file):
-            self.which_file.disable(session, "u")
-
-        return super(JobOutput, self).render(session, *args)
-
-    def render_loading(self, session, *args):
-        file = self.which_file.get_current_file_name(session)
-        return file and "loading..." or "Output, Error, and UserLog file names are invalid."
-
-    def get_file_args(self, session):
-        first_last = self.first_last.get(session)
-        if first_last == "t":
-            start = -2048
-            end = 0
-        else:
-            start = 0
-            end = 2048
-        file = self.which_file.get_current_file_name(session)
-        return (file, start, end)
-
-    class OutputFile(AjaxField):
-        def get_url(self, session):
-            job = self.parent.frame.get_args(session)[0]
-            if job:
-                file, start, end = self.parent.get_file_args(session)
-                if file:
-                    fl = self.parent.first_last.get(session)
-                    args = "%s&%i&%i&%s" % (file, start, end, fl)
-                    args = escape_amp(args)
-                    return "call.xml?class=job;id=%i;method=fetch;xargs=%s" % (job.id, args)
-
-        def do_render(self, session):
-            return self.render_script(session)
-
-    class FetchButton(FormButton):
-        def render_content(self, session):
-            return "Refresh"
-
-    class FileSwitch(StateSwitch):
-        def __init__(self, app, name):
-            super(JobOutput.FileSwitch, self).__init__(app, name)
-
-            self.add_state("o", "Output")
-            self.add_state("e", "Error")
-            self.add_state("u", "UserLog")
-
-            self.disabled = self.DisabledList(app, "disabled")
-            self.add_attribute(self.disabled)
-
-            self.link_titles = self.Titles(app, "link_titles")
-            self.add_attribute(self.link_titles)
-
-        class DisabledList(Attribute):
-            def get_default(self, session):
-                return list()
-
-        class Titles(Attribute):
-            def get_default(self, session):
-                return dict()
-
-        def disable(self, session, state):
-            disabled = self.disabled.get(session)
-            disabled.append(state)
-            self.disabled.set(session, disabled)
-            if state == self.get(session):
-                self.select_first_enabled(session)
-
-        def set_file_name(self, session, state, link_title):
-            link_titles = self.link_titles.get(session)
-            link_titles[state] = link_title
-            self.link_titles.set(session, link_titles)
-
-        def get_file_name(self, session, state):
-            link_titles = self.link_titles.get(session)
-            return state in link_titles and link_titles[state] or ""
-
-        def get_current_file_name(self, session):
-            state = self.get(session)
-            return self.get_file_name(session, state)
-
-        def select_first_enabled(self, session):
-            states = self.get_items(session)
-            disabled = self.disabled.get(session)
-            for state in states:
-                if not state in disabled:
-                    self.set(session, state)
-                    break
-
-        def render_item_link(self, session, state):
-            branch = session.branch()
-            self.set(branch, state)
-
-            title = self.get_title(state)
-            link_titles = self.link_titles.get(session)
-            link_title = state in link_titles and link_titles[state] or ""
-            disabled = self.disabled.get(session)
-            if state in disabled:
-                class_ = "disabled"
-                href = "javascript:void(0)"
-            else:
-                class_ = self.get(session) == state and "selected"
-                href = branch.marshal()
-            return fmt_link(href, title, class_, link_title=link_title)
-
-        def is_bad(self, file):
-            bad = False
-            if not file:
-                bad = True
-            elif "/dev/null" in file.lower():
-                bad = True
-            return bad
-
-
-    class FLSwitch(StateSwitch):
-        def __init__(self, app, name):
-            super(JobOutput.FLSwitch, self).__init__(app, name)
-
-            self.add_state("t", "Tail", "Display end of file")
-            self.add_state("h", "Head", "Display beginning of file")
-
-class JobStatus(CuminStatus):
-    def render_color(self, session, job):
-        if job:
-            return JobStatusInfo.get_status_color(job.JobStatus)
-
-    def render_job_status(self, session, job):
-        if job:
-            return JobStatusInfo.get_status_string(job.JobStatus)
-
-class JobGroupSet(CuminTable):
-    def __init__(self, app, name):
-        super(JobGroupSet, self).__init__(app, name)
-
-        self.ids = CheckboxStringIdColumn(app, "id")
-        self.add_column(self.ids)
-
-        col = self.GroupColumn(app, "job_group")
-        self.add_column(col)
-
-        col = self.JobsCountColumn(app, "jobs")
-        col.alignment = "right"
-        self.add_column(col)
-
-    class GroupColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Job Group"
-
-        def render_content(self, session, data):
-            name = data[self.name]
-
-            if name:
-                group = Identifiable(name)
-                href = self.page.main.pool.job_group.get_href(session, group)
-                return fmt_link(href, fmt_shorten(name))
-
-    class JobsCountColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Jobs"
-
-class JobsAndGroupsTab(Widget):
-    def __init__(self, app, name):
-        super(JobsAndGroupsTab, self).__init__(app, name)
-
-        self.is_group = GroupSwitch(app, "group")
-        self.add_child(self.is_group)
-
-        self.job_tab = JobTab(app, "jobtab")
-        self.add_child(self.job_tab)
-
-        self.job_group_tab = JobGroupTab(app, "jobgrouptab")
-        self.add_child(self.job_group_tab)
-
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, *args):
-        return "Jobs %s" % fmt_count(self.job_tab.get_full_item_count(session, *args))
-
-    def show_status_switch(self, session):
-        is_group = self.is_group.get(session)
-        return is_group == "j"
-
-    def set_switch(self, session, switch):
-        if switch == "group":
-            self.is_group.set(session, "g")
-        else:
-            self.is_group.set(session, "j")
-
-    def render_phase(self, session, *args):
-        is_group = self.is_group.get(session)
-        if is_group == "j":
-            return self.job_tab.phase.render(session)
-
-    def render_jobs(self, session, *args):
-        is_group = self.is_group.get(session)
-        if is_group == "j":
-            return self.job_tab.render(session)
-
-    def render_job_groups(self, session, *args):
-        is_group = self.is_group.get(session)
-        if is_group == "g":
-            return self.job_group_tab.render(session)
-
-class JobGroupTab(JobGroupSet, Form):
-    def __init__(self, app, name):
-        super(JobGroupTab, self).__init__(app, name)
-
-        self.__remove = self.Remove(app, "remove")
-        self.add_child(self.__remove)
-
-        self.__hold = self.Hold(app, "hold")
-        self.add_child(self.__hold)
-
-        self.__release = self.Release(app, "release")
-        self.add_child(self.__release)
-
-        self.set_default_column_name("job_group")
-
-    class Remove(FormButton):
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            href = self.frame.job_group_remove.get_href(session, ids)
-            self.page.set_redirect_url(session, href)
-
-        def render_content(self, session):
-            return "Remove"
-
-    class Hold(FormButton):
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            href = self.frame.job_group_hold.get_href(session, ids)
-            self.page.set_redirect_url(session, href)
-
-        def render_content(self, session):
-            return "Hold"
-
-    class Release(FormButton):
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            href = self.frame.job_group_release.get_href(session, ids)
-            self.page.set_redirect_url(session, href)
-
-        def render_content(self, session):
-            return "Release"
-
-class JobReasonBulkActionForm(CuminBulk):
-    def __init__(self, app, name):
-        super(JobReasonBulkActionForm, self).__init__(app, name)
-
-        self.reason = Parameter(app, "reason")
-        self.add_parameter(self.reason)
-
-        self.error = Attribute(app, "error")
-        self.add_attribute(self.error)
-
-        self.error_tmpl = Template(self, "reason_html")
-
-    def render_reason_text(self, session, *args):
-        return "Reason"
-
-    def render_reason_path(self, session, *args):
-        return self.reason.path
-
-    def render_reason_value(self, session, *args):
-        return escape_entity(self.reason.get(session))
-
-    def render_reason_error(self, session, *args):
-        if self.error.get(session):
-            writer = Writer()
-            self.error_tmpl.render(writer, session, *args)
-            return writer.to_string()
-
-    def render_reason_error_text(self, session, *args):
-        return self.error.get(session)
-
-    def render_form_heading(self, session, *args):
-        pass
-
-    def process_submit(self, session, *args):
-        reason = self.reason.get(session)
-        if not reason:
-            self.error.set(session, "Reason is required")
-        else:
-            super(JobReasonBulkActionForm, self).process_submit(session, *args)
-
-    def process_return(self, session, *args):
-        self.reason.set(session, "")
-        branch = session.branch()
-        self.frame.show_view(branch)
-        self.page.set_frame(branch, self.frame)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def get_reason(self, session, verb):
-        """ returns <verb> by username[: <user input reason>] """
-        reason = [self.reason.get(session)]
-        verb_by = "%s by %s" % (verb, session.user_session.subject.name)
-        reason.insert(0, verb_by)
-        return ": ".join(reason)
-
-class JobReasonIntBulkActionForm(JobReasonBulkActionForm, CuminIntIdList):
-    def get_items(self, session, *args):
-        return self.ids.get(session)
-
-class JobSetHold(JobReasonIntBulkActionForm):
-    def process_item(self, session, id):
-        job = Job.get(id)
-        action = self.app.model.job.hold
-        reason = self.get_reason(session, "held")
-        action.invoke(job, reason)
-
-    def render_title(self, session):
-        ids = self.ids.get(session)
-        return len(ids) > 1 and "Hold Jobs" or "Hold Job"
-
-    def render_item_content(self, session, id):
-        return "Hold Job '%s'" % Job.get(id).CustomId
-
-    def render_reason_text(self, session, *args):
-        return "Hold Reason"
-
-class JobSetRelease(JobReasonIntBulkActionForm):
-    def process_item(self, session, id):
-        job = Job.get(id)
-        action = self.app.model.job.release
-        reason = self.get_reason(session, "released")
-        action.invoke(job, reason)
-
-    def render_title(self, session):
-        ids = self.ids.get(session)
-        return len(ids) > 1 and "Release Jobs" or "Release Job"
-
-    def render_item_content(self, session, id):
-        return "Release Job '%s'" % Job.get(id).CustomId
-
-    def render_reason_text(self, session, *args):
-        return "Release Reason"
-
-class JobSetRemove(JobReasonIntBulkActionForm):
-    def process_item(self, session, id):
-        job = Job.get(id)
-        action = self.app.model.job.remove
-        reason = self.get_reason(session, "removed")
-        action.invoke(job, reason)
-
-    def render_title(self, session):
-        ids = self.ids.get(session)
-        return len(ids) > 1 and "Remove Jobs" or "Remove Job"
-
-    def render_item_content(self, session, id):
-        return "Remove Job '%s'" % Job.get(id).CustomId
-
-    def render_reason_text(self, session, *args):
-        return "Remove Reason"
-
-class JobReasonStringBulkActionForm(JobReasonBulkActionForm, CuminStringIdList):
-    def get_items(self, session, *args):
-        return self.ids.get(session)
-
-class JobGroupHold(JobReasonStringBulkActionForm):
-    def process_item(self, session, id):
-        sel = "custom_group='%s'" % id
-        action = self.app.model.job.hold
-        reason = self.get_reason(session, "held")
-        for job in Job.select(sel):
-            action.invoke(job, reason)
-
-    def render_title(self, session):
-        ids = self.ids.get(session)
-        return len(ids) > 1 and "Hold Job Groups" or "Hold Job Group"
-
-    def render_item_content(self, session, group):
-        return group
-
-    def render_reason_text(self, session, *args):
-        return "Hold Reason"
-
-class JobGroupRelease(JobReasonStringBulkActionForm):
-    def process_item(self, session, id):
-        sel = "custom_group='%s'" % id
-        action = self.app.model.job.release
-        reason = self.get_reason(session, "released")
-        for job in Job.select(sel):
-            action.invoke(job, reason)
-
-    def render_title(self, session):
-        ids = self.ids.get(session)
-        return len(ids) > 1 and "Release Job Groups" or "Release Job Group"
-
-    def render_item_content(self, session, group):
-        return group
-
-    def render_reason_text(self, session, *args):
-        return "Release Reason"
-
-class JobGroupRemove(JobReasonStringBulkActionForm):
-    def process_item(self, session, id):
-        sel = "custom_group='%s'" % id
-        action = self.app.model.job.remove
-        reason = self.get_reason(session, "removed")
-        for job in Job.select(sel):
-            action.invoke(job, reason)
-
-    def render_title(self, session):
-        ids = self.ids.get(session)
-        return len(ids) > 1 and "Remove Job Groups" or "Remove Job Group"
-
-    def render_item_content(self, session, group):
-        return group
-
-    def render_reason_text(self, session, *args):
-        return "Remove Reason"
-
-class JobStatusSwitch(StateSwitch):
-    def __init__(self, app, name):
-        super(JobStatusSwitch, self).__init__(app, name)
-
-        self.add_state("a", "All")
-        self.add_state("r", "Running")
-        self.add_state("i", "Idle")
-        self.add_state("h", "Held")
-        self.add_state("c", "Completed")
-        self.add_state("d", "Removed")
-
-    def get_sql_constraint(self, session, phase=None):
-        if not phase:
-            phase = self.get(session)
-
-        alive = "((c.qmf_update_time is null or " + \
-            "c.qmf_update_time <= now() - interval '10 minutes')" + \
-            " and j.qmf_delete_time is null and j.job_status != %i)" % JobStatusInfo.get_status_int("Removed")
-
-        if phase == "a":
-            sql = alive
-        elif phase == "r":
-            sql = "(j.job_status = %i" % JobStatusInfo.get_status_int("Running") + \
-                    " and %s)" % alive
-        elif phase == "i":
-            sql = "(j.job_status = %i" % JobStatusInfo.get_status_int("Idle") + \
-                    " and %s)" % alive
-        elif phase == "h":
-            sql = "(j.job_status = %i" % JobStatusInfo.get_status_int("Held") + \
-                    " and %s)" % alive
-        elif phase == "c":
-            comotose = "(c.qmf_update_time is null or " + \
-                "c.qmf_update_time <= now() - interval '10 minutes')"
-            sql = "(j.job_status = %i" % JobStatusInfo.get_status_int("Completed") + \
-                    " and %s)" % comotose
-        else:
-            not_completed = "(j.qmf_delete_time is not null and j.job_status <> %i )" % JobStatusInfo.get_status_int("Completed")
-            is_removed = "j.job_status = %i" % JobStatusInfo.get_status_int("Removed")
-            sql = " or ".join((not_completed, is_removed))
-
-        return sql
-
-class JobStatusInfo(object):
-    stat_strings = ["Unexpanded", "Idle", "Running", "Removed", "Completed", "Held", "Submission Error"]
-    stat_colors = ["red", "clear", "green", "black", "blue", "yellow", "red"]
-    @classmethod
-    def get_status_string(cls, stat):
-        try:
-            return cls.stat_strings[stat]
-        except:
-            return ""
-
-    @classmethod
-    def get_status_color(cls, stat):
-        try:
-            return cls.stat_colors[stat]
-        except:
-            return "red"
-
-    @classmethod
-    def get_status_int(cls, stat):
-        try:
-            return cls.stat_strings.index(stat)
-        except:
-            return -1
-
-    @classmethod
-    def get_zipped_colors(cls):
-        return zip(cls.stat_strings, cls.stat_colors)

Deleted: mgmt/trunk/cumin/python/cumin/job.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/job.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/job.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,438 +0,0 @@
-[JobSet.sql]
-select
-  j.id,
-  j.accounting_group as agroup,
-  j.args,
-  j.cluster_id,
-  j.concurrency_limits,
-  j.custom_group,
-  j.custom_id,
-  j.custom_priority,
-  j.job_status,
-  j.title,
-  s.name as scheduler,
-  b.name as submitter,
-  j.scheduler_id,
-  j.submitter_id,
-  j.cmd,
-  j.qmf_delete_time
-from job as j
-left outer join job_stats as c on c.id = j.stats_curr_id
-left outer join job_stats as p on p.id = j.stats_prev_id
-inner join scheduler as s on s.id = j.scheduler_id
-inner join submitter as b on b.id = j.submitter_id
-{sql_where}
-{sql_orderby}
-{sql_limit}
-
-[JobSet.find_sql]
-select
-        j.id,
-        j.custom_id
-from job as j
-left outer join job_stats as c on c.id = j.stats_curr_id
-left outer join job_stats as p on p.id = j.stats_prev_id
-inner join scheduler as s on s.id = j.scheduler_id
-inner join submitter as b on b.id = j.submitter_id
-
-[JobSet.count_sql]
-select count(1)
-from job as j
-left outer join job_stats as c on c.id = j.stats_curr_id
-left outer join job_stats as p on p.id = j.stats_prev_id
-inner join scheduler as s on s.id = j.scheduler_id
-inner join submitter as b on b.id = j.submitter_id
-{sql_where}
-
-[TopJobSet.sql]
-select
-  j.id,
-  j.custom_id as name,
-  j.q_date,
-  s.pool
-from job as j
-join scheduler s on s.id = j.scheduler_id
-where j.job_status = 2
-  and j.qmf_update_time > now() - interval '60 seconds'
-order by j.q_date asc
-limit 5
-
-[TopJobSet.count_sql]
---
-
-[JobTab.css]
-input.search_input {
-    color: #555;
-    border: 1px solid #333;
-    font-size: 0.9em;
-    font-weight: normal;
-    padding-left: 0.25em;
-}
-
-input.search_error {
-    color: #CC0000 !important;
-}
-
-div.searchbox {
-    padding-top: 2px;
-}
-
-
-[JobTab.javascript]
-function JobSearchFocus() {
-    var val = this.value;
-
-    if (val == job_search_prompt) {
-        this.value = "";
-        this.style.color = "#000";
-        this.className = "search_input"; // remove search_error class
-    }
-}
-
-function JobSearchBlur() {
-    var val = this.value;
-
-    if (val == "") {
-        this.style.color = "#555";
-        job_search_prompt = job_search_default_prompt;
-        this.value = job_search_prompt;
-    }
-}
-
-window.addEvent('domready', function () {
-    var oInput = document.getElementById("job_search");
-
-    if (oInput) {
-        oInput.onfocus = JobSearchFocus;
-        oInput.onblur = JobSearchBlur;
-    }
-});
-
-[JobTab.html]
-<form id="{id}" method="post" action="?">
-  <div class="sactions">
-    {job_search}
-    <h2>Act on Selected Jobs:</h2>
-    {hold} {release} {remove}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-        <th class="setnav" colspan="{column_count}">
-          <div class="rfloat">{page}</div>
-          {count}
-        </th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>
-
-[JobSearch.html]
-<div class="rfloat searchbox">
-  <h2><label for="job_search">Go To Job:</label></h2>
-  <input class="search_input {search_class}" type="text" name="{name}" id="job_search" value="{search_prompt}" />
-  {go}
-</div>
-<script type="text/javascript">
-  var job_search_default_prompt = "{search_default_prompt}"
-  var job_search_prompt = "{search_prompt}"
-</script>
-
-[JobGroupSet.sql]
-select
-  j.custom_group as id,
-  j.custom_group as job_group,
-  count(*) as jobs
-from job as j
-inner join scheduler as s on s.id = j.scheduler_id
-{sql_where}
-group by j.custom_group
-{sql_orderby}
-{sql_limit}
-
-[JobGroupSet.count_sql]
-select count(distinct j.custom_group)
-from job as j
-{sql_where}
-
-[JobGroupStats.html]
-  <h2>General</h2>
-  <div style="width:50%;">
-  {general}
-  </div>
-
-
-[JobsAndGroupsTab.html]
-  <div class="rfloat">{phase}</div>
-{group}
-
-{jobs}{job_groups}
-
-
-[JobGroupTab.html]
-<form id="{id}" method="post" action="?">
-  <div class="sactions">
-    <h2>Act on Selected Groups:</h2>
-    {hold} {release} {remove}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-        <th class="setnav" colspan="{column_count}">
-          <div class="rfloat">{page}</div>
-          {count}
-        </th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>
-
-[JobGroupJobSet.html]
-<div class="rfloat">{phase}</div>
-<form id="{id}" style="clear:right;" method="post" action="?">
-
-  <div class="sactions">
-    {job_search}
-    <h2>Act on Selected Jobs:</h2>
-    {hold} {release} {remove}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-        <th class="setnav" colspan="{column_count}">
-          <div class="rfloat">{page}</div>
-          {count}
-        </th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>
-
-[JobStatus.html]
-<div id="{id}" class="CuminStatus {color}">
-  <h2>Job Status</h2>
-  {job_status}
-</div>
-
-
-[JobAdsViewer.html]
-<ul class="actions">
-  <li><a class="nav" href="{edit_ads_url}">Edit Attributes</a></li>
-</ul>
-<table class="CuminDetails">
-  <tbody>
-    <tr>
-      <td>
-        {groups}
-      </td>
-    </tr>
-  </tbody>
-</table>
-<ul class="actions">
-  <li><a class="nav" href="{edit_ads_url}">Edit Attributes</a></li>
-</ul>
-
-[JobAdsViewer.group_html]
-<div class="sactions">
-    <h2>{group_name}</h2>
-</div>
-<table class="PropertySet">
-  <thead>
-    <tr>
-      <th style="width: 33%;">Name</th>
-      <th style="width: 33%;">Value</th>
-      <th style="width: 33%;">&nbsp;</th>
-    </tr>
-  </thead>
-  <tbody>
-  {properties}
-  </tbody>
-</table>
-
-
-[JobAdsViewer.property_html]
-<tr>
-  <th>{title}</th><td>{value}</td><td>{inline_help}</td>
-</tr>
-
-[JobAdsEditor.css]
-div.inline_help {
-        float: right;
-}
-
-div.inline_help h2 {
-        display: inline;
-}
-
-[JobAdsEditor.html]
-<form id="{id}" class="mform editform" method="post" action="?">
-  <div class="inline_help">
-    <h2>Legend</h2>
-    <span class="edit_number">Numeric input expected</span>
-    <span class="edit_string">String input expected</span>
-  </div>
-  {help} {submit} {cancel}
-  <table class="CuminDetails Editable">
-    <tbody>
-      <tr>
-        <td>
-          {groups}
-        </td>
-      </tr>
-    </tbody>
-  </table>
-  {help} {submit} {cancel}
-  <div>{hidden_inputs}</div>
-</form>
-
-[JobReasonBulkActionForm.css]
-div.action_reason {
-    margin: 1em;
-}
-
-div.action_reason label {
-    font-weight: bold;
-    margin-right: 0.5em;
-}
-
-div.action_reason input {
-    width: 20em;
-}
-
-div.action_reason div.reason_error {
-    float: right;
-    border: 1px solid red;
-    color: red;
-    padding: 0.5em;
-}
-
-[JobReasonBulkActionForm.reason_html]
-        <div class="reason_error">{reason_error_text}</div>
-
-[JobReasonBulkActionForm.html]
-<form id="{id}" class="mform" method="post" action="?">
-  <div class="head">
-    <h1>{title}</h1>
-  </div>
-  <div class="body">
-    <span class="legend">{form_heading}</span>
-    <div class="action_reason">
-      {reason_error}
-      <label for="reason">{reason_text}</label> <input type="text" name="{reason_path}" id="reason" value="{reason_value}" maxlength="4000" />
-    </div>
-    <fieldset>
-      <ul>{items}</ul>
-    </fieldset>
-
-    {hidden_inputs}
-  </div>
-  <div class="foot">
-    {help}
-    {submit}
-    {cancel}
-  </div>
-</form>
-<script type="text/javascript">
-//<![CDATA[
-  wooly.doc().elembyid("{id}").node.elements[0].focus();
-//]]>
-</script>
-
-[JobOutput.css]
-textarea#job_output {
-    height: 25em;
-    width: 100%;
-    border: 1px solid #EAEAEA;
-    font-family: Fixed, monospace;
-    line-height: 1.15em;
-    background-color: #FFF;
-    color: #333;
-}
-
-div.out_actions {
-    padding:1em 1em 0 1em;
-}
-
-div.refresh_info h2 {
-    position: relative;
-    top: -0.5em;
-}
-
-[JobOutput.javascript]
-function scrollToEnd (element) {
-    if (typeof element.scrollTop != 'undefined'
-        && typeof element.scrollHeight != 'undefined') {
-        element.scrollTop = element.scrollHeight;
-    }
-}
-
-function outputEnd() {
-    var tarea = document.getElementById("job_output");
-
-    if (tarea) {
-        scrollToEnd(tarea);
-        setTimeout("get_job_output()", 5000);
-    }
-}
-
-[JobOutput.html]
-<form id="{id}" style="width:100%; border:0px;" class="mform" method="post" action="?">
-  <div class="out_actions">
-    <div class="rfloat">{first_last}</div>
-
-    {file}
-  </div>
-
-  <div class="sactions refresh_info">{refresh} <h2>Last refresh was at <span id="out_time"></span></h2></div>
-
-  <div>
-    <textarea name="job_output" id="job_output" rows="20" cols="80">
-      {loading}{job_output}
-    </textarea>
-
-    {hidden_inputs}
-  </div>
-</form>
-
-[OutTime.javascript]
-function got_out_time(obj, id) {
-    var elem = document.getElementById(id);
-
-    if (elem) {
-        var str = obj.time.value;
-        elem.innerHTML = str;
-    }
-}
-
-[OutputFile.javascript]
-function got_job_output(obj, id) {
-    var elem = document.getElementById(id);
-
-    if (elem) {
-        var str = obj.fetch.output;
-        elem.value = str;
-
-        if (obj.fetch.tail == "t") {
-            outputEnd();
-        }
-
-        var d = new Date();
-        var out_time = document.getElementById("out_time");
-
-        if (out_time) {
-            out_time.innerHTML = d.toLocaleString();
-        }
-    }
-}

Deleted: mgmt/trunk/cumin/python/cumin/limits.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/limits.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/limits.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,277 +0,0 @@
-import logging
-
-from wooly import *
-from wooly.widgets import *
-from wooly.forms import *
-from wooly.resources import *
-from wooly.tables import *
-
-from stat import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-from job import *
-
-strings = StringCatalog(__file__)
-log = logging.getLogger("cumin.Limits")
-
-class LimitActions(object):
-    def fetch_limits(self, session):
-        negotiator = self.get_negotiator(session)
-        if negotiator:
-            limits = self.get_raw_limits(session, negotiator)
-            if "timeout" in limits:
-                del limits["timeout"]
-            return limits
-        else:
-            return dict()
-
-    def get_negotiator(self, session):
-#TODO: find better way to get the negotiator. from pool perhaps?
-        pool = self.frame.get_args(session)[0]
-        most_recent = None
-        negotiators = Negotiator.select("pool='%s'" % pool.id)
-        for negotiator in negotiators:
-            if negotiator.qmfBrokerId:
-                if not most_recent:
-                    most_recent = negotiator
-                try:
-                    if negotiator.statsCurr.qmfUpdateTime > \
-                            most_recent.statsCurr.qmfUpdateTime:
-                        most_recent = negotiator
-                except:
-                    pass
-
-        return most_recent
-
-    def set_limit(self, session, limit):
-        negotiator = self.get_negotiator(session)
-        action = self.app.model.limit.setlimit
-        action.invoke(limit, negotiator)
-#TODO: this probably shouldn't be called until after the invoke completes
-        def completion():
-            pass
-        negotiator.Reconfig(self.app.model.mint.model, completion)
-
-    def get_raw_limits(self, session, negotiator):
-        action = self.app.model.negotiator.GetLimits
-        return action.do_invoke(negotiator)
-
-class LimitsSet(ItemTable, LimitActions):
-    def __init__(self, app, name):
-        super(LimitsSet, self).__init__(app, name)
-
-        col = self.NameColumn(app, "name")
-        self.add_column(col)
-        self.set_default_column(col)
-
-        col = self.CurrentColumn(app, "curr")
-        col.alignment = "right"
-        self.add_column(col)
-
-        col = self.MaxColumn(app, "max")
-        col.alignment = "right"
-        self.add_column(col)
-
-        self.limits = self.Limits(self, "limits")
-        self.add_attribute(self.limits)
-
-        self.limit_count = self.LimitCount(app, "limit_count")
-        self.add_child(self.limit_count)
-
-    def do_get_items(self, session, *args):
-        limits = self.limits.get(session)
-        if not len(limits):
-            limits = self.fetch_limits(session)
-            self.limits.set(session, limits)
-        keys = limits.keys()
-        keys.sort()
-        return [{"name":x, "curr":limits[x]["CURRENT"], "max":limits[x]["MAX"]} for x in keys]
-
-    def render_title(self, session):
-        return self.limit_count.get_title(session, "Limits")
-
-    class LimitCount(AjaxField):
-        def get_url(self, session):
-            negotiator = self.parent.get_negotiator(session)
-            return negotiator and \
-                "call.xml?class=negotiator;id=%i;method=GetLimitCount" % negotiator.id
-
-        def get_title(self, session, title):
-            script = self.render_script(session)
-            count = script and "?" or "0"
-            return "%s <span id=\"%s\"><span class='count'>(%s)</span>%s</span>" % \
-                (title, self.name, count, script)
-
-    class NameColumn(ItemTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-        def render_content(self, session, data):
-            limit = Identifiable(data["name"])
-            href = self.frame.limit.get_href(session, limit)
-            return fmt_link(href, data["name"])
-
-    class CurrentColumn(ItemTableColumn):
-        def render_title(self, session, data):
-            return "Current Usage"
-
-    class MaxColumn(ItemTableColumn):
-        def render_title(self, session, data):
-            return "Max Allowance"
-
-    class Limits(Attribute):
-        def get_default(self, session):
-            return dict()
-
-class LimitsFrame(CuminFrame, LimitActions):
-    def __init__(self, app, name):
-        super(LimitsFrame, self).__init__(app, name)
-
-        self.object = LimitParameter(app, "id")
-        self.add_parameter(self.object)
-
-        view = LimitsView(app, "view")
-        self.add_mode(view)
-        self.set_view_mode(view)
-
-        edit = LimitEdit(app, "edit")
-        self.add_mode(edit)
-        self.set_edit_mode(edit)
-
-    def get_object(self, session):
-        obj = self.object.get(session)
-        if not getattr(obj, "name", None):
-            limits = self.fetch_limits(session)
-            obj.name = obj.id
-            obj.curr = limits[obj.id]["CURRENT"]
-            obj.max = limits[obj.id]["MAX"]
-            self.object.set(session, obj)
-
-        return obj
-
-
-class LimitEdit(CuminForm):
-    def __init__(self, app, name):
-        super(LimitEdit, self).__init__(app, name)
-
-        self.max = Parameter(app, "max")
-        self.add_parameter(self.max)
-
-        self.error = self.Errors(self, "error")
-        self.add_attribute(self.error)
-
-        self.error_tmpl = Template(self, "error_html")
-
-    class Errors(Attribute):
-        def get_default(self, session):
-            return dict()
-
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, *args):
-        return "Edit Concurrency Limit '%s'" % args[0].id
-
-    def render_input_id(self, session, *args):
-        return self.max.path
-
-    def render_label(self, session, *args):
-        return "Maximum Allowance"
-
-    def render_input_name(self, session, *args):
-        return self.max.path
-
-    def render_input_value(self, session, *args):
-        max = self.max.get(session)
-        if not max:
-            max = args[0].max
-        return str(max)
-
-    def render_inline_help(self, session, *args):
-        return "Set the maximum number of jobs that can run concurrently using this limiter."
-
-    def render_limit_error(self, session, *args):
-        error = self.error.get(session)
-        if "max" in error:
-            writer = Writer()
-            self.error_tmpl.render(writer, session, *args)
-            return writer.to_string()
-
-    def render_error(self, session, *args):
-        error = self.error.get(session)
-        if "max" in error:
-            return error["max"]
-
-    def render_original_value(self, session, *args):
-        error = self.error.get(session)
-        if "max" in error:
-            return "Original value was %s" % str(args[0].max)
-
-    def process_submit(self, session, *args):
-        max = self.max.get(session)
-        fmax = 0
-        errors = False
-        try:
-            fmax = float(max)
-            if fmax < 1.0 or fmax > 99999.0:
-                raise "out of bounds"
-        except:
-            errors = True
-            error = self.error.get(session)
-            error["max"] = "Numeric value between 1 and 99999 expected"
-            self.error.set(session, error)
-
-        if not errors:
-            limit = args[0]
-            limit.max = fmax
-            self.frame.set_limit(session, limit)
-            self.process_cancel(session, *args)
-
-class LimitsView(CuminView):
-    def __init__(self, app, name):
-        super(LimitsView, self).__init__(app, name)
-
-        status = LimitsStatus(app, "status")
-        self.add_child(status)
-
-        self.__tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.__tabs)
-
-        jobs = LimitsJobSet(app, "jobs")
-        self.__tabs.add_tab(jobs)
-
-        details = CuminDetails(app, "details")
-        self.__tabs.add_tab(details)
-
-class LimitsStatus(CuminStatus):
-    def render_title(self, session, *args):
-        return "Limits Status"
-
-class LimitsJobSet(JobTab):
-    def get_visible_columns(self, session):
-        return self.get_request_visible_columns(session,
-                                                ["custom_group",
-                                                 "scheduler",
-                                                 "submitter"])
-
-    def get_sql_values(self, session, *args):
-        pass
-
-    def render_sql_where(self, session, limit):
-        phase_sql = self.get_phase_sql(session)
-        limits_sql = self.get_limits_sql(session, limit)
-        return "where %s" % " and ".join([phase_sql, limits_sql])
-
-    def render_title(self, session, limit):
-        limits_sql = self.get_limits_sql(session, limit)
-        return "Jobs %s" % fmt_count(Job.select(limits_sql).count())
-
-    def render_count(self, session, *args):
-        str = super(LimitsJobSet, self).render_count(session, *args)
-        return "%s with Concurrency Limit '%s'" % (str, args[0].id)
-
-    def get_limits_sql(self, session, limit):
-        x = limit.id
-        return "concurrency_limits similar to '(%s|%s,%%|%%,%s|%%,%s,%%)'" % (x, x, x, x)

Deleted: mgmt/trunk/cumin/python/cumin/limits.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/limits.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/limits.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,105 +0,0 @@
-[LimitsSet.html]
-<table class="mobjects">
-  <thead>
-    <tr>
-      <th class="setnav" colspan="{column_count}">
-        {count}
-      </th>
-    </tr>
-    <tr>{headers}</tr>
-  </thead>
-  <tbody>{items}</tbody>
-</table>
-
-
-[LimitCount.javascript]
-function got_limit_count(obj, id) {
-    var elem = document.getElementById(id);
-
-    if (elem) {
-        var str = "<span class='count'>(" + obj.count.value + ")</span>";
-        elem.innerHTML = str;
-    }
-}
-
-[LimitEdit.css]
-form.limitform {
-    /* padding: 1em; */
-}
-
-form.limitform div.label, form.limitform div.input {
-    float: left;
-    height: 3em;
-    margin-left: 1em;
-}
-
-form.limitform div.input input {
-    position: relative;
-    top: -0.2em;
-    width: 4em;
-}
-
-form.limitform div.foot {
-    clear: left;
-}
-
-form.limitform div.help {
-    margin: 0.5em 1em 1em 0;
-}
-
-form.limitform div.original_value {
-    color: #333;
-    font-size: 0.9em;
-    font-style: italic;
-}
-
-[LimitEdit.html]
-<form id="{id}" class="mform limitform" method="post" action="?">
-  <div class="head">
-    <h1>{title}</h1>
-  </div>
-  <div class="body">
-    <div class="help">
-      {inline_help}
-    </div>
-    <div class="label">
-      <label for="{input_id}">{label}</label>
-    </div>
-    <div class="input">
-      <input id="{input_id}" type="text" name="{input_name}" value="{input_value}" />
-      <div class="original_value">{original_value}</div>
-    </div>{limit_error}
-    <div style="clear:both;"><!-- --></div>
-  </div>
-  <div class="foot">
-    {help} {submit} {cancel}
-  </div>
-  <div>{hidden_inputs}</div>
-</form>
-
-[LimitEdit.error_html]
-<ul class="errors"><li>{error}</li></ul>
-
-[LimitsJobSet.html]
-<div class="rfloat">{phase}</div>
-<form id="{id}" style="clear:right;" method="post" action="?">
-
-  <div class="sactions">
-    <h2>Act on Selected Jobs:</h2>
-    {hold} {release} {remove}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-	<th class="setnav" colspan="{column_count}">
-	  <div class="rfloat">{page}</div>
-	  {count}
-	</th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>

Modified: mgmt/trunk/cumin/python/cumin/managementserver.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/managementserver.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/managementserver.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -88,8 +88,7 @@
 
     def process_cancel(self, session):
         branch = session.branch()
-        self.page.pop_current_frame(branch)
-        self.page.get_current_frame(branch).show_view(branch)
+        self.frame.view.show(branch)
         self.page.set_redirect_url(session, branch.marshal())
 
     def process_submit(self, session):
@@ -321,8 +320,7 @@
 
     def process_cancel(self, session):
         branch = session.branch()
-        self.page.pop_frame(branch)
-        self.page.get_frame(branch).show_view(branch)
+        self.frame.view.show(branch)
         self.page.set_redirect_url(session, branch.marshal())
 
     def process_submit(self, session):

Added: mgmt/trunk/cumin/python/cumin/messaging/__init__.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/__init__.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/__init__.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1 @@
+from main import *

Copied: mgmt/trunk/cumin/python/cumin/messaging/binding.py (from rev 3256, mgmt/trunk/cumin/python/cumin/binding.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/binding.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/binding.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,418 @@
+import logging
+
+from wooly import Template, Writer, Attribute, Parameter, Widget
+from wooly.forms import FormInput, FormField, Form
+from wooly.parameters import DictParameter
+from wooly.resources import StringCatalog
+from cumin.util import sorted_by
+from cumin.widgets import SubmitSwitch
+from cumin.formats import *
+
+from exchange import ExchangeInfo
+
+strings = StringCatalog(__file__)
+log = logging.getLogger("cumin.messaging.exchange")
+
+class ExchangeInput(Widget):
+    def __init__(self, app, name):
+        super(ExchangeInput, self).__init__(app, name)
+
+        self.exchange = None
+        self.instance_data = None
+
+        self.name_tmpl = Template(self, "name_html")
+        self.key_tmpl = Template(self, "key_html")
+
+        self.form = None
+
+    def init(self):
+        super(ExchangeInput, self).init()
+
+        for anc in self.ancestors:
+            if isinstance(anc, Form):
+                self.form = anc
+
+    def get_args(self, session):
+        return (self.exchange,)
+
+    def get_exchange_info(self, session, exchange):
+        binding_info = self.form.bindings.dict_param.get(session)
+        if str(exchange.id) in binding_info:
+            return binding_info[str(exchange.id)]
+
+    def get_exchange_info_for(self, session, exchange, key):
+        exchange_info = self.get_exchange_info(session, exchange)
+        if exchange_info:
+            if key in exchange_info:
+                return exchange_info[key]
+
+    def render_exchange_name(self, session, exchange):
+        return exchange.name
+
+    def render_exchange_fmt_name(self, session, exchange):
+        return fmt_shorten(exchange.name)
+
+    def render_name_path(self, session, *args):
+        return DictParameter.sep().join((self.instance_data, "name"))
+
+    def render_exchange_type(self, session, exchange):
+        return exchange.type
+
+    def render_exchange_type_path(self, session, exchange):
+        return DictParameter.sep().join((self.instance_data, "type"))
+
+    def render_exchange_id(self, session, exchange):
+        return exchange.id
+
+    def render_exchange_checked(self, session, exchange):
+        exchange_info = self.get_exchange_info(session, exchange)
+        if exchange_info:
+            if "name" in exchange_info:
+                return "checked=\"checked\""
+
+    def render_exchange_name_input(self, session, exchange):
+        writer = Writer()
+        self.name_tmpl.render(writer, session, exchange)
+        return writer.to_string()
+
+    def render_exchange_key_input(self, session, exchange):
+        writer = Writer()
+        self.key_tmpl.render(writer, session, exchange)
+        return writer.to_string()
+
+    def render_onclick(self, session, exchange):
+        pass
+
+    def render_list_error(self, session, exchange):
+        errors = self.parent.binding_errors.get(session)
+        if exchange.name in errors:
+            return "<ul class=\"errors\" style=\"margin:0; float:left;\"><li>%s</li></ul>" % \
+                "</li><li>".join(errors[exchange.name])
+
+    def render_dict_error(self, session, exchange, key):
+        errors = self.parent.binding_errors.get(session)
+        if exchange.name in errors:
+            exchange_errors = errors[exchange.name]
+            if key in exchange_errors:
+                return "<ul class=\"errors\" style=\"margin:0; float:left;\"><li>%s</li></ul>" % \
+                "</li><li>".join(exchange_errors[key])
+
+    def set_instance_data(self, exchange, dict_key):
+        self.exchange = exchange
+        self.instance_data = dict_key
+
+class FanoutExchangeInput(ExchangeInput):
+    pass
+
+class BindingKeyExchangeInput(ExchangeInput):
+    def __init__(self, app, name):
+        super(BindingKeyExchangeInput, self).__init__(app, name)
+
+    def render_key_path(self, session, exchange):
+        return DictParameter.sep().join((self.instance_data, "key"))
+
+    def render_key_error(self, session, exchange):
+        return self.render_list_error(session, exchange)
+
+    def render_key_value(self, session, exchange):
+        return self.get_exchange_info_for(session, exchange, "key")
+
+class DirectExchangeInput(BindingKeyExchangeInput):
+    pass
+
+class TopicExchangeInput(BindingKeyExchangeInput):
+    pass
+
+class XMLExchangeInput(BindingKeyExchangeInput):
+    def __init__(self, app, name):
+        super(XMLExchangeInput, self).__init__(app, name)
+
+    def render_xquery_path(self, session, exchange):
+        return DictParameter.sep().join((self.instance_data, "xquery"))
+
+    def render_headers_class(self, session, exchange):
+        exchange_info = self.get_exchange_info(session, exchange)
+        if not exchange_info or not "name" in exchange_info:
+            return "initial_header_state"
+
+    def render_key_error(self, session, exchange):
+        return self.render_dict_error(session, exchange, "key")
+
+    def render_onclick(self, session, exchange):
+        return "onclick=\"toggle_row(this, 'xml_extra.%s')\"" % str(exchange.id)
+
+    def render_xml_extra(self, session, exchange):
+        return "xml_extra.%s" % str(exchange.id)
+
+    def render_xquery_error(self, session, exchange):
+        return self.render_dict_error(session, exchange, "xquery")
+
+    def render_xquery_value(self, session, exchange):
+        return self.get_exchange_info_for(session, exchange, "xquery")
+
+    def process_input(self, this_exchange, arguments):
+        if "xquery" in this_exchange:
+            arguments["xquery"] = this_exchange["xquery"]
+
+class HeadersExchangeInput(BindingKeyExchangeInput):
+    def __init__(self, app, name):
+        super(HeadersExchangeInput, self).__init__(app, name)
+
+    def render_x_match_path(self, session, exchange):
+        return DictParameter.sep().join((self.instance_data, "x-match"))
+
+    def render_mkey_path(self, session, exchange):
+        return DictParameter.sep().join((self.instance_data, "mkey"))
+
+    def render_headers_class(self, session, exchange):
+        exchange_info = self.get_exchange_info(session, exchange)
+        if not exchange_info or not "name" in exchange_info:
+            return "initial_header_state"
+
+    def render_all_checked(self, session, exchange):
+        checked = self.render_any_checked(session, exchange)
+        if not checked:
+            return "checked=\"checked\""
+
+    def render_any_checked(self, session, exchange):
+        exchange_info = self.get_exchange_info(session, exchange)
+        if exchange_info:
+            if "x-match" in exchange_info:
+                if exchange_info["x-match"] == "any":
+                    return "checked=\"checked\""
+
+    def render_mkey1_value(self, session, exchange):
+        return self.get_exchange_info_for(session, exchange, "mkey.1")
+
+    def render_mkey2_value(self, session, exchange):
+        return self.get_exchange_info_for(session, exchange, "mkey.2")
+
+    def render_mkey3_value(self, session, exchange):
+        return self.get_exchange_info_for(session, exchange, "mkey.3")
+
+    def render_mnv1_value(self, session, exchange):
+        return self.get_exchange_info_for(session, exchange, "mkey.1.nv")
+
+    def render_mnv2_value(self, session, exchange):
+        return self.get_exchange_info_for(session, exchange, "mkey.2.nv")
+
+    def render_mnv3_value(self, session, exchange):
+        return self.get_exchange_info_for(session, exchange, "mkey.3.nv")
+
+    def render_key_error(self, session, exchange):
+        return self.render_dict_error(session, exchange, "key")
+
+    def render_mkey1_error(self, session, exchange):
+        return self.render_dict_error(session, exchange, "mkey.1")
+
+    def render_mkey2_error(self, session, exchange):
+        return self.render_dict_error(session, exchange, "mkey.2")
+
+    def render_mkey3_error(self, session, exchange):
+        return self.render_dict_error(session, exchange, "mkey.3")
+
+    def render_onclick(self, session, exchange):
+        return "onclick=\"toggle_row(this, 'headers_extra.%s')\"" % str(exchange.id)
+
+    def render_headers_extra(self, session, exchange):
+        return "headers_extra.%s" % str(exchange.id)
+
+    def process_input(self, this_exchange, arguments):
+        # x-match is a radio button, it must have a value
+        arguments["x-match"] = this_exchange["x-match"]
+        # Fill out the other arguments.
+        # The form has input boxes named mkey.* and mkey.*.nv
+        # We need to create an arguments dictionary entry
+        # of the form {mkey.*.value: mkey.*.nv.value}
+        for match_info in this_exchange:
+            if this_exchange[match_info]:
+                if match_info.startswith("mkey") \
+                    and not match_info.endswith("nv"):
+                    # find the value in the matching .nv field
+                    match_value = self._find_match_value(this_exchange, match_info)
+                    # it is valid for the value in the .nv field
+                    # to be empty
+                    arguments[this_exchange[match_info]] = \
+                        match_value or None
+
+    def _find_match_value(self, this_exchange, match_info):
+        for m_info in this_exchange:
+            if m_info.startswith(match_info):
+                if m_info.endswith("nv"):
+                    return this_exchange[m_info]
+
+class ExchangeState(SubmitSwitch):
+    def __init__(self, app, name):
+        super(ExchangeState, self).__init__(app, name)
+
+        self.add_state("c", "Active", bm="phase")
+        self.add_state("a", "All", bm="phase")
+
+    def is_all(self, session):
+        return self.get(session) == "a"
+
+    def is_active(self, session):
+        return self.get(session) == "c"
+
+class ExchangeKeysField(FormField):
+    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)
+
+        self.direct_input = DirectExchangeInput(app, "direct")
+        self.add_child(self.direct_input)
+
+        self.topic_input = TopicExchangeInput(app, "topic")
+        self.add_child(self.topic_input)
+
+        self.fanout_input = FanoutExchangeInput(app, "fanout")
+        self.add_child(self.fanout_input)
+
+        self.xml_input = XMLExchangeInput(app, "xml")
+        self.add_child(self.xml_input)
+
+        self.headers_input = HeadersExchangeInput(app, "headers")
+        self.add_child(self.headers_input)
+
+        self.title = title
+
+        self.binding_errors = self.Errors(self, "binding_errors")
+        self.add_attribute(self.binding_errors)
+
+        self.state = ExchangeState(app, "phase")
+        self.add_child(self.state)
+
+    class Errors(Attribute):
+        def get_default(self, session):
+            return dict()
+
+    def render_title(self, session):
+        return self.title
+
+    def render_exchanges(self, session):
+        vhost = self.vhost.get(session)
+        sortedExchanges = sorted_by(vhost.exchanges)
+
+        # render each exchange we support
+        writer = Writer()
+        for exchange in sortedExchanges:
+            if ExchangeInfo.is_builtin(exchange) or \
+                (not exchange._get_qmfDeleteTime() and \
+                 not (self.state.is_active(session) and not is_active(exchange))):
+                # instance_key gives us a unique path for each exchange
+                # we will be rendering
+                instance_key = self.dict_param.get_instance_key(str(exchange.id))
+                if exchange.type == "direct":
+                    if exchange.name:
+                        self.direct_input.set_instance_data(exchange, instance_key)
+                        writer.write(self.direct_input.render(session))
+                elif exchange.type == "topic":
+                    if not exchange.name == "qpid.management":
+                        self.topic_input.set_instance_data(exchange, instance_key)
+                        writer.write(self.topic_input.render(session))
+                elif exchange.type == "fanout":
+                    self.fanout_input.set_instance_data(exchange, instance_key)
+                    writer.write(self.fanout_input.render(session))
+                elif exchange.type == "xml":
+                    self.xml_input.set_instance_data(exchange, instance_key)
+                    writer.write(self.xml_input.render(session))
+                elif exchange.type == "headers":
+                    self.headers_input.set_instance_data(exchange, instance_key)
+                    writer.write(self.headers_input.render(session))
+
+        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)
+
+        for exchange in form_binding_info:
+            type = form_binding_info[exchange]["type"]
+            if (type == "topic") or (type == "direct"):
+                try:
+                    val = form_binding_info[exchange]["key"]
+                    if not val:
+                        raise KeyError
+                except KeyError:
+                    name = form_binding_info[exchange]["name"]
+                    errs = berrs.setdefault(name, list())
+                    errs.append("A binding key is required")
+            elif type == "headers":
+                try:
+                    val = form_binding_info[exchange]["key"]
+                    if not val:
+                        raise KeyError
+                except KeyError:
+                    name = form_binding_info[exchange]["name"]
+                    errs = berrs.setdefault(name, dict())
+                    errs["key"] = ["A binding key is required"]
+                for key_num in ("1", "2", "3"):
+                    mkey = "mkey."+key_num
+                    mkeynv = mkey+".nv"
+                    if mkeynv in binding_info[exchange] and binding_info[exchange][mkeynv]:
+                        try:
+                            val = binding_info[exchange][mkey]
+                            if not val:
+                                raise KeyError
+                        except KeyError:
+                            name = binding_info[exchange]["name"]
+                            if not name in berrs:
+                                berrs.setdefault(name, dict())
+                            berrs[name][mkey] = ["Missing key"]
+            elif type == "xml":
+                try:
+                    val = form_binding_info[exchange]["key"]
+                    if not val:
+                        raise KeyError
+                except KeyError:
+                    name = form_binding_info[exchange]["name"]
+                    errs = berrs.setdefault(name, dict())
+                    errs["key"] = ["A binding key is required"]
+                try:
+                    val = binding_info[exchange]["xquery"]
+                    if not val:
+                        raise KeyError
+                except KeyError:
+                    name = binding_info[exchange]["name"]
+                    if not name in berrs:
+                        berrs.setdefault(name, dict())
+                    berrs[name]["xquery"] = ["Missing xquery"]
+
+        return (len(berrs), form_binding_info)
+
+    def process_binding_info(self, session, queue_name):
+        """ Processes the raw binding_info from the DictParameter into
+        a "form_binding_info" dictionary that contains four keys:
+        name, key, arguments, and type
+        """
+        binding_info = self.dict_param.get(session)
+        form_binding_info = dict()
+        for this_exchange in binding_info:
+            # if the exchange checkbox is checked
+            if "name" in binding_info[this_exchange]:
+                type = binding_info[this_exchange]["type"]
+                #if type == "direct":
+                #    binding_info[this_exchange]["key"] = queue_name
+
+                form_binding_info[this_exchange] = dict()
+                form_binding_info[this_exchange]["name"] = binding_info[this_exchange]["name"]
+                if "key" in binding_info[this_exchange] and binding_info[this_exchange]["key"]:
+                    form_binding_info[this_exchange]["key"] = binding_info[this_exchange]["key"]
+                form_binding_info[this_exchange]["type"] = type
+
+                arguments = dict()
+                if type == "headers":
+                    self.headers_input.process_input(binding_info[this_exchange], arguments)
+                elif type == "xml":
+                    self.xml_input.process_input(binding_info[this_exchange], arguments)
+                #direct, topic and fanout exchanges don't have aditional arguments
+                form_binding_info[this_exchange]["arguments"] = arguments
+
+        return form_binding_info


Property changes on: mgmt/trunk/cumin/python/cumin/messaging/binding.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/messaging/binding.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/binding.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/binding.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/binding.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,159 @@
+[ExchangeInput.name_html]
+<td>
+  <input type="checkbox" id="{id}.{exchange_id}" name="{name_path}"
+         value="{exchange_name}" size="15" tabindex="100" {exchange_checked}
+         {onclick} />
+  <input type="hidden" name="{exchange_type_path}" value="{exchange_type}" />
+</td>
+<td><label class="exchange_name" for="{id}.{exchange_id}">{exchange_fmt_name}</label></td>
+<td class="exchange_type">{exchange_type}</td>
+
+[ExchangeInput.key_html]
+<td>
+  <input type="text" name="{key_path}" id="{exchange_name}"
+         value="{key_value}" size="32" maxlength="256" tabindex="100" />
+  {key_error}
+</td>
+
+[DirectExchangeInput.html]
+<tr>
+  {exchange_name_input}
+  {exchange_key_input}
+</tr>
+
+[TopicExchangeInput.html]
+<tr>
+  {exchange_name_input}
+  {exchange_key_input}
+</tr>
+
+[FanoutExchangeInput.html]
+<tr>
+  {exchange_name_input}
+  <td>&nbsp;</td>
+</tr>
+
+[XMLExchangeInput.html]
+<tr>
+  {exchange_name_input}
+  {exchange_key_input}
+</tr>
+<tr id="{xml_extra}" class="{headers_class}">
+  <td colspan="4"><table>
+    <tr>
+      <td>XQuery:</td>
+      <td colspan="3"><textarea name="{xquery_path}" id="{exchange_name}" tabindex="100" rows="4" cols="40">{xquery_value}</textarea>{xquery_error}</td>
+     </tr>
+  </table></td>
+</tr>
+
+[HeadersExchangeInput.html]
+<tr>
+  {exchange_name_input}
+  {exchange_key_input}
+</tr>
+<tr id="{headers_extra}" class="{headers_class}">
+  <td colspan="4"><table>
+    <tr>
+      <td>&nbsp;</td>
+      <td>x-match Type:</td>
+      <td colspan="2">
+        <input type="radio" id="headers.x-match.all" name="{x_match_path}" value="all" {all_checked}/>
+        <label for="headers.x-match.all">All</label>
+        <input type="radio" id="headers.x-match.any" name="{x_match_path}" value="any" {any_checked}/>
+        <label for="headers.x-match.any">Any</label>
+      </td>
+    </tr>
+    <tr>
+      <td>&nbsp;</td>
+      <td>Match Keys:</td>
+      <td colspan="2">
+        <table class="xmlExchange">
+          <thead>
+            <tr>
+              <th>Key</th><th>type, value</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <td><input type="text" name="{mkey_path}.1" value="{mkey1_value}" tabindex="100" />{mkey1_error}</td>
+              <td><input type="text" name="{mkey_path}.1.nv" value="{mnv1_value}" tabindex="100" /></td>
+            </tr>
+            <tr>
+              <td><input type="text" name="{mkey_path}.2" value="{mkey2_value}" tabindex="100" />{mkey2_error}</td>
+              <td><input type="text" name="{mkey_path}.2.nv" value="{mnv2_value}" tabindex="100" /></td>
+            </tr>
+            <tr>
+              <td><input type="text" name="{mkey_path}.3" value="{mkey3_value}" tabindex="100" />{mkey3_error}</td>
+              <td><input type="text" name="{mkey_path}.3.nv" value="{mnv3_value}" tabindex="100" /></td>
+            </tr>
+          </tbody>
+        </table>
+      </td>
+    </tr>
+</table></td></tr>
+
+[ExchangeKeysField.css]
+td.exchange_type {
+    font-style: italic;
+}
+
+table.mobjects tr#headers_extra {
+    border-top: 0px;
+}
+
+table.mobjects tr.initial_header_state {
+    display:none;
+}
+
+table.xmlExchange {
+    border-collapse: collapse;
+    border: 1px dotted #ccc;
+    margin: 0;
+}
+
+table.xmlExchange tr {
+    border-top: 0px solid #fff;
+}
+
+table.mobjects label.exchange_name {
+    font-weight: bold;
+}
+
+table.mobjects td.exchange_type, table.mobjects th.exchange_type {
+    font-style: italic;
+}
+
+[ExchangeKeysField.javascript]
+function toggle_row(chk, row_id) {
+    var display = "none";
+    var headers_extra = document.getElementById(row_id);
+
+    if (chk.checked) {
+        display = "table-row";
+    }
+
+    headers_extra.style.display = display;
+}
+
+[ExchangeKeysField.html]
+<div class="field">
+  <div class="rfloat">{phase}</div>
+  <div class="title">{title}</div>
+  <div class="rclear">&nbsp;</div>
+
+  <div class="inputs">
+    <table class="mobjects" id="exchange_types">
+      <thead>
+        <tr>
+          <th colspan="2"><label class="exchange_name">Exchange Name</label></th>
+          <th class="exchange_type">Exchange Type</th>
+          <th>Binding Key</th>
+        </tr>
+      </thead>
+      <tbody>
+        {exchanges}
+      </tbody>
+    </table>
+  </div>
+</div>


Property changes on: mgmt/trunk/cumin/python/cumin/messaging/binding.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/messaging/broker.py (from rev 3257, mgmt/trunk/cumin/python/cumin/broker.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/broker.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/broker.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,704 @@
+from mint import *
+from wooly import *
+from wooly.widgets import *
+from random import random
+from psycopg2 import IntegrityError
+from cumin.modelwidgets import *
+from cumin.widgets import *
+from cumin.parameters import *
+from cumin.formats import *
+from cumin.util import *
+
+from queue import *
+from exchange import *
+from brokerlink import *
+from client import *
+
+strings = StringCatalog(__file__)
+
+class NewBrokerSet(CuminClassTable):
+    def __init__(self, app, name):
+        super(NewBrokerSet, self).__init__(app, name, app.model.broker)
+
+        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.StatusColumn(app, "status")
+        self.add_column(col)
+
+        col = self.ClusterColumn(app, "cluster")
+        self.add_column(col)
+
+    def render_title(self, session):
+        count = self.get_item_count(session)
+        return "Brokers %s" % fmt_count(count)
+
+    def render_sql_where(self, session):
+        constraints = self.get_sql_where_constraints(session)
+
+        if constraints:
+            return "where %s" % " and ".join(constraints)
+
+    def get_sql_where_constraints(self, session):
+        constraints = list()
+        group = self.group.get(session)
+
+        if group:
+            subquery = \
+                "select 1 from broker_group_mapping " + \
+                "where broker_group_id = %(group_id)r " + \
+                "and broker_id = b.id"
+
+            constraints.append("exists (%s)" % subquery)
+
+        return constraints
+
+    def get_sql_values(self, session):
+        group = self.group.get(session)
+
+        if group:
+            return {"group_id": group.id}
+
+    class NameColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+        def render_content(self, session, data):
+            broker = Identifiable(data["id"])
+            href = self.page.main.messaging.broker.get_href(session, broker)
+            return fmt_link(href, fmt_shorten(data["name"], 32, 8))
+
+    class StatusColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Status"
+
+        def render_content(self, session, data):
+            scopeId = data["qmf_scope_id"]
+            dt = self.app.model.mint.model.getLatestHeartbeat(scopeId)
+
+            if dt is None:
+                return fmt_none()
+            else:
+                return fmt_datetime(dt)
+
+    class ClusterColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Cluster"
+
+        def render_content(self, session, data):
+            return data["cluster"] or fmt_none()
+
+class TopBrokerSet(CuminTable):
+    def __init__(self, app, name):
+        super(TopBrokerSet, self).__init__(app, name)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+        self.set_default_column(col)
+
+    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.messaging.broker.get_href(session, reg)
+            return fmt_link(href, fmt_shorten(data["name"]))
+
+class BrokerFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(BrokerFrame, self).__init__(app, name)
+
+        self.object = BrokerParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.vhost = self.VhostAttribute(app, "vhost")
+        self.add_attribute(self.vhost)
+
+        self.view = BrokerView(app, "view", self.vhost)
+        self.add_mode(self.view)
+
+        self.edit = BrokerEdit(app, "edit")
+        self.add_mode(self.edit)
+
+        self.queue = QueueFrame(app, "queue")
+        self.add_mode(self.queue)
+
+        self.queues_purge = QueueSetPurge(app, "queuespurge")
+        self.add_mode(self.queues_purge)
+
+        self.queues_remove = QueueSetRemove(app, "queuesremove")
+        self.add_mode(self.queues_remove)
+
+        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.vhost)
+        self.add_mode(self.exchange_add)
+
+        self.exchanges_remove = ExchangeSetRemove(app, "exchangesremove")
+        self.add_mode(self.exchanges_remove)
+
+        self.bindings_remove = BindingSetRemove(app, "bindingsremove")
+        self.add_mode(self.bindings_remove)
+
+        self.link = PeerFrame(app, "link")
+        self.add_mode(self.link)
+
+        self.link_add = BrokerLinkAdd(app, "linkadd", self.vhost)
+        self.add_mode(self.link_add)
+
+        self.links_close = BrokerSetClose(app, "linksclose")
+        self.add_mode(self.links_close)
+
+        self.connection = ConnectionFrame(app, "conn")
+        self.add_mode(self.connection)
+
+        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, 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, object):
+        if self.connected.get(session):
+            return "Connected"
+        else:
+            return "Disconnected"
+
+    def render_color(self, session, object):
+        if self.connected.get(session):
+            return "green"
+        else:
+            return "yellow"
+
+    class ConnectedAttribute(Attribute):
+        def get_default(self, session):
+            connected = False
+            broker = self.widget.frame.get_object(session)
+
+            try:
+                id = broker.qmfBrokerId
+                mbroker = self.app.model.mint.model.mintBrokersById[id]
+                connected = mbroker.connected
+            except KeyError:
+                pass
+
+            return connected
+
+class BrokerView(CuminView):
+    def __init__(self, app, name, vhost):
+        super(BrokerView, self).__init__(app, name)
+
+        self.vhost = vhost
+
+        status = BrokerStatus(app, "status", vhost)
+        self.add_child(status)
+
+        tabs = TabbedModeSet(app, "tabs")
+        self.add_child(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))
+
+    def render_group_links(self, session, object):
+        return "XXX"
+
+        links = list()
+
+        for group in reg.groups:
+            branch = session.branch()
+            self.frame.frame.show_broker_group(branch, group).view.show \
+                (branch)
+            links.append(fmt_olink(branch, group))
+
+        return ", ".join(links)
+
+    # XXX see if we can't get rid of this
+    class BrokerQueueTab(Widget):
+        def __init__(self, app, name, vhost):
+            super(BrokerView.BrokerQueueTab, self).__init__(app, name)
+
+            self.__queues = QueueSet(app, "items", vhost)
+            self.add_child(self.__queues)
+
+        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):
+            branch = session.branch()
+            self.frame.queue.add.show(branch, None)
+            return branch.marshal()
+
+    class BrokerLogTab(Widget):
+        def render_title(self, session):
+            return "Log Messages"
+
+    class BrokerDetailsTab(Widget):
+        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)
+
+            actions = self.Actions(app, "actions")
+            self.add_child(actions)
+
+        def render_title(self, session):
+            return "Details"
+
+        class Properties(CuminProperties):
+            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]
+
+                return props
+
+        class Actions(CuminActions):
+            def do_get_items(self, session, object):
+                broker = self.parent.vhost.get(session).broker
+
+                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
+
+class ModuleNotEnabled(Widget):
+    def do_render(self, session):
+        return "This module is not enabled"
+
+class BrokerAccessControl(ModeSet):
+    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.acl)
+        self.add_mode(self.__view)
+
+    class AclModuleAttribute(Attribute):
+        def get_default(self, session):
+            broker = self.widget.vhost.get(session).broker
+
+            for acl in Acl.selectBy(broker=broker):
+                return acl
+
+    def do_process(self, session):
+        if self.acl.get(session):
+            self.__view.show(session)
+
+    def render_title(self, session):
+        return "Access Control"
+
+class BrokerAccessControlView(Widget):
+    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.acl.get(session),)
+
+    class Stats(StatSet):
+        def get_args(self, session):
+            return (self.parent.acl.get(session),)
+
+class BrokerClustering(ModeSet):
+    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.cluster)
+        self.add_mode(self.__view)
+
+    class ClusteringModuleAttribute(Attribute):
+        def get_default(self, session):
+            broker = self.widget.vhost.get(session).broker
+
+            for cluster in Cluster.selectBy(broker=broker):
+                return cluster
+
+    def do_process(self, session):
+        if self.cluster.get(session):
+            self.__view.show(session)
+
+    def render_title(self, session):
+        return "Clustering"
+
+class BrokerClusteringView(Widget):
+    def __init__(self, app, name, cluster):
+        super(BrokerClusteringView, self).__init__(app, name)
+
+        self.cluster = cluster
+
+        props = self.Properties(app, "props")
+        self.add_child(props)
+
+        stats = self.Stats(app, "stats", "general")
+        self.add_child(stats)
+
+    class Properties(CuminProperties):
+        def get_args(self, session):
+            return (self.parent.cluster.get(session),)
+
+    class Stats(StatSet):
+        def get_args(self, session):
+            return (self.parent.cluster.get(session),)
+
+class BrokerStats(Widget):
+    def __init__(self, app, name):
+        super(BrokerStats, self).__init__(app, name)
+
+    def render_title(self, session):
+        return "Statistics"
+
+class BrokerBrowser(Widget):
+    def __init__(self, app, name):
+        super(BrokerBrowser, self).__init__(app, name)
+
+        self.group_tmpl = Template(self, "group_html")
+
+        self.brokers = NewBrokerSet(app, "brokers")
+        self.add_child(self.brokers)
+
+    def render_title(self, session, *args):
+        return "Brokers %s" % fmt_count(Broker.select().count())
+
+    def render_clear_filters_href(self, session):
+        branch = session.branch()
+        self.brokers.group.set(branch, None)
+        return branch.marshal()
+
+    def render_group_filters(self, session):
+        groups = BrokerGroup.select()
+        return self._render_filters(session, groups, self.group_tmpl)
+
+    def render_group_link(self, session, group):
+        return self._render_filter_link(session, group, self.brokers.group)
+
+    def _render_filters(self, session, collection, template):
+        writer = Writer()
+
+        for object in collection:
+            template.render(writer, session, object)
+
+        template.render(writer, session, None)
+
+        return writer.to_string()
+
+    def _render_filter_link(self, session, object, param):
+        branch = session.branch()
+        param.set(branch, object)
+        href = branch.marshal()
+
+        name = object and object.name or "Any"
+
+        class_ = param.get(session) is object and "selected"
+
+        return fmt_link(href, name, class_)
+
+class BrokerSetForm(CuminForm, Frame):
+    def __init__(self, app, name):
+        super(BrokerSetForm, 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.group_param = BrokerGroupParameter(app, "group_param")
+        self.group_param.default = None
+        self.add_parameter(self.group_param)
+
+        self.groups = ListParameter(app, "group", self.group_param)
+        self.add_parameter(self.groups)
+
+        self.fields = IntegerParameter(app, "fields")
+        self.fields.default = 3
+        self.add_parameter(self.fields)
+
+        self.field_tmpl = Template(self, "field_html")
+        self.group_tmpl = Template(self, "group_html")
+
+        self.more = self.MoreEntries(app, "more")
+        self.add_child(self.more)
+
+    class Errors(Attribute):
+        def get_default(self, session):
+            return dict()
+
+    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 escape_entity(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 escape_entity(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_field_group_name(self, session, index):
+        return self.groups.path
+
+    def render_groups(self, session, index):
+        writer = Writer()
+
+        for group in BrokerGroup.select():
+            self.group_tmpl.render(writer, session, index, group)
+
+        return writer.to_string()
+
+    def render_group_value(self, session, index, group):
+        return group.id
+
+    def render_group_name(self, session, index, group):
+        return group.name
+
+    def render_group_selected_attr(self, session, index, group):
+        groups = self.groups.get(session)
+        if len(groups) > index:
+            if groups[index] and group.id == groups[index].id:
+                return "selected=\"selected\""
+
+    class MoreEntries(FormButton):
+        def render_content(self, session):
+            return "More Entries"
+
+class BrokerSetAdd(BrokerSetForm):
+    def process_cancel(self, session):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_submit(self, session):
+        action = self.app.model.broker_registration.add
+
+        addrs = self.addrs.get(session)
+        names = self.names.get(session)
+        groups = self.groups.get(session)
+        fields = self.fields.get(session)
+
+        if self.validate(session, addrs, names, groups):
+            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)
+
+                    if len(groups) > i:
+                        group = groups[i]
+
+                        if group:
+                            reg.addBrokerGroup(group)
+
+            self.process_cancel(session)
+
+    def validate(self, session, addrs, names, groups):
+        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:
+                    #host, port = parse_broker_addr(addr)
+                    count = BrokerRegistration.selectBy \
+                        (url=addr).count()
+
+                    if count:
+                        errs = aerrs.setdefault(i, list())
+                        errs.append("The broker at %s " % (addr) +
+                                    "is already registered")
+
+        return not len(nerrs) and not len(aerrs)
+
+    def render_title(self, session):
+        return "Register New Brokers"
+
+class BrokerEdit(CuminFieldForm):
+    def __init__(self, app, name):
+        super(BrokerEdit, self).__init__(app, name)
+
+        self.broker_name = UniqueNameField(app, "name", BrokerRegistration)
+        self.add_field(self.broker_name)
+
+        self.groups = BrokerGroupCheckboxField(app, "groups")
+        self.add_field(self.groups)
+
+    def init(self):
+        super(BrokerEdit, self).init()
+
+        self.broker_name.set_object_attr(self.frame.object)
+
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, reg):
+        return "Edit Broker '%s'" % reg.name
+
+    def process_cancel(self, session, reg):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_submit(self, session, reg):
+        errors = self.validate(session)
+
+        if errors:
+            pass
+        else:
+            action = self.app.model.management_server.edit
+            args = {"name": self.broker_name.get(session)}
+            action.invoke(reg, args)
+
+            for group in self.groups.get(session):
+                if group not in reg.groups:
+                    reg.addBrokerGroup(group)
+
+            for group in reg.groups:
+                if group not in self.groups.get(session):
+                    reg.removeBrokerGroup(group)
+
+            reg.syncUpdate()
+
+            self.process_cancel(session, reg)
+
+    def process_display(self, session, reg):
+        self.broker_name.set(session, reg.name)
+
+        for group in reg.groups:
+            self.groups.get(session).append(group)
+
+class BrokerSetEngroup(CuminSetActionForm):
+    def __init__(self, app, name):
+        param = BrokerParameter(app, "item")
+
+        super(BrokerSetEngroup, self).__init__ \
+            (app, name, app.model.broker.engroup_set, param)
+
+from brokergroup import BrokerGroupCheckboxField


Property changes on: mgmt/trunk/cumin/python/cumin/messaging/broker.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/messaging/broker.strings (from rev 3257, mgmt/trunk/cumin/python/cumin/broker.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/broker.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/broker.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,200 @@
+[BrokerSet.sql]
+select br.id, br.name, c.cluster_name as cluster
+from broker_registration as br
+left outer join broker as b on b.registration_id = br.id
+left outer join cluster as c on c.broker_id = b.id
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[BrokerSet.count_sql]
+select count(*)
+from broker_registration as br
+{sql_where}
+
+[BrokerSet.css]
+div.sactions button.unregister {
+	margin-right: 2em;
+}
+
+[BrokerSet.html]
+<form id="{id}" method="post" action="?">
+  <!-- <select onchange="document.getElementById('{id}.submit').submit()"> -->
+
+  <div class="sactions">
+    <h2>Act on Selection:</h2>
+    {unregister}
+
+    <h2>Add to Group:</h2>
+    {groups} {groupify}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+        <th class="setnav" colspan="{column_count}">
+          <div class="rfloat">{page}</div>
+          {count}
+        </th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <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}
+
+[BrokerQueueTab.html]
+{items}
+
+[BrokerDetailsTab.html]
+<table class="CuminDetails">
+  <tbody>
+  <tr>
+    <td>
+      <h2>Properties</h2>
+      {properties}
+    </td>
+    <td>
+      <h2>Actions</h2>
+      {actions}
+    </td>
+  </tr>
+  </tbody>
+</table>
+
+[BrokerStatus.html]
+<div id="{id}" class="CuminStatus {color}">
+  <h2>Broker Status</h2>
+
+  <div>{status}</div>
+</div>
+
+[BrokerStats.html]
+<table class="twocol">
+  <tbody>
+  <tr>
+    <td>
+      <h2>Access Control</h2>
+      {acl}
+    </td>
+    <td>
+<!-- -->
+    </td>
+  </tr>
+  </tbody>
+</table>
+
+[BrokerBrowser.css]
+table.BrokerBrowser {
+  width: 100%;
+}
+
+table.BrokerBrowser td {
+  vertical-align: top;
+}
+
+table.BrokerBrowser td.nav {
+  width: 20%;
+  vertical-align: top;
+}
+
+table.BrokerBrowser td.nav h2 {
+  font-weight: normal;
+  font-size: 0.9em;
+}
+
+table.BrokerBrowser td.nav ul.slist {
+  margin: 0.5em 0 1em 0;
+}
+
+table.BrokerBrowser td.view {
+  width: 80%;
+}
+
+[BrokerBrowser.html]
+<table class="BrokerBrowser">
+  <tr>
+    <td class="nav">
+      <ul class="actions">
+        <li><a href="{clear_filters_href}">Clear Filters</a></li>
+      </ul>
+
+      <h2>Filter by Group</h2>
+      <ul class="slist">{group_filters}</ul>
+    </td>
+    <td class="view">{brokers}</td>
+  </tr>
+</table>
+
+[BrokerBrowser.group_html]
+<li>{group_link}</li>
+
+[BrokerSetForm.css]
+table.BrokerSetForm td, table.BrokerSetForm th {
+  padding: 0.25em;
+}
+
+table.BrokerSetForm span.example {
+  font-weight: normal;
+  font-size: 0.8em;
+  font-style: italic;
+}
+
+[BrokerGroupInputSet.item_html]
+<div class="field">
+  <input type="checkbox" id="{id}" name="{name}" value="{item_value}" tabindex="{tab_index}" {item_checked_attr}/>
+  <label for="{id}">{item_content}</label>
+</div>
+
+[BrokerAccessControlView.html]
+<table class="twocol">
+  <tbody>
+    <tr>
+      <td>
+        <h2>Properties</h2>
+        {props}
+
+        <h2>Statistics</h2>
+        {stats}
+      </td>
+      <td>
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+[BrokerClusteringView.html]
+<table class="twocol">
+  <tbody>
+    <tr>
+      <td>
+        <h2>Properties</h2>
+        {props}
+
+        <h2>Statistics</h2>
+        {stats}
+      </td>
+      <td>
+      </td>
+    </tr>
+  </tbody>
+</table>


Property changes on: mgmt/trunk/cumin/python/cumin/messaging/broker.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/messaging/brokergroup.py (from rev 3256, mgmt/trunk/cumin/python/cumin/brokergroup.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/brokergroup.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/brokergroup.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,193 @@
+from mint import *
+from wooly import *
+from wooly.widgets import *
+from wooly.forms import *
+from cumin.model import *
+from cumin.widgets import *
+from cumin.modelwidgets import *
+from cumin.parameters import *
+from cumin.formats import *
+from cumin.util import *
+
+from broker import NewBrokerSet
+
+strings = StringCatalog(__file__)
+
+class BrokerGroupSet(CuminClassTable):
+    def __init__(self, app, name):
+        cls = app.model.broker_group
+
+        super(BrokerGroupSet, self).__init__(app, name, cls)
+
+        col = CuminClassNameColumn(app, "name", cls)
+        self.add_column(col)
+
+class BrokerGroupInputSet(CheckboxInputSet):
+    def __init__(self, app, name):
+        super(BrokerGroupInputSet, self).__init__(app, name, None)
+
+        item = BrokerGroupParameter(app, "item")
+        self.param = ListParameter(app, "param", item)
+        self.add_parameter(self.param)
+
+    def do_get_items(self, session, *args):
+        return BrokerGroup.select()
+
+    def render_item_value(self, session, group):
+        return group.id
+
+    def render_item_content(self, session, group):
+        return group.name
+
+    def render_item_checked_attr(self, session, group):
+        if group in self.param.get(session):
+            return "checked=\"checked\""
+
+class BrokerGroupCheckboxField(FormField):
+    def __init__(self, app, name):
+        super(BrokerGroupCheckboxField, self).__init__(app, name)
+
+        self.__groups = BrokerGroupInputSet(app, "inputs")
+        self.add_child(self.__groups)
+
+    def get(self, session):
+        return self.__groups.get(session)
+
+    def render_title(self, session):
+        return "Broker Groups"
+
+class BrokerGroupFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(BrokerGroupFrame, self).__init__(app, name)
+
+        self.object = BrokerGroupParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.view = BrokerGroupView(app, "view", self.object)
+        self.add_child(self.view)
+
+        self.add = BrokerGroupAdd(app, "add")
+        self.add_child(self.add)
+
+        self.edit = BrokerGroupEdit(app, "edit")
+        self.add_child(self.edit)
+
+        self.remove = BrokerGroupRemove(app, "remove")
+        self.add_child(self.remove)
+
+    def render_title(self, session, group):
+        if group:
+            return super(BrokerGroupFrame, self).render_title(session, group)
+        else:
+            return "Broker Group"
+
+    def render_href(self, session, group):
+        if group:
+            return super(BrokerGroupFrame, self).render_href(session, group)
+
+class BrokerGroupStatus(CuminStatus):
+    pass
+
+class BrokerGroupView(CuminView):
+    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)
+
+        brokers = NewBrokerSet(app, "brokers")
+        brokers.group = self.group
+        self.__tabs.add_tab(brokers)
+
+        self.__tabs.add_tab(CuminDetails(app, "details"))
+
+class BrokerGroupForm(CuminFieldForm):
+    def __init__(self, app, name):
+        super(BrokerGroupForm, self).__init__(app, name)
+
+        self.group_name = UniqueNameField(app, "name", BrokerGroup)
+        self.add_field(self.group_name)
+
+    def init(self):
+        super(BrokerGroupForm, self).init()
+
+        self.group_name.set_object_attr(self.frame.object)
+
+class BrokerGroupAdd(BrokerGroupForm):
+    def process_cancel(self, session):
+        branch = session.branch()
+        self.page.main.messaging.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_submit(self, session):
+        errors = self.validate(session)
+
+        if errors:
+            pass
+        else:
+            args = {"name": self.group_name.get(session)}
+            method = self.app.model.broker_group.add
+            method.invoke(None, args)
+
+            self.process_cancel(session)
+
+    def render_title(self, session):
+        return "Add Group"
+
+class BrokerGroupEdit(BrokerGroupForm):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def process_cancel(self, session, group):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_submit(self, session, group):
+        errors = self.validate(session)
+
+        if errors:
+            pass
+        else:
+            args = {"name": self.group_name.get(session)}
+            method = self.app.model.broker_group.edit
+            method.invoke(group, args)
+
+            self.process_cancel(session, group)
+
+    def process_display(self, session, group):
+        self.group_name.set(session, group.name)
+
+    def render_title(self, session, group):
+        return "Edit Group '%s'" % group.name
+
+class BrokerGroupRemove(CuminConfirmForm, Frame):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def process_cancel(self, session, group):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_submit(self, session, group):
+        method = self.app.model.broker_group.remove
+        method.invoke(group)
+
+        branch = session.branch()
+        self.frame.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def render_title(self, session, group):
+        return "Remove Broker Group '%s'" % group.name
+
+    def render_submit_content(self, session, group):
+        return "Yes, Remove Broker Group '%s'" % group.name
+
+    def render_cancel_content(self, session, group):
+        return "No, Cancel"


Property changes on: mgmt/trunk/cumin/python/cumin/messaging/brokergroup.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/messaging/brokergroup.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/brokergroup.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/brokergroup.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/brokergroup.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,8 @@
+[BrokerGroupSet.sql]
+select bg.id, bg.name
+from broker_group as bg
+{sql_orderby}
+{sql_limit}
+
+[BrokerGroupSet.count_sql]
+select count(*) from broker_group


Property changes on: mgmt/trunk/cumin/python/cumin/messaging/brokergroup.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/messaging/brokerlink.py (from rev 3256, mgmt/trunk/cumin/python/cumin/brokerlink.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/brokerlink.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/brokerlink.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,694 @@
+import logging
+
+from mint import *
+from wooly import *
+from wooly.widgets import *
+from cumin.widgets import *
+from cumin.parameters import *
+from cumin.formats import *
+from cumin.util import *
+
+from queue import *
+from exchange import *
+
+strings = StringCatalog(__file__)
+
+class PeerSet(CuminTable, Form):
+    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)
+
+        #self.ids = CheckboxIdColumn(app, "id")
+        #self.add_column(self.ids)
+
+        col = self.AddressColumn(app, "addr")
+        self.add_column(col)
+        self.set_default_column(col)
+
+        col = self.DurableColumn(app, "durable")
+        self.add_column(col)
+
+        col = self.StateColumn(app, "state")
+        self.add_column(col)
+
+        col = self.LastErrorColumn(app, "last_error")
+        self.add_column(col)
+
+        #col = self.FromPeerColumn(app, "from_peer")
+        #self.add_column(col)
+
+        #col = self.ToPeerColumn(app, "to_peer")
+        #self.add_column(col)
+
+        self.__close = self.Close(app, "close")
+        self.add_child(self.__close)
+
+    def render_add_broker_link_url(self, session):
+        branch = session.branch()
+        self.frame.link_add.show(branch)
+        return branch.marshal()
+
+    def render_title(self, session):
+        count = self.get_item_count(session)
+        return "Broker Links %s" % fmt_count(count)
+
+    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 = self.vhost.get(session)
+        return {"vhost_id": vhost.id}
+
+    def disable_closed(self, session, data):
+        return data["state"] == "Closed"
+
+    class AddressColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Address"
+
+        def render_content(self, session, data):
+            peer = Identifiable(data["id"])
+            href = self.frame.link.get_href(session, peer)
+            name = "%s:%i" % (data["host"], data["port"])
+            return fmt_link(href, fmt_shorten(name))
+
+        def get_order_by_sql(self, session):
+            dir = self.parent.is_reversed(session) and "desc" or "asc"
+            return "order by host, port %s" % dir
+
+    class StateColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "State"
+
+    class LastErrorColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Last Error"
+
+    class DurableColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Durable"
+
+    class FromPeerColumn(NullSortColumn, FreshDataOnlyColumn):
+        def render_title(self, session, data):
+            return "Bytes from Broker"
+
+        def render_value(self, session, value):
+            return fmt_rate(value)
+
+    class ToPeerColumn(NullSortColumn, FreshDataOnlyColumn):
+        def render_title(self, session, data):
+            return "Bytes to Broker"
+
+        def render_value(self, session, value):
+            return fmt_rate(value)
+
+    class Close(FormButton):
+        def render_content(self, session):
+            return "Close"
+
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            href = self.frame.links_close.get_href(session, ids)
+            self.page.set_redirect_url(session, href)
+
+class PeerRouteSet(CuminTable, Form):
+    def __init__(self, app, name):
+        super(PeerRouteSet, self).__init__(app, name)
+
+        self.ids = CheckboxIdColumn(app, "id")
+        self.add_column(self.ids)
+
+        #col = self.SourceColumn(app, "source")
+        #self.add_column(col)
+
+        #col = self.DestinationColumn(app, "managed_broker")
+        #self.add_column(col)
+
+        col = self.ExchangeColumn(app, "exchange")
+        self.add_column(col)
+        self.set_default_column(col)
+
+        col = self.KeyColumn(app, "key")
+        self.add_column(col)
+
+        col = self.TagColumn(app, "tag")
+        self.add_column(col)
+
+        col = self.ExcludesColumn(app, "excludes")
+        self.add_column(col)
+
+        self.__remove = self.Remove(app, "remove")
+        self.add_child(self.__remove)
+
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, link):
+        count = self.get_item_count(session, link)
+        return "Link Routes %s" % fmt_count(count)
+
+    def render_sql_where(self, session, link):
+        return "where l.id = %(link_id)r and b.qmf_delete_time is null"
+
+    def get_sql_values(self, session, link):
+        return {"link_id": link.id}
+
+    def render_add_bridge_url(self, session, route):
+        branch = session.branch()
+        self.frame.show_bridge_add(branch)
+        return branch.marshal()
+
+    class SourceColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Source"
+
+        def render_content(self, session, data):
+            return "%s:%i" % (data["host"], data["port"])
+
+        def get_order_by_sql(self, session):
+            dir = self.parent.is_reversed(session) and "desc" or "asc"
+            return "order by l.host, l.port %s" % dir
+
+    class DestinationColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Destination"
+
+    class ExchangeColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Exchange"
+
+    class KeyColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Routing Key"
+
+    class TagColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Tag"
+
+    class ExcludesColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Excludes"
+
+    class Remove(FormButton):
+        def render_content(self, session):
+            return "Remove"
+
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            branch = session.branch()
+            frame = self.frame.show_routes_close(branch)
+            frame.ids.set(branch, ids)
+            self.page.set_redirect_url(session, branch.marshal())
+
+class PeerFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(PeerFrame, self).__init__(app, name)
+
+        self.object = PeerParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.view = PeerView(app, "view")
+        self.add_mode(self.view)
+
+        self.remove = LinkRemove(app, "remove")
+        self.add_mode(self.remove)
+
+        self.__bridge_add = BridgeAdd(app, "bridgeadd")
+        self.add_mode(self.__bridge_add)
+
+        self.__routes_close = PeerRouteSetClose(app, "routesclose")
+        self.add_mode(self.__routes_close)
+
+    def render_title(self, session, peer):
+        return super(PeerFrame, self).render_title(session, peer)
+
+    def show_object(self, session, peer):
+        self.page.main.broker.set_object(session, peer.vhost.broker)
+        return super(PeerFrame, self).show_object(session, peer)
+
+    def show_bridge_add(self, session):
+        self.page.set_frame(session, self.__bridge_add)
+        return self.__bridge_add.show(session)
+
+    def show_routes_close(self, session):
+        self.page.set_frame(session, self.__routes_close)
+        return self.__routes_close.show(session)
+
+class LinkRemove(CuminConfirmForm):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def process_cancel(self, session, link):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_submit(self, session, link):
+        action = self.app.model.link.close
+        action.invoke(link)
+
+        branch = session.branch()
+        self.frame.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def render_title(self, session, link):
+        return "Close Broker Link '%s:%d'" % (link.host, link.port)
+
+    def render_submit_content(self, session, link):
+        return "Yes, Close Broker Link"
+
+    def render_cancel_content(self, session, link):
+        return "No, Cancel"
+
+class PeerStatus(CuminStatus):
+    def render_color(self, session, link):
+        if link.statsCurr:
+            return link.statsCurr.lastError and "red" or "green"
+
+    def render_peer_state(self, session, peer):
+        if peer.statsCurr:
+            return peer.statsCurr.state
+
+    def render_peer_error(self, session, peer):
+        if peer.statsCurr:
+            return peer.statsCurr.lastError
+
+class PeerView(CuminView):
+    def __init__(self, app, name):
+        super(PeerView, self).__init__(app, name)
+
+        status = PeerStatus(app, "status")
+        self.add_child(status)
+
+        self.__tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.__tabs)
+
+        #self.__tabs.add_tab(PeerStats(app, "stats"))
+
+        self.__routes = PeerRouteSet(app, "routes")
+        self.__tabs.add_tab(self.__routes)
+
+        self.__tabs.add_tab(CuminDetails(app, "details"))
+
+    def show_routes(self, session):
+        return self.__routes.show(session)
+
+class PeerStats(TabbedModeSet):
+    def __init__(self, app, name):
+        super(PeerStats, self).__init__(app, name)
+
+        self.add_child(StatSet(app, "io", "io"))
+        self.add_child(StatSet(app, "general", "general"))
+
+        chart = self.ReceiveRouteDropRateChart(app, "recvroutedrop")
+        self.add_child(chart)
+
+        chart = StatValueChart(app, "producers")
+        chart.stats = ("producerCount",)
+        self.add_child(chart)
+
+    def render_title(self, session):
+        return "Statistics"
+
+    class ReceiveRouteDropRateChart(StatValueChart):
+        def __init__(self, app, name):
+            super(PeerStats.ReceiveRouteDropRateChart, self).__init__ \
+                (app, name)
+
+            self.stats = ("msgReceives", "msgRoutes", "msgDrops")
+            self.mode = "rate"
+
+        def render_title(self, session, exchange):
+            return "Messages Received, Routed, and Dropped"
+
+class ExchangeInputSet(RadioInputSet):
+    def __init__(self, app, name, state):
+        super(ExchangeInputSet, self).__init__(app, name, None)
+
+        self.param = IntegerParameter(app, "param")
+        self.add_parameter(self.param)
+
+        self.state = state
+
+    def do_get_items(self, session, *args):
+        exchanges = list()
+
+        link = self.frame.frame.get_object(session)
+        vhost = link.vhost
+        sortedExchanges = sorted_by(vhost.exchanges)
+
+        for exchange in sortedExchanges:
+            if ExchangeInfo.is_builtin(exchange) or \
+               (not exchange._get_qmfDeleteTime() and \
+                not (self.state.is_active(session) and not is_active(exchange))):
+                if not exchange.name in ["qpid.management", ""]:
+                    if not self.param.get(session):
+                        self.param.set(session, exchange.id)
+                    exchanges.append(exchange)
+
+        return exchanges
+
+    def render_item_value(self, session, exchange):
+        return exchange.id
+
+    def render_item_content(self, session, exchange):
+        return exchange.name
+
+    def render_item_checked_attr(self, session, exchange):
+        if self.param.get(session) == exchange.id:
+            return "checked=\"checked\""
+
+class ExchangeRadioField(FormField):
+    def __init__(self, app, name):
+        super(ExchangeRadioField, self).__init__(app, name)
+
+        self.state = ExchangeState(app, "phase")
+        self.add_child(self.state)
+
+        self.__exchanges = ExchangeInputSet(app, "inputs", self.state)
+        self.add_child(self.__exchanges)
+
+    def get(self, session):
+        return self.__exchanges.get(session)
+
+    def render_title(self, session):
+        return "Choose an Exchange"
+
+class BridgeAddForm(CuminFieldForm):
+    def __init__(self, app, name):
+        super(BridgeAddForm, self).__init__(app, name)
+
+        self.exchange = ExchangeRadioField(app, "exchange")
+        self.add_field(self.exchange)
+
+        self.key = TextField(app, "key")
+        self.key.set_title("Routing Key")
+        self.add_field(self.key)
+
+        self.more = MoreFieldSet(app, "more")
+        self.add_field(self.more)
+
+        self.help = self.BridgeAddHelpField(app, "help")
+        self.more.add_field(self.help)
+
+        self.tag = TextField(app, "tag")
+        self.tag.set_required(False)
+        self.tag.set_title("Tag")
+        self.more.add_field(self.tag)
+
+        self.excludes = TextField(app, "excludes")
+        self.excludes.set_required(False)
+        self.excludes.set_title("Excludes")
+        self.more.add_field(self.excludes)
+
+        self.dynamic = self.DynamicField(app, "dynamic")
+        self.more.add_field(self.dynamic)
+
+        self.sync = self.SyncField(app, "sync")
+        self.more.add_field(self.sync)
+
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, link):
+        return "Add Route to '%s:%d'" % (link.host, link.port)
+
+    def process_display(self, session, *args):
+        if not self.tag.get(session):
+            self.tag.set(session, args[0].qmfBrokerId)
+
+        if not self.excludes.get(session):
+            self.excludes.set(session, "%s:%s" % (args[0].host, args[0].port))
+
+        if not self.sync.get(session):
+            self.sync.set(session, self.sync.get_default(session))
+
+    class SyncField(IntegerField):
+        def render_title(self, session):
+            return "Ack"
+
+        def render_field_help(self, session):
+             return "Acknowledge transfers over the bridge in batches of N"
+
+        def get_default(self, session):
+            return 0
+
+    class DynamicField(TwoOptionRadioField):
+        def render_title(self, session):
+            return "Dynamic Route?"
+
+        def render_field_help(self, session):
+            return "(Should the added route be dynamic)"
+
+        def render_title_1(self, session):
+            return "Dynamic"
+
+        def render_title_2(self, session):
+            return "Not dynamic"
+
+
+    class BridgeAddHelpField(FormField):
+        pass
+
+class BridgeAdd(BridgeAddForm):
+    def process_cancel(self, session, *args):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_submit(self, session, link):
+        errors = self.validate(session)
+        if errors:
+            pass
+        else:
+            key = self.key.get(session)
+            tag = self.tag.get(session)
+            excludes = self.excludes.get(session)
+            exchange_id = self.exchange.get(session)
+            exchange = Exchange.get(int(exchange_id))
+            durable = link.durable
+            dynamic = self.dynamic.get(session) == "yes"
+            sync = self.sync.get(session)
+
+            args = {"durable": durable,
+                    "exchange": exchange.name,
+                    "key": key,
+                    "tag": tag,
+                    "excludes": excludes,
+                    "dynamic": dynamic,
+                    "sync": sync
+                    }
+
+            action = self.app.model.link.bridge
+            action.invoke(link, args)
+
+            self.process_cancel(session, link)
+
+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)
+
+        self.more = self.ShowButton(app, "more")
+        self.add_field(self.more)
+
+        self.port = self.PortField(app, "port")
+        self.more.add_field(self.port)
+
+        self.username = self.UsernameField(app, "username")
+        self.more.add_field(self.username)
+
+        self.password = self.PassField(app, "password")
+        self.more.add_field(self.password)
+
+        self.durable = self.DurableField(app, "durable")
+        self.more.add_field(self.durable)
+
+        self.transport = self.TransportField(app, "transport")
+        self.more.add_field(self.transport)
+
+    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):
+            return "Show Optional Inputs..."
+
+        def render_less_text(self, session):
+            return "Hide Optional Inputs..."
+
+    class Host(NameField):
+        def render_title(self, session):
+            return "Address"
+
+    class PortField(StringField):
+        def __init__(self, app, name):
+            super(BrokerLinkAdd.PortField, self).__init__(app, name)
+
+            self.input.size = 5
+            self.css_class = "compact first"
+
+        def render_title(self, session):
+            return "Port"
+
+        def do_validate(self, session, errors):
+            try:
+                port = self.get(session)
+                if port:
+                    int(port)
+            except:
+                errors.append(FormError("Port must be a number"))
+
+    class UsernameField(StringField):
+        def render_title(self, session):
+            return "Username"
+
+        def render_form_field_class(self, session):
+            return "compact"
+
+    class PassField(PasswordField):
+        def render_title(self, session):
+            return "Password"
+
+        def render_form_field_class(self, session):
+            return "compact last"
+
+    class TransportField(RadioField):
+        def __init__(self, app, name):
+            super(BrokerLinkAdd.TransportField, self).__init__(app, name, None)
+
+            self.param = Parameter(app, "param")
+            self.param.default = "tcp"
+            self.add_parameter(self.param)
+
+            option = self.TCP(app, "tcp", self.param)
+            self.add_option(option)
+
+            option = self.SSL(app, "ssl", self.param)
+            self.add_option(option)
+
+            option = self.RDMA(app, "rdma", self.param)
+            self.add_option(option)
+
+        def render_title(self, session):
+            return "Transport-type"
+
+        def render_field_help(self, session):
+            return "(Transport to use)"
+
+        class TCP(RadioFieldOption):
+            def render_title(self, session):
+                return "tcp"
+
+        class SSL(RadioFieldOption):
+            def render_title(self, session):
+                return "ssl"
+
+        class RDMA(RadioFieldOption):
+            def render_title(self, session):
+                return "rdma"
+
+    class DurableField(TwoOptionRadioField):
+        def render_title(self, session):
+            return "Restore if broker restarts?"
+
+        def render_field_help(self, session):
+            return "(Should the added configuration be durable)"
+
+        def render_title_1(self, session):
+            return "Yes, restore if broker restarts"
+
+        def render_title_2(self, session):
+            return "No, do not restore if broker restarts"
+
+    def process_cancel(self, session):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_submit(self, session):
+        if self.validate(session):
+            pass
+        else:
+            host = self.host.get(session)
+            port = self.port.get(session) or 5672
+            if port:
+                port = int(port)
+            username = self.username.get(session) or "anonymous"
+            password = self.password.get(session)
+            durable = self.durable.get(session)
+            transport = self.transport.get(session)
+
+            args = {
+                "host": host,
+                "port": port,
+                "durable": durable == "yes",
+                "username": username,
+                "password": password,
+                "transport": transport
+                }
+
+            action = self.app.model.broker.add_link
+            action.invoke(self.vhost.get(session).broker, args)
+
+            # navigate back to main queue frame
+            self.process_cancel(session)
+
+class BrokerSetClose(CuminBulkActionForm):
+    def process_return(self, session):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_item(self, session, id):
+        link = Link.get(id)
+        action = self.app.model.link.close
+        action.invoke(link)
+
+    def render_title(self, session):
+        return "Close Broker Link"
+
+    def render_form_heading(self, session, *args):
+        return "Close Link to"
+
+    def render_item_content(self, session, id):
+        link = Link.get(id)
+        return "Broker: %s:%d" % (link.host, link.port)
+
+class PeerRouteSetClose(CuminBulkActionForm):
+    def process_return(self, session):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_item(self, session, id):
+        bridge = Bridge.get(id)
+        action = self.app.model.route.remove
+        action.invoke(bridge)
+
+    def render_title(self, session):
+        link = self.parent.get_object(session)
+        return "Remove Route from %s:%i" % (link.host, link.port)
+
+    def render_form_heading(self, session, *args):
+        return "Remove Route"
+
+    def render_item_content(self, session, id):
+        bridge = Bridge.get(id)
+        return "<td>%s</td><td>%s</td>" % (bridge.dest, bridge.key)


Property changes on: mgmt/trunk/cumin/python/cumin/messaging/brokerlink.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/messaging/brokerlink.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/brokerlink.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/brokerlink.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/brokerlink.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,176 @@
+[PeerSet.sql]
+select
+  l.id,
+  l.host,
+  l.port,
+  l.durable,
+  c.state,
+  c.last_error
+from link as l
+join vhost as v on v.id = l.vhost_id
+left outer join link_stats as c on c.id = l.stats_curr_id
+left outer join link_stats as p on p.id = l.stats_prev_id
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[PeerSet.count_sql]
+select count(*)
+from link as l
+join vhost as v on v.id = l.vhost_id
+{sql_where}
+
+[PeerSet.html]
+<form id="{id}" method="post" action="?">
+  <ul class="actions">
+    <li><a class="nav" href="{add_broker_link_url}">Add Broker Link</a></li>
+  </ul>
+
+  <div class="sactions">
+    <h2>Act on Selected Broker Links:</h2>
+    {close}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+        <th class="setnav" colspan="{column_count}">
+          <div class="rfloat">{page}</div>
+          {count}
+        </th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>
+
+[PeerRouteSet.sql]
+select
+  b.id,
+  b.src,
+  b.dest as exchange,
+  b.key,
+  b.tag,
+  b.excludes,
+  l.host,
+  l.port,
+  l.qmf_broker_id
+from bridge as b
+join link as l on l.id = b.link_id
+left outer join bridge_stats as c on c.id = b.stats_curr_id
+left outer join bridge_stats as p on p.id = b.stats_prev_id
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[PeerRouteSet.count_sql]
+select count(*)
+from bridge as b
+join link as l on l.id = b.link_id
+{sql_where}
+
+[PeerRouteSet.html]
+<form id="{id}" method="post" action="?">
+  <ul class="actions">
+    <li><a class="nav" href="{add_bridge_url}">Add Route</a></li>
+  </ul>
+
+  <div class="sactions">
+    <h2>Act on Selected Routes:</h2>
+    {remove}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+        <th class="setnav" colspan="{column_count}">
+          <div class="rfloat">{page}</div>
+          {count}
+        </th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>
+
+[ExchangeRadioField.html]
+<div class="{form_field_class}">
+  <div class="rfloat">{phase}</div>
+  <div class="title">{title}</div> <div class="field_help">{field_help}</div><div class="clear_left"></div>
+  {errors}
+  <div class="inputs">{inputs}</div><div style="clear:left;"><!-- --></div>
+</div>
+
+[PeerRouteSetClose.html]
+<form id="{id}" class="mform" method="post" action="?">
+  <div class="head">
+    <h1>{title}</h1>
+  </div>
+  <div class="body">
+    <span class="legend">{form_heading}</span>
+          <table class="mobjects">
+            <thead>
+              <tr>
+                <th>Exchange</th>
+                <th>Key</th>
+              </tr>
+            </thead>
+            <tbody>{items}</tbody>
+          </table>
+    {hidden_inputs}
+  </div>
+  <div class="foot">
+    {help}
+    {submit}
+    {cancel}
+  </div>
+</form>
+<script type="text/javascript">
+  wooly.doc().elembyid("{id}").node.elements[0].focus();
+</script>
+
+[PeerRouteSetClose.item_html]
+<tr>{item_content}</tr>
+
+[BridgeAddHelpField.css]
+div#bridge_add_help span.tag1 {
+        color:red;
+}
+div#bridge_add_help span.tag2 {
+        color:green;
+}
+div#bridge_add_help p.example {
+        font-size: 0.9em;
+        color: #444444;
+}
+
+
+[BridgeAddHelpField.html]
+<div id="bridge_add_help">
+  <p>The <strong>Tag</strong> and <strong>Excludes</strong> are used to prevent a message from routing back
+    to the source broker and causing an infinite loop.</p>
+  <p>Enter a short <strong>tag</strong> that will be associated with the source exchange.
+    Then <strong>exclude</strong> any tags that were used for the destination exchanges.</p>
+  <p class="example">
+    <em>broker1</em> &lt;==&gt; <em>broker2</em> tag: <span class="tag2">tag2</span> excludes: <span class="tag1">tag1</span><br/>
+    <em>broker2</em> &lt;==&gt; <em>broker1</em> tag: <span class="tag1">tag1</span> excludes: <span class="tag2">tag2</span>
+  </p>
+</div>
+
+[PeerStatus.html]
+<div id="{id}" class="CuminStatus {color}">
+  <table>
+    <tr>
+      <th><strong>State</strong></th>
+      <td>{peer_state}</td>
+    </tr>
+    <tr>
+      <th><strong>Last Error</strong></th>
+      <td>{peer_error}</td>
+    </tr>
+  </table>
+</div>


Property changes on: mgmt/trunk/cumin/python/cumin/messaging/brokerlink.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/messaging/client.py (from rev 3256, mgmt/trunk/cumin/python/cumin/client.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/client.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/client.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,402 @@
+from wooly import *
+from wooly.widgets import *
+from wooly.tables import *
+from datetime import datetime
+from cumin.stat import *
+from cumin.widgets import *
+from cumin.parameters import *
+from cumin.formats import *
+from cumin.util import *
+
+strings = StringCatalog(__file__)
+
+class ConnectionSet(CuminTable, Form):
+    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)
+
+        col = self.AddressColumn(app, "addr")
+        self.add_column(col)
+
+        self.set_default_column(col)
+
+        col = self.SystemConnectionColumn(app, "sysconn")
+        self.add_column(col)
+
+        col = self.AuthIdentityColumn(app, "authid")
+        self.add_column(col)
+
+        col = self.FedLinkColumn(app, "fedlink")
+        self.add_column(col)
+
+        col = self.SentColumn(app, "sent")
+        col.alignment = "right"
+        self.add_column(col)
+
+        col = self.ReceivedColumn(app, "received")
+        col.alignment = "right"
+        self.add_column(col)
+
+        self.unit = StateSwitch(app, "unit")
+        self.unit.add_state("b", "Bytes")
+        self.unit.add_state("f", "Frames")
+        self.add_child(self.unit)
+
+        self.__phase = PhaseSwitch(app, "phase")
+        self.add_child(self.__phase)
+
+        self.__close = self.Close(app, "close")
+        self.add_child(self.__close)
+
+    def get_unit_plural(self, session):
+        return self.unit.get(session) == "b" and "Bytes" or "Frames"
+
+    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 = self.vhost.get(session)
+
+        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):
+        def render_content(self, session):
+            return "Close"
+
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            # XXX Make table a frame to elim this
+            self.parent.ids.clear(session)
+            href = self.frame.connections_close.get_href(session, ids)
+            self.page.set_redirect_url(session, href)
+
+    class AddressColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Address"
+
+        def render_content(self, session, data):
+            conn = Identifiable(data["id"])
+            href = self.frame.connection.get_href(session, conn)
+            return fmt_link(href, fmt_shorten(data["addr"]))
+
+    class SystemConnectionColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Connect Type"
+
+        def render_content(self, session, data):
+            if data['sysconn']:
+                return "System"
+            else:
+                return "Client"
+
+    class AuthIdentityColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Auth Id"
+
+    class FedLinkColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Fed Link"
+
+        def render_content(self, session, data):
+            if data['fedlink']:
+                return "Yes"
+            else:
+                return "No"
+
+    class SentColumn(NullSortColumn, FreshDataOnlyColumn):
+        def render_title(self, session, data):
+            return "%s Sent" % self.parent.get_unit_plural(session)
+
+        def get_column_key(self, session):
+            unit = self.parent.unit.get(session)
+            return unit == "b" and "bs" or "fs"
+
+        def render_value(self, session, value):
+            return fmt_rate(value, "", "sec")
+
+    class ReceivedColumn(NullSortColumn, FreshDataOnlyColumn):
+        def render_title(self, session, data):
+            return "%s Received" % self.parent.get_unit_plural(session)
+
+        def get_column_key(self, session):
+            unit = self.parent.unit.get(session)
+            return unit == "b" and "br" or "fr"
+
+        def render_value(self, session, value):
+            return fmt_rate(value, "", "sec")
+
+class ConnectionFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(ConnectionFrame, self).__init__(app, name)
+
+        self.object = ConnectionParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.view = ConnectionView(app, "view")
+        self.add_mode(self.view)
+
+        self.__close = ConnectionClose(app, "close", self.object)
+        self.add_mode(self.__close)
+
+        self.__sessions_detach = SessionSetDetach(app, "sessionsdetach")
+        self.add_mode(self.__sessions_detach)
+
+        self.__sessions_close = SessionSetClose(app, "sessionsclose")
+        self.add_mode(self.__sessions_close)
+
+    def show_object(self, session, conn):
+        if hasattr(conn, "vhost"):
+            self.frame.set_object(session, conn.vhost.broker)
+
+        return super(ConnectionFrame, self).show_object(session, conn)
+
+    def show_close(self, session):
+        return self.__close.show(session)
+
+    def show_sessions_detach(self, session):
+        return self.__sessions_detach.show(session)
+
+    def show_sessions_close(self, session):
+        return self.__sessions_close.show(session)
+
+# XXX get rid of this
+def doit(error, args):
+    pass
+    #print error, args
+    #print "did it!"
+
+class ConnectionClose(CuminConfirmForm):
+    def __init__(self, app, name, conn):
+        super(ConnectionClose, self).__init__(app, name)
+
+        self.conn = conn
+
+    def process_cancel(self, session):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    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):
+        return "Close Connection '%s'" % self.conn.get(session).address
+
+    def render_submit_content(self, session):
+        return "Yes, Close Connection '%s'" % self.conn.get(session).address
+
+    def render_cancel_content(self, session):
+        return "No, Cancel"
+
+class ConnectionSetClose(CuminBulkActionForm):
+    def process_return(self, session):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_item(self, session, id):
+        conn = ClientConnection.get(id)
+        action = self.app.model.connection.close
+        action.invoke(conn)
+
+    def render_title(self, session):
+        return "Close Connections"
+
+    def render_item_content(self, session, id):
+        return "Close Connection %s" % ClientConnection.get(id).address
+
+class ConnectionStatus(CuminStatus):
+    def render_frames_from(self, session, conn):
+        return self.app.model.connection.framesFromClient.rate_html(conn)
+
+    def render_frames_to(self, session, conn):
+        return self.app.model.connection.framesToClient.rate_html(conn)
+
+    def render_bytes_from(self, session, conn):
+        return self.app.model.connection.bytesFromClient.rate_html(conn)
+
+    def render_bytes_to(self, session, conn):
+        return self.app.model.connection.bytesToClient.rate_html(conn)
+
+class ConnectionView(CuminView):
+    def __init__(self, app, name):
+        super(ConnectionView, self).__init__(app, name)
+
+        status = ConnectionStatus(app, "status")
+        self.add_child(status)
+
+        self.__tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.__tabs)
+
+        self.__tabs.add_tab(ConnectionStats(app, "stats"))
+
+        self.__sessions = SessionSet(app, "sessions")
+        self.__tabs.add_tab(self.__sessions)
+
+        self.__tabs.add_tab(CuminDetails(app, "details"))
+
+    def show_sessions(self, session):
+        return self.__sessions.show(session)
+
+class ConnectionStats(Widget):
+    def __init__(self, app, name):
+        super(ConnectionStats, self).__init__(app, name)
+
+        self.add_child(StatSet(app, "io", "io"))
+        self.add_child(StatSet(app, "general", "general"))
+
+        chart = self.SendReceiveRateChart(app, "sendrecv")
+        self.add_child(chart)
+
+    def render_title(self, session):
+        return "Statistics"
+
+    class SendReceiveRateChart(StatValueChart):
+        def __init__(self, app, name):
+            super(ConnectionStats.SendReceiveRateChart, self).__init__(app, name)
+
+            self.stats = ("bytesFromClient", "bytesToClient")
+            self.mode = "rate"
+
+        def render_title(self, session, conn):
+            return "Bytes Sent and Received"
+
+class SessionSetDetach(CuminBulkActionForm, Frame):
+    def process_return(self, session):
+        branch = session.branch()
+        self.frame.view.show(branch).show_sessions(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_item(self, session, id):
+        session_ = Session.get(id)
+        action = self.app.model.session.detach
+        action.invoke(session_)
+
+    def render_title(self, session):
+        return "Detach Sessions"
+
+    def render_item_content(self, session, id):
+        return "Detach Session '%s'" % Session.get(id).name
+
+class SessionSetClose(CuminBulkActionForm, Frame):
+    def process_return(self, session):
+        branch = session.branch()
+        self.frame.view.show(branch).show_sessions(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_item(self, session, id):
+        session_ = Session.get(id)
+        action = self.app.model.session.close
+        action.invoke(session_)
+
+    def render_title(self, session):
+        return "Close Sessions"
+
+    def render_item_content(self, session, id):
+        return "Close Session '%s'" % Session.get(id).name
+
+class SessionSet(CuminTable, Form):
+    def __init__(self, app, name):
+        super(SessionSet, self).__init__(app, name)
+
+        self.ids = CheckboxIdColumn(app, "id")
+        self.add_column(self.ids)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+
+        self.set_default_column(col)
+
+        col = self.ExpiresColumn(app, "expires")
+        self.add_column(col)
+
+        col = self.StatusColumn(app, "status")
+        self.add_column(col)
+
+        self.__phase = PhaseSwitch(app, "phase")
+        self.add_child(self.__phase)
+
+        self.__detach = self.Detach(app, "detach")
+        self.add_child(self.__detach)
+
+        self.__close = self.Close(app, "close")
+        self.add_child(self.__close)
+
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, conn):
+        return "Sessions %s" % fmt_count(conn.sessions.count())
+
+    def render_sql_where(self, session, conn):
+        elems = list()
+        elems.append("s.client_connection_id = %(id)r")
+        elems.append(self.__phase.get_sql_constraint(session, conn))
+        return "where %s" % " and ".join(elems)
+
+    def get_sql_values(self, session, conn):
+        return {"id": conn.id}
+
+    class Detach(FormButton):
+        def render_content(self, session):
+            return "Detach"
+
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            branch = session.branch()
+            frame = self.frame.show_sessions_detach(branch)
+            frame.ids.set(branch, ids)
+            self.page.set_frame(branch, frame)
+            self.page.set_redirect_url(session, branch.marshal())
+
+    class Close(FormButton):
+        def render_content(self, session):
+            return "Close"
+
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            branch = session.branch()
+            frame = self.frame.show_sessions_close(branch)
+            frame.ids.set(branch, ids)
+            self.page.set_frame(branch, frame)
+            self.page.set_redirect_url(session, branch.marshal())
+
+    class NameColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+    class ExpiresColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Expires"
+
+        def render_value(self, session, value):
+            return fmt_datetime(value)
+
+    class StatusColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Attached?"
+
+        def render_content(self, session, data):
+            return fmt_predicate(data["attached"])


Property changes on: mgmt/trunk/cumin/python/cumin/messaging/client.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/messaging/client.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/client.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/client.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/client.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,138 @@
+[ConnectionSet.sql]
+select
+  l.id,
+  l.system_connection as sysconn,
+  l.auth_identity as authid,
+  l.federation_link as fedlink,
+  l.address as addr,
+  (c.bytes_from_client - p.bytes_from_client)
+   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as bs,
+  case when p.bytes_from_client is null then true else false end as bs_is_null,
+  (c.frames_from_client - p.frames_from_client)
+   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as fs,
+  case when p.frames_from_client is null then true else false end as fs_is_null,
+  (c.bytes_to_client - p.bytes_to_client)
+   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as br,
+  case when p.bytes_to_client is null then true else false end as br_is_null,
+  (c.frames_to_client - p.frames_to_client)
+   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as fr,
+  case when p.frames_to_client is null then true else false end as fr_is_null,
+  c.qmf_update_time
+from client_connection as l
+left outer join client_connection_stats as c on c.id = l.stats_curr_id
+left outer join client_connection_stats as p on p.id = l.stats_prev_id
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[ConnectionSet.count_sql]
+select count(*)
+from client_connection as l
+left outer join client_connection_stats as c on c.id = l.stats_curr_id
+{sql_where}
+
+[ConnectionSet.html]
+<form id="{id}" method="post" action="?">
+  <div class="rfloat">{phase}</div>
+
+  {unit}
+
+  <div class="sactions">
+    <h2>Act on Selected Connections:</h2>
+    {close}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+        <th class="setnav" colspan="{column_count}">
+          <div class="rfloat">{page}</div>
+          {count}
+        </th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>
+
+[ConnectionStatus.html]
+<div id="{id}" class="CuminStatus {color}">
+  <table>
+    <tr>
+      <th></th>
+      <th style="width: 35%;" class="ralign">Frames</th>
+      <th style="width: 35%;" class="ralign">Bytes</th>
+    </tr>
+    <tr>
+      <th>Sent</th>
+      <td class="ralign">{frames_from}</td>
+      <td class="ralign">{bytes_from}</td>
+    </tr>
+    <tr>
+      <th>Received</th>
+      <td class="ralign">{frames_to}</td>
+      <td class="ralign">{bytes_to}</td>
+    </tr>
+  </table>
+</div>
+
+[ConnectionStats.html]
+<table class="twocol">
+  <tbody>
+  <tr>
+    <td>
+      <h2>Input/Output</h2>
+      {io}
+
+      <h2>General</h2>
+      {general}
+    </td>
+    <td>
+      {sendrecv}
+    </td>
+  </tr>
+  </tbody>
+</table>
+
+[SessionSet.sql]
+select s.id, s.name, s.expire_time as expires, s.attached
+from session as s
+left outer join session_stats as c on c.id = s.stats_curr_id
+left outer join session_stats as p on p.id = s.stats_prev_id
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[SessionSet.count_sql]
+select count(*)
+from session as s
+left outer join session_stats as c on c.id = s.stats_curr_id
+{sql_where}
+
+[SessionSet.html]
+<form id="{id}" method="post" action="?">
+  <div class="rfloat">{phase}</div>
+
+  <ul class="radiotabs"><li>&nbsp;</li></ul>
+
+  <div class="sactions">
+    <h2>Act on Selected Sessions:</h2>
+    {close}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+        <th class="setnav" colspan="{column_count}">
+          <div class="rfloat">{page}</div>
+          {count}
+        </th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>


Property changes on: mgmt/trunk/cumin/python/cumin/messaging/client.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/messaging/exchange.py (from rev 3256, mgmt/trunk/cumin/python/cumin/exchange.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/exchange.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/exchange.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,554 @@
+import logging
+
+from wooly import *
+from wooly.widgets import *
+from wooly.forms import *
+from wooly.resources import *
+from cumin.stat import *
+from cumin.model import *
+from cumin.widgets import *
+from cumin.parameters import *
+from cumin.formats import *
+from cumin.util import *
+
+strings = StringCatalog(__file__)
+log = logging.getLogger("cumin.messaging.exchange")
+
+class ExchangeInputSet(RadioInputSet):
+    def __init__(self, app, name):
+        super(ExchangeInputSet, self).__init__(app, name)
+
+        param = ExchangeParameter(app, "param")
+        self.add_parameter(param)
+        self.set_parameter(param)
+
+    def do_get_items(self, session, vhost):
+        return sorted_by(vhost.exchanges)
+
+    def render_item_value(self, session, exchange):
+        return exchange.id
+
+    def render_item_content(self, session, exchange):
+        return exchange.name or "<em>Default</em>"
+
+    def render_item_checked_attr(self, session, exchange):
+        return exchange is self.param.get(session) and "checked=\"checked\""
+
+class ExchangeSet(CuminTable, Form):
+    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)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+        self.set_default_column(col)
+
+        col = self.ProducersColumn(app, "name")
+        col.alignment = "right"
+        self.add_column(col)
+
+        col = self.BindingsColumn(app, "bindings")
+        col.alignment = "right"
+        self.add_column(col)
+
+        col = self.ReceivedColumn(app, "received")
+        col.alignment = "right"
+        self.add_column(col)
+
+        col = self.RoutedColumn(app, "routed")
+        col.alignment = "right"
+        self.add_column(col)
+
+        col = self.DroppedColumn(app, "dropped")
+        col.alignment = "right"
+        self.add_column(col)
+
+        self.unit = UnitSwitch(app, "unit")
+        self.add_child(self.unit)
+
+        self.phase = PhaseSwitch(app, "phase")
+        self.add_child(self.phase)
+
+        self.__remove = self.Remove(app, "remove")
+        self.add_child(self.__remove)
+
+    def disable_exchange(self, session, data):
+        return data["name"] in ExchangeInfo.get_builtins()
+
+    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 = self.vhost.get(session)
+        return "Exchanges %s" % fmt_count(vhost.exchanges.count())
+
+    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 = self.vhost.get(session)
+        return {"id": vhost.id}
+
+    class Remove(FormButton):
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            branch = session.branch()
+            self.frame.exchanges_remove.show(branch).ids.set(branch, ids)
+            self.page.set_redirect_url(session, branch.marshal())
+
+        def render_content(self, session):
+            return "Remove"
+
+    class NameColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+        def render_content(self, session, data):
+            exchange = Identifiable(data["id"])
+            href = self.frame.exchange.get_href(session, exchange)
+            name = data["name"] or "<em>Default</em>"
+            return fmt_link(href, fmt_shorten(name))
+
+    class ProducersColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Producers"
+
+        def render_content(self, session, data):
+            return data["producers"]
+
+    class BindingsColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Bindings"
+
+        def render_content(self, session, data):
+            exchange = Identifiable(data["id"])
+            href = self.frame.exchange.get_href(session, exchange)
+            return fmt_link(href, data["bindings"])
+
+    class ReceivedColumn(NullSortColumn, FreshDataOnlyColumn):
+        def render_title(self, session, data):
+            return "%s Received" % self.parent.unit.get_brief_plural(session)
+
+        def get_column_key(self, session):
+            unit = self.parent.unit.get(session)
+            return unit == "b" and "breceived" or "mreceived"
+
+        def render_value(self, session, value):
+            return fmt_rate(value, "", "sec")
+
+    class RoutedColumn(NullSortColumn, FreshDataOnlyColumn):
+        def render_title(self, session, data):
+            return "%s Routed" % self.parent.unit.get_brief_plural(session)
+
+        def get_column_key(self, session):
+            unit = self.parent.unit.get(session)
+            return unit == "b" and "brouted" or "mrouted"
+
+        def render_value(self, session, value):
+            return fmt_rate(value, "", "sec")
+
+    class DroppedColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "%s Dropped" % self.parent.unit.get_brief_plural(session)
+
+        def get_column_key(self, session):
+            unit = self.parent.unit.get(session)
+            return unit == "b" and "bdropped" or "mdropped"
+
+class ExchangeSetRemove(CuminBulkActionForm):
+    def process_return(self, session):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_item(self, session, id):
+        exchange = Exchange.get(id)
+        reg = self.frame.get_object(session)
+        action = self.app.model.exchange.remove
+        action.invoke(exchange)
+
+    def render_title(self, session):
+        return "Remove Exchanges"
+
+    def render_item_content(self, session, id):
+        return "Remove Exchange '%s'" % Exchange.get(id).name
+
+class ExchangeFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(ExchangeFrame, self).__init__(app, name)
+
+        self.object = ExchangeParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.view = ExchangeView(app, "view")
+        self.add_mode(self.view)
+
+        self.remove = ExchangeRemove(app, "remove")
+        self.add_mode(self.remove)
+
+    def show_object(self, session, exchange):
+        if isinstance(exchange, SQLObject):
+            self.page.main.messaging.broker.set_object \
+                (session, exchange.vhost.broker)
+
+        return super(ExchangeFrame, self).show_object(session, exchange)
+
+    def render_title(self, session, exchange):
+        if exchange.name:
+            return super(ExchangeFrame, self).render_title(session, exchange)
+        else:
+            return "Default Exchange"
+
+    def render_href(self, session, exchange):
+        if exchange:
+            return super(ExchangeFrame, self).render_href(session, exchange)
+
+
+class ExchangeRemove(CuminConfirmForm):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def process_cancel(self, session, exchange):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_submit(self, session, exchange):
+        reg = self.frame.frame.get_object(session)
+        action = self.app.model.exchange.remove
+        action.invoke(exchange)
+
+        branch = session.branch()
+        self.frame.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def render_title(self, session, exchange):
+        return "Remove Exchange '%s'" % exchange.name
+
+    def render_submit_content(self, session, exchange):
+        return "Yes, Remove Exchange '%s'" % exchange.name
+
+    def render_cancel_content(self, session, exchange):
+        return "No, Cancel"
+
+class ExchangeStatus(CuminStatus):
+    def render_messages_received(self, session, exchange):
+        return self.app.model.exchange.msgReceives.rate_html(exchange)
+
+    def render_messages_routed(self, session, exchange):
+        return self.app.model.exchange.msgRoutes.rate_html(exchange)
+
+    def render_messages_dropped(self, session, exchange):
+        return self.app.model.exchange.msgDrops.value(exchange)
+
+    def render_bytes_received(self, session, exchange):
+        return self.app.model.exchange.byteReceives.rate_html(exchange)
+
+    def render_bytes_routed(self, session, exchange):
+        return self.app.model.exchange.byteRoutes.rate_html(exchange)
+
+    def render_bytes_dropped(self, session, exchange):
+        return self.app.model.exchange.byteDrops.value(exchange)
+
+class ExchangeView(CuminView):
+    def __init__(self, app, name):
+        super(ExchangeView, self).__init__(app, name)
+
+        status = ExchangeStatus(app, "status")
+        self.add_child(status)
+
+        self.__tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.__tabs)
+
+        self.__tabs.add_tab(ExchangeStats(app, "stats"))
+
+        self.__bindings = ExchangeBindingSet(app, "bindings")
+        self.__tabs.add_tab(self.__bindings)
+
+        self.__tabs.add_tab(CuminDetails(app, "details"))
+
+    def show_bindings(self, session):
+        return self.__bindings.show(session)
+
+class ExchangeBindingSet(BindingSet, Form):
+    def __init__(self, app, name):
+        super(ExchangeBindingSet, self).__init__(app, name)
+
+        self.__remove = self.Remove(app, "remove")
+        self.add_child(self.__remove)
+
+        self.set_default_column_name("q_id")
+
+    def get_visible_columns(self, session):
+        return self.get_request_visible_columns(session, ["q_id"])
+
+    def render_title(self, session, exchange):
+        return "Queue Bindings %s" % \
+            fmt_count(exchange.bindings.count())
+
+    def render_sql_where(self, session, exchange):
+        elems = list()
+        elems.append("b.exchange_id = %(id)r")
+        elems.append(self.phase.get_sql_constraint(session, exchange))
+        return "where %s" % " and ".join(elems)
+
+    class Remove(FormButton):
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            href = self.page.main.messaging.broker.bindings_remove.get_href \
+                (session, ids)
+            self.page.set_redirect_url(session, href)
+
+        def render_content(self, session):
+            return "Remove"
+
+class BindingSetRemove(CuminBulkActionForm):
+    def process_item(self, session, id):
+        binding = Binding.get(id)
+        action = self.app.model.binding.remove
+        action.invoke(binding)
+
+    def render_title(self, session):
+        return "Remove Binding"
+
+    def render_form_heading(self, session, *args):
+        return "Remove Binding between:"
+
+    def render_item_content(self, session, id):
+        binding = Binding.get(id)
+        ename = binding.exchange.name or "Default"
+        qname = binding.queue.name
+        return "Exchange: %s <i>and</i> Queue: %s" % (ename, qname)
+
+class ExchangeForm(CuminFieldForm):
+    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)
+
+        self.exchange_type = self.ExchangeTypeField(app, "exchange_type")
+        self.add_field(self.exchange_type)
+
+        self.more = MoreFieldSet(app, "more")
+        self.add_field(self.more)
+
+        self.durable = self.ExchangeDurabilityField(app, "durable")
+        self.more.add_field(self.durable)
+
+        self.sequence = self.SequenceField(app, "sequence")
+        self.more.add_field(self.sequence)
+
+        self.ive = self.IVEField(app, "ive")
+        self.more.add_field(self.ive)
+
+    class SequenceField(TwoOptionRadioField):
+        def render_title(self, session):
+            return "Insert Sequence?"
+
+        def render_field_help(self, session):
+            return "(Exchange will insert a 'qpid.msg_sequence' field in the message header)"
+
+        def render_title_1(self, session):
+            return "Insert Sequence"
+
+        def render_title_2(self, session):
+            return "No Sequence"
+
+    class IVEField(TwoOptionRadioField):
+        def render_title(self, session):
+            return "Initial Value Exchange?"
+
+        def render_field_help(self, session):
+            return "(Exchange will behave as an 'initial-value-exchange', keeping a reference to the last message forwarded and enqueuing that message to newly bound queues)"
+
+        def render_title_1(self, session):
+            return "Initial-Value-Exchange"
+
+        def render_title_2(self, session):
+            return "No IVE"
+
+    class ExchangeDurabilityField(TwoOptionRadioField):
+        def render_title(self, session):
+            return "Durable?"
+
+        def render_field_help(self, session):
+            return "(Queue is durable)"
+
+        def render_title_1(self, session):
+            return "Durable"
+
+        def render_title_2(self, session):
+            return "Transient"
+
+    class ExchangeTypeField(RadioField):
+        def __init__(self, app, name):
+            super(ExchangeForm.ExchangeTypeField, self).__init__(app, name, None)
+
+            self.param = Parameter(app, "param")
+            self.param.default = "direct"
+            self.add_parameter(self.param)
+
+            option = self.Direct(app, "direct", self.param)
+            self.add_option(option)
+
+            option = self.Topic(app, "topic", self.param)
+            self.add_option(option)
+
+            option = self.Fanout(app, "fanout", self.param)
+            self.add_option(option)
+
+            option = self.Headers(app, "headers", self.param)
+            self.add_option(option)
+
+            option = self.XML(app, "xml", self.param)
+            self.add_option(option)
+
+        def render_title(self, session):
+            return "Exchange Type"
+
+        def render_field_help(self, session):
+            return "(Type of exchange to add)"
+
+        class Direct(RadioFieldOption):
+            def render_value(self, session):
+                return "direct"
+
+            def render_title(self, session):
+                return "<em>Direct:</em> Route messages to queues by queue name"
+
+        class Topic(RadioFieldOption):
+            def render_value(self, session):
+                return "topic"
+
+            def render_title(self, session):
+                return "<em>Topic:</em> Route messages to queues by topic keyword match"
+
+        class Fanout(RadioFieldOption):
+            def render_value(self, session):
+                return "fanout"
+
+            def render_title(self, session):
+                return "<em>Fan Out:</em> Route message to all queues attached to this exchange"
+
+        class Headers(RadioFieldOption):
+            def render_value(self, session):
+                return "headers"
+
+            def render_title(self, session):
+                return "<em>Headers:</em> Route message to queues based on content of the message header"
+
+        class XML(RadioFieldOption):
+            def render_value(self, session):
+                return "xml"
+
+            def render_title(self, session):
+                return "<em>XML:</em> Route message to queues based on XML content of the message"
+
+class ExchangeAdd(ExchangeForm):
+    def process_cancel(self, session):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_submit(self, session):
+        errors = self.validate(session)
+
+        if errors:
+            pass
+        else:
+            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"
+
+            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):
+        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)
+
+        self.add_child(StatSet(app, "io", "io"))
+        self.add_child(StatSet(app, "general", "general"))
+
+        chart = self.ReceiveRouteDropRateChart(app, "recvroutedrop")
+        self.add_child(chart)
+
+        chart = StatValueChart(app, "producers")
+        chart.stats = ("producerCount",)
+        self.add_child(chart)
+
+    def render_title(self, session):
+        return "Statistics"
+
+    class ReceiveRouteDropRateChart(StatValueChart):
+        def __init__(self, app, name):
+            super(ExchangeStats.ReceiveRouteDropRateChart, self).__init__ \
+                (app, name)
+
+            self.stats = ("msgReceives", "msgRoutes", "msgDrops")
+            self.mode = "rate"
+
+        def render_title(self, session, exchange):
+            return "Messages Received, Routed, and Dropped"
+
+class ExchangeProducerSet(ItemSet):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, exchange):
+        return "Producers %s" % \
+            fmt_count(self.get_item_count(session, exchange))
+
+    def get_item_count(self, session, exchange):
+        return exchange.producers.count()
+
+    def do_get_items(self, session, exchange):
+        return exchange.producers
+
+    def render_item_name(self, session, producer):
+        return producer.name
+
+class ExchangeInfo(object):
+    @classmethod
+    def is_builtin(cls, exchange):
+        return exchange.name in ExchangeInfo.get_builtins()
+
+    @classmethod
+    def get_builtins(cls):
+        return ["", "amq.direct", "amq.topic", "amq.match", "amq.fanout", "qpid.management"]


Property changes on: mgmt/trunk/cumin/python/cumin/messaging/exchange.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/messaging/exchange.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/exchange.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/exchange.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/exchange.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,183 @@
+[ExchangeInputSet.item_html]
+<div class="field">
+  <input type="radio" name="{name}" value="{item_value}" tabindex="{tab_index}" {item_checked_attr}/>
+  {item_content}
+</div>
+
+[ExchangeSet.sql]
+select
+  e.id,
+  e.name,
+  c.producer_count as producers,
+  c.binding_count as bindings,
+  (c.msg_receives - p.msg_receives)
+   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as mreceived,
+  case when p.msg_receives is null then true else false end as mreceived_is_null,
+  (c.byte_receives - p.byte_receives)
+   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as breceived,
+  case when p.byte_receives is null then true else false end as breceived_is_null,
+  (c.msg_routes - p.msg_routes)
+   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as mrouted,
+  case when p.msg_routes is null then true else false end as mrouted_is_null,
+  (c.byte_routes - p.byte_routes)
+   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as brouted,
+  case when p.byte_routes is null then true else false end as brouted_is_null,
+  c.msg_drops as mdropped,
+  c.byte_drops as bdropped,
+  c.qmf_update_time
+from exchange as e
+left outer join exchange_stats as c on c.id = e.stats_curr_id
+left outer join exchange_stats as p on p.id = e.stats_prev_id
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+
+[ExchangeSet.count_sql]
+select count(*)
+from exchange as e
+left outer join exchange_stats as c on c.id = e.stats_curr_id
+{sql_where}
+
+[ExchangeSet.css]
+ul.ExchangeSet li:before {
+  content: url(resource?name=exchange-20.png);
+  vertical-align: -30%;
+  padding: 0 0.25em;
+}
+
+[ExchangeSet.html]
+<form id="{id}" method="post" action="?">
+  <ul class="actions">
+    <li><a class="nav" href="{add_exchange_url}">Add New Exchange</a></li>
+  </ul>
+
+  <div class="rfloat">{phase}</div>
+  {unit}
+
+    <div class="sactions">
+      <h2>Act on Selected Exchanges:</h2>
+      {remove}
+    </div>
+
+    <table class="mobjects">
+      <thead>
+        <tr>
+          <th class="setnav" colspan="{column_count}">
+            <div class="rfloat">{page}</div>
+            {count}
+          </th>
+        </tr>
+        <tr>{headers}</tr>
+      </thead>
+      <tbody>{items}</tbody>
+    </table>
+
+  <div>{hidden_inputs}</div>
+</form>
+
+[ExchangeSet.item_html]
+<tr>{cells}</tr>
+
+[ExchangeStatus.html]
+<div id="{id}" class="CuminStatus {color}">
+  <table>
+    <tr>
+      <th></th>
+      <th style="width: 35%;" class="ralign">Messages</th>
+      <th style="width: 35%;" class="ralign">Bytes</th>
+    </tr>
+    <tr>
+      <th>Received</th>
+      <td class="ralign">{messages_received}</td>
+      <td class="ralign">{bytes_received}</td>
+    </tr>
+    <tr>
+      <th>Routed</th>
+      <td class="ralign">{messages_routed}</td>
+      <td class="ralign">{bytes_routed}</td>
+    </tr>
+    <tr>
+      <th>Dropped</th>
+      <td class="ralign">{messages_dropped}</td>
+      <td class="ralign">{bytes_dropped}</td>
+    </tr>
+  </table>
+</div>
+
+[ExchangeBindingSet.html]
+<form id="{id}" method="post" action="?">
+
+  <div class="rfloat">{phase}</div>
+  <ul class="radiotabs"><li>&nbsp;</li></ul>
+
+  <div class="sactions">
+    <h2>Act on Selected Bindings:</h2>
+    {remove}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+        <th class="setnav" colspan="{column_count}">
+          <div class="rfloat">{page}</div>
+          {count}
+        </th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>
+
+[ExchangeBindingSet.item_html]
+<tr>{cells}</tr>
+
+[ExchangeStats.html]
+<table class="twocol">
+  <tbody>
+  <tr>
+    <td>
+      <h2>Input/Output</h2>
+      {io}
+
+      <h2>General</h2>
+      {general}
+    </td>
+    <td>
+      {recvroutedrop}
+      {producers}
+    </td>
+  </tr>
+  </tbody>
+</table>
+
+[ExchangeProducerSet.html]
+<div class="sactions">
+  <h2>Act on Selected Producers:</h2>
+  <button>Start</button>
+  <button>Stop</button>
+  <button>Throttle</button>
+</div>
+
+<table class="mobjects">
+  <tr>
+    <th><input type="checkbox"/></th>
+    <th>Name</th>
+    <th class="ralign" colspan="2">Msgs. Produced</th>
+    <th class="ralign" colspan="2">Bytes Produced</th>
+  </tr>
+
+  {items}
+</table>
+
+[ExchangeProducerSet.item_html]
+<tr>
+  <td><input type="checkbox"/></td>
+  <td>{item_name}</td>
+  <td class="ralign">{item_messages_produced_rate}</td>
+  <td class="ralign">{item_messages_produced}</td>
+  <td class="ralign">{item_bytes_produced_rate}</td>
+  <td class="ralign">{item_bytes_produced}</td>
+</tr>


Property changes on: mgmt/trunk/cumin/python/cumin/messaging/exchange.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Added: mgmt/trunk/cumin/python/cumin/messaging/main.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/main.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/main.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,55 @@
+from wooly import *
+from wooly.widgets import *
+from wooly.resources import *
+from cumin.widgets import *
+from cumin.util import *
+
+from broker import *
+from brokergroup import *
+
+strings = StringCatalog(__file__)
+
+class MessagingFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(MessagingFrame, self).__init__(app, name)
+
+        self.view = MessagingView(app, "view")
+        self.add_mode(self.view)
+
+        self.broker = BrokerFrame(app, "broker")
+        self.add_mode(self.broker)
+
+        self.broker_group = BrokerGroupFrame(app, "group")
+        self.add_mode(self.broker_group)
+
+        self.brokers_group = BrokerSetEngroup(app, "brokersengroup")
+        self.add_mode(self.brokers_group)
+
+        action = self.app.model.broker_group.remove_set
+        item = BrokerGroupParameter(app, "item")
+        self.broker_groups_remove = CuminSetActionForm \
+            (app, "groupsremove", action, item)
+        self.add_mode(self.broker_groups_remove)
+
+    def render_title(self, session):
+        return "Messaging"
+
+class MessagingView(Widget):
+    def __init__(self, app, name):
+        super(MessagingView, self).__init__(app, name)
+
+        heading = self.Heading(app, "heading")
+        self.add_child(heading)
+
+        self.tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.tabs)
+
+        self.tabs.add_tab(BrokerBrowser(app, "brokers"))
+        self.tabs.add_tab(BrokerGroupSet(app, "groups"))
+
+    class Heading(CuminHeading):
+        def render_title(self, session):
+            return "Messaging"
+
+        def render_icon_href(self, session):
+            return "resource?name=broker-36.png"

Added: mgmt/trunk/cumin/python/cumin/messaging/main.strings
===================================================================

Copied: mgmt/trunk/cumin/python/cumin/messaging/queue.py (from rev 3256, mgmt/trunk/cumin/python/cumin/queue.py)
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/queue.py	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/queue.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,1086 @@
+import logging
+
+from mint import Queue, Journal, Exchange
+from wooly import *
+from wooly.widgets import *
+from wooly.forms import *
+from wooly.resources import *
+from wooly.tables import *
+from datetime import datetime
+from sqlobject.sqlbuilder import LEFTJOINOn
+from cumin.stat import *
+from cumin.widgets import *
+from cumin.parameters import *
+from cumin.formats import *
+from cumin.util import *
+
+from binding import *
+from exchange import ExchangeInputSet
+
+strings = StringCatalog(__file__)
+log = logging.getLogger("cumin.messaging.queue")
+
+class QueueSet(CuminTable, Form):
+    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)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+
+        self.set_default_column(col)
+
+        col = self.ConsumersColumn(app, "consumers")
+        col.alignment = "right"
+        self.add_column(col)
+
+        col = self.BindingsColumn(app, "bindings")
+        col.alignment = "right"
+        self.add_column(col)
+
+        col = self.EnqueuedColumn(app, "enqueued")
+        col.alignment = "right"
+        self.add_column(col)
+
+        col = self.DequeuedColumn(app, "dequeued")
+        col.alignment = "right"
+        self.add_column(col)
+
+        col = self.DepthColumn(app, "depth")
+        col.alignment = "right"
+        self.add_column(col)
+
+        self.unit = UnitSwitch(app, "unit")
+        self.add_child(self.unit)
+
+        self.phase = PhaseSwitch(app, "phase")
+        self.add_child(self.phase)
+
+        self.__purge = self.Purge(app, "purge")
+        self.add_child(self.__purge)
+
+        self.__remove = self.Remove(app, "remove")
+        self.add_child(self.__remove)
+
+    def render_add_queue_url(self, session):
+        branch = session.branch()
+        self.frame.queue_add.show(branch)
+        return branch.marshal()
+
+    def render_title(self, session):
+        return "Queues %s" % fmt_count(Queue.select().count())
+
+    def render_sql_where(self, session):
+        vhost = self.vhost.get(session)
+
+        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):
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            branch = session.branch()
+            self.frame.queues_purge.show(branch).ids.set(branch, ids)
+            self.page.set_redirect_url(session, branch.marshal())
+
+        def render_content(self, session):
+            return "Purge"
+
+    class Remove(FormButton):
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            branch = session.branch()
+            self.frame.queues_remove.show(branch).ids.set(branch, ids)
+            self.page.set_redirect_url(session, branch.marshal())
+
+        def render_content(self, session):
+            return "Remove"
+
+    class NameColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+        def render_content(self, session, data):
+            queue = Identifiable(data["id"])
+            href = self.page.main.messaging.broker.queue.get_href \
+                (session, queue)
+            return fmt_link(href, fmt_shorten(data["name"]))
+
+    class ConsumersColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Consumers"
+
+        def render_value(self, session, value):
+            if value is None:
+                return fmt_none_brief()
+            else:
+                return value
+
+    class BindingsColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "Bindings"
+
+        def render_content(self, session, data):
+            queue = Identifiable(data["id"])
+            branch = session.branch()
+            self.frame.queue.object.set(branch, queue)
+            self.frame.queue.view.bindings.show(branch)
+            return fmt_link(branch.marshal(), data["bindings"] or "0")
+
+    class EnqueuedColumn(NullSortColumn, FreshDataOnlyColumn):
+        def render_title(self, session, data):
+            return "%s Enqueued" % self.parent.unit.get_brief_plural(session)
+
+        def get_column_key(self, session):
+            unit = self.parent.unit.get(session)
+            return unit == "b" and "benqueued" or "menqueued"
+
+        def render_value(self, session, value):
+            return fmt_rate(value, "", "sec")
+
+    class DequeuedColumn(NullSortColumn, FreshDataOnlyColumn):
+        def render_title(self, session, data):
+            return "%s Dequeued" % self.parent.unit.get_brief_plural(session)
+
+        def get_column_key(self, session):
+            unit = self.parent.unit.get(session)
+            return unit == "b" and "bdequeued" or "mdequeued"
+
+        def render_value(self, session, value):
+            return fmt_rate(value, "", "sec")
+
+    class DepthColumn(SqlTableColumn):
+        def render_title(self, session, data):
+            return "%s Depth" % self.parent.unit.get_brief_singular(session)
+
+        def get_column_key(self, session):
+            unit = self.parent.unit.get(session)
+            return unit == "b" and "bdepth" or "mdepth"
+
+        def render_value(self, session, value):
+            if value is None:
+                return fmt_none_brief()
+            else:
+                return value
+
+class TopQueueSet(TopTable):
+    def __init__(self, app, name):
+        super(TopQueueSet, self).__init__(app, name)
+
+        col = self.NameColumn(app, "name")
+        self.add_column(col)
+
+        self.set_default_column(col)
+
+        col = self.EnqueuesColumn(app, "enqueues")
+        col.alignment = "right"
+        self.add_column(col)
+
+    class NameColumn(TopTableColumn):
+        def render_title(self, session, data):
+            return "Name"
+
+        def render_content(self, session, data):
+            broker = Identifiable(data["broker_id"])
+            queue = Identifiable(data["id"])
+
+            big = self.parent.get_fullpage(session)
+            branch = session.branch()
+            self.page.main.messaging.broker.object.set(branch, broker)
+            self.page.main.messaging.broker.queue.object.set(branch, queue)
+            self.page.main.messaging.broker.queue.show(branch)
+            name = big and data["name"] or fmt_shorten(data["name"])
+            return fmt_link(branch.marshal(), name)
+
+    class EnqueuesColumn(TopTableColumn):
+        def render_title(self, session, data):
+            return "Recent Enqueues"
+
+class QueueFrame(CuminFrame):
+    def __init__(self, app, name):
+        super(QueueFrame, self).__init__(app, name)
+
+        self.object = QueueParameter(app, "id")
+        self.add_parameter(self.object)
+
+        self.view = QueueView(app, "view")
+        self.add_mode(self.view)
+
+        self.purge = QueuePurge(app, "purge")
+        self.add_mode(self.purge)
+
+        self.binding_add = QueueBindingAdd(app, "bindingadd", self.object)
+        self.add_mode(self.binding_add)
+
+        self.remove = QueueRemove(app, "remove")
+        self.add_mode(self.remove)
+
+        self.move_messages = QueueMoveMessages(app, "move_messages")
+        self.add_mode(self.move_messages)
+
+    def show_object(self, session, queue):
+        #XXX self.page.main.messaging.broker.object.set(session, queue.vhost.broker)
+        return super(QueueFrame, self).show_object(session, queue)
+
+    def render_href(self, session, queue):
+        if queue:
+            return super(QueueFrame, self).render_href(session, queue)
+
+    def render_title(self, session, queue):
+        if queue:
+            return super(QueueFrame, self).render_title(session, queue)
+        else:
+            return "Queue"
+
+class QueueStatus(CuminStatus):
+    def render_consumers(self, session, queue):
+        return self.app.model.queue.consumers.value(queue)
+
+    def render_messages_enqueued(self, session, queue):
+        return self.app.model.queue.msgTotalEnqueues.rate_html(queue)
+
+    def render_messages_dequeued(self, session, queue):
+        return self.app.model.queue.msgTotalDequeues.rate_html(queue)
+
+    def render_message_depth(self, session, queue):
+        return self.app.model.queue.msgDepth.value(queue)
+
+    def render_message_depth_accel(self, session, queue):
+        return self.app.model.queue.msgDepth.rate_html(queue)
+
+    def render_bytes_enqueued(self, session, queue):
+        return self.app.model.queue.byteTotalEnqueues.rate_html(queue)
+
+    def render_bytes_dequeued(self, session, queue):
+        return self.app.model.queue.byteTotalDequeues.rate_html(queue)
+
+    def render_byte_depth(self, session, queue):
+        return self.app.model.queue.byteDepth.value(queue)
+
+    def render_byte_depth_accel(self, session, queue):
+        return self.app.model.queue.byteDepth.rate_html(queue)
+
+class QueueView(CuminView):
+    def __init__(self, app, name):
+        super(QueueView, self).__init__(app, name)
+
+        status = QueueStatus(app, "status")
+        self.add_child(status)
+
+        self.__tabs = TabbedModeSet(app, "tabs")
+        self.add_child(self.__tabs)
+
+        self.__tabs.add_tab(QueueStats(app, "stats"))
+
+        self.bindings = QueueBindingSet(app, "bindings")
+        self.__tabs.add_tab(self.bindings)
+
+        self.details = CuminDetails(app, "details")
+        self.__tabs.add_tab(self.details)
+
+    def show_bindings(self, session):
+        self.bindings.show(session);
+
+class QueueBindingSet(BindingSet, Form):
+    def __init__(self, app, name):
+        super(QueueBindingSet, self).__init__(app, name)
+
+        self.__remove = self.Remove(app, "remove")
+        self.add_child(self.__remove)
+
+        self.set_default_column_name("e_id")
+
+    def get_visible_columns(self, session):
+        return self.get_request_visible_columns(session, ["e_id"])
+
+    def render_add_queue_binding_url(self, session, *args):
+        branch = session.branch()
+        self.frame.binding_add.show(branch)
+        return branch.marshal()
+
+    def render_sql_where(self, session, queue):
+        elems = list()
+        elems.append("b.queue_id = %(id)r")
+        elems.append(self.phase.get_sql_constraint(session, queue))
+        return "where %s" % " and ".join(elems)
+
+    def render_title(self, session, queue):
+        return "Exchange Bindings %s" % \
+            fmt_count(queue.bindings.count())
+
+    class Remove(FormButton):
+        def process_submit(self, session):
+            ids = self.parent.ids.get(session)
+            self.parent.ids.clear(session)
+
+            href = self.frame.frame.bindings_remove.get_href \
+                (session, ids)
+            self.page.set_redirect_url(session, href)
+
+        def render_content(self, session):
+            return "Remove"
+
+class QueueForm(CuminFieldForm):
+    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)
+
+        self.more = MoreFieldSet(app, "more")
+        self.add_field(self.more)
+
+        self.durable = self.QueueDurabilityField(app, "durable")
+        self.more.add_field(self.durable)
+
+        self.cluster_durable = self.ClusterDurabilityField(app, "cluster_durable")
+        self.more.add_field(self.cluster_durable)
+
+        self.lvq = self.LVQField(app, "lvq")
+        self.more.add_field(self.lvq)
+
+        self.optimistic = self.OptimisticField(app, "optimistic")
+        self.more.add_field(self.optimistic)
+
+        self.file_count = self.FileCountField(app, "file_count")
+        self.file_count.input.param.default = 8
+        self.more.add_field(self.file_count)
+
+        self.file_size = self.FileSizeField(app, "file_size")
+        self.file_size.input.param.default = 24
+        self.more.add_field(self.file_size)
+
+        self.policy = self.PolicyField(app, "policy")
+        self.more.add_field(self.policy)
+
+        self.q_size = self.QSizeField(app, "q_size")
+        self.more.add_field(self.q_size)
+
+        self.q_count = self.QCountField(app, "q_count")
+        self.more.add_field(self.q_count)
+
+        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>"
+
+        def render_field_help(self, session):
+            return "(Maximum in-memory queue size as a number of messages. Applies if Policy is set.)"
+
+    class QSizeField(IntegerField):
+        def render_title(self, session):
+            return "<div style=\"padding-left: 1em;\">Max Queue Size</div>"
+
+        def render_field_help(self, session):
+            return "(Maximum in-memory queue size as bytes. Applies if Policy is set.)"
+
+    class FileCountField(IntegerField):
+        def render_title(self, session):
+            return "File Count"
+
+        def render_field_help(self, session):
+            return "(Number of files in queue's persistence journal)"
+
+    class FileSizeField(IntegerField):
+        def render_title(self, session):
+            return "File Size"
+
+        def render_field_help(self, session):
+            return "(File size in pages - 64Kb/page)"
+
+    class QueueDurabilityField(TwoOptionRadioField):
+        def render_title(self, session):
+            return "Durable?"
+
+        def render_field_help(self, session):
+            return "(Queue is durable)"
+
+        def render_title_1(self, session):
+            return "Durable"
+
+        def render_title_2(self, session):
+            return "Transient"
+
+    class ClusterDurabilityField(TwoOptionRadioField):
+        def render_title(self, session):
+            return "Cluster Durable?"
+
+        def render_field_help(self, session):
+            return "(Queue becomes durable if there is only one functioning cluster node)"
+
+        def render_title_1(self, session):
+            return "Cluster Durable"
+
+        def render_title_2(self, session):
+            return "Not Cluster Durable"
+
+    class LVQField(TwoOptionRadioField):
+        def render_title(self, session):
+            return "Enable Last Value Queue?"
+
+        def render_field_help(self, session):
+            return "(Enable LVQ behavior on the queue)"
+
+        def render_title_1(self, session):
+            return "Enabled"
+
+        def render_title_2(self, session):
+            return "Not Enabled"
+
+    class OptimisticField(TwoOptionRadioField):
+        def render_title(self, session):
+            return "Enable Optimistic Consume?"
+
+        def render_field_help(self, session):
+            return "(Enable optimistic consume on the queue)"
+
+        def render_title_1(self, session):
+            return "Enabled"
+
+        def render_title_2(self, session):
+            return "Not Enabled"
+
+    class PolicyField(RadioField):
+        def __init__(self, app, name):
+            super(QueueForm.PolicyField, self).__init__(app, name, None)
+
+            self.param = Parameter(app, "param")
+            self.param.default = "none"
+            self.add_parameter(self.param)
+
+            option = self.NoneField(app, "none", self.param)
+            self.add_option(option)
+
+            option = self.Reject(app, "reject", self.param)
+            self.add_option(option)
+
+            option = self.Flow(app, "flow", self.param)
+            self.add_option(option)
+
+            option = self.Ring(app, "ring", self.param)
+            self.add_option(option)
+
+            option = self.RingStrict(app, "ring_strict", self.param)
+            self.add_option(option)
+
+        def render_title(self, session):
+            return "Policy-type"
+
+        def render_field_help(self, session):
+            return "(Action taken when queue limit is reached)"
+
+        class NoneField(RadioFieldOption):
+            def render_value(self, session):
+                return "none"
+
+            def render_title(self, session):
+                return "None"
+
+        class Reject(RadioFieldOption):
+            def render_value(self, session):
+                return "reject"
+
+            def render_title(self, session):
+                return "Reject"
+
+        class Flow(RadioFieldOption):
+            def render_value(self, session):
+                return "flow"
+
+            def render_title(self, session):
+                return "Flow to disc"
+
+        class Ring(RadioFieldOption):
+            def render_value(self, session):
+                return "ring"
+
+            def render_title(self, session):
+                return "Ring"
+
+        class RingStrict(RadioFieldOption):
+            def render_value(self, session):
+                return "ring_strict"
+
+            def render_title(self, session):
+                return "Ring Strict"
+
+class QueueAdd(QueueForm):
+    def __init__(self, app, name, vhost):
+        super(QueueAdd, self).__init__(app, name, vhost)
+
+    def process_cancel(self, session):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    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, binding_info = self.validate(session, name)
+
+        if not errors:
+            action = self.app.model.broker.add_queue
+            invoc = action.begin(vhost)
+
+            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):
+        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):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, queue):
+        return "Remove Queue '%s'" % queue.name
+
+    def process_submit(self, session, queue):
+        action = self.app.model.queue.remove
+        action.invoke(queue)
+
+        self.process_cancel(session, queue)
+
+    def render_submit_content(self, session, queue):
+        return "Yes, Remove Queue '%s'" % queue.name
+
+    def render_cancel_content(self, session, queue):
+        return "No, Cancel"
+
+class QueuePurge(CuminFieldForm):
+    def __init__(self, app, name):
+        super(QueuePurge, self).__init__(app, name)
+
+        self.purge_request = MultiplicityField(app, "purge_request")
+        self.add_field(self.purge_request)
+
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, queue):
+        return "Purge Messages from  Queue '%s'" % queue.name
+
+    def process_submit(self, session, queue):
+        request_amt = self.purge_request.get(session)
+        args = dict()
+
+        if request_amt == "all":
+            args["request"] = 0
+        elif request_amt == "top":
+            args["request"] = 1
+        elif request_amt == "N":
+            args["request"] = self.purge_request.top_n.get_n_value(session)
+        else:
+            raise Exception("Wrong Value")
+
+        action = self.app.model.queue.purge
+        action.invoke(queue, args)
+
+        self.process_cancel(session, queue)
+
+    def render_submit_content(self, session, queue):
+        return "Yes, Purge Messages from Queue '%s'" % queue.name
+
+    def render_cancel_content(self, session, queue):
+        return "No, Cancel"
+
+class QueueSetPurge(CuminBulkActionForm):
+    def process_return(self, session):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_item(self, session, id):
+        queue = Queue.get(id)
+
+        args = dict()
+        args["request"] = 0
+
+        action = self.app.model.queue.purge
+        action.invoke(queue, args)
+
+    def render_title(self, session):
+        return "Purge Queues"
+
+    def render_item_content(self, session, id):
+        return "Purge Queue '%s'" % Queue.get(id).name
+
+
+class QueueSetRemove(CuminBulkActionForm):
+    def process_return(self, session):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    def process_item(self, session, id):
+        queue = Queue.get(id)
+        action = self.app.model.queue.remove
+        action.invoke(queue)
+
+    def render_title(self, session):
+        return "Remove Queues"
+
+    def render_item_content(self, session, id):
+        return "Remove Queue '%s'" % Queue.get(id).name
+
+class BindSummaryPropertiesField(FormField):
+    def __init__(self, app, name):
+        super(BindSummaryPropertiesField, self).__init__(app, name)
+
+        self.sum_props = self.SummaryProperties(app, "properties")
+        self.add_child(self.sum_props)
+
+        self.prop_tmpl = Template(self, "properties_html")
+
+    class SummaryProperties(CuminProperties):
+        def do_get_items(self, session, queue):
+            return [("Name", queue.name),
+                    ("Durable", queue.durable),
+                    ("Exclusive", queue.exclusive),
+                    ("Auto-Delete", queue.autoDelete)]
+
+    def render_inputs(self, session, *args):
+        writer = Writer()
+        self.prop_tmpl.render(writer, session, args)
+        return writer.to_string()
+
+    def render_prop_items(self, session, args):
+        return self.sum_props.render_items(session, *args)
+
+    def get_args(self, session):
+        return (self.frame.frame.get_object(session),)
+
+class QueueBindingAdd(CuminFieldForm):
+    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", self.vhost,
+                                          title="Bind to Exchange:")
+        self.add_field(self.bindings)
+
+        self.errors = self.Errors(self, "errors")
+        self.add_attribute(self.errors)
+
+    class VhostAttribute(Attribute):
+        def get_default(self, session):
+            return self.widget.queue.get(session).vhost
+
+    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):
+        branch = session.branch()
+        self.frame.view.show(branch)
+        self.page.set_redirect_url(session, branch.marshal())
+
+    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):
+            # no exhchanges were selected is not an
+            # error that ExchangeKeysField looks for
+            errors = self.errors.get(session)
+            errs = errors.setdefault("no_exchanges", list())
+            errs.append("At least one exchange must be selected")
+            errors = True
+
+        if errors:
+            pass
+        else:
+            reg = self.frame.frame.get_object(session)
+            args = {
+                    "exchange_keys": form_binding_info,
+                    "reg": reg}
+
+            action = self.app.model.queue.bind
+            action.invoke(queue, args)
+
+            # navigate back to main queue frame
+            self.process_cancel(session)
+
+    def render_title(self, session, *args):
+        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):
+            return dict()
+
+class QueueBindingRemove(CuminConfirmForm):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def process_submit(self, session, binding):
+        log.info("Removing binding %s" % binding)
+
+        self.process_cancel(session, binding)
+
+    def render_title(self, session, binding):
+        return "Remove Binding"
+
+    def render_submit_content(self, session, binding):
+        return "Yes, Remove Binding"
+
+    def render_cancel_content(self, session, binding):
+        return "No, Cancel"
+
+class QueueStats(TabbedModeSet):
+    def __init__(self, app, name):
+        super(QueueStats, self).__init__(app, name)
+
+        self.add_tab(QueueStatsGeneral(app, "gen"))
+        self.add_tab(QueueStatsDurability(app, "dur"))
+        self.add_tab(QueueStatsTransactions(app, "txn"))
+
+    def render_title(self, session):
+        return "Statistics"
+
+class QueueStatsGeneral(Widget):
+    def __init__(self, app, name):
+        super(QueueStatsGeneral, self).__init__(app, name)
+
+        self.add_child(StatSet(app, "general", "general"))
+        self.add_child(StatSet(app, "io", "io"))
+
+        chart = self.EnqueueDequeueRateChart(app, "enqdeq")
+        self.add_child(chart)
+
+        chart = self.DepthChart(app, "depth")
+        self.add_child(chart)
+
+        chart = StatValueChart(app, "consumers")
+        chart.stats = ("consumerCount",)
+        self.add_child(chart)
+
+    def render_title(self, session):
+        return "General"
+
+    class EnqueueDequeueRateChart(StatValueChart):
+        def __init__(self, app, name):
+            super(QueueStatsGeneral.EnqueueDequeueRateChart,
+                  self).__init__(app, name)
+
+            self.stats = ("msgTotalEnqueues", "msgTotalDequeues")
+            self.mode = "rate"
+
+        def render_title(self, session, queue):
+            return "Messages Enqueued and Dequeued"
+
+    class DepthChart(StatValueChart):
+        def __init__(self, app, name):
+            super(QueueStatsGeneral.DepthChart, self).__init__(app, name)
+
+            self.stats = ("msgDepth",)
+
+        def render_title(self, session, queue):
+            return "Queue Depth"
+
+class QueueStatsDurability(Widget):
+    def __init__(self, app, name):
+        super(QueueStatsDurability, self).__init__(app, name)
+
+        self.add_child(StatSet(app, "io", "io.durable"))
+        self.add_child(JournalStats(app, "jrnl", "io.journal"))
+
+        chart = self.EnqueueDequeueRateChart(app, "enqdeq")
+        self.add_child(chart)
+
+    def render_title(self, session):
+        return "Durability"
+
+    class EnqueueDequeueRateChart(StatValueChart):
+        def __init__(self, app, name):
+            super(QueueStatsDurability.EnqueueDequeueRateChart,
+                  self).__init__(app, name)
+
+            self.stats = ("msgPersistEnqueues", "msgPersistDequeues")
+            self.mode = "rate"
+
+        def render_title(self, session, queue):
+            return "Durable Messages Enqueued and Dequeued"
+
+class JournalStats(StatSet):
+    def get_args(self, session):
+        queue = self.frame.get_args(session)[0]
+
+        try:
+            jrnl = Journal.selectBy(queue=queue)[0]
+        except IndexError:
+            jrnl = None
+
+        return (jrnl,)
+
+    def render_title(self, session, jrnl):
+        return "Journal"
+
+    def do_render(self, session, jrnl):
+        if jrnl:
+            return super(JournalStats, self).do_render(session, jrnl)
+        else:
+            return "<div class=\"iblock\">%s</div>" % fmt_none()
+
+class QueueStatsTransactions(Widget):
+    def __init__(self, app, name):
+        super(QueueStatsTransactions, self).__init__(app, name)
+
+        self.add_child(StatSet(app, "transactions", "txn"))
+        self.add_child(StatSet(app, "io", "io.txn"))
+
+        chart = self.EnqueueTransactionRateChart(app, "enqtxn")
+        self.add_child(chart)
+
+        chart = self.DequeueTransactionRateChart(app, "deqtxn")
+        self.add_child(chart)
+
+        chart = self.EnqueueDequeueRateChart(app, "enqdeq")
+        self.add_child(chart)
+
+    def render_title(self, session):
+        return "Transactions"
+
+    class EnqueueTransactionRateChart(StatValueChart):
+        def __init__(self, app, name):
+            super(QueueStatsTransactions.EnqueueTransactionRateChart,
+                  self).__init__(app, name)
+
+            self.stats = ("enqueueTxnStarts", "enqueueTxnCommits",
+                          "enqueueTxnRejects")
+            self.mode = "rate"
+
+        def render_title(self, session, queue):
+            return "Enqueue Transaction Operations per Second"
+
+    class DequeueTransactionRateChart(StatValueChart):
+        def __init__(self, app, name):
+            super(QueueStatsTransactions.DequeueTransactionRateChart,
+                  self).__init__(app, name)
+
+            self.stats = ("dequeueTxnStarts", "dequeueTxnCommits",
+                          "dequeueTxnRejects")
+            self.mode = "rate"
+
+        def render_title(self, session, queue):
+            return "Dequeue Transaction Operations per Second"
+
+    class EnqueueDequeueRateChart(StatValueChart):
+        def __init__(self, app, name):
+            super(QueueStatsTransactions.EnqueueDequeueRateChart,
+                  self).__init__(app, name)
+
+            self.stats = ("msgTxnEnqueues", "msgTxnDequeues")
+            self.mode = "rate"
+
+        def render_title(self, session, queue):
+            return "Transactional Messages Enqueued and Dequeued"
+
+class QueueConsumerSet(PaginatedItemSet):
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, queue):
+        count = fmt_count(self.get_item_count(session, queue))
+        return "Consumers %s" % count
+
+    def get_item_count(self, session, queue):
+        return queue.consumers.count()
+
+    def do_get_items(self, session, queue):
+        start, end = self.get_bounds(session)
+        return queue.consumers[start:end]
+
+    def render_item_name(self, session, consumer):
+        return consumer.name
+
+    def render_item_messages_consumed(self, session, consumer):
+        return self.app.model.consumer.msgsConsumed.value(consumer)
+
+    def render_item_messages_consumed_rate(self, session, consumer):
+        return self.app.model.consumer.msgsConsumed.rate_html(consumer)
+
+    def render_item_bytes_consumed(self, session, consumer):
+        return self.app.model.consumer.bytesConsumed.value(consumer)
+
+    def render_item_bytes_consumed_rate(self, session, consumer):
+        return self.app.model.consumer.bytesConsumed.rate_html(consumer)
+
+    def render_item_unacked_messages(self, session, consumer):
+        return self.app.model.consumer.unackedMessages.value(consumer)
+
+
+class QueueSelectField(FormField):
+    def __init__(self, app, name, form):
+        super(QueueSelectField, self).__init__(app, name)
+
+        param = QueueParameter(app, "param")
+        self.param = param
+        self.add_parameter(param)
+
+        self.queue_set = self.QueueInputSet(app, "queue_set", param)
+        self.add_child(self.queue_set)
+
+    def get(self, session):
+        return self.param.get(session)
+
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, queue):
+        return "Select the destination queue"
+
+    def render_inputs(self, session, queue):
+        return self.queue_set.render(session)
+
+    class QueueInputSet(RadioInputSet):
+        def get_args(self, session):
+            return self.frame.get_args(session)
+
+        def do_get_items(self, session, queue):
+            queue_list_full = sorted_by(list(queue.vhost.queues))
+            delta = timedelta(minutes=10)
+            queue_list = []
+            for _queue in queue_list_full:
+                if (_queue.qmfUpdateTime > (datetime.now() - delta)) and (_queue.name != queue.name):
+                    queue_list.append(_queue)
+            return queue_list
+
+        def render_item_value(self, session, queue):
+            return queue.id
+
+        def render_item_content(self, session, queue):
+            return queue.name or "<em>Default</em>"
+
+        def render_item_checked_attr(self, session, queue):
+            return queue is self.param.get(session) and "checked=\"checked\"" or None
+
+class QueueMoveMessages(CuminFieldForm):
+    def __init__(self, app, name):
+        super(QueueMoveMessages, self).__init__(app, name)
+
+        self.move_to = QueueSelectField(app, "move_to", self)
+        self.add_field(self.move_to)
+
+        self.move_qty = MultiplicityField(app, "move_qty")
+        self.add_field(self.move_qty)
+
+    def get_args(self, session):
+        return self.frame.get_args(session)
+
+    def render_title(self, session, queue):
+        return "Move Messages from  Queue '%s'" % queue.name
+
+    def process_submit(self, session, queue):
+        request_qty = self.move_qty.get(session)
+        args = dict()
+        args["destQueue"] = self.move_to.get(session).name
+        args["srcQueue"] = queue.name
+
+        if request_qty == "all":
+            args["qty"] = 0
+        elif request_qty == "top":
+            args["qty"] = 1
+        elif request_qty == "N":
+            args["qty"] = self.move_qty.top_n.get_n_value(session)
+        else:
+            raise Exception("Wrong Value")
+
+        action = self.app.model.queue.move_messages
+        action.invoke(queue, args)
+        self.process_cancel(session, queue)
+
+    def render_submit_content(self, session, queue):
+        return "Yes, Move Messages from Queue '%s'" % queue.name
+
+    def render_cancel_content(self, session, queue):
+        return "No, Cancel"


Property changes on: mgmt/trunk/cumin/python/cumin/messaging/queue.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: mgmt/trunk/cumin/python/cumin/messaging/queue.strings (from rev 3256, mgmt/trunk/cumin/python/cumin/queue.strings)
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/queue.strings	                        (rev 0)
+++ mgmt/trunk/cumin/python/cumin/messaging/queue.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -0,0 +1,254 @@
+[QueueSet.sql]
+select
+  q.id,
+  q.name,
+  c.consumer_count as consumers,
+  c.binding_count as bindings,
+  (c.msg_total_enqueues - p.msg_total_enqueues)
+   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as menqueued,
+  case when p.msg_total_enqueues is null then true else false end as menqueued_is_null,
+  (c.byte_total_enqueues - p.byte_total_enqueues)
+   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as benqueued,
+  case when p.byte_total_enqueues is null then true else false end as benqueued_is_null,
+  (c.msg_total_dequeues - p.msg_total_dequeues)
+   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as mdequeued,
+  case when p.msg_total_dequeues is null then true else false end as mdequeued_is_null,
+  (c.byte_total_dequeues - p.byte_total_dequeues)
+   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as bdequeued,
+  case when p.byte_total_dequeues is null then true else false end as bdequeued_is_null,
+  c.msg_depth as mdepth,
+  c.byte_depth as bdepth,
+  1 as mdepthaccel,
+  1 as bdepthaccel,
+  c.qmf_update_time
+from queue as q
+left outer join queue_stats as c on c.id = q.stats_curr_id
+left outer join queue_stats as p on p.id = q.stats_prev_id
+{sql_where}
+{sql_orderby}
+{sql_limit}
+
+[QueueSet.count_sql]
+select count(*)
+from queue as q
+left outer join queue_stats as c on c.id = q.stats_curr_id
+{sql_where}
+
+[QueueSet.html]
+<form id="{id}" method="post" action="?">
+  <ul class="actions">
+    <li><a class="nav" href="{add_queue_url}">Add New Queue</a></li>
+  </ul>
+  <div class="rfloat">{phase}</div>
+  {unit}
+
+  <div class="sactions">
+    <h2>Act on Selected Queues:</h2>
+    {purge} {remove}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+        <th class="setnav" colspan="{column_count}">
+          <div class="rfloat">{page}</div>
+          {count}
+        </th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>
+
+[TopQueueSet.sql]
+select
+  q.id,
+  q.name,
+  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 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'
+order by enqueues desc
+limit 5
+
+[TopQueueSet.count_sql]
+--
+
+[QueueStatus.html]
+<div id="{id}" class="CuminStatus {color}">
+  <table>
+    <tr>
+      <th></th>
+      <th style="width: 35%;" class="ralign">Messages</th>
+      <th style="width: 35%;" class="ralign">Bytes</th>
+    </tr>
+    <tr>
+      <th>Enqueued</th>
+      <td class="ralign">{messages_enqueued}</td>
+      <td class="ralign">{bytes_enqueued}</td>
+    </tr>
+    <tr>
+      <th>Dequeued</th>
+      <td class="ralign">{messages_dequeued}</td>
+      <td class="ralign">{bytes_dequeued}</td>
+    </tr>
+    <tr>
+      <th>Depth</th>
+      <td class="ralign">{message_depth}</td>
+      <td class="ralign">{byte_depth}</td>
+    </tr>
+  </table>
+</div>
+
+[QueueBindingSet.html]
+<form id="{id}" method="post" action="?">
+  <div class="rfloat">{phase}</div>
+
+  <ul class="actions">
+    <li><a class="nav" href="{add_queue_binding_url}">Add Binding</a></li>
+  </ul>
+
+  <div class="sactions">
+    <h2>Act on Selected Bindings:</h2>
+    {remove}
+  </div>
+
+  <table class="mobjects">
+    <thead>
+      <tr>
+	<th class="setnav" colspan="{column_count}">
+	  <div class="rfloat">{page}</div>
+	  {count}
+	</th>
+      </tr>
+      <tr>{headers}</tr>
+    </thead>
+    <tbody>{items}</tbody>
+  </table>
+  <div>{hidden_inputs}</div>
+</form>
+
+[ExchangeBindingSet.item_html]
+<tr>{cells}</tr>
+
+[QueueStats.html]
+<ul class="radiotabs tabs">{tabs}</ul>
+<div class="radiotabs mode">{content}</div>
+
+[QueueStatsGeneral.html]
+<table class="twocol">
+  <tbody>
+  <tr>
+    <td>
+      <h2>Input/Output</h2>
+      {io}
+
+      <h2>General</h2>
+      {general}
+    </td>
+    <td>
+      {enqdeq}
+      {depth}
+      {consumers}
+    </td>
+  </tr>
+  </tbody>
+</table>
+
+[QueueStatsDurability.html]
+<table class="twocol">
+  <tbody>
+  <tr>
+    <td>
+      <h2>Durable Input/Output</h2>
+      {io}
+
+      <h2>Journal</h2>
+      {jrnl}
+    </td>
+    <td>
+      {enqdeq}
+    </td>
+  </tr>
+  </tbody>
+</table>
+
+[JournalStats.html]
+<table id="{id}" class="StatSet">
+  <thead>
+    <tr>
+      <th style="width: 50%; text-align: left;">Statistic</th>
+      <th style="width: 25%;">Value</th>
+      <th style="width: 25%;">Per Second</th>
+    </tr>
+  </thead>
+  <tbody>
+    {items}
+  </tbody>
+</table>
+
+[QueueStatsTransactions.html]
+<table class="twocol">
+  <tbody>
+  <tr>
+    <td>
+      <h2>Transactions</h2>
+      {transactions}
+
+      <h2>Transactional Input/Output</h2>
+      {io}
+    </td>
+    <td>
+      {enqtxn}
+      {deqtxn}
+      {enqdeq}
+    </td>
+  </tr>
+  </tbody>
+</table>
+
+[QueueConsumerSet.html]
+<div class="sactions">
+  <h2>Act on Selected Consumers:</h2>
+  <button>Start</button>
+  <button>Stop</button>
+  <button>Close</button>
+  <button>Throttle</button>
+</div>
+
+<table class="mobjects">
+  <tr>
+    <th><input type="checkbox"/></th>
+    <th>Name</th>
+    <th class="ralign" colspan="2">Msgs. Consumed</th>
+    <th class="ralign" colspan="2">Bytes Consumed</th>
+    <th class="ralign">Msgs. Unacked</th>
+  </tr>
+
+  {items}
+</table>
+
+[QueueConsumerSet.item_html]
+<tr>
+  <td><input type="checkbox"/></td>
+  <td>{item_name}</td>
+  <td class="ralign">{item_messages_consumed_rate}</td>
+  <td class="ralign">{item_messages_consumed}</td>
+  <td class="ralign">{item_bytes_consumed_rate}</td>
+  <td class="ralign">{item_bytes_consumed}</td>
+  <td class="ralign">{item_unacked_messages}</td>
+</tr>
+
+[BindSummaryPropertiesField.properties_html]
+<div class="properties" style="width:80%">
+  <table class="PropertySet">
+    <tbody>
+      {prop_items}
+    </tbody>
+  </table>
+</div>


Property changes on: mgmt/trunk/cumin/python/cumin/messaging/queue.strings
___________________________________________________________________
Name: svn:mergeinfo
   + 

Modified: mgmt/trunk/cumin/python/cumin/model.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/model.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/model.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -7,13 +7,12 @@
 from wooly.parameters import *
 from wooly.widgets import *
 
+from grid.job import *
+from grid.pool import PoolSlotSet, PoolJobStats
+from grid.slot import SlotStatSet
+from inventory.system import SystemSlotSet
 from formats import *
-from job import *
 from parameters import *
-from pool import PoolSlotSet, PoolJobStats
-from slot import SlotStatSet
-from system import SystemSlotSet
-from time import *
 from util import *
 
 log = logging.getLogger("cumin.model")
@@ -526,7 +525,7 @@
 
     def get_object_href(self, session, object):
         branch = session.branch()
-        self.show_object(branch, object).show_view(branch)
+        self.show_object(branch, object)
         return branch.marshal()
 
     def get_object_href_by_id(self, session, id):
@@ -682,7 +681,7 @@
         #action.summary = True
 
     def init(self):
-        self.frame = self.model.frame.system
+        self.frame = self.model.frame.inventory.system
 
     def get_title(self, session):
         return "System"
@@ -731,7 +730,7 @@
         return "resource?name=system-36.png"
 
     def show_object(self, session, system):
-        return self.model.frame.system.show_object(session, system)
+        return self.model.frame.inventory.system.show_object(session, system)
 
     def get_object_name(self, object):
         return object.Name
@@ -801,7 +800,7 @@
         action.summary = True
 
     def init(self):
-        self.frame = self.model.frame.broker
+        self.frame = self.model.frame.messaging.broker
 
     def get_icon_href(self, session):
         return "resource?name=broker-36.png"
@@ -838,7 +837,7 @@
 
     class EngroupSet(CuminSetAction):
         def show(self, session, brokers):
-            frame = self.model.frame.brokers_group
+            frame = self.model.frame.messaging.brokers_group
             frame.objects.set(session, brokers)
             return frame.show(session)
 
@@ -1117,7 +1116,7 @@
         action.summary = True
 
     def init(self):
-        self.frame = self.model.frame.broker.queue
+        self.frame = self.model.frame.messaging.broker.queue
 
         action = self.MoveMessages(self, "move_messages")
         action.summary = True
@@ -1130,7 +1129,7 @@
 
     class Purge(CuminAction):
         def show(self, session, queue):
-            frame = self.model.frame.broker
+            frame = self.model.frame.messaging.broker
             frame.queue.set_object(session, queue)
             return frame.queue.purge.show(session)
 
@@ -1142,7 +1141,7 @@
 
     class Remove(CuminAction):
         def show(self, session, queue):
-            frame = self.model.frame.broker
+            frame = self.model.frame.messaging.broker
             frame.queue.set_object(session, queue)
             return frame.queue.remove.show(session)
 
@@ -1157,7 +1156,7 @@
 
     class Bind(CuminAction):
         def show(self, session, queue):
-            frame = self.model.frame.broker
+            frame = self.model.frame.messaging.broker
             frame.queue.set_object(session, queue)
             return frame.queue.binding_add.show(session)
 
@@ -1250,7 +1249,7 @@
         action.summary = True
 
     def init(self):
-        self.frame = self.model.frame.broker.exchange
+        self.frame = self.model.frame.messaging.broker.exchange
 
     def get_title(self, session):
         return "Exchange"
@@ -1408,7 +1407,7 @@
         action.summary = True
 
     def init(self):
-        self.frame = self.model.frame.broker.connection
+        self.frame = self.model.frame.messaging.broker.connection
 
     def get_title(self, session):
         return "Connection"
@@ -1556,7 +1555,7 @@
         action.summary = True
 
     def init(self):
-        self.frame = self.model.frame.broker.link
+        self.frame = self.model.frame.messaging.broker.link
 
     def get_title(self, session):
         return "Broker Link"
@@ -1745,7 +1744,7 @@
         action = self.RemoveSet(self, "remove_set")
 
     def init(self):
-        self.frame = self.model.frame.broker
+        self.frame = self.model.frame.messaging.broker # XXX
 
     def get_title(self, session):
         return "Management Server"
@@ -1758,7 +1757,7 @@
             return "Add Management Servers"
 
         def show(self, session, object):
-            frame = self.model.frame.mservers_add
+            frame = self.model.frame.home.mservers_add
             frame.show(session)
 
         def do_invoke(self, object, args, completion):
@@ -1777,7 +1776,7 @@
             return "Remove"
 
         def show(self, session, objects):
-            frame = self.model.frame.mservers_remove
+            frame = self.model.frame.home.mservers_remove
             frame.objects.set(session, objects)
             return frame.show(session)
 
@@ -1809,7 +1808,7 @@
         action.title = "Remove"
 
     def init(self):
-        self.frame = self.model.frame.broker_group
+        self.frame = self.model.frame.messaging.broker_group
 
     def get_title(self, session):
         return "Broker Group"
@@ -1820,7 +1819,7 @@
     class Add(CuminAction):
         def show(self, session, object):
             frame = self.cumin_class.show_object(session, object)
-            return frame.show_add(session)
+            return frame.add.show(session)
 
         def do_invoke(self, object, args, completion):
             assert object is None
@@ -1850,7 +1849,7 @@
 
     class Remove(CuminAction):
         def show(self, session, object):
-            frame = self.model.frame.broker_group
+            frame = self.model.frame.messaging.broker_group
             frame.object.set(session, object)
             return frame.remove.show(session)
 
@@ -1864,7 +1863,7 @@
 
     class RemoveSet(CuminSetAction):
         def show(self, session, groups):
-            frame = self.model.frame.broker_groups_remove
+            frame = self.model.frame.messaging.broker_groups_remove
             frame.objects.set(session, groups)
             return frame.show(session)
 
@@ -1937,7 +1936,7 @@
         self.status.navigable = False
 
     def init(self):
-        self.frame = self.model.frame.pool
+        self.frame = self.model.frame.grid.pool
 
     def get_title(self, session):
         return "Pool"
@@ -1951,7 +1950,7 @@
         return title
 
     def get_icon_href(self, session):
-        return "resource?name=cluster-36.png"
+        return "resource?name=pool-36.png"
 
     class SeeAllPools(CuminAction):
         def get_title(self, session):
@@ -1959,7 +1958,7 @@
 
         def get_href(self, session, object):
             branch = session.branch()
-            self.model.frame.view.show(branch)
+            self.model.frame.grid.view.show(branch)
             return branch.marshal()
 
     def write_stat_xml(self, session, writer, object):
@@ -2093,7 +2092,7 @@
         action.title = "Set Limit"
 
     def init(self):
-        self.frame = self.model.frame.pool.limit
+        self.frame = self.model.frame.grid.pool.limit
 
     def get_title(self, session):
         return "Concurrency Limit"
@@ -2155,7 +2154,7 @@
         action.summary = True
 
     def init(self):
-        self.frame = self.model.frame.pool.job_group
+        self.frame = self.model.frame.grid.pool.job_group
 
     def get_object_title(self, session, group):
         title = self.get_title(session)
@@ -2170,19 +2169,19 @@
 
     class Hold(CuminAction):
         def show(self, session, group):
-            frame = self.model.frame.pool.job_group_hold.show(session)
+            frame = self.model.frame.grid.pool.job_group_hold.show(session)
             frame.ids.set(session, [group.id])
             return frame
 
     class Release(CuminAction):
         def show(self, session, group):
-            frame = self.model.frame.pool.job_group_release.show(session)
+            frame = self.model.frame.grid.pool.job_group_release.show(session)
             frame.ids.set(session, [group.id])
             return frame
 
     class Remove(CuminAction):
         def show(self, session, group):
-            frame = self.model.frame.pool.job_group_remove.show(session)
+            frame = self.model.frame.grid.pool.job_group_remove.show(session)
             frame.ids.set(session, [group.id])
             return frame
 
@@ -2377,7 +2376,7 @@
         action.navigable = False
 
     def init(self):
-        self.frame = self.model.frame.pool.job
+        self.frame = self.model.frame.grid.pool.job
 
     def get_title(self, session):
         return "Job"
@@ -2395,20 +2394,22 @@
     class GroupProperty(CuminProperty):
         def value(self, session, job):
             group = JobGroup(job.CustomGroup)
-            href = self.model.frame.pool.job_group.get_href(session, group)
+            href = self.model.frame.grid.pool.job_group.get_href \
+                (session, group)
             content = fmt_shorten(group.id, 12, 3)
             return fmt_link(href, group.get_id())
 
     class SubmitterProperty(CuminProperty):
         def value(self, session, job):
             sub = job.submitter
-            href = self.model.frame.pool.submitter.get_href(session, sub)
+            href = self.model.frame.grid.pool.submitter.get_href(session, sub)
             return fmt_link(href, sub.Name)
 
     class SchedulerProperty(CuminProperty):
         def value(self, session, job):
             sched = job.scheduler
-            href = self.model.frame.pool.scheduler.get_href(session, sched)
+            href = self.model.frame.grid.pool.scheduler.get_href \
+                (session, sched)
             return fmt_link(href, sched.Name)
 
     class GetAd(CuminAction):
@@ -2476,7 +2477,7 @@
 
     class Hold(CuminAction):
         def show(self, session, job):
-            frame = self.model.frame.pool.jobs_hold.show(session)
+            frame = self.model.frame.grid.pool.jobs_hold.show(session)
             frame.ids.set(session, [job.id])
             return frame
 
@@ -2493,7 +2494,7 @@
 
     class Release(CuminAction):
         def show(self, session, job):
-            frame = self.model.frame.pool.jobs_release.show(session)
+            frame = self.model.frame.grid.pool.jobs_release.show(session)
             frame.ids.set(session, [job.id])
             return frame
 
@@ -2510,7 +2511,7 @@
 
     class Remove(CuminAction):
         def show(self, session, job):
-            frame = self.model.frame.pool.jobs_remove.show(session)
+            frame = self.model.frame.grid.pool.jobs_remove.show(session)
             frame.ids.set(session, [job.id])
             return frame
 
@@ -2601,7 +2602,7 @@
         action.navigable = False
 
     def init(self):
-        self.frame = self.model.frame.pool.scheduler
+        self.frame = self.model.frame.grid.pool.scheduler
 
     def get_title(self, session):
         return "Scheduler"
@@ -2611,7 +2612,7 @@
 
     class Start(CuminAction):
         def show(self, session, sched):
-            frame = self.model.frame.pool.show_scheds_start(session)
+            frame = self.model.frame.grid.pool.show_scheds_start(session)
             frame.ids.set(session, [sched.id])
             return frame
 
@@ -2620,7 +2621,7 @@
 
     class Stop(CuminAction):
         def show(self, session, sched):
-            frame = self.model.frame.pool.show_scheds_stop(session)
+            frame = self.model.frame.grid.pool.show_scheds_stop(session)
             frame.ids.set(session, [sched.id])
             return frame
 
@@ -2645,7 +2646,7 @@
         stat.title = "Held Jobs"
 
     def init(self):
-        self.frame = self.model.frame.pool.submitter
+        self.frame = self.model.frame.grid.pool.submitter
 
     def get_title(self, session):
         return "Submitter"
@@ -2658,7 +2659,7 @@
 
         assert pool
 
-        self.model.frame.pool.set_object(session, pool)
+        self.model.frame.grid.pool.set_object(session, pool)
 
         return self.frame.show_object(session, sub)
 
@@ -2695,7 +2696,7 @@
         stat.title = "Total Slots"
 
     def init(self):
-        self.frame = self.model.frame.pool.collector
+        self.frame = self.model.frame.grid.pool.collector
 
     def get_title(self, session):
         return "Collector"
@@ -2705,7 +2706,7 @@
 
     class Start(CuminAction):
         def show(self, session, collector):
-            frame = self.model.frame.pool.show_colls_start(session)
+            frame = self.model.frame.grid.pool.show_colls_start(session)
             ids = [collector.id]
             frame.ids.set(session, ids)
             return frame
@@ -2715,7 +2716,7 @@
 
     class Stop(CuminAction):
         def show(self, session, collector):
-            frame = self.model.frame.pool.show_colls_stop(session)
+            frame = self.model.frame.grid.pool.show_colls_stop(session)
             ids = [collector.id]
             frame.ids.set(session, ids)
             return frame
@@ -2776,7 +2777,7 @@
         action.navigable = False
 
     def init(self):
-        self.frame = self.model.frame.pool.negotiator
+        self.frame = self.model.frame.grid.pool.negotiator
 
     def get_title(self, session):
         return "Negotiator"
@@ -2786,7 +2787,7 @@
 
     class Start(CuminAction):
         def show(self, session, neg):
-            frame = self.model.frame.pool.show_negs_start(session)
+            frame = self.model.frame.grid.pool.show_negs_start(session)
             frame.ids.set(session, [neg.id])
             return frame
 
@@ -2795,7 +2796,7 @@
 
     class Stop(CuminAction):
         def show(self, session, neg):
-            frame = self.model.frame.pool.show_negs_stop(session)
+            frame = self.model.frame.grid.pool.show_negs_stop(session)
             frame.ids.set(session, [neg.id])
             return frame
 

Deleted: mgmt/trunk/cumin/python/cumin/negotiator.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/negotiator.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/negotiator.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,165 +0,0 @@
-import logging
-
-from wooly import *
-from wooly.widgets import *
-from wooly.forms import *
-from wooly.resources import *
-from wooly.tables import *
-
-from stat import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-from job import *
-
-strings = StringCatalog(__file__)
-log = logging.getLogger("cumin.negotiator")
-
-class NegotiatorSet(CuminTable, Form):
-    def __init__(self, app, name):
-        super(NegotiatorSet, self).__init__(app, name)
-
-        self.ids = CheckboxIdColumn(app, "id")
-        self.add_column(self.ids)
-
-        col = self.NameColumn(app, "name")
-        self.add_column(col)
-        self.set_default_column(col)
-
-        col = self.SystemColumn(app, "system")
-        self.add_column(col)
-
-        self.__start = self.StartButton(app, "start")
-        self.add_child(self.__start)
-
-        self.__stop = self.StopButton(app, "stop")
-        self.add_child(self.__stop)
-
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, negotiator):
-        count = self.get_item_count(session, negotiator)
-        return "Negotiators %s" % fmt_count(count)
-
-    def render_sql_where(self, session, negotiator):
-        sql = "((c.qmf_update_time is not null and " + \
-            "c.qmf_update_time > now() - interval '10 minutes')" + \
-            " and qmf_delete_time is null)"
-        return "where %s" % sql
-
-    class NameColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-        def render_content(self, session, data):
-            branch = session.branch()
-
-            neg = Identifiable(data["id"])
-            self.app.model.negotiator.show_object(branch, neg)
-
-            return fmt_olink(branch, neg, name=data["name"])
-
-    class SystemColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "System"
-
-        def render_content(self, session, data):
-            id = data["system_id"]
-
-            if id:
-                sys = Identifiable(id)
-                href = self.page.main.system.get_href(session, sys)
-                return fmt_link(href, data["system_name"])
-
-    class StartButton(FormButton):
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            branch = session.branch()
-            frame = self.frame.show_negs_start(branch)
-            frame.ids.set(branch, ids)
-            self.page.set_redirect_url(session, branch.marshal())
-
-        def render_content(self, session):
-            return "Start"
-
-    class StopButton(FormButton):
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            branch = session.branch()
-            frame = self.frame.show_negs_stop(branch)
-            frame.ids.set(branch, ids)
-            self.page.set_redirect_url(session, branch.marshal())
-
-        def render_content(self, session):
-            return "Stop"
-
-class NegotiatorFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(NegotiatorFrame, self).__init__(app, name)
-
-        self.object = NegotiatorParameter(app, "id")
-        self.add_parameter(self.object)
-
-        self.view = NegotiatorView(app, "view")
-        self.add_mode(self.view)
-        self.set_view_mode(self.view)
-
-class NegotiatorView(CuminView):
-    def __init__(self, app, name):
-        super(NegotiatorView, self).__init__(app, name)
-
-        status = self.NegotiatorStatus(app, "status")
-        self.add_child(status)
-
-        self.__tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.__tabs)
-
-        details = CuminDetails(app, "details")
-        self.__tabs.add_tab(details)
-
-    class NegotiatorStatus(StartStopStatus):
-        def get_url(self, session):
-            negotiator = self.get_args(session)[0]
-            if negotiator:
-                return "call.xml?class=negotiator;id=%i;method=GetStarted" % negotiator.id
-
-        def render_title(self, session, *args):
-            return "Negotiator Status"
-
-class NegStart(CuminBulkActionForm):
-    def render_title(self, session, *args):
-        return "Start Negotiator"
-
-    def render_form_heading(self, session, *args):
-        return ""
-
-    def render_item_content(self, session, id):
-        return "Start Negotiator '%s'" % Negotiator.get(id).Name
-
-    def process_item(self, session, item):
-        negotiator = Negotiator.get(item)
-        action = self.app.model.master.start
-        action.invoke(negotiator, {"subsystem": "NEGOTIATOR"})
-        self.process_cancel(session)
-
-class NegStop(CuminBulkActionForm):
-    def render_title(self, session, *args):
-        return "Stop Negotiator"
-
-    def render_form_heading(self, session, *args):
-        return ""
-
-    def render_item_content(self, session, id):
-        return "Stop Negotiator '%s'" % Negotiator.get(id).Name
-
-    def process_item(self, session, item):
-        negotiator = Negotiator.get(item)
-        action = self.app.model.master.stop
-        action.invoke(negotiator, {"subsystem": "NEGOTIATOR"})
-        self.process_cancel(session)

Deleted: mgmt/trunk/cumin/python/cumin/negotiator.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/negotiator.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/negotiator.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,40 +0,0 @@
-[NegotiatorSet.sql]
-select
-  n.id,
-  n.name,
-  y.id as system_id,
-  y.node_name as system_name
-from negotiator as n
-left outer join negotiator_stats as c on c.id = n.stats_curr_id
-left outer join sysimage as y on n.system = y.node_name
-{sql_where}
-{sql_orderby}
-{sql_limit}
-
-[NegotiatorSet.count_sql]
-select count(1) from negotiator as n
-left outer join negotiator_stats as c on c.id = n.stats_curr_id
-{sql_where}
-
-[NegotiatorSet.html]
-<form id="{id}" method="post" action="?">
-
-  <div class="sactions">
-    <h2>Act on Selected Negotiators:</h2>
-    {start} {stop}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-	<th class="setnav" colspan="{column_count}">
-	  <div class="rfloat">{page}</div>
-	  {count}
-	</th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>

Modified: mgmt/trunk/cumin/python/cumin/page.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/page.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/page.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,19 +1,21 @@
 from wooly import *
 from wooly.widgets import *
 from wooly.resources import *
-from time import sleep
 
-from broker import *
-from brokergroup import *
 from managementserver import *
-from pool import *
-from job import *
-from system import *
 from user import *
 from action import *
 from widgets import *
 from util import *
 
+from messaging.queue import TopQueueSet
+from grid.job import TopJobSet
+from inventory.system import TopSystemSet
+
+from messaging import MessagingFrame, MessagingView
+from grid import GridFrame, GridView
+from inventory import InventoryFrame, InventoryView
+
 # We have a wooly.widgets.Link and a mint.Link; we want the former
 from wooly.widgets import Link
 from wooly import Session
@@ -31,72 +33,35 @@
     def render_title(self, session):
         return "MRG Management"
 
-    def render_content(self, session):
-        return self.render_mode(session)
-
-class MainFrame(CuminFrame):
+class MainFrame(TabbedModeSet):
     def __init__(self, app, name):
         super(MainFrame, self).__init__(app, name)
 
         self.__frame_tmpl = Template(self, "frame_html")
 
-        self.__tabs = MainFrameTabs(app, "tabs")
-        self.add_child(self.__tabs)
-
         self.actions = ActionInvocationStatus(app, "actions")
         self.add_child(self.actions)
 
-        self.view = MainView(app, "view")
-        self.add_mode(self.view)
-        self.set_view_mode(self.view)
+        self.home = HomeFrame(app, "home")
+        self.add_tab(self.home)
 
-        self.broker = BrokerFrame(app, "broker")
-        self.add_mode(self.broker)
+        self.messaging = MessagingFrame(app, "messaging")
+        self.add_tab(self.messaging)
 
-        self.broker_group = BrokerGroupFrame(app, "group")
-        self.add_mode(self.broker_group)
+        self.grid = GridFrame(app, "grid")
+        self.add_tab(self.grid)
 
-        self.system = SystemFrame(app, "system")
-        self.add_mode(self.system)
+        self.inventory = InventoryFrame(app, "inventory")
+        self.add_tab(self.inventory)
 
-        self.pool = PoolFrame(app, "pool")
-        self.add_mode(self.pool)
+    def show_child(self, session, child):
+        super(MainFrame, self).show_child(session, child)
 
-        self.sticky_pool = Parameter(app, "last_pool")
-        self.add_parameter(self.sticky_pool)
+        frame = self.page.get_frame(session)
 
-        self.change_password = ChangePasswordForm(app, "password")
-        self.add_mode(self.change_password)
+        if child not in frame.ancestors:
+            self.page.set_frame(session, child)
 
-        self.mservers_add = ManagementServerSetAdd(app, "mserversadd")
-        self.add_mode(self.mservers_add)
-
-        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)
-
-        self.jobs_release = JobSetRelease(app, "jobsrelease")
-        self.add_mode(self.jobs_release)
-
-        self.jobs_remove = JobSetRemove(app, "jobsremove")
-        self.add_mode(self.jobs_remove)
-
-        action = self.app.model.broker_group.remove_set
-        item = BrokerGroupParameter(app, "item")
-        self.broker_groups_remove = CuminSetActionForm \
-            (app, "groupsremove", action, item)
-        self.add_mode(self.broker_groups_remove)
-
-    def do_process(self, session):
-        self.actions.process(session)
-
-        super(MainFrame, self).do_process(session)
-
     def render_title(self, session):
         return "Main"
 
@@ -114,136 +79,25 @@
 
         return lsess.marshal()
 
-    def render_frames(self, session):
-        writer = Writer()
-
-        for frame in self.page.get_frames(session):
-            self.__frame_tmpl.render(writer, session, frame)
-
-        return writer.to_string()
-
-    def render_frame_href(self, session, frame):
-        args = frame.get_args(session)
-        return frame.render_href(session, *args)
-
-    def render_frame_title(self, session, frame):
-        args = frame.get_args(session)
-        return frame.render_title(session, *args)
-
-    def show_grid_tab(self, session):
-        self.__tabs.set_grid_tab(session)
-        self.view.set_grid_mode(session)
-
-    def show_system_tab(self, session):
-        self.__tabs.set_system_tab(session)
-        self.view.set_systems_mode(session)
-
-    def set_messaging_tab(self, session):
-        self.__tabs.set_messaging_tab(session)
-        self.view.set_messaging_mode(session)
-
-    def set_last_pool(self, session, pool):
-        self.sticky_pool.set(session, pool)
-
-    def get_last_pool(self, session):
-        return self.sticky_pool.get(session)
-
-class MainFrameTabs(LinkSet):
+class HomeFrame(CuminFrame):
     def __init__(self, app, name):
-        super(MainFrameTabs, self).__init__(app, name)
+        super(HomeFrame, self).__init__(app, name)
 
-        self.selection = Parameter(app, "sel")
-        self.selection.default = "htab"
-        self.add_parameter(self.selection)
+        self.view = HomeView(app, "view")
+        self.add_mode(self.view)
 
-        self.add_link(self.HomeTab(app, "htab"))
-        self.add_link(self.MessagingTab(app, "mtab"))
-        self.add_link(self.GridTab(app, "gtab"))
-        self.add_link(self.SystemsTab(app, "stab"))
+        self.change_password = ChangePasswordForm(app, "password")
+        self.add_mode(self.change_password)
 
-    def render_class(self, session):
-        return "tabs"
+        self.mservers_add = ManagementServerSetAdd(app, "mserversadd")
+        self.add_mode(self.mservers_add)
 
-    def set_grid_tab(self, session):
-        self.selection.set(session, "gtab")
+        self.mservers_remove = ManagementServerSetRemove(app, "mserversremove")
+        self.add_mode(self.mservers_remove)
 
-    def set_system_tab(self, session):
-        self.selection.set(session, "stab")
+    def render_title(self, session):
+        return "Home"
 
-    def set_messaging_tab(self, session):
-        self.selection.set(session, "mtab")
-
-    class Tab(Link):
-        def render_class(self, session):
-            return (self.parent.selection.get(session) == self.name) \
-                and "selected" or "not-selected"
-
-    class HomeTab(Tab):
-        def render_content(self, session):
-            return "Home"
-
-        def edit_session(self, session):
-            self.parent.selection.set(session, self.name)
-            self.page.main.view.home.show(session)
-
-    class MessagingTab(Tab):
-        def render_content(self, session):
-            return "Messaging"
-
-        def edit_session(self, session):
-            self.parent.selection.set(session, self.name)
-            self.page.main.view.messaging.show(session)
-
-    class GridTab(Tab):
-        def render_content(self, session):
-            return "Grid"
-
-        def edit_session(self, session):
-            self.parent.selection.set(session, self.name)
-            self.page.main.view.grid.show(session)
-
-            last_pool = self.page.main.get_last_pool(session)
-            if last_pool:
-                pool = model.Pool.get(last_pool)
-            else:
-                pool = self.app.model.get_main_pool()
-
-            if pool:
-                self.page.main.pool.show_object(session, pool)
-
-    class SystemsTab(Tab):
-        def render_content(self, session):
-            return "Systems"
-
-        def edit_session(self, session):
-            self.parent.selection.set(session, self.name)
-            self.page.main.view.systems.show(session)
-
-class MainView(ModeSet):
-    def __init__(self, app, name):
-        super(MainView, self).__init__(app, name)
-
-        self.home = HomeView(app, "home")
-        self.add_mode(self.home)
-
-        self.messaging = MessagingView(app, "msg")
-        self.add_mode(self.messaging)
-
-        self.grid = GridView(app, "grd")
-        self.add_mode(self.grid)
-
-        self.systems = SystemsView(app, "sys")
-        self.add_mode(self.systems)
-
-    def set_messaging_mode(self, session):
-        self.set_selected_mode(session, self.messaging)
-
-    def set_grid_mode(self, session):
-        self.set_selected_mode(session, self.grid)
-
-    def set_systems_mode(self, session):
-        self.set_selected_mode(session, self.systems)
-
 class HomeView(TabbedModeSet):
     def __init__(self, app, name):
         super(HomeView, self).__init__(app, name)
@@ -263,10 +117,10 @@
 
     class Heading(CuminHeading):
         def render_title(self, session):
-            return "MRG Management"
+            return "Management Home"
 
         def render_icon_href(self, session):
-            return "resource?name=shadowman-36.png"
+            return "resource?name=action-36.png"
 
     class OverviewTab(Widget):
         def __init__(self, app, name):
@@ -327,52 +181,3 @@
         def render_user(self, session, *args):
             if hasattr(session, "user_session"):
                 return session.user_session.subject.name
-
-class MessagingView(TabbedModeSet):
-    def __init__(self, app, name):
-        super(MessagingView, self).__init__(app, name)
-
-        heading = self.Heading(app, "heading")
-        self.add_child(heading)
-
-        self.add_tab(BrokerBrowser(app, "brokers"))
-        self.add_tab(BrokerGroupSet(app, "groups"))
-
-    class Heading(CuminHeading):
-        def render_title(self, session):
-            return "Messaging"
-
-        def render_icon_href(self, session):
-            return "resource?name=broker-36.png"
-
-class GridView(TabbedModeSet):
-    def __init__(self, app, name):
-        super(GridView, self).__init__(app, name)
-
-        heading = self.Heading(app, "heading")
-        self.add_child(heading)
-
-        self.add_tab(PoolSet(app, "pools"))
-
-    class Heading(CuminHeading):
-        def render_title(self, session):
-            return "Grid"
-
-        def render_icon_href(self, session):
-            return "resource?name=cluster-36.png"
-
-class SystemsView(TabbedModeSet):
-    def __init__(self, app, name):
-        super(SystemsView, self).__init__(app, name)
-
-        heading = self.Heading(app, "heading")
-        self.add_child(heading)
-
-        self.add_tab(SystemSet(app, "systems"))
-
-    class Heading(CuminHeading):
-        def render_title(self, session):
-            return "Systems"
-
-        def render_icon_href(self, session):
-            return "resource?name=system-36.png"

Modified: mgmt/trunk/cumin/python/cumin/page.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/page.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/page.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,133 +1,82 @@
 [MainFrame.css]
 #head {
     padding: 0;
-    border-bottom: 1px solid #999;
-    color: #ddd;
-    background: #666 url("resource?name=mrg-banner.png") no-repeat scroll center;
+    min-height: 2.75em;
+    background: #f9f9ff url("resource?name=shade.png") repeat-x scroll bottom center;
 }
 
-#trans0 {
-    background-color: black;
-    height: 0.15em;
-    width: 100%;
+#logo {
+    float: left;
+    margin: 0.25em 1em;
 }
 
-#head a {
-    color: #c0d0e0;
+#tabs {
+    padding: 0 0 0 2em;
+    position: relative;
+    top: 1.175em;
 }
 
-body.modal #head {
-    opacity: 0.2;
-}
-
-#head .tabs {
-    padding: 0 0 0.25em 0.5em;
-}
-
-#head .tabs li {
+#tabs li {
     display: inline;
 }
 
-#head .tabs li a {
-    padding: 0.225em 0.5em 0.275em 0.5em;
-    border-right: 2px solid #444;
-    background-color: #333;
-    color: #ccc;
-    line-height: 1.5em;
-    vertical-align: -15%;
+#tabs li a {
+    padding: 0.275em 0.5em;
+    border-top: 1px solid #ccc;
+    border-right: 1px solid #ccc;
+    border-left: 1px solid #e7e7e7;
+    -moz-border-radius: 0.35em 0.35em 0 0;
+    -webkit-border-radius: 0.35em 0.35em 0 0;
+    color: #333;
+    background-color: #f7f7f7;
+    line-height: 1.6em;
 }
 
-#head .tabs li:last-child a {
-    border-right: 0;
+#tabs li:first-child a {
+    border-left: 1px solid #ccc;
 }
 
-#head .tabs li a.selected {
-    background-color: #000;
-    color: #fff;
+#tabs li a.selected {
+    background-color: #fff;
+    position: relative;
+    z-index: 2;
 }
 
-#body {
-    padding: 1em;
-}
-
-#logo {
-    vertical-align: -20%;
-}
-
 #user {
     padding: 0.25em 0.5em;
     float: right;
-    color: #fff;
     font-size: 0.9em;
 }
 
-#logout {
-    color: #06c;
-}
-
 #actions {
     padding: 0.25em 0.5em;
     float: right;
     font-size: 0.9em;
 }
 
-#context {
-    display: inline;
-    list-style: none;
-    padding: 0 1em;
-    margin: 0;
-    line-height: 1.75em;
-    font-size: 0.9em;
-    color: #fff;
+#body {
+  border-top: 1px solid #ccc;
+  padding: 0.75em 1em;
+  position: relative;
+  z-index: 1;
+  min-height: 20em;
 }
 
-#context li {
-    display: inline;
-}
-
-#context li:before {
-    content: " > ";
-    font-weight: bold;
-    font-size: 0.8em;
-    color: #ccc;
-}
-
-#context li:last-child a {
-    color: #ddd;
-}
-
-#context li:first-child:before {
-    content: "";
-}
-
-#trans1 {
-    padding: 0;
-    margin: 0;
-    border-top: 1px solid #bbb;
-    border-bottom: 1px solid #ddd;
-}
-
 [MainFrame.html]
-<div id="trans0"/>
 <div id="head">
-  <div>
-    <div id="user">
-      Hi, {user_name}
-      <strong>&#183;</strong>
-      <a id="logout" onclick="wooly.clearUpdates()" href="{logout_href}">Log Out</a>
-    </div>
-
-    {tabs}
+  <div id="user">
+    Hi, {user_name}
+    <strong>&#183;</strong>
+    <a id="logout" onclick="wooly.clearUpdates()" href="{logout_href}">Log Out</a>
   </div>
 
-  <div>
-    <div id="actions">{actions}</div>
+  <img id="logo" src="resource?name=rhlogo-32.png"/>
 
-    <ul id="context">{frames}</ul>
-  </div>
+  <ul id="tabs">{tabs}</ul>
 </div>
-<div id="trans1"></div>
-<div id="body">{mode}</div>
+
+<div id="body">{content}</div>
+
 <div id="foot"/>
 
 [MainFrame.frame_html]
@@ -138,7 +87,7 @@
   {heading}
 
   <ul class="TabbedModeSet tabs">{tabs}</ul>
-  <div class="TabbedModeSet mode">{mode}</div>
+  <div class="TabbedModeSet mode">{content}</div>
 </div>
 
 [OverviewTab.css]
@@ -221,7 +170,7 @@
   {heading}
 
   <ul class="TabbedModeSet tabs">{tabs}</ul>
-  <div class="TabbedModeSet mode">{mode}</div>
+  <div class="TabbedModeSet mode">{content}</div>
 </div>
 
 [GridView.html]
@@ -229,7 +178,7 @@
   {heading}
 
   <ul class="TabbedModeSet tabs">{tabs}</ul>
-  <div class="TabbedModeSet mode">{mode}</div>
+  <div class="TabbedModeSet mode">{content}</div>
 </div>
 
 [SystemsView.html]
@@ -237,7 +186,7 @@
   {heading}
 
   <ul class="TabbedModeSet tabs">{tabs}</ul>
-  <div class="TabbedModeSet mode">{mode}</div>
+  <div class="TabbedModeSet mode">{content}</div>
 </div>
 
 [MyGridJobs.html]

Deleted: mgmt/trunk/cumin/python/cumin/pool.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/pool.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/pool.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,356 +0,0 @@
-import logging
-
-from wooly import *
-from wooly.widgets import *
-from wooly.forms import *
-from wooly.resources import *
-from wooly.tables import *
-
-from stat import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-from job import *
-from scheduler import SchedulerSet, SchedulerFrame, SchedulerStart, SchedulerStop
-from submitter import SubmitterSet, SubmitterFrame
-from collector import CollectorSet, CollectorFrame, CollectorStart, CollectorStop
-from negotiator import NegotiatorSet, NegotiatorFrame, NegStart, NegStop
-from limits import LimitsSet, LimitsFrame
-from slot import SlotSet, SlotStatSet
-from visualizations import SlotMap
-
-strings = StringCatalog(__file__)
-log = logging.getLogger("cumin.pool")
-
-class PoolSet(CuminTable):
-    def __init__(self, app, name):
-        super(PoolSet, self).__init__(app, name)
-
-        col = self.NameColumn(app, "name")
-        self.add_column(col)
-
-        self.set_default_column(col)
-
-        col = self.JobsColumn(app, "jobs")
-        self.add_column(col)
-
-        col = self.StatusColumn(app, "status")
-        self.add_column(col)
-
-    def render_title(self, session):
-        count = self.get_item_count(session)
-        return "Pools %s" % fmt_count(count)
-
-    class NameColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-        def render_content(self, session, data):
-            pool = Identifiable(data["id"])
-            self.page.main.set_last_pool(session, data["id"])
-            href = self.frame.pool.get_href(session, pool)
-
-            return fmt_link(href, data["name"])
-
-    class JobsColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Jobs"
-
-        def render_content(self, session, data):
-            return data["jobs"]
-
-    class StatusColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Status"
-
-        def render_content(self, session, data):
-            return "Active"
-
-class PoolFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(PoolFrame, self).__init__(app, name)
-
-        self.object = PoolParameter(app, "id")
-        self.add_parameter(self.object)
-
-        self.view = PoolView(app, "view")
-        self.add_mode(self.view)
-        self.set_view_mode(self.view)
-
-        self.job = JobFrame(app, "job")
-        self.add_mode(self.job)
-
-        self.job_group = JobGroupFrame(app, "jobgroup")
-        self.add_mode(self.job_group)
-
-        self.scheduler = SchedulerFrame(app, "sched")
-        self.add_mode(self.scheduler)
-
-        self.submitter = SubmitterFrame(app, "sub")
-        self.add_mode(self.submitter)
-
-        self.collector = CollectorFrame(app, "coll")
-        self.add_mode(self.collector)
-
-        self.limit = LimitsFrame(app, "limit")
-        self.add_mode(self.limit)
-
-        self.negotiator = NegotiatorFrame(app, "neg")
-        self.add_mode(self.negotiator)
-
-        self.__startneg = NegStart(app, "startneg")
-        self.add_mode(self.__startneg)
-
-        self.__stopneg = NegStop(app, "stopneg")
-        self.add_mode(self.__stopneg)
-
-        self.__startcoll = CollectorStart(app, "startcoll")
-        self.add_mode(self.__startcoll)
-
-        self.__stopcoll = CollectorStop(app, "stopcoll")
-        self.add_mode(self.__stopcoll)
-
-        self.__startsched = SchedulerStart(app, "startsched")
-        self.add_mode(self.__startsched)
-
-        self.__stopsched = SchedulerStop(app, "stopsched")
-        self.add_mode(self.__stopsched)
-
-        self.jobs_hold = JobSetHold(app, "jobshold")
-        self.add_mode(self.jobs_hold)
-
-        self.jobs_release = JobSetRelease(app, "jobsrelease")
-        self.add_mode(self.jobs_release)
-
-        self.jobs_remove = JobSetRemove(app, "jobsremove")
-        self.add_mode(self.jobs_remove)
-
-        self.job_group_hold = JobGroupHold(app, "jobgrouphold")
-        self.add_mode(self.job_group_hold)
-
-        self.job_group_release = JobGroupRelease(app, "jobgrouprelease")
-        self.add_mode(self.job_group_release)
-
-        self.job_group_remove = JobGroupRemove(app, "jobgroupremove")
-        self.add_mode(self.job_group_remove)
-
-    def show_job_frame(self, session):
-        self.page.set_frame(session, self.job)
-        return self.show_mode(session, self.job)
-
-    def show_negs_start(self, session):
-        self.page.set_frame(session, self.__startneg)
-        return self.show_mode(session, self.__startneg)
-
-    def show_negs_stop(self, session):
-        self.page.set_frame(session, self.__stopneg)
-        return self.show_mode(session, self.__stopneg)
-
-    def show_scheds_start(self, session):
-        self.page.set_frame(session, self.__startsched)
-        return self.show_mode(session, self.__startsched)
-
-    def show_scheds_stop(self, session):
-        self.page.set_frame(session, self.__stopsched)
-        return self.show_mode(session, self.__stopsched)
-
-    def show_colls_start(self, session):
-        self.page.set_frame(session, self.__startcoll)
-        return self.show_mode(session, self.__startcoll)
-
-    def show_colls_stop(self, session):
-        self.page.set_frame(session, self.__stopcoll)
-        return self.show_mode(session, self.__stopcoll)
-
-class PoolView(CuminView):
-    def __init__(self, app, name):
-        super(PoolView, self).__init__(app, name)
-
-        status = PoolStatus(app, "status")
-        self.add_child(status)
-
-        self.__tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.__tabs)
-
-        stats = PoolStats(app, "stats")
-        self.__tabs.add_tab(stats)
-
-        self.jobs = JobsAndGroupsTab(app, "jobs")
-        self.__tabs.add_tab(self.jobs)
-
-        self.scheds = PoolSchedulerSet(app, "scheds")
-        self.__tabs.add_tab(self.scheds)
-
-        subs = PoolSubmitterSet(app, "subs")
-        self.__tabs.add_tab(subs)
-
-        self.colls = PoolCollectorSet(app, "colls")
-        self.__tabs.add_tab(self.colls)
-
-        self.negs = PoolNegotiatorSet(app, "negs")
-        self.__tabs.add_tab(self.negs)
-
-        limits = self.LimitsTab(app, "limits")
-        self.__tabs.add_tab(limits)
-
-    class LimitsTab(LimitsSet):
-        pass
-
-    def set_collector_tab(self, session):
-        self.__tabs.set_selected_mode(session, self.colls)
-
-    def set_negotiator_tab(self, session):
-        self.__tabs.set_selected_mode(session, self.negs)
-
-    def set_scheduler_tab(self, session):
-        self.__tabs.set_selected_mode(session, self.scheds)
-
-class PoolSchedulerSet(SchedulerSet):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def get_sql_values(self, session, pool):
-        return {"pool": pool.id}
-
-    def render_title(self, session, pool):
-        count = self.get_item_count(session, pool)
-        return "Schedulers %s" % fmt_count(count)
-
-    def render_sql_where(self, session, pool):
-        return "where s.pool = %(pool)s"
-
-class PoolSubmitterSet(SubmitterSet):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def get_sql_values(self, session, pool):
-        return {"pool": pool.id}
-
-    def render_title(self, session, pool):
-        count = self.get_item_count(session, pool)
-        return "Submitters %s" % fmt_count(count)
-
-    def render_sql_where(self, session, pool):
-        return "where d.pool = %(pool)s"
-
-class PoolCollectorSet(CollectorSet):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def get_sql_values(self, session, pool):
-        return {"pool": pool.id}
-
-    def render_title(self, session, pool):
-        count = self.get_item_count(session, pool)
-        return "Collectors %s" % fmt_count(count)
-
-    def render_sql_where(self, session, pool):
-        return "where c.pool = %(pool)s"
-
-class PoolNegotiatorSet(NegotiatorSet):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def get_sql_values(self, session, pool):
-        return {"pool": pool.id}
-
-    def render_title(self, session, pool):
-        count = self.get_item_count(session, pool)
-        return "Negotiators %s" % fmt_count(count)
-
-    def render_sql_where(self, session, pool):
-        return "where n.pool = %(pool)s"
-
-class PoolSlotSet(SlotSet):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_sql_where(self, session, pool):
-        elems = list()
-        elems.append("s.pool = %(pool)s")
-        recent = self.get_recent_sql_where(session)
-        if recent:
-            elems.append(recent)
-
-        return "where %s" % " and ".join(elems)
-
-    def get_sql_values(self, session, pool):
-        return {"pool": pool.id}
-
-    def render_title(self, session, pool):
-        count = self.get_item_count(session, pool)
-        return "Slots %s" % fmt_count(count)
-
-    def filter(self, session, system, slots):
-        return slots
-
-class PoolStats(Widget):
-    def __init__(self, app, name):
-        super(PoolStats, self).__init__(app, name)
-
-        stats = PoolStatSet(app, "general", "general")
-        self.add_child(stats)
-
-        self.slot_map = self.PoolSlotMap(app, "pool_slot_map")
-        self.add_child(self.slot_map)
-
-    def render_title(self, session):
-        return "Statistics"
-
-    class PoolSlotMap(SlotMap):
-        def get_title_name(self, session, pool):
-            return pool.name
-
-        def render_slot_clip_size(self, session, *args):
-            return 400
-
-class PoolStatSet(StatSet):
-    def render_rate_text(self, session, args):
-        return "Percentage"
-
-    def do_get_items(self, session, pool):
-        stats = super(PoolStatSet, self).do_get_items(session, pool)
-
-        action = self.app.model.pool.fakestats
-        record = action.get_stat_record(session, pool)
-
-        fake_stats = list()
-        for stat in stats:
-            fake_stats.append((stat[0], record))
-
-        return fake_stats
-
-class PoolJobStats(CuminTable):
-    def render_sql_where(self, session, pool):
-        elems = list()
-        elems.append("s.pool = %(pool)s")
-        return "where %s" % " and ".join(elems)
-
-    def get_sql_values(self, session, pool):
-        values = {"pool": pool.id}
-        return values
-
-class PoolStatus(CuminStatus):
-    def __init__(self, app, name):
-        super(PoolStatus, self).__init__(app, name)
-
-        self.item_tmpl = Template(self, "status_html")
-
-    def render_title(self, session, pool):
-        return "Pool Status"
-
-    def render_status(self, session, pool):
-        action = self.app.model.pool.poolstatus
-        record = action.get_stat_record(session, pool)
-        if record and ("idl" in record) and ("all" in record):
-            if record["idl"] and record["all"]: # not None
-                writer = Writer()
-                self.item_tmpl.render(writer, session, record)
-                return writer.to_string()
-
-    def render_idle(self, session, record):
-        return record["idl"]
-
-    def render_total(self, session, record):
-        return record["all"]

Deleted: mgmt/trunk/cumin/python/cumin/pool.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/pool.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/pool.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,58 +0,0 @@
-[PoolSet.sql]
-select p.pool as id, p.name, j.jobs
-from
-  (select pool, name
-   from collector
-   group by pool, name) as p
-left outer join
-  (select s.pool, count(*) as jobs
-   from job j
-   left outer join scheduler as s on j.scheduler_id = s.id
-   group by s.pool) as j
-  on j.pool = p.pool
-
-[PoolSet.count_sql]
-select count(*)
-from
-  (select 1 from collector group by pool) as l
-
-[PoolJobStats.sql]
-select
- sum(case when job_status=2 then 1 else 0 end) as running,
- sum(case when job_status=4 then 1 else 0 end) as completed,
- sum(case when job_status=5 then 1 else 0 end) as held,
- sum(case when job_status=1 and j.qmf_delete_time is null then 1 else 0 end) as idle,
- sum(case when job_status=3 or (job_status=1 and j.qmf_delete_time is not null) then 1 else 0 end) as removed,
- sum(1) as total,
- s.pool
-from job as j
-left outer join scheduler as s on s.id = j.scheduler_id
-{sql_where}
-group by s.pool
-
-[PoolJobStats.count_sql]
-1
-
-[PoolStatus.html]
-<div id="{id}" class="CuminStatus {color}">
-  <h2>{title}</h2>
-
-  {status}
-</div>
-
-[PoolStatus.status_html]
-<div>
-  <span>{idle}</span> of <span>{total}</span> slots idle
-</div>
-
-[PoolStats.html]
-<div style="width: 40%; float: left;">
-  <h2>General</h2>
-  <div>
-  {general}
-  </div>
-</div>
-<div style="float: left; margin-left: 4em;">
-  {pool_slot_map}
-</div>
-<div style="clear:left;"><!-- --></div>

Deleted: mgmt/trunk/cumin/python/cumin/queue.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/queue.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/queue.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,1092 +0,0 @@
-import logging
-
-from mint.schema import Queue, Journal, Exchange
-from wooly import *
-from wooly.widgets import *
-from wooly.forms import *
-from wooly.resources import *
-from wooly.tables import *
-from datetime import datetime
-from sqlobject.sqlbuilder import LEFTJOINOn
-
-from binding import *
-from exchange import ExchangeInputSet
-from stat import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-
-strings = StringCatalog(__file__)
-log = logging.getLogger("cumin.queue")
-
-class QueueSet(CuminTable, Form):
-    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)
-
-        col = self.NameColumn(app, "name")
-        self.add_column(col)
-
-        self.set_default_column(col)
-
-        col = self.ConsumersColumn(app, "consumers")
-        col.alignment = "right"
-        self.add_column(col)
-
-        col = self.BindingsColumn(app, "bindings")
-        col.alignment = "right"
-        self.add_column(col)
-
-        col = self.EnqueuedColumn(app, "enqueued")
-        col.alignment = "right"
-        self.add_column(col)
-
-        col = self.DequeuedColumn(app, "dequeued")
-        col.alignment = "right"
-        self.add_column(col)
-
-        col = self.DepthColumn(app, "depth")
-        col.alignment = "right"
-        self.add_column(col)
-
-        self.unit = UnitSwitch(app, "unit")
-        self.add_child(self.unit)
-
-        self.phase = PhaseSwitch(app, "phase")
-        self.add_child(self.phase)
-
-        self.__purge = self.Purge(app, "purge")
-        self.add_child(self.__purge)
-
-        self.__remove = self.Remove(app, "remove")
-        self.add_child(self.__remove)
-
-    def render_add_queue_url(self, session):
-        branch = session.branch()
-        self.frame.queue_add.show(branch)
-        return branch.marshal()
-
-    def render_title(self, session):
-        return "Queues %s" % fmt_count(Queue.select().count())
-
-    def render_sql_where(self, session):
-        vhost = self.vhost.get(session)
-
-        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):
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            branch = session.branch()
-            self.frame.queues_purge.show(branch).ids.set(branch, ids)
-            self.page.set_redirect_url(session, branch.marshal())
-
-        def render_content(self, session):
-            return "Purge"
-
-    class Remove(FormButton):
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            branch = session.branch()
-            self.frame.queues_remove.show(branch).ids.set(branch, ids)
-            self.page.set_redirect_url(session, branch.marshal())
-
-        def render_content(self, session):
-            return "Remove"
-
-    class NameColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-        def render_content(self, session, data):
-            queue = Identifiable(data["id"])
-            href = self.page.main.broker.queue.get_href(session, queue)
-            return fmt_link(href, fmt_shorten(data["name"]))
-
-    class ConsumersColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Consumers"
-
-        def render_value(self, session, value):
-            if value is None:
-                return fmt_none_brief()
-            else:
-                return value
-
-    class BindingsColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Bindings"
-
-        def render_content(self, session, data):
-            queue = Identifiable(data["id"])
-            branch = session.branch()
-            self.frame.queue.object.set(branch, queue)
-            self.frame.queue.view.bindings.show(branch)
-            return fmt_link(branch.marshal(), data["bindings"] or "0")
-
-    class EnqueuedColumn(NullSortColumn, FreshDataOnlyColumn):
-        def render_title(self, session, data):
-            return "%s Enqueued" % self.parent.unit.get_brief_plural(session)
-
-        def get_column_key(self, session):
-            unit = self.parent.unit.get(session)
-            return unit == "b" and "benqueued" or "menqueued"
-
-        def render_value(self, session, value):
-            return fmt_rate(value, "", "sec")
-
-    class DequeuedColumn(NullSortColumn, FreshDataOnlyColumn):
-        def render_title(self, session, data):
-            return "%s Dequeued" % self.parent.unit.get_brief_plural(session)
-
-        def get_column_key(self, session):
-            unit = self.parent.unit.get(session)
-            return unit == "b" and "bdequeued" or "mdequeued"
-
-        def render_value(self, session, value):
-            return fmt_rate(value, "", "sec")
-
-    class DepthColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "%s Depth" % self.parent.unit.get_brief_singular(session)
-
-        def get_column_key(self, session):
-            unit = self.parent.unit.get(session)
-            return unit == "b" and "bdepth" or "mdepth"
-
-        def render_value(self, session, value):
-            if value is None:
-                return fmt_none_brief()
-            else:
-                return value
-
-class TopQueueSet(TopTable):
-    def __init__(self, app, name):
-        super(TopQueueSet, self).__init__(app, name)
-
-        col = self.NameColumn(app, "name")
-        self.add_column(col)
-
-        self.set_default_column(col)
-
-        col = self.EnqueuesColumn(app, "enqueues")
-        col.alignment = "right"
-        self.add_column(col)
-
-    class NameColumn(TopTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-        def render_content(self, session, data):
-            broker = Identifiable(data["broker_id"])
-            queue = Identifiable(data["id"])
-
-            big = self.parent.get_fullpage(session)
-            branch = session.branch()
-            self.page.main.broker.object.set(branch, broker)
-            self.page.main.broker.queue.object.set(branch, queue)
-            self.page.main.broker.queue.show(branch)
-            name = big and data["name"] or fmt_shorten(data["name"])
-            return fmt_link(branch.marshal(), name)
-
-    class EnqueuesColumn(TopTableColumn):
-        def render_title(self, session, data):
-            return "Recent Enqueues"
-
-class QueueFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(QueueFrame, self).__init__(app, name)
-
-        self.object = QueueParameter(app, "id")
-        self.add_parameter(self.object)
-
-        self.view = QueueView(app, "view")
-        self.add_mode(self.view)
-        self.set_view_mode(self.view)
-
-        self.purge = QueuePurge(app, "purge")
-        self.add_mode(self.purge)
-
-        self.binding_add = QueueBindingAdd(app, "bindingadd", self.object)
-        self.add_mode(self.binding_add)
-
-        self.remove = QueueRemove(app, "remove")
-        self.add_mode(self.remove)
-        self.set_remove_mode(self.remove)
-
-        self.move_messages = QueueMoveMessages(app, "move_messages")
-        self.add_mode(self.move_messages)
-
-    def show_object(self, session, queue):
-        self.page.main.broker.object.set(session, queue.vhost.broker)
-        return super(QueueFrame, self).show_object(session, queue)
-
-    def render_href(self, session, queue):
-        if queue:
-            return super(QueueFrame, self).render_href(session, queue)
-
-    def render_title(self, session, queue):
-        if queue:
-            return super(QueueFrame, self).render_title(session, queue)
-        else:
-            return "Queue"
-
-    def show_move(self, session):
-        return self.show_mode(session, self.move_messages)
-
-class QueueStatus(CuminStatus):
-    def render_consumers(self, session, queue):
-        return self.app.model.queue.consumers.value(queue)
-
-    def render_messages_enqueued(self, session, queue):
-        return self.app.model.queue.msgTotalEnqueues.rate_html(queue)
-
-    def render_messages_dequeued(self, session, queue):
-        return self.app.model.queue.msgTotalDequeues.rate_html(queue)
-
-    def render_message_depth(self, session, queue):
-        return self.app.model.queue.msgDepth.value(queue)
-
-    def render_message_depth_accel(self, session, queue):
-        return self.app.model.queue.msgDepth.rate_html(queue)
-
-    def render_bytes_enqueued(self, session, queue):
-        return self.app.model.queue.byteTotalEnqueues.rate_html(queue)
-
-    def render_bytes_dequeued(self, session, queue):
-        return self.app.model.queue.byteTotalDequeues.rate_html(queue)
-
-    def render_byte_depth(self, session, queue):
-        return self.app.model.queue.byteDepth.value(queue)
-
-    def render_byte_depth_accel(self, session, queue):
-        return self.app.model.queue.byteDepth.rate_html(queue)
-
-class QueueView(CuminView):
-    def __init__(self, app, name):
-        super(QueueView, self).__init__(app, name)
-
-        status = QueueStatus(app, "status")
-        self.add_child(status)
-
-        self.__tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.__tabs)
-
-        self.__tabs.add_tab(QueueStats(app, "stats"))
-
-        self.bindings = QueueBindingSet(app, "bindings")
-        self.__tabs.add_tab(self.bindings)
-
-        self.details = CuminDetails(app, "details")
-        self.__tabs.add_tab(self.details)
-
-    def show_bindings(self, session):
-        self.__tabs.show_mode(session, self.bindings);
-
-class QueueBindingSet(BindingSet, Form):
-    def __init__(self, app, name):
-        super(QueueBindingSet, self).__init__(app, name)
-
-        self.__remove = self.Remove(app, "remove")
-        self.add_child(self.__remove)
-
-        self.set_default_column_name("e_id")
-
-    def get_visible_columns(self, session):
-        return self.get_request_visible_columns(session, ["e_id"])
-
-    def render_add_queue_binding_url(self, session, *args):
-        branch = session.branch()
-        self.frame.binding_add.show(branch)
-        return branch.marshal()
-
-    def render_sql_where(self, session, queue):
-        elems = list()
-        elems.append("b.queue_id = %(id)r")
-        elems.append(self.phase.get_sql_constraint(session, queue))
-        return "where %s" % " and ".join(elems)
-
-    def render_title(self, session, queue):
-        return "Exchange Bindings %s" % \
-            fmt_count(queue.bindings.count())
-
-    class Remove(FormButton):
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            href = self.frame.frame.bindings_remove.get_href \
-                (session, ids)
-            self.page.set_redirect_url(session, href)
-
-        def render_content(self, session):
-            return "Remove"
-
-class QueueForm(CuminFieldForm):
-    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)
-
-        self.more = MoreFieldSet(app, "more")
-        self.add_field(self.more)
-
-        self.durable = self.QueueDurabilityField(app, "durable")
-        self.more.add_field(self.durable)
-
-        self.cluster_durable = self.ClusterDurabilityField(app, "cluster_durable")
-        self.more.add_field(self.cluster_durable)
-
-        self.lvq = self.LVQField(app, "lvq")
-        self.more.add_field(self.lvq)
-
-        self.optimistic = self.OptimisticField(app, "optimistic")
-        self.more.add_field(self.optimistic)
-
-        self.file_count = self.FileCountField(app, "file_count")
-        self.file_count.input.param.default = 8
-        self.more.add_field(self.file_count)
-
-        self.file_size = self.FileSizeField(app, "file_size")
-        self.file_size.input.param.default = 24
-        self.more.add_field(self.file_size)
-
-        self.policy = self.PolicyField(app, "policy")
-        self.more.add_field(self.policy)
-
-        self.q_size = self.QSizeField(app, "q_size")
-        self.more.add_field(self.q_size)
-
-        self.q_count = self.QCountField(app, "q_count")
-        self.more.add_field(self.q_count)
-
-        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>"
-
-        def render_field_help(self, session):
-            return "(Maximum in-memory queue size as a number of messages. Applies if Policy is set.)"
-
-    class QSizeField(IntegerField):
-        def render_title(self, session):
-            return "<div style=\"padding-left: 1em;\">Max Queue Size</div>"
-
-        def render_field_help(self, session):
-            return "(Maximum in-memory queue size as bytes. Applies if Policy is set.)"
-
-    class FileCountField(IntegerField):
-        def render_title(self, session):
-            return "File Count"
-
-        def render_field_help(self, session):
-            return "(Number of files in queue's persistence journal)"
-
-    class FileSizeField(IntegerField):
-        def render_title(self, session):
-            return "File Size"
-
-        def render_field_help(self, session):
-            return "(File size in pages - 64Kb/page)"
-
-    class QueueDurabilityField(TwoOptionRadioField):
-        def render_title(self, session):
-            return "Durable?"
-
-        def render_field_help(self, session):
-            return "(Queue is durable)"
-
-        def render_title_1(self, session):
-            return "Durable"
-
-        def render_title_2(self, session):
-            return "Transient"
-
-    class ClusterDurabilityField(TwoOptionRadioField):
-        def render_title(self, session):
-            return "Cluster Durable?"
-
-        def render_field_help(self, session):
-            return "(Queue becomes durable if there is only one functioning cluster node)"
-
-        def render_title_1(self, session):
-            return "Cluster Durable"
-
-        def render_title_2(self, session):
-            return "Not Cluster Durable"
-
-    class LVQField(TwoOptionRadioField):
-        def render_title(self, session):
-            return "Enable Last Value Queue?"
-
-        def render_field_help(self, session):
-            return "(Enable LVQ behavior on the queue)"
-
-        def render_title_1(self, session):
-            return "Enabled"
-
-        def render_title_2(self, session):
-            return "Not Enabled"
-
-    class OptimisticField(TwoOptionRadioField):
-        def render_title(self, session):
-            return "Enable Optimistic Consume?"
-
-        def render_field_help(self, session):
-            return "(Enable optimistic consume on the queue)"
-
-        def render_title_1(self, session):
-            return "Enabled"
-
-        def render_title_2(self, session):
-            return "Not Enabled"
-
-    class PolicyField(RadioField):
-        def __init__(self, app, name):
-            super(QueueForm.PolicyField, self).__init__(app, name, None)
-
-            self.param = Parameter(app, "param")
-            self.param.default = "none"
-            self.add_parameter(self.param)
-
-            option = self.NoneField(app, "none", self.param)
-            self.add_option(option)
-
-            option = self.Reject(app, "reject", self.param)
-            self.add_option(option)
-
-            option = self.Flow(app, "flow", self.param)
-            self.add_option(option)
-
-            option = self.Ring(app, "ring", self.param)
-            self.add_option(option)
-
-            option = self.RingStrict(app, "ring_strict", self.param)
-            self.add_option(option)
-
-        def render_title(self, session):
-            return "Policy-type"
-
-        def render_field_help(self, session):
-            return "(Action taken when queue limit is reached)"
-
-        class NoneField(RadioFieldOption):
-            def render_value(self, session):
-                return "none"
-
-            def render_title(self, session):
-                return "None"
-
-        class Reject(RadioFieldOption):
-            def render_value(self, session):
-                return "reject"
-
-            def render_title(self, session):
-                return "Reject"
-
-        class Flow(RadioFieldOption):
-            def render_value(self, session):
-                return "flow"
-
-            def render_title(self, session):
-                return "Flow to disc"
-
-        class Ring(RadioFieldOption):
-            def render_value(self, session):
-                return "ring"
-
-            def render_title(self, session):
-                return "Ring"
-
-        class RingStrict(RadioFieldOption):
-            def render_value(self, session):
-                return "ring_strict"
-
-            def render_title(self, session):
-                return "Ring Strict"
-
-class QueueAdd(QueueForm):
-    def __init__(self, app, name, vhost):
-        super(QueueAdd, self).__init__(app, name, vhost)
-
-    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):
-        vhost = self.vhost.get(session)
-        name = self.namef.get(session)
-        durable = self.durable.get(session)
-        policy = self.policy.get(session)
-
-        errors, binding_info = self.validate(session, name)
-
-        if not errors:
-            action = self.app.model.broker.add_queue
-            invoc = action.begin(vhost)
-
-            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):
-        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):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, queue):
-        return "Remove Queue '%s'" % queue.name
-
-    def process_submit(self, session, queue):
-        action = self.app.model.queue.remove
-        action.invoke(queue)
-
-        self.process_cancel(session, queue)
-
-    def render_submit_content(self, session, queue):
-        return "Yes, Remove Queue '%s'" % queue.name
-
-    def render_cancel_content(self, session, queue):
-        return "No, Cancel"
-
-class QueuePurge(CuminFieldForm):
-    def __init__(self, app, name):
-        super(QueuePurge, self).__init__(app, name)
-
-        self.purge_request = MultiplicityField(app, "purge_request")
-        self.add_field(self.purge_request)
-
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, queue):
-        return "Purge Messages from  Queue '%s'" % queue.name
-
-    def process_submit(self, session, queue):
-        request_amt = self.purge_request.get(session)
-        args = dict()
-
-        if request_amt == "all":
-            args["request"] = 0
-        elif request_amt == "top":
-            args["request"] = 1
-        elif request_amt == "N":
-            args["request"] = self.purge_request.top_n.get_n_value(session)
-        else:
-            raise Exception("Wrong Value")
-
-        action = self.app.model.queue.purge
-        action.invoke(queue, args)
-
-        self.process_cancel(session, queue)
-
-    def render_submit_content(self, session, queue):
-        return "Yes, Purge Messages from Queue '%s'" % queue.name
-
-    def render_cancel_content(self, session, queue):
-        return "No, Cancel"
-
-class QueueSetPurge(CuminBulkActionForm):
-    def process_return(self, session):
-        branch = session.branch()
-        self.frame.show_view(branch)
-        self.page.set_frame(branch, self.frame)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_item(self, session, id):
-        queue = Queue.get(id)
-
-        args = dict()
-        args["request"] = 0
-
-        action = self.app.model.queue.purge
-        action.invoke(queue, args)
-
-    def render_title(self, session):
-        return "Purge Queues"
-
-    def render_item_content(self, session, id):
-        return "Purge Queue '%s'" % Queue.get(id).name
-
-
-class QueueSetRemove(CuminBulkActionForm):
-    def process_return(self, session):
-        branch = session.branch()
-        self.frame.show_view(branch)
-        self.page.set_frame(branch, self.frame)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    def process_item(self, session, id):
-        queue = Queue.get(id)
-        action = self.app.model.queue.remove
-        action.invoke(queue)
-
-    def render_title(self, session):
-        return "Remove Queues"
-
-    def render_item_content(self, session, id):
-        return "Remove Queue '%s'" % Queue.get(id).name
-
-class BindSummaryPropertiesField(FormField):
-    def __init__(self, app, name):
-        super(BindSummaryPropertiesField, self).__init__(app, name)
-
-        self.sum_props = self.SummaryProperties(app, "properties")
-        self.add_child(self.sum_props)
-
-        self.prop_tmpl = Template(self, "properties_html")
-
-    class SummaryProperties(CuminProperties):
-        def do_get_items(self, session, queue):
-            return [("Name", queue.name),
-                    ("Durable", queue.durable),
-                    ("Exclusive", queue.exclusive),
-                    ("Auto-Delete", queue.autoDelete)]
-
-    def render_inputs(self, session, *args):
-        writer = Writer()
-        self.prop_tmpl.render(writer, session, args)
-        return writer.to_string()
-
-    def render_prop_items(self, session, args):
-        return self.sum_props.render_items(session, *args)
-
-    def get_args(self, session):
-        return (self.frame.frame.get_object(session),)
-
-class QueueBindingAdd(CuminFieldForm):
-    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", self.vhost,
-                                          title="Bind to Exchange:")
-        self.add_field(self.bindings)
-
-        self.errors = self.Errors(self, "errors")
-        self.add_attribute(self.errors)
-
-    class VhostAttribute(Attribute):
-        def get_default(self, session):
-            return self.widget.queue.get(session).vhost
-
-    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):
-        branch = session.branch()
-        self.frame.show_view(branch)
-        self.page.set_redirect_url(session, branch.marshal())
-
-    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):
-            # no exhchanges were selected is not an
-            # error that ExchangeKeysField looks for
-            errors = self.errors.get(session)
-            errs = errors.setdefault("no_exchanges", list())
-            errs.append("At least one exchange must be selected")
-            errors = True
-
-        if errors:
-            pass
-        else:
-            reg = self.frame.frame.get_object(session)
-            args = {
-                    "exchange_keys": form_binding_info,
-                    "reg": reg}
-
-            action = self.app.model.queue.bind
-            action.invoke(queue, args)
-
-            # navigate back to main queue frame
-            self.process_cancel(session)
-
-    def render_title(self, session, *args):
-        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):
-            return dict()
-
-class QueueBindingRemove(CuminConfirmForm):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def process_submit(self, session, binding):
-        log.info("Removing binding %s" % binding)
-
-        self.process_cancel(session, binding)
-
-    def render_title(self, session, binding):
-        return "Remove Binding"
-
-    def render_submit_content(self, session, binding):
-        return "Yes, Remove Binding"
-
-    def render_cancel_content(self, session, binding):
-        return "No, Cancel"
-
-class QueueStats(TabbedModeSet):
-    def __init__(self, app, name):
-        super(QueueStats, self).__init__(app, name)
-
-        self.add_tab(QueueStatsGeneral(app, "gen"))
-        self.add_tab(QueueStatsDurability(app, "dur"))
-        self.add_tab(QueueStatsTransactions(app, "txn"))
-
-    def render_title(self, session):
-        return "Statistics"
-
-class QueueStatsGeneral(Widget):
-    def __init__(self, app, name):
-        super(QueueStatsGeneral, self).__init__(app, name)
-
-        self.add_child(StatSet(app, "general", "general"))
-        self.add_child(StatSet(app, "io", "io"))
-
-        chart = self.EnqueueDequeueRateChart(app, "enqdeq")
-        self.add_child(chart)
-
-        chart = self.DepthChart(app, "depth")
-        self.add_child(chart)
-
-        chart = StatValueChart(app, "consumers")
-        chart.stats = ("consumerCount",)
-        self.add_child(chart)
-
-    def render_title(self, session):
-        return "General"
-
-    class EnqueueDequeueRateChart(StatValueChart):
-        def __init__(self, app, name):
-            super(QueueStatsGeneral.EnqueueDequeueRateChart,
-                  self).__init__(app, name)
-
-            self.stats = ("msgTotalEnqueues", "msgTotalDequeues")
-            self.mode = "rate"
-
-        def render_title(self, session, queue):
-            return "Messages Enqueued and Dequeued"
-
-    class DepthChart(StatValueChart):
-        def __init__(self, app, name):
-            super(QueueStatsGeneral.DepthChart, self).__init__(app, name)
-
-            self.stats = ("msgDepth",)
-
-        def render_title(self, session, queue):
-            return "Queue Depth"
-
-class QueueStatsDurability(Widget):
-    def __init__(self, app, name):
-        super(QueueStatsDurability, self).__init__(app, name)
-
-        self.add_child(StatSet(app, "io", "io.durable"))
-        self.add_child(JournalStats(app, "jrnl", "io.journal"))
-
-        chart = self.EnqueueDequeueRateChart(app, "enqdeq")
-        self.add_child(chart)
-
-    def render_title(self, session):
-        return "Durability"
-
-    class EnqueueDequeueRateChart(StatValueChart):
-        def __init__(self, app, name):
-            super(QueueStatsDurability.EnqueueDequeueRateChart,
-                  self).__init__(app, name)
-
-            self.stats = ("msgPersistEnqueues", "msgPersistDequeues")
-            self.mode = "rate"
-
-        def render_title(self, session, queue):
-            return "Durable Messages Enqueued and Dequeued"
-
-class JournalStats(StatSet):
-    def get_args(self, session):
-        queue = self.frame.get_args(session)[0]
-
-        try:
-            jrnl = Journal.selectBy(queue=queue)[0]
-        except IndexError:
-            jrnl = None
-
-        return (jrnl,)
-
-    def render_title(self, session, jrnl):
-        return "Journal"
-
-    def do_render(self, session, jrnl):
-        if jrnl:
-            return super(JournalStats, self).do_render(session, jrnl)
-        else:
-            return "<div class=\"iblock\">%s</div>" % fmt_none()
-
-class QueueStatsTransactions(Widget):
-    def __init__(self, app, name):
-        super(QueueStatsTransactions, self).__init__(app, name)
-
-        self.add_child(StatSet(app, "transactions", "txn"))
-        self.add_child(StatSet(app, "io", "io.txn"))
-
-        chart = self.EnqueueTransactionRateChart(app, "enqtxn")
-        self.add_child(chart)
-
-        chart = self.DequeueTransactionRateChart(app, "deqtxn")
-        self.add_child(chart)
-
-        chart = self.EnqueueDequeueRateChart(app, "enqdeq")
-        self.add_child(chart)
-
-    def render_title(self, session):
-        return "Transactions"
-
-    class EnqueueTransactionRateChart(StatValueChart):
-        def __init__(self, app, name):
-            super(QueueStatsTransactions.EnqueueTransactionRateChart,
-                  self).__init__(app, name)
-
-            self.stats = ("enqueueTxnStarts", "enqueueTxnCommits",
-                          "enqueueTxnRejects")
-            self.mode = "rate"
-
-        def render_title(self, session, queue):
-            return "Enqueue Transaction Operations per Second"
-
-    class DequeueTransactionRateChart(StatValueChart):
-        def __init__(self, app, name):
-            super(QueueStatsTransactions.DequeueTransactionRateChart,
-                  self).__init__(app, name)
-
-            self.stats = ("dequeueTxnStarts", "dequeueTxnCommits",
-                          "dequeueTxnRejects")
-            self.mode = "rate"
-
-        def render_title(self, session, queue):
-            return "Dequeue Transaction Operations per Second"
-
-    class EnqueueDequeueRateChart(StatValueChart):
-        def __init__(self, app, name):
-            super(QueueStatsTransactions.EnqueueDequeueRateChart,
-                  self).__init__(app, name)
-
-            self.stats = ("msgTxnEnqueues", "msgTxnDequeues")
-            self.mode = "rate"
-
-        def render_title(self, session, queue):
-            return "Transactional Messages Enqueued and Dequeued"
-
-class QueueConsumerSet(PaginatedItemSet):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, queue):
-        count = fmt_count(self.get_item_count(session, queue))
-        return "Consumers %s" % count
-
-    def get_item_count(self, session, queue):
-        return queue.consumers.count()
-
-    def do_get_items(self, session, queue):
-        start, end = self.get_bounds(session)
-        return queue.consumers[start:end]
-
-    def render_item_name(self, session, consumer):
-        return consumer.name
-
-    def render_item_messages_consumed(self, session, consumer):
-        return self.app.model.consumer.msgsConsumed.value(consumer)
-
-    def render_item_messages_consumed_rate(self, session, consumer):
-        return self.app.model.consumer.msgsConsumed.rate_html(consumer)
-
-    def render_item_bytes_consumed(self, session, consumer):
-        return self.app.model.consumer.bytesConsumed.value(consumer)
-
-    def render_item_bytes_consumed_rate(self, session, consumer):
-        return self.app.model.consumer.bytesConsumed.rate_html(consumer)
-
-    def render_item_unacked_messages(self, session, consumer):
-        return self.app.model.consumer.unackedMessages.value(consumer)
-
-
-class QueueSelectField(FormField):
-    def __init__(self, app, name, form):
-        super(QueueSelectField, self).__init__(app, name)
-
-        param = QueueParameter(app, "param")
-        self.param = param
-        self.add_parameter(param)
-
-        self.queue_set = self.QueueInputSet(app, "queue_set", param)
-        self.add_child(self.queue_set)
-
-    def get(self, session):
-        return self.param.get(session)
-
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, queue):
-        return "Select the destination queue"
-
-    def render_inputs(self, session, queue):
-        return self.queue_set.render(session)
-
-    class QueueInputSet(RadioInputSet):
-        def get_args(self, session):
-            return self.frame.get_args(session)
-
-        def do_get_items(self, session, queue):
-            queue_list_full = sorted_by(list(queue.vhost.queues))
-            delta = timedelta(minutes=10)
-            queue_list = []
-            for _queue in queue_list_full:
-                if (_queue.qmfUpdateTime > (datetime.now() - delta)) and (_queue.name != queue.name):
-                    queue_list.append(_queue)
-            return queue_list
-
-        def render_item_value(self, session, queue):
-            return queue.id
-
-        def render_item_content(self, session, queue):
-            return queue.name or "<em>Default</em>"
-
-        def render_item_checked_attr(self, session, queue):
-            return queue is self.param.get(session) and "checked=\"checked\"" or None
-
-class QueueMoveMessages(CuminFieldForm):
-    def __init__(self, app, name):
-        super(QueueMoveMessages, self).__init__(app, name)
-
-        self.move_to = QueueSelectField(app, "move_to", self)
-        self.add_field(self.move_to)
-
-        self.move_qty = MultiplicityField(app, "move_qty")
-        self.add_field(self.move_qty)
-
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, queue):
-        return "Move Messages from  Queue '%s'" % queue.name
-
-    def process_submit(self, session, queue):
-        request_qty = self.move_qty.get(session)
-        args = dict()
-        args["destQueue"] = self.move_to.get(session).name
-        args["srcQueue"] = queue.name
-
-        if request_qty == "all":
-            args["qty"] = 0
-        elif request_qty == "top":
-            args["qty"] = 1
-        elif request_qty == "N":
-            args["qty"] = self.move_qty.top_n.get_n_value(session)
-        else:
-            raise Exception("Wrong Value")
-
-        action = self.app.model.queue.move_messages
-        action.invoke(queue, args)
-        self.process_cancel(session, queue)
-
-    def render_submit_content(self, session, queue):
-        return "Yes, Move Messages from Queue '%s'" % queue.name
-
-    def render_cancel_content(self, session, queue):
-        return "No, Cancel"

Deleted: mgmt/trunk/cumin/python/cumin/queue.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/queue.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/queue.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,254 +0,0 @@
-[QueueSet.sql]
-select
-  q.id,
-  q.name,
-  c.consumer_count as consumers,
-  c.binding_count as bindings,
-  (c.msg_total_enqueues - p.msg_total_enqueues)
-   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as menqueued,
-  case when p.msg_total_enqueues is null then true else false end as menqueued_is_null,
-  (c.byte_total_enqueues - p.byte_total_enqueues)
-   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as benqueued,
-  case when p.byte_total_enqueues is null then true else false end as benqueued_is_null,
-  (c.msg_total_dequeues - p.msg_total_dequeues)
-   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as mdequeued,
-  case when p.msg_total_dequeues is null then true else false end as mdequeued_is_null,
-  (c.byte_total_dequeues - p.byte_total_dequeues)
-   / (extract(epoch from (c.qmf_update_time - p.qmf_update_time)) + 0.0001) as bdequeued,
-  case when p.byte_total_dequeues is null then true else false end as bdequeued_is_null,
-  c.msg_depth as mdepth,
-  c.byte_depth as bdepth,
-  1 as mdepthaccel,
-  1 as bdepthaccel,
-  c.qmf_update_time
-from queue as q
-left outer join queue_stats as c on c.id = q.stats_curr_id
-left outer join queue_stats as p on p.id = q.stats_prev_id
-{sql_where}
-{sql_orderby}
-{sql_limit}
-
-[QueueSet.count_sql]
-select count(*)
-from queue as q
-left outer join queue_stats as c on c.id = q.stats_curr_id
-{sql_where}
-
-[QueueSet.html]
-<form id="{id}" method="post" action="?">
-  <ul class="actions">
-    <li><a class="nav" href="{add_queue_url}">Add New Queue</a></li>
-  </ul>
-  <div class="rfloat">{phase}</div>
-  {unit}
-
-  <div class="sactions">
-    <h2>Act on Selected Queues:</h2>
-    {purge} {remove}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-        <th class="setnav" colspan="{column_count}">
-          <div class="rfloat">{page}</div>
-          {count}
-        </th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>
-
-[TopQueueSet.sql]
-select
-  q.id,
-  q.name,
-  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 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'
-order by enqueues desc
-limit 5
-
-[TopQueueSet.count_sql]
---
-
-[QueueStatus.html]
-<div id="{id}" class="CuminStatus {color}">
-  <table>
-    <tr>
-      <th></th>
-      <th style="width: 35%;" class="ralign">Messages</th>
-      <th style="width: 35%;" class="ralign">Bytes</th>
-    </tr>
-    <tr>
-      <th>Enqueued</th>
-      <td class="ralign">{messages_enqueued}</td>
-      <td class="ralign">{bytes_enqueued}</td>
-    </tr>
-    <tr>
-      <th>Dequeued</th>
-      <td class="ralign">{messages_dequeued}</td>
-      <td class="ralign">{bytes_dequeued}</td>
-    </tr>
-    <tr>
-      <th>Depth</th>
-      <td class="ralign">{message_depth}</td>
-      <td class="ralign">{byte_depth}</td>
-    </tr>
-  </table>
-</div>
-
-[QueueBindingSet.html]
-<form id="{id}" method="post" action="?">
-  <div class="rfloat">{phase}</div>
-
-  <ul class="actions">
-    <li><a class="nav" href="{add_queue_binding_url}">Add Binding</a></li>
-  </ul>
-
-  <div class="sactions">
-    <h2>Act on Selected Bindings:</h2>
-    {remove}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-	<th class="setnav" colspan="{column_count}">
-	  <div class="rfloat">{page}</div>
-	  {count}
-	</th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>
-
-[ExchangeBindingSet.item_html]
-<tr>{cells}</tr>
-
-[QueueStats.html]
-<ul class="radiotabs tabs">{tabs}</ul>
-<div class="radiotabs mode">{mode}</div>
-
-[QueueStatsGeneral.html]
-<table class="twocol">
-  <tbody>
-  <tr>
-    <td>
-      <h2>Input/Output</h2>
-      {io}
-
-      <h2>General</h2>
-      {general}
-    </td>
-    <td>
-      {enqdeq}
-      {depth}
-      {consumers}
-    </td>
-  </tr>
-  </tbody>
-</table>
-
-[QueueStatsDurability.html]
-<table class="twocol">
-  <tbody>
-  <tr>
-    <td>
-      <h2>Durable Input/Output</h2>
-      {io}
-
-      <h2>Journal</h2>
-      {jrnl}
-    </td>
-    <td>
-      {enqdeq}
-    </td>
-  </tr>
-  </tbody>
-</table>
-
-[JournalStats.html]
-<table id="{id}" class="StatSet">
-  <thead>
-    <tr>
-      <th style="width: 50%; text-align: left;">Statistic</th>
-      <th style="width: 25%;">Value</th>
-      <th style="width: 25%;">Per Second</th>
-    </tr>
-  </thead>
-  <tbody>
-    {items}
-  </tbody>
-</table>
-
-[QueueStatsTransactions.html]
-<table class="twocol">
-  <tbody>
-  <tr>
-    <td>
-      <h2>Transactions</h2>
-      {transactions}
-
-      <h2>Transactional Input/Output</h2>
-      {io}
-    </td>
-    <td>
-      {enqtxn}
-      {deqtxn}
-      {enqdeq}
-    </td>
-  </tr>
-  </tbody>
-</table>
-
-[QueueConsumerSet.html]
-<div class="sactions">
-  <h2>Act on Selected Consumers:</h2>
-  <button>Start</button>
-  <button>Stop</button>
-  <button>Close</button>
-  <button>Throttle</button>
-</div>
-
-<table class="mobjects">
-  <tr>
-    <th><input type="checkbox"/></th>
-    <th>Name</th>
-    <th class="ralign" colspan="2">Msgs. Consumed</th>
-    <th class="ralign" colspan="2">Bytes Consumed</th>
-    <th class="ralign">Msgs. Unacked</th>
-  </tr>
-
-  {items}
-</table>
-
-[QueueConsumerSet.item_html]
-<tr>
-  <td><input type="checkbox"/></td>
-  <td>{item_name}</td>
-  <td class="ralign">{item_messages_consumed_rate}</td>
-  <td class="ralign">{item_messages_consumed}</td>
-  <td class="ralign">{item_bytes_consumed_rate}</td>
-  <td class="ralign">{item_bytes_consumed}</td>
-  <td class="ralign">{item_unacked_messages}</td>
-</tr>
-
-[BindSummaryPropertiesField.properties_html]
-<div class="properties" style="width:80%">
-  <table class="PropertySet">
-    <tbody>
-      {prop_items}
-    </tbody>
-  </table>
-</div>

Deleted: mgmt/trunk/cumin/python/cumin/scheduler.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/scheduler.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/scheduler.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,235 +0,0 @@
-import logging
-
-from wooly import *
-from wooly.widgets import *
-from wooly.forms import *
-from wooly.resources import *
-from wooly.tables import *
-
-from stat import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-from job import *
-
-strings = StringCatalog(__file__)
-log = logging.getLogger("cumin.scheduler")
-
-class SchedulerSet(CuminTable, Form):
-    def __init__(self, app, name):
-        super(SchedulerSet, self).__init__(app, name)
-
-        self.ids = CheckboxIdColumn(app, "id")
-        self.add_column(self.ids)
-
-        col = self.NameColumn(app, "name")
-        self.add_column(col)
-        self.set_default_column(col)
-
-        col = self.SystemColumn(app, "system")
-        self.add_column(col)
-
-        col = self.UsersColumn(app, "users")
-        col.alignment = "right"
-        self.add_column(col)
-
-        col = self.RunningJobsColumn(app, "running")
-        col.alignment = "right"
-        self.add_column(col)
-
-        col = self.HeldJobsColumn(app, "held")
-        col.alignment = "right"
-        self.add_column(col)
-
-        self.__start = self.StartButton(app, "start")
-        self.add_child(self.__start)
-
-        self.__stop = self.StopButton(app, "stop")
-        self.add_child(self.__stop)
-
-    def render_title(self, session, *args):
-        return "Schedulers %s" % fmt_count(Scheduler.select().count())
-
-    class NameColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-        def render_content(self, session, data):
-            sched = Identifiable(data["id"])
-            href = self.page.main.pool.scheduler.get_href(session, sched)
-            return fmt_link(href, data["name"])
-
-    class UsersColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Users"
-
-    class RunningJobsColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Running Jobs"
-
-    class HeldJobsColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Held Jobs"
-
-    class SystemColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "System"
-
-        def render_content(self, session, data):
-            id = data["system_id"]
-
-            if id:
-                sys = Identifiable(id)
-                href = self.page.main.system.get_href(session, sys)
-                return fmt_link(href, data["system_name"])
-
-    class StartButton(FormButton):
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            branch = session.branch()
-            frame = self.frame.show_scheds_start(branch)
-            frame.ids.set(branch, ids)
-            self.page.set_redirect_url(session, branch.marshal())
-
-        def render_content(self, session):
-            return "Start"
-
-    class StopButton(FormButton):
-        def process_submit(self, session):
-            ids = self.parent.ids.get(session)
-            self.parent.ids.clear(session)
-
-            branch = session.branch()
-            frame = self.frame.show_scheds_stop(branch)
-            frame.ids.set(branch, ids)
-            self.page.set_redirect_url(session, branch.marshal())
-
-        def render_content(self, session):
-            return "Stop"
-
-class SchedulerFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(SchedulerFrame, self).__init__(app, name)
-
-        self.object = SchedulerParameter(app, "id")
-        self.add_parameter(self.object)
-
-        view = SchedulerView(app, "view")
-        self.add_mode(view)
-        self.set_view_mode(view)
-
-class SchedulerView(CuminView):
-    def __init__(self, app, name):
-        super(SchedulerView, self).__init__(app, name)
-
-        status = self.SchedulerStatus(app, "status")
-        self.add_child(status)
-
-        self.__tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.__tabs)
-
-        stats = SchedulerStats(app, "stats")
-        self.__tabs.add_tab(stats)
-
-        jobs = SchedulerJobSet(app, "jobs")
-        self.__tabs.add_tab(jobs)
-
-        details = CuminDetails(app, "details")
-        self.__tabs.add_tab(details)
-
-    class SchedulerStatus(StartStopStatus):
-        def get_url(self, session):
-            scheduler = self.get_args(session)[0]
-            if scheduler:
-                return "call.xml?class=scheduler;id=%i;method=GetStarted" % scheduler.id
-
-        def render_title(self, session, *args):
-            return "Scheduler Status"
-
-class SchedulerStats(Widget):
-    def __init__(self, app, name):
-        super(SchedulerStats, self).__init__(app, name)
-
-        stats = StatSet(app, "general", "general")
-        self.add_child(stats)
-
-        chart = self.UsersChart(app, "users")
-        chart.duration.param.default = "h"
-        self.add_child(chart)
-
-        chart = self.JobsChart(app, "jobs")
-        chart.duration.param.default = "h"
-        self.add_child(chart)
-
-    def render_title(self, session):
-        return "Statistics"
-
-    class UsersChart(StatValueChart):
-        def __init__(self, app, name):
-            super(SchedulerStats.UsersChart, self).__init__(app, name)
-
-            self.stats = ("NumUsers",)
-
-        def render_title(self, session, sched):
-            return "Users"
-
-    class JobsChart(StatValueChart):
-        def __init__(self, app, name):
-            super(SchedulerStats.JobsChart, self).__init__ \
-                (app, name)
-
-            self.stats = ("TotalRunningJobs", "TotalIdleJobs", "TotalHeldJobs")
-
-        def render_title(self, session, sched):
-            return "Jobs"
-
-class SchedulerJobSet(JobTab):
-    def __init__(self, app, name):
-        super(SchedulerJobSet, self).__init__(app, name)
-
-    def get_visible_columns(self, session):
-        return self.get_request_visible_columns(session, ["custom_group", "submitter"])
-
-    def render_sql_where(self, session, scheduler):
-        phase_sql = self.get_phase_sql(session)
-        scheduler_sql = "j.scheduler_id = %i" % scheduler.id
-        return "where %s" % " and ".join([phase_sql, scheduler_sql])
-
-    def render_title(self, session, scheduler):
-        where_scheduler = "scheduler_id = %i" % scheduler.id
-        return "Jobs %s" % fmt_count(Job.select(where_scheduler).count())
-
-class SchedulerStart(CuminBulkActionForm):
-    def render_title(self, session, *args):
-        return "Start Scheduler"
-
-    def render_form_heading(self, session, *args):
-        return ""
-
-    def render_item_content(self, session, id):
-        return "Start Scheduler '%s'" % Scheduler.get(id).Name
-
-    def process_item(self, session, item):
-        scheduler = Scheduler.get(item)
-        action = self.app.model.master.start
-        action.invoke(scheduler, {"subsystem": "SCHEDD"})
-        self.process_cancel(session)
-
-class SchedulerStop(CuminBulkActionForm):
-    def render_title(self, session, *args):
-        return "Stop Scheduler"
-
-    def render_form_heading(self, session, *args):
-        return ""
-
-    def render_item_content(self, session, id):
-        return "Stop Scheduler '%s'" % Scheduler.get(id).Name
-
-    def process_item(self, session, item):
-        scheduler = Scheduler.get(item)
-        action = self.app.model.master.stop
-        action.invoke(scheduler, {"subsystem": "SCHEDD"})
-        self.process_cancel(session)

Deleted: mgmt/trunk/cumin/python/cumin/scheduler.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/scheduler.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/scheduler.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,82 +0,0 @@
-[SchedulerSet.sql]
-select
-  s.id,
-  s.name,
-  y.id as system_id,
-  y.node_name as system_name,
-  c.num_users as users,
-  c.total_running_jobs as running,
-  c.total_held_jobs as held
-from scheduler as s
-left outer join scheduler_stats as c on c.id = s.stats_curr_id
-left outer join sysimage as y on s.system = y.node_name
-{sql_where}
-{sql_orderby}
-{sql_limit}
-
-[SchedulerSet.count_sql]
-select count(1) from scheduler as s
-{sql_where}
-
-[SchedulerSet.html]
-<form id="{id}" method="post" action="?">
-  <div class="sactions">
-    <h2>Act on Selected Schedulers:</h2>
-    {start} {stop}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-	<th class="setnav" colspan="{column_count}">
-	  <div class="rfloat">{page}</div>
-	  {count}
-	</th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>
-
-[SchedulerStats.html]
-<table class="twocol">
-  <tbody>
-  <tr>
-    <td>
-      <h2>General</h2>
-      {general}
-    </td>
-    <td>
-      {users}
-      {jobs}
-    </td>
-  </tr>
-  </tbody>
-</table>
-
-[SchedulerJobSet.html]
-<div class="rfloat">{phase}</div>
-
-<form id="{id}" style="clear:right;" method="post" action="?">
-  <div class="sactions">
-    {job_search}
-    <h2>Act on Selected Jobs:</h2>
-    {hold} {release} {remove}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-	<th class="setnav" colspan="{column_count}">
-	  <div class="rfloat">{page}</div>
-	  {count}
-	</th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>

Deleted: mgmt/trunk/cumin/python/cumin/slot.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/slot.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/slot.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,51 +0,0 @@
-import logging
-
-from wooly import *
-from wooly.widgets import *
-from wooly.forms import *
-from wooly.resources import *
-from wooly.tables import *
-
-from widgets import *
-
-strings = StringCatalog(__file__)
-log = logging.getLogger("cumin.job")
-
-# XXX marked for death
-class UniqueSlot(CuminTable):
-    def get_recent_sql_where(self, session):
-        return """
-            s.qmf_update_time > now() - interval '60 minutes'
-            """
-
-    def do_get_items(self, session, *args):
-        cursor = super(UniqueSlot, self).do_get_items(session, *args)
-        items = self.cursor_to_rows(cursor)
-        self.items.set(session, items)
-        return items
-
-class SlotSet(UniqueSlot):
-    def __init__(self, app, name):
-        super(SlotSet, self).__init__(app, name)
-
-        col = self.Name(app, "name")
-        self.add_column(col)
-
-    class Name(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-    def render_items(self, session, *args):
-        """ overridden because a slotset query is expensive.
-            the rows are cached """
-
-        rows = self.get_items(session, *args)
-        writer = Writer()
-
-        for row in rows:
-            self.item_tmpl.render(writer, session, row)
-
-        return writer.to_string()
-
-class SlotStatSet(UniqueSlot):
-    pass

Deleted: mgmt/trunk/cumin/python/cumin/slot.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/slot.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/slot.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,36 +0,0 @@
-[SlotSet.sql]
-select
-  s.id,
-  s.name,
-  s.machine,
-  s.system,
-  s.job_id,
-  j.id as jid,
-  c.activity,
-  c.state
-from slot as s
-left outer join slot_stats as c on c.id = s.stats_curr_id
-left outer join job as j on j.custom_id = s.job_id
-{sql_where}
-{sql_orderby}
-{sql_limit}
-
-[SlotSet.count_sql]
-select count(1)
-from (select distinct name from slot as s {sql_where}) as s
-
-[SlotStatSet.sql]
-select
-  sum(case activity when 'Idle' then 1 else 0 end) as idl,
-  sum(1) as all
-from (select
-  s.name,
-  s.pool,
-  s.qmf_update_time,
-  c.activity
-from slot as s
-left outer join slot_stats as c on c.id = s.stats_curr_id) as s
-{sql_where}
-
-[SlotStatSet.count_sql]
-1

Deleted: mgmt/trunk/cumin/python/cumin/submitter.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/submitter.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/submitter.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,111 +0,0 @@
-import logging
-
-from wooly import *
-from wooly.widgets import *
-from wooly.forms import *
-from wooly.resources import *
-from wooly.tables import *
-
-from stat import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-from job import *
-
-strings = StringCatalog(__file__)
-log = logging.getLogger("cumin.submitter")
-
-class SubmitterSet(CuminTable):
-    def __init__(self, app, name):
-        super(SubmitterSet, self).__init__(app, name)
-
-        col = self.NameColumn(app, "name")
-        self.add_column(col)
-
-        self.set_default_column(col)
-
-    def render_title(self, session):
-        return "Submitters %s" % fmt_count(Submitter.select().count())
-
-    class NameColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-        def render_content(self, session, data):
-            sub = Identifiable(data["id"])
-            href = self.page.main.pool.submitter.get_href(session, sub)
-            return fmt_link(href, data["name"])
-
-class SubmitterFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(SubmitterFrame, self).__init__(app, name)
-
-        self.object = SubmitterParameter(app, "id")
-        self.add_parameter(self.object)
-
-        view = SubmitterView(app, "view")
-        self.add_mode(view)
-        self.set_view_mode(view)
-
-class SubmitterView(CuminView):
-    def __init__(self, app, name):
-        super(SubmitterView, self).__init__(app, name)
-
-        status = SubmitterStatus(app, "status")
-        self.add_child(status)
-
-        self.__tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.__tabs)
-
-        stats = SubmitterStats(app, "stats")
-        self.__tabs.add_tab(stats)
-
-        jobs = SubmitterJobSet(app, "jobs")
-        self.__tabs.add_tab(jobs)
-
-        details = CuminDetails(app, "details")
-        self.__tabs.add_tab(details)
-
-class SubmitterStatus(CuminStatus):
-    def render_title(self, session, submitter):
-        return "Submitter Status"
-
-class SubmitterStats(Widget):
-    def __init__(self, app, name):
-        super(SubmitterStats, self).__init__(app, name)
-
-        stats = StatSet(app, "general", "general")
-        self.add_child(stats)
-
-        chart = self.JobsChart(app, "jobs")
-        self.add_child(chart)
-
-    def render_title(self, session):
-        return "Statistics"
-
-    class JobsChart(StatValueChart):
-        def __init__(self, app, name):
-            super(SubmitterStats.JobsChart, self).__init__ \
-                (app, name)
-
-            self.stats = ("RunningJobs", "IdleJobs", "HeldJobs")
-
-        def render_title(self, session, sched):
-            return "Jobs"
-
-class SubmitterJobSet(JobTab):
-    def __init__(self, app, name):
-        super(SubmitterJobSet, self).__init__(app, name)
-
-    def get_visible_columns(self, session):
-        return self.get_request_visible_columns(session, ["custom_group", "scheduler"])
-
-    def render_sql_where(self, session, submitter):
-        phase_sql = self.get_phase_sql(session)
-        submitter_sql = "j.submitter_id = %i" % submitter.id
-        return "where %s" % " and ".join([phase_sql, submitter_sql])
-
-    def render_title(self, session, submitter):
-        submitter_sql = "submitter_id = %i" % submitter.id
-        return "Jobs %s" % fmt_count(Job.select(submitter_sql).count())

Deleted: mgmt/trunk/cumin/python/cumin/submitter.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/submitter.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/submitter.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,54 +0,0 @@
-[SubmitterSet.sql]
-select
-  s.id,
-  s.name
-from submitter as s
-inner join scheduler as d on s.scheduler_id = d.id
-{sql_where}
-{sql_orderby}
-{sql_limit}
-
-[SubmitterSet.count_sql]
-select count(*) from submitter as s
-inner join scheduler as d on s.scheduler_id = d.id
-{sql_where}
-
-[SubmitterStats.html]
-<table class="twocol">
-  <tbody>
-  <tr>
-    <td>
-      <h2>General</h2>
-      {general}
-    </td>
-    <td>
-      {jobs}
-    </td>
-  </tr>
-  </tbody>
-</table>
-
-[SubmitterJobSet.html]
-<div class="rfloat">{phase}</div>
-<form id="{id}" style="clear:right;" method="post" action="?">
-
-  <div class="sactions">
-    {job_search}
-    <h2>Act on Selected Jobs:</h2>
-    {hold} {release} {remove}
-  </div>
-
-  <table class="mobjects">
-    <thead>
-      <tr>
-	<th class="setnav" colspan="{column_count}">
-	  <div class="rfloat">{page}</div>
-	  {count}
-	</th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>

Deleted: mgmt/trunk/cumin/python/cumin/system.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/system.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/system.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,279 +0,0 @@
-from mint import *
-from wooly import *
-from wooly.widgets import *
-
-from stat import *
-from widgets import *
-from parameters import *
-from formats import *
-from util import *
-from visualizations import SlotMap
-
-strings = StringCatalog(__file__)
-
-class SystemSet(CuminTable, Form):
-    def __init__(self, app, name):
-        super(SystemSet, self).__init__(app, name)
-
-        self.ids = CheckboxIdColumn(app, "id")
-        self.add_column(self.ids)
-
-        col = self.NameColumn(app, "name")
-        self.add_column(col)
-        self.set_default_column(col)
-
-        col = self.KernelColumn(app, "kernel")
-        self.add_column(col)
-
-        col = self.ArchColumn(app, "arch")
-        self.add_column(col)
-
-        col = self.FreeMemoryColumn(app, "mem_free")
-        col.alignment = "right"
-        self.add_column(col)
-
-        col = self.LoadColumn(app, "load")
-        col.alignment = "right"
-        self.add_column(col)
-
-    def render_title(self, session, *args):
-        return "Systems %s" % fmt_count(self.get_item_count(session, *args))
-
-    class NameColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-        def render_content(self, session, data):
-            system = Identifiable(data["id"])
-            href = self.page.main.system.get_href(session, system)
-            return fmt_link(href, fmt_shorten(data["name"]))
-
-    class KernelColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Kernel"
-
-    class ArchColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Arch"
-
-    class FreeMemoryColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Free Memory"
-
-        def render_content(self, session, data):
-            mem_free = data["mem_free"]
-
-            if mem_free:
-                return "%i KB" % mem_free
-            else:
-                return fmt_none_brief()
-
-    class LoadColumn(SqlTableColumn):
-        def render_title(self, session, data):
-            return "Load Average"
-
-        def render_content(self, session, data):
-            load = data["load"]
-
-            if load:
-                return "%0.3f" % load
-            else:
-                return fmt_none_brief()
-
-class TopSystemSet(TopTable):
-    def __init__(self, app, name):
-        super(TopSystemSet, self).__init__(app, name)
-
-        col = self.NameColumn(app, "name")
-        self.add_column(col)
-
-        self.set_default_column(col)
-
-        col = self.LoadColumn(app, "load")
-        col.alignment = "right"
-        self.add_column(col)
-
-    class NameColumn(TopTableColumn):
-        def render_title(self, session, data):
-            return "Name"
-
-        def render_content(self, session, data):
-            system = Identifiable(data["id"])
-            href = self.page.main.system.get_href(session, system)
-            return fmt_link(href, fmt_shorten(data["name"]))
-
-    class LoadColumn(TopTableColumn):
-        def render_title(self, session, data):
-            return "Load Average"
-
-        def render_content(self, session, data):
-            return "%0.3f" % data["load_avg"]
-
-class SystemFrame(CuminFrame):
-    def __init__(self, app, name):
-        super(SystemFrame, self).__init__(app, name)
-
-        self.object = SystemParameter(app, "id")
-        self.add_parameter(self.object)
-
-        self.view = SystemView(app, "view")
-        self.add_mode(self.view)
-        self.set_view_mode(self.view)
-
-class SystemStatus(CuminStatus):
-    def render_mem_free(self, session, system):
-        return self.app.model.system.memFree.value_html(system)
-
-    def render_load_average(self, session, system):
-        return self.app.model.system.loadAverage1Min.value_html(system)
-
-class SystemStats(Widget):
-    def __init__(self, app, name):
-        super(SystemStats, self).__init__(app, name)
-
-        self.add_child(StatSet(app, "stats", "general"))
-
-        chart = StatValueChart(app, "freemem")
-        chart.stats = ("memFree",)
-        self.add_child(chart)
-
-        chart = StatValueChart(app, "loadavg")
-        chart.stats = ("loadAverage1Min",)
-        self.add_child(chart)
-
-        vis = self.SystemSlotMap(app, "system_slot_map")
-        self.add_child(vis)
-
-    def render_title(self, session):
-        return "Statistics"
-
-    def render_slot_job_url(self, session):
-        job = Identifiable("XXX")
-        return self.page.main.pool.job.get_href(session, job)
-
-    class SystemSlotMap(SlotMap):
-        def get_title_name(self, session, sysimage):
-            return sysimage.nodeName
-
-        def render_slot_clip_size(self, session, *args):
-            return 240
-
-class SystemView(CuminView):
-    def __init__(self, app, name):
-        super(SystemView, self).__init__(app, name)
-
-        summary = CuminSummary(app, "summary")
-        self.add_child(summary)
-
-        status = SystemStatus(app, "status")
-        self.add_child(status)
-
-        self.__tabs = TabbedModeSet(app, "tabs")
-        self.add_child(self.__tabs)
-
-        self.__tabs.add_tab(SystemStats(app, "stats"))
-        self.__tabs.add_tab(SystemJobSet(app, "jobs"))
-        self.__tabs.add_tab(SystemSlotSet(app, "slots"))
-        self.__tabs.add_tab(SystemServices(app, "services"))
-        self.__tabs.add_tab(CuminDetails(app, "details"))
-
-from job import JobTab
-
-class SystemJobSet(JobTab):
-    def render_title(self, session, system):
-        return "Grid Jobs %s" % fmt_count(self.get_item_count(session, system))
-
-    def render_sql_where(self, session, system):
-        elems = list()
-        elems.append("s.system = %(nodeName)s")
-        elems.append(self.get_phase_sql(session))
-        return "where %s" % " and ".join(elems)
-
-    def get_sql_values(self, session, system):
-        return {"nodeName": system.nodeName}
-
-from slot import SlotSet
-
-class SystemSlotSet(SlotSet):
-    def get_args(self, session):
-        return self.frame.get_args(session)
-
-    def render_title(self, session, system):
-        # dont' use self.get_item_count because it will cause a costly sql query
-        # instead, use the systemslotset in model so it will be cached
-        count = self.app.model.system.slots.get_slot_count(session, system)
-        return "Grid Slots %s" % fmt_count(count)
-
-    def render_sql_where(self, session, system):
-        elems = list()
-        elems.append("system = %(nodeName)s")
-        recent = self.get_recent_sql_where(session)
-        if recent:
-            elems.append(recent)
-
-        return "where %s" % " and ".join(elems)
-
-    def get_sql_values(self, session, system):
-        return {"nodeName": system.nodeName}
-
-class SystemServices(ItemSet):
-    def render_title(self, session, *args):
-        return "Services"
-
-    def get_args(self, session):
-        return (self.frame.get_object(session),)
-
-    def do_get_items(self, session, system):
-        daemons = list()
-        daemon_types = [Scheduler, Collector, Negotiator]
-        sql = "system = '%s'" % system.nodeName
-
-        for daemon in daemon_types:
-            system_daemons = daemon.select(sql)
-            for devil in system_daemons:
-                try:
-                    daemons.append(devil)
-                except Exception, e:
-                    pass
-
-        # using a loop instead of an sql select with an outer join
-        brokers = Broker.select()
-        for broker in brokers:
-            if broker.system.nodeName == system.nodeName:
-                daemons.append(BrokerRegistration.get(broker.registrationID))
-
-        return daemons
-
-    def render_item_content(self, session, item):
-        if isinstance(item, BrokerRegistration):
-            reg = Identifiable(item.id)
-            self.page.main.set_messaging_tab(session)
-            href = self.page.main.broker.get_href(session, reg)
-            return fmt_link(href, item.url)
-        else:
-            pool = model.Pool.get(item.Pool)
-            self.page.main.pool.set_object(session, pool)
-            self.page.main.show_grid_tab(session)
-            daemon = Identifiable(item.id)
-            if isinstance(item, Collector):
-                self.page.main.pool.view.set_collector_tab(session)
-                href = self.page.main.pool.collector.get_href(session, daemon)
-            elif isinstance(item, Scheduler):
-                self.page.main.pool.view.set_scheduler_tab(session)
-                href = self.page.main.pool.scheduler.get_href(session, daemon)
-            elif isinstance(item, Negotiator):
-                self.page.main.pool.view.set_negotiator_tab(session)
-                href = self.page.main.pool.negotiator.get_href(session, daemon)
-            return fmt_link(href, item.Name)
-
-    def render_item_type(self, session, item):
-        if isinstance(item, Collector):
-            return "Collector"
-        elif isinstance(item, Scheduler):
-            return "Scheduler"
-        elif isinstance(item, Negotiator):
-            return "Negotiator"
-        elif isinstance(item, BrokerRegistration):
-            return "Broker"
-        else:
-            return "Daemon"

Deleted: mgmt/trunk/cumin/python/cumin/system.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/system.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/system.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -1,111 +0,0 @@
-[SystemSet.sql]
-select
-  s.id,
-  s.node_name as name,
-  (s.os_name || ' ' || s.release) as kernel,
-  s.machine as arch,
-  c.mem_free,
-  c.load_average1_min as load
-from sysimage as s
-left outer join sysimage_stats as c on c.id = s.stats_curr_id
-{sql_where}
-{sql_orderby}
-{sql_limit}
-
-[SystemSet.count_sql]
-select count(*) from sysimage as s
-{sql_where}
-
-[SystemSet.html]
-<form id="{id}" method="post" action="?">
-  <table class="mobjects">
-    <thead>
-      <tr>
-        <th class="setnav" colspan="{column_count}">
-          <div class="rfloat">{page}</div>
-          {count}
-        </th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>
-
-[TopSystemSet.sql]
-select
-  s.id,
-  s.node_name as name,
-  c.load_average1_min as load_avg
-from sysimage s
-join sysimage_stats as c on s.stats_curr_id = c.id
-order by load_avg desc
-limit 5
-
-[TopSystemSet.count_sql]
---
-
-[SystemStatus.html]
-<div id="{id}" class="CuminStatus {color}">
-  <table>
-    <tr>
-      <th>Free Memory</th>
-      <td class="ralign">{mem_free}</td>
-    </tr>
-    <tr>
-      <th>Load Average</th>
-      <td class="ralign">{load_average}</td>
-    </tr>
-  </table>
-</div>
-
-[SystemStats.html]
-<table class="twocol">
-  <tbody>
-    <tr>
-      <td>
-        <h2>Memory/Load</h2>
-        {stats}
-	{system_slot_map}
-      </td>
-      <td>
-	{freemem}
-	{loadavg}
-      </td>
-    </tr>
-  </tbody>
-</table>
-<script type="text/javascript">
-    // <![CDATA[
-    var show_slot_job_url = "{slot_job_url}";
-    // ]]>
-</script>
-
-[SystemJobSet.html]
-<div class="rfloat">{phase}</div>
-
-<form id="{id}" style="clear:right;" method="post" action="?">
-  <table class="mobjects">
-    <thead>
-      <tr>
-	<th class="setnav" colspan="{column_count}">
-	  <div class="rfloat">{page}</div>
-	  {count}
-	</th>
-      </tr>
-      <tr>{headers}</tr>
-    </thead>
-    <tbody>{items}</tbody>
-  </table>
-  <div>{hidden_inputs}</div>
-</form>
-
-[SystemServices.html]
-<h2>Services</h2>
-<table class="PropertySet">
-  <tbody>{items}</tbody>
-</table>
-
-[SystemServices.item_html]
-<tr><th>{item_type}</th><td>{item_content}</td></tr>

Modified: mgmt/trunk/cumin/python/cumin/user.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/user.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/user.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -172,7 +172,7 @@
 
     def process_cancel(self, session):
         branch = session.branch()
-        self.page.main.view.show(branch)
+        self.page.main.home.view.show(branch)
         self.page.set_redirect_url(session, branch.marshal())
 
     def process_submit(self, session):

Modified: mgmt/trunk/cumin/python/cumin/visualizations.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/visualizations.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/visualizations.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -11,7 +11,6 @@
 from parameters import *
 from formats import *
 from util import *
-from job import *
 
 strings = StringCatalog(__file__)
 
@@ -53,7 +52,7 @@
 
     def render_slot_job_url(self, session, *args):
         job = Identifiable("XXX")
-        return self.page.main.pool.job.get_href(session, job)
+        return self.page.main.grid.pool.job.get_href(session, job)
 
     def render_slot_clip_size(self, session, *args):
         return 400

Modified: mgmt/trunk/cumin/python/cumin/widgets.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/widgets.py	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/widgets.py	2009-04-09 15:40:23 UTC (rev 3274)
@@ -56,7 +56,10 @@
 
     def show_object(self, session, object):
         self.object.set(session, object)
-        self.__view.show(session)
+
+        if hasattr(self, "view"):
+            self.view.show(session)
+
         return self
 
     def get_args(self, session):
@@ -74,34 +77,9 @@
 
     def get_href(self, session, object):
         branch = session.branch()
-        self.object.set(branch, object)
-        self.__view.show(branch)
+        self.show_object(branch, object)
         return branch.marshal()
 
-    def set_view_mode(self, mode):
-        self.__view = mode
-
-    def show_view(self, session):
-        return self.show_mode(session, self.__view)
-
-    def set_add_mode(self, mode):
-        self.__add = mode
-
-    def show_add(self, session):
-        return self.show_mode(session, self.__add)
-
-    def set_edit_mode(self, mode):
-        self.__edit = mode
-
-    def show_edit(self, session):
-        return self.show_mode(session, self.__edit)
-
-    def set_remove_mode(self, mode):
-        self.__remove = mode
-
-    def show_remove(self, session):
-        return self.show_mode(session, self.__remove)
-
     def do_process(self, session, *args):
         self.page.get_frames(session).append(self)
 
@@ -109,7 +87,10 @@
 
     def render_href(self, session, *args):
         branch = session.branch()
-        self.__view.show(branch)
+
+        if hasattr(self, "view"):
+            self.view.show(branch)
+
         return branch.marshal()
 
     def render_title(self, session, *args):
@@ -123,6 +104,8 @@
     def __init__(self, app, name):
         super(CuminView, self).__init__(app, name)
 
+        self.__frame_tmpl = Template(self, "frame_html")
+
         summary = CuminSummary(app, "summary")
         self.add_child(summary)
 
@@ -138,6 +121,22 @@
     def render_title(self, session, *args):
         return self.frame.render_title(session, *args)
 
+    def render_frames(self, session, *args):
+        writer = Writer()
+
+        for frame in self.page.get_frames(session)[:-1]:
+            self.__frame_tmpl.render(writer, session, frame)
+
+        return writer.to_string()
+
+    def render_frame_href(self, session, frame):
+        args = frame.get_args(session)
+        return frame.render_href(session, *args)
+
+    def render_frame_title(self, session, frame):
+        args = frame.get_args(session)
+        return frame.render_title(session, *args)
+
 class FormHelp(Widget):
     def __init__(self, app, name):
         super(FormHelp, self).__init__(app, name)
@@ -839,7 +838,8 @@
 
         def render_content(self, session, data):
             queue = Queue.get(data["q_id"])
-            href = self.page.main.broker.queue.get_href(session, queue)
+            href = self.page.main.messaging.broker.queue.get_href \
+                (session, queue)
             return fmt_link(href, fmt_shorten(queue.name))
 
     class ENameColumn(SqlTableColumn):
@@ -848,7 +848,8 @@
 
         def render_content(self, session, data):
             exchange = Exchange.get(data["e_id"])
-            href = self.page.main.broker.exchange.get_href(session, exchange)
+            href = self.page.main.messaging.broker.exchange.get_href \
+                (session, exchange)
 
             if exchange.name:
                 name = fmt_shorten(exchange.name)
@@ -1143,7 +1144,7 @@
     def render_script(self, session):
         script = """
         <script type="text/javascript">
-        window.addEvent('domready', function get_%s() { 
+        window.addEvent('domready', function get_%s() {
             var now = new Date();
             wooly.backgroundUpdate('%s'+';ts='+now.getTime(), got_%s, "%s");
         });

Modified: mgmt/trunk/cumin/python/cumin/widgets.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/widgets.strings	2009-04-09 15:40:04 UTC (rev 3273)
+++ mgmt/trunk/cumin/python/cumin/widgets.strings	2009-04-09 15:40:23 UTC (rev 3274)
@@ -16,14 +16,40 @@
 left outer join binding_stats as c on c.id = b.stats_curr_id
 {sql_where}
 
+[CuminView.css]
+ul.context {
+    display: inline;
+    list-style: none;
+    padding: 0;
+    margin: 0;
+    line-height: 1.75em;
+    font-size: 0.9em;
+    color: #fff;
+}
 
+ul.context li {
+    display: inline;
+}
+
+ul.context li:after {
+    content: " > ";
+    font-weight: bold;
+    font-size: 0.8em;
+    color: #ccc;
+}
+
 [CuminView.html]
 {status}
 
+<ul class="context">{frames}</ul>
+
 {summary}
 
 {tabs}
 
+[CuminView.frame_html]
+<li><a href="{frame_href}">{frame_title}</a></li>
+
 [CuminForm.html]
 <form id="{id}" class="mform" method="post" action="?">
   <div class="head">{title}</div>




More information about the rhmessaging-commits mailing list