Author: eallen
Date: 2008-08-05 16:33:37 -0400 (Tue, 05 Aug 2008)
New Revision: 2244
Added:
mgmt/trunk/cumin/python/cumin/binding.py
mgmt/trunk/cumin/python/cumin/binding.strings
Log:
FormField for entering and validating binding info
Added: mgmt/trunk/cumin/python/cumin/binding.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/binding.py (rev 0)
+++ mgmt/trunk/cumin/python/cumin/binding.py 2008-08-05 20:33:37 UTC (rev 2244)
@@ -0,0 +1,365 @@
+from cumin.util import sorted_by, is_active
+from formats import fmt_shorten
+from wooly.forms import FormInput, FormField
+from wooly.resources import StringCatalog
+from wooly import Template, Writer, Attribute
+from wooly.parameters import DictParameter
+
+strings = StringCatalog(__file__)
+
+class ExchangeInput(FormInput):
+ def __init__(self, app, name, form):
+ super(ExchangeInput, self).__init__(app, name, form)
+
+ self.exchange = None
+ self.instance_data = None
+
+ self.name_tmpl = Template(self, "name_html")
+ self.key_tmpl = Template(self, "key_html")
+
+ 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 "_".join((self.instance_data, "name"))
+
+ def render_exchange_type(self, session, exchange):
+ return exchange.type
+
+ def render_exchange_type_path(self, session, exchange):
+ return "_".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 DirectExchangeInput(ExchangeInput):
+ pass
+
+class FanoutExchangeInput(ExchangeInput):
+ pass
+
+class BindingKeyExchangeInput(ExchangeInput):
+ def __init__(self, app, name, form):
+ super(BindingKeyExchangeInput, self).__init__(app, name, form)
+
+ def render_key_path(self, session, exchange):
+ return "_".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 TopicExchangeInput(BindingKeyExchangeInput):
+ pass
+
+class XMLExchangeInput(BindingKeyExchangeInput):
+ def __init__(self, app, name, form):
+ super(XMLExchangeInput, self).__init__(app, name, form)
+
+ def render_xquery_path(self, session, exchange):
+ return "_".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')\""
+
+ 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")
+
+class HeadersExchangeInput(BindingKeyExchangeInput):
+ def __init__(self, app, name, form):
+ super(HeadersExchangeInput, self).__init__(app, name, form)
+
+ def render_x_match_path(self, session, exchange):
+ return "_".join((self.instance_data, "x-match"))
+
+ def render_mkey_path(self, session, exchange):
+ return "_".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')\""
+
+
+
+class ExchangeKeysField(FormField):
+ def __init__(self, app, name, form, title="Initial bindings:"):
+ super(ExchangeKeysField, self).__init__(app, name, form)
+
+ self.dict_param = DictParameter(app, "exchange", form)
+ self.add_parameter(self.dict_param)
+ form.add_form_parameter(self.dict_param)
+
+ self.direct_input = DirectExchangeInput(app, "direct", form)
+ self.add_child(self.direct_input)
+
+ self.topic_input = TopicExchangeInput(app, "topic", form)
+ self.add_child(self.topic_input)
+
+ self.fanout_input = FanoutExchangeInput(app, "fanout", form)
+ self.add_child(self.fanout_input)
+
+ self.xml_input = XMLExchangeInput(app, "xml", form)
+ self.add_child(self.xml_input)
+
+ self.headers_input = HeadersExchangeInput(app, "headers", form)
+ self.add_child(self.headers_input)
+
+ self.title = title
+
+ self.binding_errors = self.Errors(self, "binding_errors")
+ self.add_attribute(self.binding_errors)
+
+ def get_args(self, session):
+ broker = self.get_parent_named("broker")
+ reg = broker.get_object(session)
+ return (reg.getDefaultVhost(),)
+
+ class Errors(Attribute):
+ def get_default(self, session):
+ return dict()
+
+ def render_title(self, session, vhost):
+ return self.title
+
+ def render_exchanges(self, session, vhost):
+ sortedExchanges = sorted_by(vhost.exchanges)
+
+ # render each exchange we support
+ writer = Writer()
+ for exchange in sortedExchanges:
+ if 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_info(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":
+ if not "key" in form_binding_info[exchange]:
+ name = form_binding_info[exchange]["name"]
+ errs = berrs.setdefault(name, list())
+ errs.append("A binding key is required")
+ elif type == "headers":
+ if not "key" in form_binding_info[exchange]:
+ 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]:
+ if not mkey in binding_info[exchange]:
+ name = binding_info[exchange]["name"]
+ if not name in berrs:
+ berrs.setdefault(name, dict())
+ berrs[name][mkey] = ["Missing key"]
+ elif type == "xml":
+ if not "key" in form_binding_info[exchange]:
+ name = form_binding_info[exchange]["name"]
+ errs = berrs.setdefault(name, dict())
+ errs["key"] = ["A binding key is required"]
+ if not "xquery" in form_binding_info[exchange]:
+ name = binding_info[exchange]["name"]
+ if not name in berrs:
+ berrs.setdefault(name, dict())
+ berrs[name]["xquery"] = ["Missing xquery"]
+
+ if len(berrs):
+ # Tell dictionary to clear out any
+ # values the next time the page is submitted
+ # before it starts adding new entries.
+ # This is needed because checkboxes don't
+ # send a blank value when they are cleared.
+ self.dict_param.set_clear_on_add()
+ else:
+ self.dict_param.clear()
+
+ return (len(berrs), form_binding_info)
+
+ def process_binding_info(self, session, queue_name):
+ 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]:
+ form_binding_info[this_exchange] = dict()
+ arguments = dict()
+ type = binding_info[this_exchange]["type"]
+ if type == "headers":
+ arguments["x-match"] =
binding_info[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 binding_info[this_exchange]:
+ if binding_info[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(binding_info,
+ this_exchange, match_info)
+ # it is valid for the value in the .nv field
+ # to be empty
+ arguments[binding_info[this_exchange][match_info]] = \
+ match_value or None
+ elif type == "xml":
+ if "xquery" in binding_info[this_exchange]:
+ arguments["xquery"] =
binding_info[this_exchange]["xquery"]
+ elif type == "direct":
+ binding_info[this_exchange]["key"] = queue_name
+ #topic and fanout exchanges don't need any processing
+
+ form_binding_info[this_exchange]["name"] =
binding_info[this_exchange]["name"]
+ if "key" in binding_info[this_exchange]:
+ form_binding_info[this_exchange]["key"] =
binding_info[this_exchange]["key"]
+ form_binding_info[this_exchange]["arguments"] = arguments
+ # type is used in form validation only
+ form_binding_info[this_exchange]["type"] =
binding_info[this_exchange]["type"]
+
+ return form_binding_info
+
+ def _find_match_value(self, binding_info, this_exchange, match_info):
+ for m_info in binding_info[this_exchange]:
+ if m_info.startswith(match_info):
+ if m_info.endswith("nv"):
+ return binding_info[this_exchange][m_info]
+
Added: mgmt/trunk/cumin/python/cumin/binding.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/binding.strings (rev 0)
+++ mgmt/trunk/cumin/python/cumin/binding.strings 2008-08-05 20:33:37 UTC (rev 2244)
@@ -0,0 +1,155 @@
+
+[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}
+ <td> </td>
+ </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]
+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="title">{title}</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>
+