Author: eallen
Date: 2010-03-23 14:29:24 -0400 (Tue, 23 Mar 2010)
New Revision: 3878
Modified:
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/exchange.py
mgmt/trunk/cumin/python/cumin/messaging/main.py
mgmt/trunk/cumin/python/cumin/messaging/model.py
mgmt/trunk/cumin/python/cumin/messaging/queue.py
mgmt/trunk/cumin/python/cumin/widgets.py
mgmt/trunk/cumin/python/cumin/widgets.strings
mgmt/trunk/cumin/resources/app.css
mgmt/trunk/cumin/resources/app.js
Log:
Add 'Add binding" form to broker pages
Modified Add binding form to:
work given either a broker, queue, or exchange parameter
use an autocomplete edit box for queue and exchange names
bind to only one exchange at a time
display optional argumnents fields based on exchange type
Modified: mgmt/trunk/cumin/python/cumin/messaging/binding.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/binding.py 2010-03-23 17:06:23 UTC (rev 3877)
+++ mgmt/trunk/cumin/python/cumin/messaging/binding.py 2010-03-23 18:29:24 UTC (rev 3878)
@@ -93,234 +93,6 @@
binding = Binding.get(data["id"])
return self.app.model.binding.msgMatched.value(binding)
-class ExchangeInput(Widget):
- def __init__(self, app, name):
- super(ExchangeInput, self).__init__(app, name)
-
- self.exchange = None
- self.instance_data = None
-
- self.name_tmpl = WidgetTemplate(self, "name_html")
- self.key_tmpl = WidgetTemplate(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)
@@ -335,168 +107,109 @@
return self.get(session) == "c"
class ExchangeKeysField(FormField):
- def __init__(self, app, name, vhost, title="Initial bindings:"):
+ def __init__(self, app, name, exchange):
super(ExchangeKeysField, self).__init__(app, name)
- assert vhost
+ self.title = "Initial bindings"
+ self.exchange = exchange
- self.vhost = vhost
+ name = StringParameter(app, "name")
+ self.names = ListParameter(app, "names", name)
+ self.add_parameter(self.names)
- self.dict_param = DictParameter(app, "exchange")
- self.add_parameter(self.dict_param)
+ value = StringParameter(app, "value")
+ self.values = ListParameter(app, "values", value)
+ self.add_parameter(self.values)
- self.direct_input = DirectExchangeInput(app, "direct")
- self.add_child(self.direct_input)
+ self.count = IntegerParameter(app, "count")
+ self.count.default = 3
+ self.add_parameter(self.count)
- self.topic_input = TopicExchangeInput(app, "topic")
- self.add_child(self.topic_input)
+ self.inputs_container_tmpl = WidgetTemplate(self,
"input_container_html")
+ self.inputs_tmpl = WidgetTemplate(self, "inputs_html")
- self.fanout_input = FanoutExchangeInput(app, "fanout")
- self.add_child(self.fanout_input)
+ def init(self):
+ """ we added parameters directly to the FormField instead
+ of adding FormInputs. XXX should this logic be moved up to FormField?
"""
+ super(ExchangeKeysField, self).init()
+ for param in self.parameters:
+ self.form.form_params.add(param)
- 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
+ def render_input_fields(self, session, *args):
+ count = self.count.get(session)
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))
+ for i in range(count):
+ self.inputs_tmpl.render(writer, session, i)
+ return writer.to_string()
+ def render_inputs(self, session, *args):
+ writer = Writer()
+ self.inputs_container_tmpl.render(writer, session, *args)
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)
+ def render_n_name(self, session, i):
+ return self.names.path
- 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"]
+ def render_v_name(self, session, i):
+ return self.values.path
- return (len(berrs), form_binding_info)
+ def render_n_value(self, session, i):
+ names = self.names.get(session)
+ return len(names) > i and names[i] or ""
- 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
+ def render_v_value(self, session, i):
+ values = self.values.get(session)
+ return len(values) > i and values[i] or ""
- 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
+ def get(self, session):
+ ret_dict = dict()
+ exchange = self.exchange.get(session)
+ if exchange:
+ if exchange.type == "headers" or exchange.type == "xml":
+ names = self.names.get(session)
+ values = self.values.get(session)
- 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
+ for name, value in zip(names, values):
+ if name:
+ ret_dict[name] = value
+ return ret_dict
- return form_binding_info
+ def validate(self, session):
+ exchange = self.exchange.get(session)
+ names = self.names.get(session)
+ values = self.values.get(session)
+ if exchange:
+ if exchange.type == "headers":
+ if not "x-match" in names:
+ error = FormError("x-match argument is required for this
exchange")
+ self.form.errors.add(session, error)
+
+ for i in range(len(names)):
+ if names[i]:
+ if names[i] == "x-match":
+ if not values[i] == "all" and not values[i] ==
"any":
+ error = FormError("Argument name x-match must have a
value of <i>all</i> or <i>any</i>")
+ self.form.errors.add(session, error)
+ else:
+ if not values[i]:
+ error = FormError("Missing argument value for name:
%s" % names[i])
+ self.form.errors.add(session, error)
+
+ for i in range(len(values)):
+ if values[i]:
+ if not names[i]:
+ error = FormError("Missing argument name for value:
%s" % values[i])
+ self.form.errors.add(session, error)
+
+ elif exchange.type == "xml":
+ if not "xquery" in names:
+ error = FormError("xquery argument is required for this
exchange")
+ self.form.errors.add(session, error)
+
class BindingSetTaskForm(CuminTaskForm):
def __init__(self, app, name, task):
super(BindingSetTaskForm, self).__init__(app, name, task)
@@ -505,5 +218,3 @@
self.object = ListParameter(app, "binding", item)
self.add_parameter(self.object)
-
-from exchange import ExchangeInfo
Modified: mgmt/trunk/cumin/python/cumin/messaging/binding.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/binding.strings 2010-03-23 17:06:23 UTC (rev
3877)
+++ mgmt/trunk/cumin/python/cumin/messaging/binding.strings 2010-03-23 18:29:24 UTC (rev
3878)
@@ -16,172 +16,26 @@
left outer join binding_stats as c on c.id = b.stats_curr_id
{sql_where}
-[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> </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> </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> </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]
-table.FormFieldSet div.inputs {
- position: relative;
- left: -4em;
-}
-
-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 {
+table th.NameHeader {
+ color: red;
+ font-size: 0.8em;
font-weight: bold;
+ text-align: left;
}
-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);
+[ExchangeKeysField.input_container_html]
+<table>
+ <tr>
+ <th class="NameHeader">Name</th>
+ <th class="NameHeader">Value</th>
+ </tr>
+ {input_fields}
+</table>
- if (chk.checked) {
- display = "table-row";
- }
-
- headers_extra.style.display = display;
-}
-
-[ExchangeKeysField.html]
+[ExchangeKeysField.inputs_html]
<tr>
- <th>
- <div class="title">{title}</div>
- <div class="help">{help}</div>
- </th>
- <td>
- <div class="rfloat">{phase}</div>
- <div class="rclear"> </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>
- </td>
+ <td><input class="NameInput" type="text"
size="15" name="{n_name}" value="{n_value}"
tabindex="100"/> = </td>
+ <td><input class="ValueInput" type="text"
size="15" name="{v_name}" value="{v_value}"
tabindex="100"/></td>
</tr>
Modified: mgmt/trunk/cumin/python/cumin/messaging/broker.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/broker.py 2010-03-23 17:06:23 UTC (rev 3877)
+++ mgmt/trunk/cumin/python/cumin/messaging/broker.py 2010-03-23 18:29:24 UTC (rev 3878)
@@ -358,3 +358,164 @@
if len(brokers):
self.task.invoke(session, brokers, groups)
self.task.exit_with_redirect(session, brokers)
+
+class BindingAddForm(FieldSubmitForm):
+ def __init__(self, app, name, task):
+ super(BindingAddForm, self).__init__(app, name)
+
+ self.task = task
+
+ self.vhost = VhostParameter(app, "vhost")
+ self.add_parameter(self.vhost)
+
+ self.queue = QueueParameter(app, "queue")
+ self.add_parameter(self.queue)
+ self.q_field = self.QueueBindingField(app, "q_field", self.vhost,
self.queue)
+ self.add_field(self.q_field)
+
+ self.exchange = ExchangeParameter(app, "exchange")
+ self.add_parameter(self.exchange)
+ self.x_field = self.ExchangeBindingField(app, "x_field", self.vhost,
self.exchange)
+ self.add_field(self.x_field)
+
+ self.key = self.KeyField(app, "key")
+ self.add_field(self.key)
+
+ self.bindings = self.ExchangeBindings(app, "bindings", self.exchange)
+ self.add_field(self.bindings)
+
+ def init(self):
+ super(BindingAddForm, self).init()
+ self.form_params.add(self.queue)
+ self.form_params.add(self.exchange)
+
+ def render_title(self, session):
+ obj = self.vhost.get(session)
+ if self.queue.get(session):
+ obj = self.queue.get(session)
+ if self.exchange.get(session):
+ obj = self.exchange.get(session)
+ return self.task.get_description(session, obj)
+
+ def render_key_id(self, session):
+ return self.key.path
+
+ def validate(self, session):
+ super(BindingAddForm, self).validate(session)
+
+ queue = self.queue.get(session)
+ exchange = self.exchange.get(session)
+ key = self.key.get(session)
+
+ if not queue:
+ error = FormError("A valid queue name is required")
+ self.errors.add(session, error)
+ if not exchange:
+ error = FormError("A valid exchange name is required")
+ self.errors.add(session, error)
+ else:
+ if not exchange.type == "fanout":
+ if not key:
+ error = MissingValueError(self.key)
+ self.errors.add(session, error)
+
+ def process_submit(self, session):
+ self.validate(session)
+ if not self.errors.get(session):
+ vhost = self.vhost.get(session)
+ queue = self.queue.get(session)
+ exchange = self.exchange.get(session)
+ key = self.key.get(session)
+ arguments = self.bindings.get(session)
+
+ self.task.task_invoke(session, vhost, queue, exchange, key, arguments)
+ self.task.exit_with_redirect(session, queue)
+
+ class KeyField(StringField):
+ def render_row_id(self, session):
+ return "id='%s'" % self.path
+
+ def render_title(self, session):
+ return "Binding Key"
+
+ class QueueBindingField(ScalarField):
+ def __init__(self, app, name, vhost, queue):
+ input = QueueInput(app, "input", vhost, queue)
+ super(BindingAddForm.QueueBindingField, self).__init__(app, name, input)
+ self.add_child(input)
+
+ def render_title(self, session):
+ return "Queue"
+
+ class ExchangeBindingField(ScalarField):
+ def __init__(self, app, name, vhost, exchange):
+ input = ExchangeInput(app, "input", vhost, exchange)
+ super(BindingAddForm.ExchangeBindingField, self).__init__(app, name, input)
+ self.add_child(input)
+
+ def render_title(self, session):
+ return "Exchange"
+
+ class ExchangeBindings(ExchangeKeysField):
+ def render_id(self, session, *args):
+ s = fmt_bytes(1)
+ cls = "ExchangeHiddenRow"
+ exchange = self.exchange.get(session)
+ if exchange and exchange.type == 'headers':
+ cls = ""
+ return cls and "%s\" class=\"%s" % (self.path, cls) or
self.path
+
+ def render_title(self, session):
+ return "Arguments"
+
+class BaseBindingInput(IncrementalSearchInput):
+ def __init__(self, app, name, vhost, field_param):
+ super(BaseBindingInput, self).__init__(app, name, field_param)
+
+ self.vhost = vhost
+ self.field = field_param
+
+ def render_item_content(self, session, field):
+ return field.name or "Default"
+
+ def render_item_value(self, session, field):
+ return field.id
+
+ def render_value(self, session):
+ if self.disabled:
+ field = self.field.get(session)
+ return fmt_shorten(field.name, pre=36, post=4)
+ else:
+ input_value = self.param.get(session)
+ return input_value and input_value or ""
+
+ def base_get_items(self, session, objects):
+ obj_list = []
+ if not self.disabled:
+ obj_list_full = sorted_by(list(objects))
+
+ delta = timedelta(minutes=10)
+ for _obj in obj_list_full:
+ if (_obj.qmfUpdateTime > (datetime.now() - delta)):
+ obj_list.append(_obj)
+
+ return obj_list
+
+class QueueInput(BaseBindingInput):
+ def do_get_items(self, session):
+ vhost = self.vhost.get(session)
+ return self.base_get_items(session, vhost.queues)
+
+class ExchangeInput(BaseBindingInput):
+ def render_item_value(self, session, exchange):
+ return "%s|%s" % (exchange.id, exchange.type)
+
+ def render_key_id(self, session):
+ return self.parent.parent.parent.key.path
+
+ def render_args_id(self, session):
+ return self.parent.parent.parent.bindings.path
+
+ def do_get_items(self, session):
+ vhost = self.vhost.get(session)
+ return sorted_by(list(vhost.exchanges))
\ No newline at end of file
Modified: mgmt/trunk/cumin/python/cumin/messaging/broker.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/broker.strings 2010-03-23 17:06:23 UTC (rev
3877)
+++ mgmt/trunk/cumin/python/cumin/messaging/broker.strings 2010-03-23 18:29:24 UTC (rev
3878)
@@ -149,3 +149,45 @@
window.addEvent('domready',function () {
$$('button')[0].focus();
});
+
+[BindingAddForm.javascript]
+function bindingExchangeChanged(xtype, keyid, argsid) {
+ var keyrow = $(keyid);
+ var keytitle = keyrow.getElement('div');
+ var keyinput = keyrow.getElement('input');
+ if (xtype == 'fanout') {
+ keyinput.setProperty('disabled', true);
+ } else {
+ keyinput.setProperty('disabled', false);
+ }
+ var argsrow = $(argsid);
+ if (xtype == 'headers') {
+ argsrow.setStyle('display', 'table-row');
+ var names = argsrow.getElements("input.NameInput");
+ names.each( function (item, index) { item.value = ""; } );
+ names[0].value = "x-match";
+ names[1].focus();
+ var values = argsrow.getElements("input.ValueInput");
+ values.each( function (item, index) { item.value = ""; } );
+ values[0].value = "all";
+ } else {
+ argsrow.setStyle('display', 'none');
+ }
+}
+
+[ExchangeBindings.css]
+tr.ExchangeHiddenRow {
+ display: none;
+}
+
+[ExchangeInput.select_html]
+ function (value, data) {
+ if (typeof data == "undefined")
+ data = "|";
+ var exchangeData = data.split('|');
+ var xid = exchangeData[0], xtype = exchangeData[1];
+ var xinput = document.forms[0].elements['{alt_value_path}'];
+ xinput.value = xid;
+ bindingExchangeChanged(xtype, '{key_id}', '{args_id}');
+ }
+
Modified: mgmt/trunk/cumin/python/cumin/messaging/exchange.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/exchange.py 2010-03-23 17:06:23 UTC (rev
3877)
+++ mgmt/trunk/cumin/python/cumin/messaging/exchange.py 2010-03-23 18:29:24 UTC (rev
3878)
@@ -228,6 +228,9 @@
self.set_default_column_name("q_id")
+ task = main.module.xbinding_add
+ self.links.add_child(TaskLink(app, "add", task, self.exchange))
+
def get_visible_columns(self, session):
return self.get_request_visible_columns(session, ["q_id"])
Modified: mgmt/trunk/cumin/python/cumin/messaging/main.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/main.py 2010-03-23 17:06:23 UTC (rev 3877)
+++ mgmt/trunk/cumin/python/cumin/messaging/main.py 2010-03-23 18:29:24 UTC (rev 3878)
@@ -19,6 +19,7 @@
self.exchange_add = ExchangeAddTask(app, broker)
self.link_add = LinkAddTask(app, broker)
self.queue_add = QueueAddTask(app, broker)
+ self.bbinding_add = BindingAddTask(app, broker)
broker_group = app.model.broker_group
@@ -34,13 +35,14 @@
self.queue_set_remove = QueueSetRemoveTask(app, queue)
self.queue_purge = QueuePurgeTask(app, queue)
self.queue_set_purge = QueueSetPurgeTask(app, queue)
- self.binding_add = BindingAddTask(app, queue)
+ self.qbinding_add = QBindingAddTask(app, queue)
self.move_messages = MoveMessagesTask(app, queue)
exchange = app.model.exchange
self.exchange_remove = ExchangeRemoveTask(app, exchange)
self.exchange_set_remove = ExchangeSetRemoveTask(app, exchange)
+ self.xbinding_add = XBindingAddTask(app, exchange)
binding = app.model.binding
Modified: mgmt/trunk/cumin/python/cumin/messaging/model.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/model.py 2010-03-23 17:06:23 UTC (rev 3877)
+++ mgmt/trunk/cumin/python/cumin/messaging/model.py 2010-03-23 18:29:24 UTC (rev 3878)
@@ -161,27 +161,6 @@
def do_enter(self, session, queues):
self.form.object.set(session, queues)
-class BindingAddTask(Task):
- def __init__(self, app, cls):
- super(BindingAddTask, self).__init__(app, cls)
-
- self.form = BindingAddForm(app, "binding_add", self)
-
- def get_title(self, session):
- return "Add binding"
-
- def get_description(self, session, queue):
- return "Add binding to queue '%s'" % queue.name
-
- def do_enter(self, session, queue):
- self.form.queue.set(session, queue)
-
- def do_invoke(self, session, queue, exchange, binding_key, arguments):
- session = self.app.model.get_session_by_object(queue)
- session.exchange_bind(queue=queue.name, exchange=exchange.name,
- binding_key=binding_key, arguments=arguments)
- session.sync()
-
class BindingRemoveTask(Task):
def __init__(self, app, cls):
super(BindingRemoveTask, self).__init__(app, cls)
@@ -492,3 +471,68 @@
port = broker.port
return "%s:%i" % (name, port)
+
+class BindingAddTask(Task):
+ def __init__(self, app, cls, name=None):
+ super(BindingAddTask, self).__init__(app, cls)
+
+ name = name or "bbinding_add"
+ self.form = BindingAddForm(app, name, self)
+
+ def get_title(self, session):
+ return "Add binding"
+
+ def get_description(self, session, vhost):
+ return "Add binding to broker '%s'" % get_vhost_name(vhost)
+
+ def do_enter(self, session, vhost):
+ self.form.vhost.set(session, vhost)
+
+ def task_invoke(self, session, vhost, queue, exchange, key, arguments):
+ self.invoke(session, vhost, queue, exchange, key, arguments)
+
+ def do_invoke(self, session, vhost, queue, exchange, binding_key, arguments):
+ msess = self.app.model.get_session_by_object(vhost)
+ msess.exchange_bind(queue=queue.name, exchange=exchange.name,
+ binding_key=binding_key, arguments=arguments)
+ msess.sync()
+
+class QBindingAddTask(BindingAddTask):
+ def __init__(self, app, cls):
+ super(QBindingAddTask, self).__init__(app, cls, "qbinding_add")
+
+ self.form.q_field.input.disabled = True
+
+ def get_description(self, session, queue):
+ return "Add binding to queue '%s'" % queue.name
+
+ def do_enter(self, session, queue):
+ super(QBindingAddTask, self).do_enter(session, queue.vhost)
+ self.form.queue.set(session, queue)
+
+ def task_invoke(self, session, vhost, queue, exchange, key, arguments):
+ """ invoke needs to be called with the tasks's object first
"""
+ self.invoke(session, queue, vhost, exchange, key, arguments)
+
+ def do_invoke(self, session, queue, vhost, exchange, binding_key, arguments):
+ super(QBindingAddTask, self).do_invoke(session, vhost, queue, exchange,
binding_key, arguments)
+
+class XBindingAddTask(BindingAddTask):
+ def __init__(self, app, cls):
+ super(XBindingAddTask, self).__init__(app, cls, "xbinding_add")
+
+ self.form.x_field.input.disabled = True
+
+ def get_description(self, session, exchange):
+ return "Add binding to exchange '%s'" % exchange.name
+
+ def do_enter(self, session, exchange):
+ super(XBindingAddTask, self).do_enter(session, exchange.vhost)
+ self.form.exchange.set(session, exchange)
+
+ def task_invoke(self, session, vhost, queue, exchange, key, arguments):
+ """ invoke needs to be called with the tasks's object first
"""
+ self.invoke(session, exchange, vhost, queue, key, arguments)
+
+ def do_invoke(self, session, exchange, vhost, queue, binding_key, arguments):
+ super(XBindingAddTask, self).do_invoke(session, vhost, queue, exchange,
binding_key, arguments)
Modified: mgmt/trunk/cumin/python/cumin/messaging/queue.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/messaging/queue.py 2010-03-23 17:06:23 UTC (rev 3877)
+++ mgmt/trunk/cumin/python/cumin/messaging/queue.py 2010-03-23 18:29:24 UTC (rev 3878)
@@ -220,7 +220,7 @@
self.set_default_column_name("e_id")
- task = main.module.binding_add
+ task = main.module.qbinding_add
self.links.add_child(TaskLink(app, "add", task, self.queue))
def get_visible_columns(self, session):
@@ -289,8 +289,8 @@
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)
+ #self.bindings = ExchangeKeysField(app, "bindings", self.vhost)
+ #self.add_field(self.bindings)
class AdvancedOptions(MoreFieldSet):
def render_title(self, session):
@@ -450,11 +450,11 @@
errors = self.errors.get(session)
- binding_errors, binding_info = self.bindings.get_binding_errors \
- (session, name)
+ #binding_errors, binding_info = self.bindings.get_binding_errors \
+ # (session, name)
- if not errors:
- errors = binding_errors
+ #if not errors:
+ # errors = binding_errors
if not errors:
invoc = self.task.start(session, vhost)
@@ -486,6 +486,7 @@
durable=durable,
arguments=args)
+ """
for exchange in binding_info:
if "key" in binding_info[exchange]:
binding_key = binding_info[exchange]["key"]
@@ -499,6 +500,7 @@
exchange=ename,
binding_key=binding_key,
arguments=eargs)
+ """
self.task.end(invoc)
except Exception, e:
@@ -587,53 +589,6 @@
def render_prop_items(self, session):
return self.sum_props.render_items(session)
-class BindingAddForm(FieldSubmitForm):
- def __init__(self, app, name, task):
- super(BindingAddForm, self).__init__(app, name)
-
- self.task = task
-
- self.queue = QueueParameter(app, "queue")
- self.add_parameter(self.queue)
-
- self.vhost = self.VhostAttribute(app, "vhost")
- self.add_attribute(self.vhost)
-
- self.props = BindSummaryPropertiesField(app, "props", self.queue)
- self.add_field(self.props)
-
- self.bindings = self.ExchangeBindings(app, "bindings", self.vhost)
- self.add_field(self.bindings)
-
- class ExchangeBindings(ExchangeKeysField):
- def render_title(self, session):
- return "Exchange Bindings"
-
- class VhostAttribute(Attribute):
- def get(self, session):
- return self.widget.queue.get(session).vhost
-
- 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 exchanges were selected is not an error that
- # ExchangeKeysField looks for
- error = FormError("At least one exchange must be selected")
- self.errors.add(session, error)
-
- if not self.errors.get(session):
- print "XXX queue binding add", queue, form_binding_info
-
- #self.task.invoke(session, queue, args)
- self.task.exit_with_redirect(session, queue)
-
- def render_title(self, session):
- queue = self.queue.get(session)
- return self.task.get_description(session, queue)
-
class BindingRemoveForm(CuminTaskForm):
def __init__(self, app, name, task):
super(BindingRemoveForm, self).__init__(app, name, task)
@@ -767,17 +722,15 @@
return "Transactional messages enqueued and dequeued"
class QueueSelectField(FormField):
- def __init__(self, app, name, form):
+ def __init__(self, app, name, form, queue):
super(QueueSelectField, self).__init__(app, name)
- self.queue_set = self.QueueSearchInputSet(app, "queue_set")
+ self.queue = queue
+ self.queue_set = self.QueueSearchInputSet(app, "queue_set",
self.queue)
self.add_child(self.queue_set)
- self.param = self.QueueStringParameter(app, "param", self.queue_set)
- self.add_parameter(self.param)
-
def get(self, session):
- return self.param.get(session)
+ return self.queue.get(session)
def render_title(self, session):
return "Select the destination queue"
@@ -787,7 +740,7 @@
class QueueSearchInputSet(IncrementalSearchInput):
def do_get_items(self, session):
- queue = self.form.queue.get(session) # XXX
+ queue = self.value_param.get(session) # XXX
queue_list_full = sorted_by(list(queue.vhost.queues))
delta = timedelta(minutes=10)
queue_list = []
@@ -800,20 +753,6 @@
def render_item_content(self, session, queue):
return queue.name or "<em>Default</em>"
- class QueueStringParameter(Parameter):
- def __init__(self, app, name, queue_string):
- super(QueueSelectField.QueueStringParameter, self).__init__(app, name)
-
- self.queue_string = queue_string
-
- def get(self, session):
- queue_string = self.queue_string.get(session)
- queue_where = "name = '%s'" % queue_string
- try:
- return Queue.select(queue_where)[0]
- except IndexError:
- return None
-
class MoveMessagesForm(FieldSubmitForm):
def __init__(self, app, name, task):
super(MoveMessagesForm, self).__init__(app, name)
@@ -823,7 +762,7 @@
self.queue = QueueParameter(app, "queue")
self.add_parameter(self.queue)
- self.dest_queue = QueueSelectField(app, "dest", self)
+ self.dest_queue = QueueSelectField(app, "dest", self, self.queue)
self.add_field(self.dest_queue)
self.count = MultiplicityField(app, "count")
Modified: mgmt/trunk/cumin/python/cumin/widgets.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/widgets.py 2010-03-23 17:06:23 UTC (rev 3877)
+++ mgmt/trunk/cumin/python/cumin/widgets.py 2010-03-23 18:29:24 UTC (rev 3878)
@@ -1529,8 +1529,39 @@
import cumin.account.model
class IncrementalSearchInput(StringInput, ItemSet):
+ def __init__(self, app, name, field_param):
+ super(IncrementalSearchInput, self).__init__(app, name)
+
+ self.disabled_tmpl = WidgetTemplate(self, "disabled_html")
+ self.select_tmpl = WidgetTemplate(self, "select_html")
+
+ self.value_param = field_param
+
def do_get_items(self, session):
return ()
def render_item_class(self, session, item):
return "list_item"
+
+ def render_alt_value_path(self, session):
+ return self.value_param.path
+
+ def render_alt_value(self, session):
+ value_param = self.value_param.get(session)
+ return value_param and value_param.id or ""
+
+ def render_select(self, session, *args):
+ writer = Writer()
+ self.select_tmpl.render(writer, session, *args)
+ return writer.to_string()
+
+ def do_render(self, session, *args):
+ if self.disabled:
+ writer = Writer()
+
+ self.disabled_tmpl.render(writer, session, *args)
+
+ return writer.to_string()
+ else:
+ return super(IncrementalSearchInput, self).do_render(session, *args)
+
Modified: mgmt/trunk/cumin/python/cumin/widgets.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/widgets.strings 2010-03-23 17:06:23 UTC (rev 3877)
+++ mgmt/trunk/cumin/python/cumin/widgets.strings 2010-03-23 18:29:24 UTC (rev 3878)
@@ -326,9 +326,17 @@
div.CuminSummary {
width: 50em;
margin: 0 0 2em 0;
- min-height: 6em;
+ min-height: 4em;
}
+div.CuminSummary:after {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+}
+
div.CuminSummary h1 {
font-size: 1.1em;
margin: 0;
@@ -894,20 +902,45 @@
width: 80%;
}
+[IncrementalSearchInput.javascript]
+addJavascript('resource?name=incrementalSearch.js', 'head');
+
[IncrementalSearchInput.css]
-div.IncrementalSearchInput ul {
+div.IncrementalSearchInput select {
display: none;
}
+div.IncrementalSearchInput input[disabled='disabled'] {
+ background:white;
+ color:black;
+ border: 0px solid white;
+ cursor:default;
+}
[IncrementalSearchInput.html]
<div class="IncrementalSearchInput">
-<input id="{id}" type="text" name="{name}"
value="{value}" tabindex="{tab_index}" {disabled_attr}
size="{size}" autocomplete="off"/>
-<ul id="{id}.list">{items}</ul>
+ <input id="{id}" type="text" name="{name}"
value="{value}" tabindex="{tab_index}" size="{size}"
autocomplete="off"/>
+ <input id="{alt_value_path}" name="{alt_value_path}"
type="hidden" value="{alt_value}" />
+ <select id="{id}.list">{items}</select>
</div>
<script type="text/javascript">
//<![CDATA[
-window.addEvent("domready", function () {
- new IncrementalSearch($("{id}"), Inc_CIBeginning, "autocomplete",
"{id}.list", 8); });
+window.addEvent("domready",
+ function () {
+ new IncrementalSearch($("{id}"), Inc_CIBeginning,
"autocomplete", "{id}.list", 8).onselect=
+ {select}
+ }
+);
//]]>
</script>
+[IncrementalSearchInput.item_html]
+<option value="{item_value}">{item_content}</option>
+
+[IncrementalSearchInput.select_html]
+ function (value, data) { if (typeof data == "undefined") data =
""; $('{alt_value_path}').value = data; }
+
+[IncrementalSearchInput.disabled_html]
+<div class="IncrementalSearchInput">
+{value}
+<input id="{alt_value_path}" name="{alt_value_path}"
type="hidden" value="{alt_value}" />
+</div>
Modified: mgmt/trunk/cumin/resources/app.css
===================================================================
--- mgmt/trunk/cumin/resources/app.css 2010-03-23 17:06:23 UTC (rev 3877)
+++ mgmt/trunk/cumin/resources/app.css 2010-03-23 18:29:24 UTC (rev 3878)
@@ -592,6 +592,9 @@
border-top: none;
background: #fff;
z-index: 2;
+ /* padding: 0 0 0 0.25em; */
+}
+.autocomplete div {
padding: 0 0.25em;
}
.autocomplete .normal{border-top: 1px solid #fefefe;}
Modified: mgmt/trunk/cumin/resources/app.js
===================================================================
--- mgmt/trunk/cumin/resources/app.js 2010-03-23 17:06:23 UTC (rev 3877)
+++ mgmt/trunk/cumin/resources/app.js 2010-03-23 18:29:24 UTC (rev 3878)
@@ -482,4 +482,3 @@
s.setAttribute('src',jsname);
th.appendChild(s);
}
-addJavascript('resource?name=incrementalSearch.js', 'head');