You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by rj...@apache.org on 2006/12/04 05:57:50 UTC

svn commit: r482072 [2/2] - /tomcat/connectors/trunk/jk/native/common/jk_status.c

Modified: tomcat/connectors/trunk/jk/native/common/jk_status.c
URL: http://svn.apache.org/viewvc/tomcat/connectors/trunk/jk/native/common/jk_status.c?view=diff&rev=482072&r1=482071&r2=482072
==============================================================================
--- tomcat/connectors/trunk/jk/native/common/jk_status.c (original)
+++ tomcat/connectors/trunk/jk/native/common/jk_status.c Sun Dec  3 20:57:49 2006
@@ -45,11 +45,13 @@
  * cmd=edit form to change configuration
  * cmd=update commit update configuration
  * cmd=reset reset lb runtime states, or lb member runtime states
+ * cmd=version show only software version
  * Query arguments:
  * re=n (refresh time in seconds, n=0: disabled)
  * w=worker (cmd should be executed for worker "worker")
  * sw=sub_worker (cmd should be executed for "sub_worker" of worker "worker")
  * from=lastcmd (the last viewing command was "lastcmd")
+ * opt=option (changes meaning of edit and list/show)
  */
 
 #define JK_STATUS_ARG_CMD                  ("cmd")
@@ -58,7 +60,7 @@
 #define JK_STATUS_ARG_REFRESH              ("re")
 #define JK_STATUS_ARG_WORKER               ("w")
 #define JK_STATUS_ARG_WORKER_MEMBER        ("sw")
-#define JK_STATUS_ARG_LB_MEMBER_ATT        ("att")
+#define JK_STATUS_ARG_OPTION               ("opt")
 
 #define JK_STATUS_ARG_LB_RETRIES           ("lr")
 #define JK_STATUS_ARG_LB_RECOVER_TIME      ("lt")
@@ -67,12 +69,12 @@
 #define JK_STATUS_ARG_LB_METHOD            ("lm")
 #define JK_STATUS_ARG_LB_LOCK              ("ll")
 
-#define JK_STATUS_ARG_LB_TEXT_RETRIES      ("Retries")
-#define JK_STATUS_ARG_LB_TEXT_RECOVER_TIME ("Recover Wait Time")
-#define JK_STATUS_ARG_LB_TEXT_STICKY       ("Sticky Sessions")
-#define JK_STATUS_ARG_LB_TEXT_STICKY_FORCE ("Force Sticky Sessions")
-#define JK_STATUS_ARG_LB_TEXT_METHOD       ("LB Method")
-#define JK_STATUS_ARG_LB_TEXT_LOCK         ("Locking")
+#define JK_STATUS_ARG_LB_TEXT_RETRIES      "Retries"
+#define JK_STATUS_ARG_LB_TEXT_RECOVER_TIME "Recover Wait Time"
+#define JK_STATUS_ARG_LB_TEXT_STICKY       "Sticky Sessions"
+#define JK_STATUS_ARG_LB_TEXT_STICKY_FORCE "Force Sticky Sessions"
+#define JK_STATUS_ARG_LB_TEXT_METHOD       "LB Method"
+#define JK_STATUS_ARG_LB_TEXT_LOCK         "Locking"
 
 #define JK_STATUS_ARG_LBM_ACTIVATION       ("wa")
 #define JK_STATUS_ARG_LBM_FACTOR           ("wf")
@@ -81,53 +83,143 @@
 #define JK_STATUS_ARG_LBM_DOMAIN           ("wc")
 #define JK_STATUS_ARG_LBM_DISTANCE         ("wd")
 
-#define JK_STATUS_ARG_LBM_TEXT_ACTIVATION  ("Activation")
-#define JK_STATUS_ARG_LBM_TEXT_FACTOR      ("LB Factor")
-#define JK_STATUS_ARG_LBM_TEXT_ROUTE       ("Route")
-#define JK_STATUS_ARG_LBM_TEXT_REDIRECT    ("Redirect Route")
-#define JK_STATUS_ARG_LBM_TEXT_DOMAIN      ("Cluster Domain")
-#define JK_STATUS_ARG_LBM_TEXT_DISTANCE    ("Distance")
+#define JK_STATUS_ARG_LBM_TEXT_ACTIVATION  "Activation"
+#define JK_STATUS_ARG_LBM_TEXT_FACTOR      "LB Factor"
+#define JK_STATUS_ARG_LBM_TEXT_ROUTE       "Route"
+#define JK_STATUS_ARG_LBM_TEXT_REDIRECT    "Redirect Route"
+#define JK_STATUS_ARG_LBM_TEXT_DOMAIN      "Cluster Domain"
+#define JK_STATUS_ARG_LBM_TEXT_DISTANCE    "Distance"
 
+#define JK_STATUS_CMD_UNKNOWN              (0)
 #define JK_STATUS_CMD_LIST                 (1)
 #define JK_STATUS_CMD_SHOW                 (2)
 #define JK_STATUS_CMD_EDIT                 (3)
 #define JK_STATUS_CMD_UPDATE               (4)
 #define JK_STATUS_CMD_RESET                (5)
-#define JK_STATUS_CMD_DEF                  (JK_STATUS_CMD_LIST)
-#define JK_STATUS_CMD_MAX                  (JK_STATUS_CMD_RESET)
+#define JK_STATUS_CMD_VERSION              (6)
+#define JK_STATUS_CMD_DEF                  (JK_STATUS_CMD_UNKNOWN)
+#define JK_STATUS_CMD_MAX                  (JK_STATUS_CMD_VERSION)
+#define JK_STATUS_CMD_TEXT_UNKNOWN         ("unknown")
 #define JK_STATUS_CMD_TEXT_LIST            ("list")
 #define JK_STATUS_CMD_TEXT_SHOW            ("show")
 #define JK_STATUS_CMD_TEXT_EDIT            ("edit")
 #define JK_STATUS_CMD_TEXT_UPDATE          ("update")
 #define JK_STATUS_CMD_TEXT_RESET           ("reset")
-#define JK_STATUS_CMD_TEXT_DEF             (JK_STATUS_CMD_TEXT_LIST)
+#define JK_STATUS_CMD_TEXT_VERSION         ("version")
+#define JK_STATUS_CMD_TEXT_DEF             (JK_STATUS_CMD_TEXT_UNKNOWN)
 
+#define JK_STATUS_MIME_UNKNOWN             (0)
 #define JK_STATUS_MIME_HTML                (1)
 #define JK_STATUS_MIME_XML                 (2)
 #define JK_STATUS_MIME_TXT                 (3)
-#define JK_STATUS_MIME_DEF                 (JK_STATUS_MIME_HTML)
-#define JK_STATUS_MIME_MAX                 (JK_STATUS_MIME_TXT)
+#define JK_STATUS_MIME_PROP                (4)
+#define JK_STATUS_MIME_DEF                 (JK_STATUS_MIME_UNKNOWN)
+#define JK_STATUS_MIME_MAX                 (JK_STATUS_MIME_PROP)
+#define JK_STATUS_MIME_TEXT_UNKNOWN        ("unknown")
 #define JK_STATUS_MIME_TEXT_HTML           ("html")
 #define JK_STATUS_MIME_TEXT_XML            ("xml")
 #define JK_STATUS_MIME_TEXT_TXT            ("txt")
-#define JK_STATUS_MIME_TEXT_DEF            (JK_STATUS_MIME_TEXT_HTML)
+#define JK_STATUS_MIME_TEXT_PROP           ("prop")
+#define JK_STATUS_MIME_TEXT_DEF            (JK_STATUS_MIME_TEXT_UNKNOWN)
+
+#define JK_STATUS_ATT_NO_MEMBERS           ("nosw")
+
+#define JK_STATUS_MASK_ACTIVE              0x000000FF
+#define JK_STATUS_MASK_DISABLED            0x0000FF00
+#define JK_STATUS_MASK_STOPPED             0x00FF0000
+#define JK_STATUS_MASK_OK                  0x00010101
+#define JK_STATUS_MASK_NA                  0x00020202
+#define JK_STATUS_MASK_BUSY                0x00040404
+#define JK_STATUS_MASK_RECOVER             0x00080808
+#define JK_STATUS_MASK_ERROR               0x00101010
+#define JK_STATUS_MASK_GOOD_DEF            0x0000000F
+#define JK_STATUS_MASK_BAD_DEF             0x00FF1010
 
 #define JK_STATUS_ESC_CHARS                ("<>?&")
 
-#define JK_STATUS_HEAD "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
-                       "DTD HTML 3.2 Final//EN\">\n"      \
-                       "<html><head><title>JK Status Manager</title>"
-
-#define JK_STATUS_COPY "Copyright &#169; 1999-2006, The Apache Software Foundation<br />" \
-                       "Licensed under the <a href=\"http://www.apache.org/licenses/LICENSE-2.0\">" \
-                       "Apache License, Version 2.0</a>."
-
-#define JK_STATUS_HEND "</head>\n<body>\n"
-#define JK_STATUS_BEND "</body>\n</html>\n"
-
-#define JK_STATUS_XMLH "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
-#define JK_NSDEF       "jk:"
-#define JK_XMLNSDEF    "xmlns:jk=\"http://tomcat.apache.org\""
+#define JK_STATUS_HEAD                     "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
+                                           "DTD HTML 3.2 Final//EN\">\n"      \
+                                           "<html><head><title>JK Status Manager</title>"
+
+#define JK_STATUS_COPYRIGHT                "Copyright &#169; 1999-2006, The Apache Software Foundation<br />" \
+                                           "Licensed under the <a href=\"http://www.apache.org/licenses/LICENSE-2.0\">" \
+                                           "Apache License, Version 2.0</a>."
+
+#define JK_STATUS_HEND                     "</head>\n<body>\n"
+#define JK_STATUS_BEND                     "</body>\n</html>\n"
+
+#define JK_STATUS_XMLH                     "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+
+#define JK_STATUS_NS_DEF                   "jk:"
+#define JK_STATUS_XMLNS_DEF                "xmlns:jk=\"http://tomcat.apache.org\""
+#define JK_STATUS_PREFIX_DEF               "worker"
+
+#define JK_STATUS_FORM_START               "<form method=\"%s\" action=\"%s\">\n"
+#define JK_STATUS_FORM_HIDDEN_INT          "<input type=\"hidden\" name=\"%s\" value=\"%d\"/>\n"
+#define JK_STATUS_FORM_HIDDEN_STRING       "<input type=\"hidden\" name=\"%s\" value=\"%s\"/>\n"
+#define JK_STATUS_TABLE_HEAD_3_STRING      "<tr><th>%s</th><th>%s</th><th>%s</th></tr>\n"
+#define JK_STATUS_TABLE_ROW_3_STRING       "<tr><td>%s</td><td>%s</td><td>%s</td></tr>\n"
+#define JK_STATUS_SHOW_AJP_HEAD            "<tr>" \
+                                           "<th>Type</th>" \
+                                           "<th>Host</th>" \
+                                           "<th>Addr</th>" \
+                                           "</tr>\n"
+#define JK_STATUS_SHOW_AJP_ROW             "<tr>" \
+                                           "<td>%s</td>" \
+                                           "<td>%s:%d</td>" \
+                                           "<td>%s</td>" \
+                                           "</tr>\n"
+#define JK_STATUS_SHOW_LB_HEAD             "<tr>" \
+                                           "<th>Type</th>" \
+                                           "<th>" JK_STATUS_ARG_LB_TEXT_STICKY "</th>" \
+                                           "<th>" JK_STATUS_ARG_LB_TEXT_STICKY_FORCE "</th>" \
+                                           "<th>" JK_STATUS_ARG_LB_TEXT_RETRIES "</th>" \
+                                           "<th>" JK_STATUS_ARG_LB_TEXT_METHOD "</th>" \
+                                           "<th>" JK_STATUS_ARG_LB_TEXT_LOCK "</th>" \
+                                           "<th>" JK_STATUS_ARG_LB_TEXT_RECOVER_TIME "</th>" \
+                                           "</tr>\n"
+#define JK_STATUS_SHOW_LB_ROW              "<tr>" \
+                                           "<td>%s</td>" \
+                                           "<td>%s</td>" \
+                                           "<td>%s</td>" \
+                                           "<td>%d</td>" \
+                                           "<td>%s</td>" \
+                                           "<td>%s</td>" \
+                                           "<td>%d</td>" \
+                                           "</tr>\n"
+#define JK_STATUS_SHOW_MEMBER_HEAD         "<tr>" \
+                                           "<th>&nbsp;</th><th>Name</th><th>Type</th>" \
+                                           "<th>Host</th><th>Addr</th>" \
+                                           "<th>Act</th><th>Stat</th>" \
+                                           "<th>D</th><th>F</th><th>M</th>" \
+                                           "<th>V</th><th>Acc</th>" \
+                                           "<th>Err</th><th>CE</th>" \
+                                           "<th>Wr</th><th>Rd</th><th>Busy</th><th>Max</th>" \
+                                           "<th>" JK_STATUS_ARG_LBM_TEXT_ROUTE "</th>" \
+                                           "<th>RR</th><th>Cd</th><th>Rs</th>" \
+                                           "</tr>\n"
+#define JK_STATUS_SHOW_MEMBER_ROW          "<td>%s</td>" \
+                                           "<td>%s</td>" \
+                                           "<td>%s:%d</td>" \
+                                           "<td>%s</td>" \
+                                           "<td>%s</td>" \
+                                           "<td>%s</td>" \
+                                           "<td>%d</td>" \
+                                           "<td>%d</td>" \
+                                           "<td>%" JK_UINT64_T_FMT "</td>" \
+                                           "<td>%" JK_UINT64_T_FMT "</td>" \
+                                           "<td>%" JK_UINT64_T_FMT "</td>" \
+                                           "<td>%" JK_UINT32_T_FMT "</td>" \
+                                           "<td>%" JK_UINT32_T_FMT "</td>" \
+                                           "<td>%s</td>" \
+                                           "<td>%s</td>" \
+                                           "<td>%u</td>" \
+                                           "<td>%u</td>" \
+                                           "<td>%s</td>" \
+                                           "<td>%s</td>" \
+                                           "<td>%s</td>" \
+                                           "<td>%u</td>" \
+                                           "</tr>\n"
 
 typedef struct status_worker status_worker_t;
 
@@ -149,9 +241,12 @@
     const char        *ns;
     const char        *xmlns;
     const char        *doctype;
+    const char        *prefix;
     int               read_only;
     char              **user_names;
     unsigned int      num_of_users;
+    jk_uint32_t       good_mask;
+    jk_uint32_t       bad_mask;
     jk_worker_t       worker;
     status_endpoint_t ep;
     jk_worker_env_t   *we;
@@ -176,20 +271,22 @@
 };
 
 static const char *cmd_type[] = {
-    "unknown",
+    JK_STATUS_CMD_TEXT_UNKNOWN,
     JK_STATUS_CMD_TEXT_LIST,
     JK_STATUS_CMD_TEXT_SHOW,
     JK_STATUS_CMD_TEXT_EDIT,
     JK_STATUS_CMD_TEXT_UPDATE,
     JK_STATUS_CMD_TEXT_RESET,
+    JK_STATUS_CMD_TEXT_VERSION,
     NULL
 };
 
 static const char *mime_type[] = {
-    "unknown",
+    JK_STATUS_MIME_TEXT_UNKNOWN,
     JK_STATUS_MIME_TEXT_HTML,
     JK_STATUS_MIME_TEXT_XML,
     JK_STATUS_MIME_TEXT_TXT,
+    JK_STATUS_MIME_TEXT_PROP,
     NULL
 };
 
@@ -291,6 +388,143 @@
     return rc;
 }
 
+static int jk_print_xml_start_elt(jk_ws_service_t *s, status_worker_t *sw,
+                                  int indentation, int close_tag,
+                                  const char *name)
+{
+    if (close_tag) {
+        jk_printf(s, "%*s<%s%s>\n", indentation, "", sw->ns, name);
+    }
+    else {
+        jk_printf(s, "%*s<%s%s\n", indentation, "", sw->ns, name);
+    }
+}
+
+static int jk_print_xml_close_elt(jk_ws_service_t *s, status_worker_t *sw,
+                                  int indentation,
+                                  const char *name)
+{
+    jk_printf(s, "%*s</%s%s>\n", indentation, "", sw->ns, name);
+}
+
+static int jk_print_xml_stop_elt(jk_ws_service_t *s,
+                                 int indentation, int close_tag)
+{
+    if (close_tag) {
+        jk_printf(s, "%*s/>\n", indentation, "");
+    }
+    else {
+        jk_printf(s, "%*s>\n", indentation, "");
+    }
+}
+
+static int jk_print_xml_att_string(jk_ws_service_t *s,
+                                   int indentation,
+                                   const char *key, const char *value)
+{
+    jk_printf(s, "%*s%s=\"%s\"\n", indentation, "", key, value ? value : "");
+}
+
+static int jk_print_xml_att_int(jk_ws_service_t *s,
+                                int indentation,
+                                const char *key, int value)
+{
+    jk_printf(s, "%*s%s=\"%d\"\n", indentation, "", key, value);
+}
+
+static int jk_print_xml_att_uint(jk_ws_service_t *s,
+                                 int indentation,
+                                 const char *key, unsigned value)
+{
+    jk_printf(s, "%*s%s=\"%u\"\n", indentation, "", key, value);
+}
+
+static int jk_print_xml_att_uint32(jk_ws_service_t *s,
+                                   int indentation,
+                                   const char *key, jk_uint32_t value)
+{
+    jk_printf(s, "%*s%s=\"%" JK_UINT32_T_FMT "\"\n", indentation, "", key, value);
+}
+
+static int jk_print_xml_att_uint64(jk_ws_service_t *s,
+                                   int indentation,
+                                   const char *key, jk_uint64_t value)
+{
+    jk_printf(s, "%*s%s=\"%" JK_UINT64_T_FMT "\"\n", indentation, "", key, value);
+}
+
+static int jk_print_prop_att_string(jk_ws_service_t *s, status_worker_t *sw,
+                                    const char *name,
+                                    const char *key, const char *value)
+{
+    if (name) {
+        jk_printf(s, "%s.%s.%s=%s\n", sw->prefix, name, key, value ? value : "");
+    }
+    else {
+        jk_printf(s, "%s.%s=%s\n", sw->prefix, key, value ? value : "");
+    }
+}
+
+static int jk_print_prop_att_int(jk_ws_service_t *s, status_worker_t *sw,
+                                 const char *name,
+                                 const char *key, int value)
+{
+    if (name) {
+        jk_printf(s, "%s.%s.%s=%d\n", sw->prefix, name, key, value);
+    }
+    else {
+        jk_printf(s, "%s.%s=%d\n", sw->prefix, key, value);
+    }
+}
+
+static int jk_print_prop_att_uint(jk_ws_service_t *s, status_worker_t *sw,
+                                  const char *name,
+                                  const char *key, unsigned value)
+{
+    if (name) {
+        jk_printf(s, "%s.%s.%s=%u\n", sw->prefix, name, key, value);
+    }
+    else {
+        jk_printf(s, "%s.%s=%u\n", sw->prefix, key, value);
+    }
+}
+
+static int jk_print_prop_att_uint32(jk_ws_service_t *s, status_worker_t *sw,
+                                    const char *name,
+                                    const char *key, jk_uint32_t value)
+{
+    if (name) {
+        jk_printf(s, "%s.%s.%s=%" JK_UINT32_T_FMT "\n", sw->prefix, name, key, value);
+    }
+    else {
+        jk_printf(s, "%s.%s=%" JK_UINT32_T_FMT "\n", sw->prefix, key, value);
+    }
+}
+
+static int jk_print_prop_att_uint64(jk_ws_service_t *s, status_worker_t *sw,
+                                    const char *name,
+                                    const char *key, jk_uint64_t value)
+{
+    if (name) {
+        jk_printf(s, "%s.%s.%s=%" JK_UINT64_T_FMT "\n", sw->prefix, name, key, value);
+    }
+    else {
+        jk_printf(s, "%s.%s=%" JK_UINT64_T_FMT "\n", sw->prefix, key, value);
+    }
+}
+
+static int jk_print_prop_item_string(jk_ws_service_t *s, status_worker_t *sw,
+                                     const char *name, const char *list, int num,
+                                     const char *key, const char *value)
+{
+    if (name) {
+        jk_printf(s, "%s.%s.%s.%d.%s=%s\n", sw->prefix, name, list, num, key, value ? value : "");
+    }
+    else {
+        jk_printf(s, "%s.%s.%d.%s=%s\n", sw->prefix, list, num, key, value ? value : "");
+    }
+}
+
 /* Actually APR's apr_strfsize */
 static char *status_strfsize(jk_uint64_t size, char *buf)
 {
@@ -326,6 +560,135 @@
     } while (1);
 }
 
+static int status_rate(worker_record_t *wr, status_worker_t *sw,
+                       jk_logger_t *l)
+{
+    jk_uint32_t mask = 0;
+    int activation = wr->s->activation;
+    int state = wr->s->state;
+    jk_uint32_t good = sw->good_mask;
+    jk_uint32_t bad = sw->bad_mask;
+    int rv = 0;
+
+    switch (activation)
+    {
+    case JK_LB_ACTIVATION_ACTIVE:
+        mask = JK_STATUS_MASK_ACTIVE;
+        break;
+    case JK_LB_ACTIVATION_DISABLED:
+        mask = JK_STATUS_MASK_DISABLED;
+        break;
+    case JK_LB_ACTIVATION_STOPPED:
+        mask = JK_STATUS_MASK_STOPPED;
+        break;
+    default:
+        jk_log(l, JK_LOG_WARNING,
+               "Unknown activation type '%d'",
+               activation);
+    }
+    switch (state)
+    {
+    case JK_LB_STATE_OK:
+        mask &= JK_STATUS_MASK_OK;
+        break;
+    case JK_LB_STATE_NA:
+        mask &= JK_STATUS_MASK_NA;
+        break;
+    case JK_LB_STATE_BUSY:
+        mask &= JK_STATUS_MASK_BUSY;
+        break;
+    case JK_LB_STATE_ERROR:
+        mask &= JK_STATUS_MASK_ERROR;
+        break;
+    case JK_LB_STATE_RECOVER:
+        mask &= JK_STATUS_MASK_RECOVER;
+        break;
+    default:
+        jk_log(l, JK_LOG_WARNING,
+               "Unknown state type '%d'",
+               state);
+    }
+    if (mask&bad)
+        rv = -1;
+    else if (mask&good)
+        rv = 1;
+    else
+        rv = 0;
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+               "rating of activation '%s' and state '%s' for good '%08" JK_UINT32_T_HEX_FMT
+               "' and bad '%08" JK_UINT32_T_HEX_FMT "' is %d",
+               jk_lb_get_activation(wr, l), jk_lb_get_state(wr, l),
+               good, bad, rv);
+    return rv;
+}
+
+static jk_uint32_t status_get_single_rating(const char rating, jk_logger_t *l)
+{
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+               "rating retrieval for '%c'",
+               rating);
+    switch (rating)
+    {
+    case 'A':
+    case 'a':
+        return JK_STATUS_MASK_ACTIVE;
+    case 'D':
+    case 'd':
+        return JK_STATUS_MASK_DISABLED;
+    case 'S':
+    case 's':
+        return JK_STATUS_MASK_STOPPED;
+    case 'O':
+    case 'o':
+        return JK_STATUS_MASK_OK;
+    case 'N':
+    case 'n':
+        return JK_STATUS_MASK_NA;
+    case 'B':
+    case 'b':
+        return JK_STATUS_MASK_BUSY;
+    case 'R':
+    case 'r':
+        return JK_STATUS_MASK_RECOVER;
+    case 'E':
+    case 'e':
+        return JK_STATUS_MASK_ERROR;
+    default:
+        jk_log(l, JK_LOG_WARNING,
+               "Unknown rating type '%c'",
+               rating);
+        return 0;
+    }
+}
+
+static jk_uint32_t status_get_rating(const char *rating,
+                                     jk_logger_t *l)
+{
+    int off = 0;
+    jk_uint32_t mask = 0;
+
+    while (rating[off] == ' ' || rating[off] == '\t' || rating[off] == '.') {
+        off++;
+    }
+    mask = status_get_single_rating(rating[off], l);
+    while (rating[off] != '\0' && rating[off] != '.') {
+        off++;
+    }
+    if (rating[off] == '.') {
+        off++;
+    }
+    if (rating[off] != '\0') {
+        mask &= status_get_single_rating(rating[off], l);
+    }
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+               "rating for '%s' is '%08" JK_UINT32_T_HEX_FMT "'",
+               rating, mask);
+    return mask;
+}
+
 static const char *status_worker_type(int t)
 {
     if (t < 0 || t > 6)
@@ -342,13 +705,16 @@
         return "True";
 }
 
-static int status_get_arg_raw(const char *param, const char *req, char *buf, size_t len)
+static int status_get_arg_raw(const char *param,
+                              const char *req, char *buf, size_t len,
+                              jk_logger_t *l)
 {
     char ps[32];
     char *p;
-    size_t l = 0;
+    size_t pos = 0;
+    int rv = 0;
 
-    *buf = '\0';
+    buf[0] = '\0';
     if (!req)
         return JK_FALSE;
     if (!param)
@@ -364,53 +730,68 @@
         p += strlen(ps);
         while (*p) {
             if (*p != '&')
-                buf[l++] = *p;
+                buf[pos++] = *p;
             else
                 break;
-            if (l >= len-1)
+            if (pos >= len-1)
                 break;
             p++;
         }
-        buf[l] = '\0';
-        if (l)
-            return JK_TRUE;
+        buf[pos] = '\0';
+        if (pos)
+            rv = JK_TRUE;
         else
-            return JK_UNSET;
+            rv = JK_UNSET;
     }
     else
-        return JK_FALSE;
+        rv = JK_FALSE;
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+               "result for '%s' in '%s' is %d (%s)",
+               param, req, rv, buf);
+    return rv;
 }
 
-static int status_get_arg(const char *param, const char *req, char *buf, size_t len)
+static int status_get_arg(const char *param,
+                          const char *req, char *buf, size_t len,
+                          jk_logger_t *l)
 {
     int rv;
 
-    rv = status_get_arg_raw(param, req, buf, len);
+    rv = status_get_arg_raw(param, req, buf, len, l);
     if (rv == JK_TRUE) {
         char *off = buf;
         while ((off = strpbrk(off, JK_STATUS_ESC_CHARS)))
             off[0] = '@';
     }
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+               "result for '%s' in '%s' is %d (%s)",
+               param, req, rv, buf);
     return rv;
 }
 
-static int status_get_int(const char *param, const char *req, int def)
+static int status_get_int(const char *param,
+                          const char *req, int def,
+                          jk_logger_t *l)
 {
     char buf[32];
     int rv = def;
 
-    if (status_get_arg_raw(param, req, buf, sizeof(buf)) == JK_TRUE) {
+    if (status_get_arg_raw(param, req, buf, sizeof(buf), l) == JK_TRUE) {
         rv = atoi(buf);
     }
     return rv;
 }
 
-static int status_get_bool(const char *param, const char *req, int def)
+static int status_get_bool(const char *param,
+                           const char *req, int def,
+                           jk_logger_t *l)
 {
     char buf[32];
     int rv = def;
 
-    if (status_get_arg_raw(param, req, buf, sizeof(buf)) == JK_TRUE) {
+    if (status_get_arg_raw(param, req, buf, sizeof(buf), l) == JK_TRUE) {
         if (strcasecmp(buf, "on") == 0 ||
             strcasecmp(buf, "true") == 0 ||
             strcasecmp(buf, "1") == 0)
@@ -442,6 +823,8 @@
         return JK_STATUS_CMD_UPDATE;
     else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_RESET))
         return JK_STATUS_CMD_RESET;
+    else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_VERSION))
+        return JK_STATUS_CMD_VERSION;
     return JK_STATUS_CMD_DEF;
 }
 
@@ -460,47 +843,47 @@
         return JK_STATUS_MIME_XML;
     else if (!strcmp(mime, JK_STATUS_MIME_TEXT_TXT))
         return JK_STATUS_MIME_TXT;
+    else if (!strcmp(mime, JK_STATUS_MIME_TEXT_PROP))
+        return JK_STATUS_MIME_PROP;
     return JK_STATUS_MIME_DEF;
 }
 
 static void status_start_form(jk_ws_service_t *s, const char *method,
                               int cmd, int mime,
                               int from, int refresh,
-                              const char *worker, const char *sub_worker)
+                              const char *worker, const char *sub_worker,
+                              const char *option)
 {
     if (method)
-        jk_putv(s, "<form method=\"", method,
-        "\" action=\"", s->req_uri, "\">\n", NULL);
+        jk_printf(s, JK_STATUS_FORM_START, method, s->req_uri);
     else
         return;
     if (cmd) {
-        jk_putv(s, "<input type=\"hidden\" name=\"",
-                JK_STATUS_ARG_CMD, "\" ", NULL);
-        jk_putv(s, "value=\"", status_cmd_text(cmd), "\"/>\n", NULL);
+        jk_printf(s, JK_STATUS_FORM_HIDDEN_STRING,
+                  JK_STATUS_ARG_CMD, status_cmd_text(cmd));
         if (mime) {
-            jk_putv(s, "<input type=\"hidden\" name=\"",
-                JK_STATUS_ARG_MIME, "\" ", NULL);
-            jk_putv(s, "value=\"", status_mime_text(mime), "\"/>\n", NULL);
+            jk_printf(s, JK_STATUS_FORM_HIDDEN_STRING,
+                      JK_STATUS_ARG_MIME, status_mime_text(mime));
         }
         if (from) {
-            jk_putv(s, "<input type=\"hidden\" name=\"",
-                JK_STATUS_ARG_FROM, "\" ", NULL);
-            jk_putv(s, "value=\"", status_cmd_text(from), "\"/>\n", NULL);
+            jk_printf(s, JK_STATUS_FORM_HIDDEN_STRING,
+                      JK_STATUS_ARG_FROM, status_cmd_text(from));
         }
         if (refresh) {
-            jk_putv(s, "<input type=\"hidden\" name=\"",
-                JK_STATUS_ARG_REFRESH, "\" ", NULL);
-            jk_printf(s, "value=\"%d\"/>\n", refresh);
+            jk_printf(s, JK_STATUS_FORM_HIDDEN_INT,
+                      JK_STATUS_ARG_REFRESH, refresh);
         }
         if (worker) {
-            jk_putv(s, "<input type=\"hidden\" name=\"",
-                JK_STATUS_ARG_WORKER, "\" ", NULL);
-            jk_putv(s, "value=\"", worker, "\"/>\n", NULL);
+            jk_printf(s, JK_STATUS_FORM_HIDDEN_STRING,
+                      JK_STATUS_ARG_WORKER, worker);
         }
         if (sub_worker) {
-            jk_putv(s, "<input type=\"hidden\" name=\"",
-                JK_STATUS_ARG_WORKER_MEMBER, "\" ", NULL);
-            jk_putv(s, "value=\"", sub_worker, "\"/>\n", NULL);
+            jk_printf(s, JK_STATUS_FORM_HIDDEN_STRING,
+                      JK_STATUS_ARG_WORKER_MEMBER, sub_worker);
+        }
+        if (option) {
+            jk_printf(s, JK_STATUS_FORM_HIDDEN_STRING,
+                      JK_STATUS_ARG_OPTION, option);
         }
     }
 }
@@ -508,7 +891,8 @@
 static void status_write_uri(jk_ws_service_t *s, const char *text,
                              int cmd, int mime,
                              int from, int refresh,
-                             const char *worker, const char *sub_worker)
+                             const char *worker, const char *sub_worker,
+                             const char *option)
 {
     if (text)
         jk_puts(s, "<a href=\"");
@@ -529,6 +913,9 @@
         if (sub_worker)
             jk_putv(s, "&", JK_STATUS_ARG_WORKER_MEMBER, "=",
                     sub_worker, NULL);
+        if (option)
+            jk_putv(s, "&", JK_STATUS_ARG_OPTION, "=",
+                    option, NULL);
     }
     if (text)
         jk_putv(s, "\">", text, "</a>", NULL);
@@ -538,36 +925,40 @@
                              int *cmd, int *mime,
                              int *from, int *refresh,
                              char *worker, char *sub_worker,
+                             char *option,
                              jk_logger_t *l)
 {
-    char buf[128];
+    char buf[JK_SHM_STR_SIZ+1];
 
     JK_TRACE_ENTER(l);
-    *cmd = JK_STATUS_CMD_DEF;
-    *mime = JK_STATUS_MIME_DEF;
+    *cmd = JK_STATUS_CMD_LIST;
+    *mime = JK_STATUS_MIME_HTML;
     *from = JK_STATUS_CMD_DEF;
     worker[0] = '\0';
     sub_worker[0] = '\0';
+    option[0] = '\0';
     *refresh = 0;
     if (!s->query_string)
         return;
-    if (status_get_arg_raw(JK_STATUS_ARG_CMD, s->query_string, buf, sizeof(buf)) == JK_TRUE)
+    if (status_get_arg_raw(JK_STATUS_ARG_CMD, s->query_string, buf, sizeof(buf), l) == JK_TRUE)
         *cmd = status_cmd_int(buf);
-    if (status_get_arg_raw(JK_STATUS_ARG_MIME, s->query_string, buf, sizeof(buf)) == JK_TRUE)
+    if (status_get_arg_raw(JK_STATUS_ARG_MIME, s->query_string, buf, sizeof(buf), l) == JK_TRUE)
         *mime = status_mime_int(buf);
-    if (status_get_arg_raw(JK_STATUS_ARG_FROM, s->query_string, buf, sizeof(buf)) == JK_TRUE)
+    if (status_get_arg_raw(JK_STATUS_ARG_FROM, s->query_string, buf, sizeof(buf), l) == JK_TRUE)
         *from = status_cmd_int(buf);
-    *refresh = status_get_int(JK_STATUS_ARG_REFRESH, s->query_string, 0);
-    if (status_get_arg(JK_STATUS_ARG_WORKER, s->query_string, buf, sizeof(buf)) == JK_TRUE)
+    *refresh = status_get_int(JK_STATUS_ARG_REFRESH, s->query_string, 0, l);
+    if (status_get_arg(JK_STATUS_ARG_WORKER, s->query_string, buf, sizeof(buf), l) == JK_TRUE)
         strncpy(worker, buf, JK_SHM_STR_SIZ);
-    if (status_get_arg(JK_STATUS_ARG_WORKER_MEMBER, s->query_string, buf, sizeof(buf)) == JK_TRUE)
+    if (status_get_arg(JK_STATUS_ARG_WORKER_MEMBER, s->query_string, buf, sizeof(buf), l) == JK_TRUE)
         strncpy(sub_worker, buf, JK_SHM_STR_SIZ);
+    if (status_get_arg(JK_STATUS_ARG_OPTION, s->query_string, buf, sizeof(buf), l) == JK_TRUE)
+        strncpy(option, buf, JK_SHM_STR_SIZ);
     if (JK_IS_DEBUG_LEVEL(l))
         jk_log(l, JK_LOG_DEBUG,
                "standard request params cmd='%s' mime='%s' from='%s' refresh=%d "
-               "worker='%s' sub worker='%s%'",
+               "worker='%s' sub worker='%s' option='%s'",
                status_cmd_text(*cmd), status_mime_text(*mime),
-               status_cmd_text(*from), refresh, worker, sub_worker);
+               status_cmd_text(*from), *refresh, worker, sub_worker, option);
     JK_TRACE_EXIT(l);
 }
 
@@ -581,21 +972,18 @@
 
     JK_TRACE_ENTER(l);
     jk_putv(s, "<hr/><h3>URI Mappings for ", worker, "</h3>\n", NULL);
-    jk_puts(s, "<table>\n<tr><th>Match Type</th><th>Uri</th>"
-               "<th>Source</th></tr>\n");
+    jk_puts(s, "<table>\n");
+    jk_printf(s, JK_STATUS_TABLE_HEAD_3_STRING,
+              "Match Type", "Uri", "Source");
     for (i = 0; i < uwmap->size; i++) {
         uri_worker_record_t *uwr = uwmap->maps[i];
         if (!worker || strcmp(uwr->worker_name, worker)) {
             continue;
         }
         count++;
-        jk_putv(s, "<tr><td>",
-                uri_worker_map_get_match(uwr, buf, l),
-                "</td><td>", NULL);
-        jk_puts(s, uwr->uri);
-        jk_putv(s, "</td><td>",
-                uri_worker_map_get_source(uwr, l),
-                "</td></tr>\n", NULL);
+        jk_printf(s, JK_STATUS_TABLE_ROW_3_STRING,
+                  uri_worker_map_get_match(uwr, buf, l), uwr->uri,
+                  uri_worker_map_get_source(uwr, l));
     }
     jk_puts(s, "</table>\n");
     if (JK_IS_DEBUG_LEVEL(l))
@@ -607,7 +995,7 @@
 
 static void display_maps_xml(jk_ws_service_t *s,
                              jk_uri_worker_map_t *uwmap,
-							 status_worker_t *sw,
+                             status_worker_t *sw,
                              const char *worker, jk_logger_t *l)
 {
     char buf[64];
@@ -621,11 +1009,27 @@
             continue;
         }
         count++;
-        jk_putv(s, "      <", sw->ns, "map\n", NULL);
-        jk_printf(s, "        type=\"%s\"\n", uri_worker_map_get_match(uwr, buf, l));
-        jk_printf(s, "        uri=\"%s\"\n", uwr->uri);
-        jk_printf(s, "        source=\"%s\"/>\n", uri_worker_map_get_source(uwr, l));
     }
+    if (count) {
+        jk_print_xml_start_elt(s, sw, 6, 0, "maps");
+        jk_print_xml_att_int(s, 8, "size", count);
+        jk_print_xml_stop_elt(s, 6, 0);
+    }
+    count = 0;
+    for (i = 0; i < uwmap->size; i++) {
+        uri_worker_record_t *uwr = uwmap->maps[i];
+        if (!worker || strcmp(uwr->worker_name, worker)) {
+            continue;
+        }
+        count++;
+        jk_print_xml_start_elt(s, sw, 8, 0, "map");
+        jk_print_xml_att_int(s, 10, "id", count);
+        jk_print_xml_att_string(s, 10, "type", uri_worker_map_get_match(uwr, buf, l));
+        jk_print_xml_att_string(s, 10, "uri", uwr->uri);
+        jk_print_xml_att_string(s, 10, "source", uri_worker_map_get_source(uwr, l));
+        jk_print_xml_stop_elt(s, 8, 1);
+    }
+    jk_print_xml_close_elt(s, sw, 6, "maps");
     if (JK_IS_DEBUG_LEVEL(l))
         jk_log(l, JK_LOG_DEBUG,
                "dumped %d maps for worker '%s'",
@@ -635,9 +1039,12 @@
 
 static void display_maps_txt(jk_ws_service_t *s,
                              jk_uri_worker_map_t *uwmap,
+                             status_worker_t *sw,
                              const char *worker, jk_logger_t *l)
 {
     char buf[64];
+    char *mount;
+    char *off;
     unsigned int i;
     int count=0;
 
@@ -650,17 +1057,73 @@
         count++;
     }
     if (count) {
-        jk_printf(s, "Maps: size=%d\n", count);        
+        jk_printf(s, "Maps: size=%d\n", count);
     }
+    count = 0;
     for (i = 0; i < uwmap->size; i++) {
         uri_worker_record_t *uwr = uwmap->maps[i];
         if (!worker || strcmp(uwr->worker_name, worker)) {
             continue;
         }
+        count++;
         jk_puts(s, "Map:");
-        jk_printf(s, " type=%s", uri_worker_map_get_match(uwr, buf, l));
-        jk_printf(s, " uri=%s", uwr->uri);
-        jk_printf(s, " source=%s\n", uri_worker_map_get_source(uwr, l));
+        jk_printf(s, " id=%d", count);
+        jk_printf(s, " type=\"%s\"", uri_worker_map_get_match(uwr, buf, l));
+        jk_printf(s, " uri=\"%s\"", uwr->uri);
+        jk_printf(s, " source=\"%s\"", uri_worker_map_get_source(uwr, l));
+        jk_puts(s, "\n");
+    }
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+               "dumped %d maps for worker '%s'",
+               count, worker);
+    JK_TRACE_EXIT(l);
+}
+
+static void display_maps_prop(jk_ws_service_t *s,
+                              jk_uri_worker_map_t *uwmap,
+                              status_worker_t *sw,
+                              const char *worker, jk_logger_t *l)
+{
+    char buf[64];
+    char *mount;
+    char *off;
+    unsigned int i;
+    int count=0;
+
+    JK_TRACE_ENTER(l);
+    for (i = 0; i < uwmap->size; i++) {
+        uri_worker_record_t *uwr = uwmap->maps[i];
+        if (!worker || strcmp(uwr->worker_name, worker)) {
+            continue;
+        }
+        count++;
+    }
+    if (count) {
+        jk_print_prop_att_int(s, sw, worker, "maps.size", count);
+    }
+    count = 0;
+    for (i = 0; i < uwmap->size; i++) {
+        uri_worker_record_t *uwr = uwmap->maps[i];
+        if (!worker || strcmp(uwr->worker_name, worker)) {
+            continue;
+        }
+        count++;
+        mount = jk_pool_alloc(s->pool, sizeof(char *) * (strlen(uwr->uri)+3));
+        off = mount;
+        if (uwr->match_type & MATCH_TYPE_DISABLED) {
+            *off = '-';
+            off++;
+        }
+        if (uwr->match_type & MATCH_TYPE_NO_MATCH) {
+            *off = '!';
+            off++;
+        }
+        strcpy(off, uwr->uri);
+        jk_print_prop_att_string(s, sw, worker, "mount", mount);
+        jk_print_prop_item_string(s, sw, worker, "maps.map", count, "type", uri_worker_map_get_match(uwr, buf, l));
+        jk_print_prop_item_string(s, sw, worker, "maps.map", count, "uri", uwr->uri);
+        jk_print_prop_item_string(s, sw, worker, "maps.map", count, "source", uri_worker_map_get_source(uwr, l));
     }
     if (JK_IS_DEBUG_LEVEL(l))
         jk_log(l, JK_LOG_DEBUG,
@@ -670,8 +1133,9 @@
 }
 
 static void display_worker(jk_ws_service_t *s, jk_worker_t *w,
-                          int refresh, int single,
-                          jk_logger_t *l)
+                           status_worker_t *sw,
+                           int show_members, int refresh, int single,
+                           jk_logger_t *l)
 {
     char buf[32];
     const char *name = NULL;
@@ -681,10 +1145,6 @@
 
     JK_TRACE_ENTER(l);
     if (single) {
-        jk_puts(s, "<hr/>\n");
-        status_write_uri(s, "Back to full worker list", JK_STATUS_CMD_LIST,
-                         0, 0, refresh, NULL, NULL);
-        jk_puts(s, "<br/>\n");
         from = JK_STATUS_CMD_SHOW;
     }
     if (w->type == JK_LB_WORKER_TYPE) {
@@ -729,47 +1189,44 @@
             jk_puts(s, "S");
         }
         else {
-            status_write_uri(s, "S", JK_STATUS_CMD_SHOW,
-                             0, 0, refresh, name, NULL);
+            if (show_members) {
+                status_write_uri(s, "S", JK_STATUS_CMD_SHOW,
+                                 0, 0, refresh, name, NULL, NULL);
+            }
+            else {
+                status_write_uri(s, "S", JK_STATUS_CMD_SHOW,
+                                 0, 0, refresh, name, NULL, JK_STATUS_ATT_NO_MEMBERS);
+            }
         }
         jk_puts(s, "|");
         status_write_uri(s, "E", JK_STATUS_CMD_EDIT,
-                         0, from, refresh, name, NULL);
+                         0, from, refresh, name, NULL, NULL);
         jk_puts(s, "|");
         status_write_uri(s, "R", JK_STATUS_CMD_RESET,
-                         0, from, refresh, name, NULL);
+                         0, from, refresh, name, NULL, NULL);
         jk_puts(s, "]&nbsp;&nbsp;");
         jk_putv(s, "Worker Status for ", name, "</h3>\n", NULL);
-        jk_putv(s, "<table><tr>"
-                "<th>Type</th><th>", JK_STATUS_ARG_LB_TEXT_STICKY, "</th>"
-                "<th>", JK_STATUS_ARG_LB_TEXT_STICKY_FORCE, "</th>"
-                "<th>", JK_STATUS_ARG_LB_TEXT_RETRIES, "</th>"
-                "<th>", JK_STATUS_ARG_LB_TEXT_METHOD, "</th>"
-                "<th>", JK_STATUS_ARG_LB_TEXT_LOCK, "</th>"
-                "<th>", JK_STATUS_ARG_LB_TEXT_RECOVER_TIME, "</th>"
-                "</tr>\n<tr>", NULL);
-        jk_putv(s, "<td>", status_worker_type(w->type), "</td>", NULL);
-        jk_putv(s, "<td>", status_val_bool(lb->sticky_session),
-                "</td>", NULL);
-        jk_putv(s, "<td>", status_val_bool(lb->sticky_session_force),
-                "</td>", NULL);
-        jk_printf(s, "<td>%d</td>", lb->retries);
-        jk_printf(s, "<td>%s</td>", jk_lb_get_method(lb, l));
-        jk_printf(s, "<td>%s</td>", jk_lb_get_lock(lb, l));
-        jk_printf(s, "<td>%d</td>", lb->recover_wait_time);
-        jk_puts(s, "</tr>\n</table>\n<br/>\n");
+        jk_puts(s, "<table>" JK_STATUS_SHOW_LB_HEAD);
+        jk_printf(s, JK_STATUS_SHOW_LB_ROW,
+                  status_worker_type(w->type),
+                  status_val_bool(lb->sticky_session),
+                  status_val_bool(lb->sticky_session_force),
+                  lb->retries,
+                  jk_lb_get_method(lb, l),
+                  jk_lb_get_lock(lb, l),
+                  lb->recover_wait_time);
+        jk_puts(s, "</table>\n<br/>\n");
 
         for (j = 0; j < lb->num_of_workers; j++) {
             worker_record_t *wr = &(lb->lb_workers[j]);
-            if (wr->s->state == JK_LB_STATE_ERROR ||
-               wr->s->state == JK_LB_STATE_RECOVER ||
-               wr->s->activation == JK_LB_ACTIVATION_STOPPED)
+            int rate;
+            rate = status_rate(wr, sw, l);
+            if (rate > 0 )
+               good++;
+            else if (rate < 0 )
                bad++;
-            else if (wr->s->state == JK_LB_STATE_BUSY ||
-               wr->s->activation == JK_LB_ACTIVATION_DISABLED)
-               degraded++;
             else
-               good++;
+               degraded++;
         }
 
         jk_puts(s, "<table><tr>"
@@ -780,69 +1237,92 @@
         jk_printf(s, "<td>%d</td>", bad);
         jk_printf(s, "<td>%d</td>", lb->s->busy);
         jk_printf(s, "<td>%d</td>", lb->s->max_busy);
-        jk_puts(s, "</tr>\n</table>\n<br/>\n");
-        jk_puts(s, "<h4>Balancer Members</h4>\n");
-        jk_putv(s, "<table><tr>"
-                "<th>&nbsp;</th><th>Name</th><th>Type</th>"
-                "<th>Host</th><th>Addr</th>"
-                "<th>Act</th><th>Stat</th><th>D</th><th>F</th><th>M</th>"
-                "<th>V</th><th>Acc</th><th>Err</th><th>CE</th>"
-                "<th>Wr</th><th>Rd</th><th>Busy</th><th>Max</th><th>",
-                JK_STATUS_ARG_LBM_TEXT_ROUTE,
-                "</th><th>RR</th><th>Cd</th><th>Rs</th></tr>\n", NULL);
-        for (j = 0; j < lb->num_of_workers; j++) {
-            worker_record_t *wr = &(lb->lb_workers[j]);
-            ajp_worker_t *a = (ajp_worker_t *)wr->w->worker_private;
-            jk_puts(s, "<tr>\n<td>[");
-            status_write_uri(s, "E", JK_STATUS_CMD_EDIT,
-                             0, from, refresh, name, wr->s->name);
-            jk_puts(s, "|");
-            status_write_uri(s, "R", JK_STATUS_CMD_RESET,
-                             0, from, refresh, name, wr->s->name);
-            jk_puts(s, "]&nbsp;</td>");
-            jk_putv(s, "<td>", wr->s->name, "</td>", NULL);
-            jk_putv(s, "<td>", status_worker_type(wr->w->type), "</td>", NULL);
-            jk_printf(s, "<td>%s:%d</td>", a->host, a->port);
-            jk_putv(s, "<td>", jk_dump_hinfo(&a->worker_inet_addr, buf),
-                    "</td>", NULL);
-            /* TODO: descriptive status */
-            jk_putv(s, "<td>", jk_lb_get_activation(wr, l), "</td>", NULL);
-            jk_putv(s, "<td>", jk_lb_get_state(wr, l), "</td>", NULL);
-            jk_printf(s, "<td>%d</td>", wr->s->distance);
-            jk_printf(s, "<td>%d</td>", wr->s->lb_factor);
-            jk_printf(s, "<td>%" JK_UINT64_T_FMT "</td>", wr->s->lb_mult);
-            jk_printf(s, "<td>%" JK_UINT64_T_FMT "</td>", wr->s->lb_value);
-            jk_printf(s, "<td>%" JK_UINT64_T_FMT "</td>", wr->s->elected);
-            jk_printf(s, "<td>%" JK_UINT32_T_FMT "</td>", wr->s->errors);
-            jk_printf(s, "<td>%" JK_UINT32_T_FMT "</td>", wr->s->client_errors);
-            jk_putv(s, "<td>", status_strfsize(wr->s->transferred, buf),
-                    "</td>", NULL);
-            jk_putv(s, "<td>", status_strfsize(wr->s->readed, buf),
-                    "</td>", NULL);
-            jk_printf(s, "<td>%u</td>", wr->s->busy);
-            jk_printf(s, "<td>%u</td>", wr->s->max_busy);
-            jk_putv(s, "<td>", wr->s->route, "</td><td>", NULL);
-            if (wr->s->redirect && *wr->s->redirect)
-                jk_puts(s, wr->s->redirect);
-            else
-                jk_puts(s,"&nbsp;");
-            jk_puts(s, "</td><td>");
-            if (wr->s->domain && *wr->s->domain)
-                jk_puts(s, wr->s->domain);
-            else
-                jk_puts(s,"&nbsp;");
-            jk_puts(s, "</td><td>");
-            if (wr->s->state == JK_LB_STATE_ERROR) {
-                int rs = lb->maintain_time - (int)difftime(now, lb->s->last_maintain_time);
-                if (rs < lb->recover_wait_time - (int)difftime(now, wr->s->error_time))
-                    rs += lb->maintain_time;
-                jk_printf(s, "%u", rs < 0 ? 0 : rs);
+        jk_puts(s, "</tr>\n</table>\n\n");
+        if (show_members) {
+            jk_puts(s, "<h4>Balancer Members [");
+            if (single) {
+                status_write_uri(s, "Hide", JK_STATUS_CMD_SHOW,
+                                 JK_STATUS_MIME_HTML, from, refresh, name, NULL, JK_STATUS_ATT_NO_MEMBERS);
             }
-            else
-                jk_puts(s, "-");
-            jk_puts(s, "</td>\n</tr>\n");
+            else {
+                status_write_uri(s, "Hide", JK_STATUS_CMD_LIST,
+                                 JK_STATUS_MIME_HTML, from, refresh, name, NULL, JK_STATUS_ATT_NO_MEMBERS);
+            }
+            jk_puts(s, "]</h4>\n");
+            jk_puts(s, "<table>" JK_STATUS_SHOW_MEMBER_HEAD);
+            for (j = 0; j < lb->num_of_workers; j++) {
+                worker_record_t *wr = &(lb->lb_workers[j]);
+                ajp_worker_t *a = (ajp_worker_t *)wr->w->worker_private;
+                int rs = 0;
+                if (wr->s->state == JK_LB_STATE_ERROR) {
+                    rs = lb->maintain_time - (int)difftime(now, lb->s->last_maintain_time);
+                    if (rs < lb->recover_wait_time - (int)difftime(now, wr->s->error_time))
+                        rs += lb->maintain_time;
+                }
+                jk_puts(s, "<tr>\n<td>[");
+                status_write_uri(s, "E", JK_STATUS_CMD_EDIT,
+                                 0, from, refresh, name, wr->s->name, NULL);
+                jk_puts(s, "|");
+                status_write_uri(s, "R", JK_STATUS_CMD_RESET,
+                                 0, from, refresh, name, wr->s->name, NULL);
+                jk_puts(s, "]&nbsp;</td>");
+                jk_printf(s, JK_STATUS_SHOW_MEMBER_ROW,
+                          wr->s->name,
+                          status_worker_type(wr->w->type),
+                          a->host, a->port,
+                          jk_dump_hinfo(&a->worker_inet_addr, buf),
+                          jk_lb_get_activation(wr, l),
+                          jk_lb_get_state(wr, l),
+                          wr->s->distance,
+                          wr->s->lb_factor,
+                          wr->s->lb_mult,
+                          wr->s->lb_value,
+                          wr->s->elected,
+                          wr->s->errors,
+                          wr->s->client_errors,
+                          status_strfsize(wr->s->transferred, buf),
+                          status_strfsize(wr->s->readed, buf),
+                          wr->s->busy,
+                          wr->s->max_busy,
+                          wr->s->route,
+                          wr->s->redirect ? (*wr->s->redirect ? wr->s->redirect : "&nbsp;") : "&nbsp",
+                          wr->s->domain ? (*wr->s->domain ? wr->s->domain : "&nbsp;") : "&nbsp",
+                          rs);
+            }
+            jk_puts(s, "</table><br/>\n");
+            jk_puts(s, "<b>E</b>dit one attribute for all members: [");
+            status_write_uri(s, JK_STATUS_ARG_LBM_TEXT_ACTIVATION, JK_STATUS_CMD_EDIT,
+                             0, from, refresh, name, NULL, JK_STATUS_ARG_LBM_ACTIVATION);
+            jk_puts(s, "\n|");
+            status_write_uri(s, JK_STATUS_ARG_LBM_TEXT_FACTOR, JK_STATUS_CMD_EDIT,
+                             0, from, refresh, name, NULL, JK_STATUS_ARG_LBM_FACTOR);
+            jk_puts(s, "\n|");
+            status_write_uri(s, JK_STATUS_ARG_LBM_TEXT_ROUTE, JK_STATUS_CMD_EDIT,
+                             0, from, refresh, name, NULL, JK_STATUS_ARG_LBM_ROUTE);
+            jk_puts(s, "\n|");
+            status_write_uri(s, JK_STATUS_ARG_LBM_TEXT_REDIRECT, JK_STATUS_CMD_EDIT,
+                             0, from, refresh, name, NULL, JK_STATUS_ARG_LBM_REDIRECT);
+            jk_puts(s, "\n|");
+            status_write_uri(s, JK_STATUS_ARG_LBM_TEXT_DOMAIN, JK_STATUS_CMD_EDIT,
+                             0, from, refresh, name, NULL, JK_STATUS_ARG_LBM_DOMAIN);
+            jk_puts(s, "\n|");
+            status_write_uri(s, JK_STATUS_ARG_LBM_TEXT_DISTANCE, JK_STATUS_CMD_EDIT,
+                             0, from, refresh, name, NULL, JK_STATUS_ARG_LBM_DISTANCE);
+            jk_puts(s, "\n]<br/>\n");
         }
-        jk_puts(s, "</table><br/>\n");
+        else {
+            jk_puts(s, "<p>\n");
+            if (single) {
+                status_write_uri(s, "Show Balancer Members", JK_STATUS_CMD_SHOW,
+                                 JK_STATUS_MIME_HTML, from, refresh, name, NULL, NULL);
+            }
+            else {
+                status_write_uri(s, "Show Balancer Members", JK_STATUS_CMD_LIST,
+                                 JK_STATUS_MIME_HTML, from, refresh, name, NULL, NULL);
+            }
+            jk_puts(s, "</p>\n");
+        }
+
     }
     else if (aw) {
         jk_puts(s, "<hr/><h3>[");
@@ -850,16 +1330,14 @@
             jk_puts(s, "S");
         else
             status_write_uri(s, "S", JK_STATUS_CMD_SHOW,
-                             0, from, refresh, name, NULL);
+                             0, from, refresh, name, NULL, NULL);
         jk_puts(s, "]&nbsp;&nbsp;");
         jk_putv(s, "Worker Status for ", name, "<h3/>\n", NULL);
-        jk_puts(s, "\n\n<table><tr>"
-                "<th>Type</th><th>Host</th><th>Addr</th>"
-                "</tr>\n<tr>");
-        jk_putv(s, "<td>", status_worker_type(w->type), "</td>", NULL);
-        jk_printf(s, "<td>%s:%d</td>", aw->host, aw->port);
-        jk_putv(s, "<td>", jk_dump_hinfo(&aw->worker_inet_addr, buf),
-                "</td>\n</tr>\n", NULL);
+        jk_puts(s, "<table>" JK_STATUS_SHOW_AJP_HEAD);
+        jk_printf(s, JK_STATUS_SHOW_AJP_ROW,
+                  status_worker_type(w->type),
+                  aw->host, aw->port,
+                  jk_dump_hinfo(&aw->worker_inet_addr, buf));
         jk_puts(s, "</table>\n");
     }
     if (name)
@@ -868,7 +1346,7 @@
 }
 
 static void display_worker_xml(jk_ws_service_t *s, jk_worker_t *w,
-                               status_worker_t *sw, int single,
+                               status_worker_t *sw, int show_members, int single,
                                jk_logger_t *l)
 {
     char buf[32];
@@ -916,91 +1394,94 @@
 
         for (j = 0; j < lb->num_of_workers; j++) {
             worker_record_t *wr = &(lb->lb_workers[j]);
-            if (wr->s->state == JK_LB_STATE_ERROR ||
-               wr->s->state == JK_LB_STATE_RECOVER ||
-               wr->s->activation == JK_LB_ACTIVATION_STOPPED)
+            int rate;
+            rate = status_rate(wr, sw, l);
+            if (rate > 0 )
+               good++;
+            else if (rate < 0 )
                bad++;
-            else if (wr->s->state == JK_LB_STATE_BUSY ||
-               wr->s->activation == JK_LB_ACTIVATION_DISABLED)
-               degraded++;
             else
-               good++;
+               degraded++;
         }
 
-        jk_putv(s, "  <", sw->ns, "balancer\n", NULL);
-        jk_printf(s, "    name=\"%s\"\n", name);
-        jk_printf(s, "    type=\"%s\"\n", status_worker_type(w->type));
-        jk_printf(s, "    sticky=\"%s\"\n", status_val_bool(lb->sticky_session));
-        jk_printf(s, "    stickyforce=\"%s\"\n", status_val_bool(lb->sticky_session_force));
-        jk_printf(s, "    retries=\"%d\"\n", lb->retries);
-        jk_printf(s, "    recover=\"%d\"\n", lb->recover_wait_time);
-        jk_printf(s, "    method=\"%s\"\n", jk_lb_get_method(lb, l));
-        jk_printf(s, "    lock=\"%s\"\n", jk_lb_get_lock(lb, l));
-        jk_printf(s, "    good=\"%d\"\n", good);
-        jk_printf(s, "    degraded=\"%d\"\n", degraded);
-        jk_printf(s, "    bad=\"%d\"\n", bad);
-        jk_printf(s, "    busy=\"%d\"\n", lb->s->busy);
-        jk_printf(s, "    max_busy=\"%d\">\n", lb->s->max_busy);
-
-        for (j = 0; j < lb->num_of_workers; j++) {
-            worker_record_t *wr = &(lb->lb_workers[j]);
-            ajp_worker_t *a = (ajp_worker_t *)wr->w->worker_private;
-            int rs = 0;
-            /* TODO: descriptive status */
-            jk_putv(s, "      <", sw->ns, "member\n", NULL);
-            jk_printf(s, "        name=\"%s\"\n", wr->s->name);
-            jk_printf(s, "        type=\"%s\"\n", status_worker_type(wr->w->type));
-            jk_printf(s, "        host=\"%s\"\n", a->host);
-            jk_printf(s, "        port=\"%d\"\n", a->port);
-            jk_printf(s, "        address=\"%s\"\n", jk_dump_hinfo(&a->worker_inet_addr, buf));
-            jk_printf(s, "        activation=\"%s\"\n", jk_lb_get_activation(wr, l));
-            jk_printf(s, "        lbfactor=\"%d\"\n", wr->s->lb_factor);
-            jk_printf(s, "        route=\"%s\"\n", wr->s->route ? wr->s->route : "");
-            jk_printf(s, "        redirect=\"%s\"\n", wr->s->redirect ? wr->s->redirect : "");
-            jk_printf(s, "        domain=\"%s\"\n", wr->s->domain ? wr->s->domain : "");
-            jk_printf(s, "        distance=\"%d\"\n", wr->s->distance);
-            jk_printf(s, "        state=\"%s\"\n", jk_lb_get_state(wr, l));
-            jk_printf(s, "        lbmult=\"%" JK_UINT64_T_FMT "\"\n", wr->s->lb_mult);
-            jk_printf(s, "        lbvalue=\"%" JK_UINT64_T_FMT "\"\n", wr->s->lb_value);
-            jk_printf(s, "        elected=\"%" JK_UINT64_T_FMT "\"\n", wr->s->elected);
-            jk_printf(s, "        errors=\"%" JK_UINT32_T_FMT "\"\n", wr->s->errors);
-            jk_printf(s, "        clienterrors=\"%" JK_UINT32_T_FMT "\"\n", wr->s->client_errors);
-            jk_printf(s, "        transferred=\"%" JK_UINT64_T_FMT "\"\n", wr->s->transferred);
-            jk_printf(s, "        readed=\"%" JK_UINT64_T_FMT "\"\n", wr->s->readed);
-            jk_printf(s, "        busy=\"%u\"\n", wr->s->busy);
-            jk_printf(s, "        maxbusy=\"%u\"\n", wr->s->max_busy);
-            if (wr->s->state == JK_LB_STATE_ERROR) {
-                int rs = lb->maintain_time - (int)difftime(now, lb->s->last_maintain_time);
-                if (rs < lb->recover_wait_time - (int)difftime(now, wr->s->error_time))
-                    rs += lb->maintain_time;
-            }
-            jk_printf(s, "        time_to_recover=\"%u\"", rs < 0 ? 0 : rs);
-            /* Terminate the tag */
-            jk_puts(s, "/>\n");
+        jk_print_xml_start_elt(s, sw, 2, 0, "balancer");
+        jk_print_xml_att_string(s, 4, "name", name);
+        jk_print_xml_att_string(s, 4, "type", status_worker_type(w->type));
+        jk_print_xml_att_string(s, 4, "sticky_session", status_val_bool(lb->sticky_session));
+        jk_print_xml_att_string(s, 4, "sticky_session_force", status_val_bool(lb->sticky_session_force));
+        jk_print_xml_att_int(s, 4, "retries", lb->retries);
+        jk_print_xml_att_int(s, 4, "recover_time", lb->recover_wait_time);
+        jk_print_xml_att_string(s, 4, "method", jk_lb_get_method(lb, l));
+        jk_print_xml_att_string(s, 4, "lock", jk_lb_get_lock(lb, l));
+        jk_print_xml_att_int(s, 4, "member_count", lb->num_of_workers);
+        jk_print_xml_att_int(s, 4, "good", good);
+        jk_print_xml_att_int(s, 4, "degraded", degraded);
+        jk_print_xml_att_int(s, 4, "bad", bad);
+        jk_print_xml_att_int(s, 4, "busy", lb->s->busy);
+        jk_print_xml_att_int(s, 4, "max_busy", lb->s->max_busy);
+        jk_print_xml_stop_elt(s, 2, 0);
+
+        if (show_members) {
+            for (j = 0; j < lb->num_of_workers; j++) {
+                worker_record_t *wr = &(lb->lb_workers[j]);
+                ajp_worker_t *a = (ajp_worker_t *)wr->w->worker_private;
+                int rs = 0;
+                if (wr->s->state == JK_LB_STATE_ERROR) {
+                    rs = lb->maintain_time - (int)difftime(now, lb->s->last_maintain_time);
+                    if (rs < lb->recover_wait_time - (int)difftime(now, wr->s->error_time))
+                        rs += lb->maintain_time;
+                }
+                /* TODO: descriptive status */
+                jk_print_xml_start_elt(s, sw, 6, 0, "member");
+                jk_print_xml_att_string(s, 8, "name", wr->s->name);
+                jk_print_xml_att_string(s, 8, "type", status_worker_type(wr->w->type));
+                jk_print_xml_att_string(s, 8, "host", a->host);
+                jk_print_xml_att_int(s, 8, "port", a->port);
+                jk_print_xml_att_string(s, 8, "address", jk_dump_hinfo(&a->worker_inet_addr, buf));
+                jk_print_xml_att_string(s, 8, "activation", jk_lb_get_activation(wr, l));
+                jk_print_xml_att_int(s, 8, "lbfactor", wr->s->lb_factor);
+                jk_print_xml_att_string(s, 8, "route", wr->s->route);
+                jk_print_xml_att_string(s, 8, "redirect", wr->s->redirect);
+                jk_print_xml_att_string(s, 8, "domain", wr->s->domain);
+                jk_print_xml_att_int(s, 8, "distance", wr->s->distance);
+                jk_print_xml_att_string(s, 8, "state", jk_lb_get_state(wr, l));
+                jk_print_xml_att_uint64(s, 8, "lbmult", wr->s->lb_mult);
+                jk_print_xml_att_uint64(s, 8, "lbvalue", wr->s->lb_value);
+                jk_print_xml_att_uint64(s, 8, "elected", wr->s->elected);
+                jk_print_xml_att_uint32(s, 8, "errors", wr->s->errors);
+                jk_print_xml_att_uint32(s, 8, "client_errors", wr->s->client_errors);
+                jk_print_xml_att_uint64(s, 8, "transferred", wr->s->transferred);
+                jk_print_xml_att_uint64(s, 8, "read", wr->s->readed);
+                jk_print_xml_att_uint(s, 8, "busy", wr->s->busy);
+                jk_print_xml_att_uint(s, 8, "max_busy", wr->s->max_busy);
+                jk_print_xml_att_uint(s, 8, "time_to_recover", rs < 0 ? 0 : rs);
+                /* Terminate the tag */
+                jk_print_xml_stop_elt(s, 6, 1);
+            }
         }
         if (name)
             display_maps_xml(s, s->uw_map, sw, name, l);
-        jk_putv(s, "  </", sw->ns, "balancer>\n", NULL);
+        jk_print_xml_close_elt(s, sw, 2, "balancer");
     }
     else if (aw) {
-        jk_putv(s, "<", sw->ns, "ajp\n", NULL);
-        jk_printf(s, "  name=\"%s\"\n", name);
-        jk_printf(s, "  type=\"%s\"\n", status_worker_type(w->type));
-        jk_printf(s, "  host=\"%s\"\n", aw->host);
-        jk_printf(s, "  port=\"%d\"\n", aw->port);
-        jk_printf(s, "  address=\"%s\"", jk_dump_hinfo(&aw->worker_inet_addr, buf));
+        jk_print_xml_start_elt(s, sw, 0, 0, "ajp");
+        jk_print_xml_att_string(s, 2, "name", name);
+        jk_print_xml_att_string(s, 2, "type", status_worker_type(w->type));
+        jk_print_xml_att_string(s, 2, "host", aw->host);
+        jk_print_xml_att_int(s, 2, "port", aw->port);
+        jk_print_xml_att_string(s, 2, "address", jk_dump_hinfo(&aw->worker_inet_addr, buf));
         /* Terminate the tag */
-        jk_puts(s, ">\n");
+        jk_print_xml_stop_elt(s, 0, 0);
         if (name)
             display_maps_xml(s, s->uw_map, sw, name, l);
-        jk_putv(s, "</", sw->ns, "ajp>\n", NULL);
+        jk_print_xml_close_elt(s, sw, 0, "ajp");
     }
     JK_TRACE_EXIT(l);
 }
 
 static void display_worker_txt(jk_ws_service_t *s, jk_worker_t *w,
-                              int single,
-                              jk_logger_t *l)
+                               status_worker_t *sw, int show_members, int single,
+                               jk_logger_t *l)
 {
     char buf[32];
     const char *name = NULL;
@@ -1047,78 +1528,201 @@
 
         for (j = 0; j < lb->num_of_workers; j++) {
             worker_record_t *wr = &(lb->lb_workers[j]);
-            if (wr->s->state == JK_LB_STATE_ERROR ||
-               wr->s->state == JK_LB_STATE_RECOVER ||
-               wr->s->activation == JK_LB_ACTIVATION_STOPPED)
+            int rate;
+            rate = status_rate(wr, sw, l);
+            if (rate > 0 )
+               good++;
+            else if (rate < 0 )
                bad++;
-            else if (wr->s->state == JK_LB_STATE_BUSY ||
-               wr->s->activation == JK_LB_ACTIVATION_DISABLED)
-               degraded++;
             else
-               good++;
+               degraded++;
         }
 
-        jk_printf(s, "Balancer:");
+        jk_puts(s, "Balancer Worker:");
         jk_printf(s, " name=%s", name);
         jk_printf(s, " type=%s", status_worker_type(w->type));
-        jk_printf(s, " sticky=%s", status_val_bool(lb->sticky_session));
-        jk_printf(s, " stickyforce=%s", status_val_bool(lb->sticky_session_force));
+        jk_printf(s, " sticky_session=%s", status_val_bool(lb->sticky_session));
+        jk_printf(s, " sticky_session_force=%s", status_val_bool(lb->sticky_session_force));
         jk_printf(s, " retries=%d", lb->retries);
-        jk_printf(s, " recover=%d", lb->recover_wait_time);
+        jk_printf(s, " recover_time=%d", lb->recover_wait_time);
         jk_printf(s, " method=%s", jk_lb_get_method(lb, l));
         jk_printf(s, " lock=%s", jk_lb_get_lock(lb, l));
+        jk_printf(s, " member_count=%d", lb->num_of_workers);
         jk_printf(s, " good=%d", good);
         jk_printf(s, " degraded=%d", degraded);
         jk_printf(s, " bad=%d", bad);
         jk_printf(s, " busy=%d", lb->s->busy);
         jk_printf(s, " max_busy=%d", lb->s->max_busy);
-        jk_printf(s, " members=%d\n", lb->num_of_workers);
+        jk_puts(s, "\n");
 
-        for (j = 0; j < lb->num_of_workers; j++) {
-            worker_record_t *wr = &(lb->lb_workers[j]);
-            ajp_worker_t *a = (ajp_worker_t *)wr->w->worker_private;
-            int rs = 0;
-            /* TODO: descriptive status */
-            jk_printf(s, "Member:");
-            jk_printf(s, " name=%s", wr->s->name);
-            jk_printf(s, " type=%s", status_worker_type(wr->w->type));
-            jk_printf(s, " host=%s", a->host);
-            jk_printf(s, " port=%d", a->port);
-            jk_printf(s, " address=%s", jk_dump_hinfo(&a->worker_inet_addr, buf));
-            jk_printf(s, " activation=%s", jk_lb_get_activation(wr, l));
-            jk_printf(s, " lbfactor=%d", wr->s->lb_factor);
-            jk_printf(s, " route=%s", wr->s->route ? wr->s->route : "");
-            jk_printf(s, " redirect=%s", wr->s->redirect ? wr->s->redirect : "");
-            jk_printf(s, " domain=%s", wr->s->domain ? wr->s->domain : "");
-            jk_printf(s, " distance=%d", wr->s->distance);
-            jk_printf(s, " state=%s", jk_lb_get_state(wr, l));
-            jk_printf(s, " lbmult=%" JK_UINT64_T_FMT, wr->s->lb_mult);
-            jk_printf(s, " lbvalue=%" JK_UINT64_T_FMT, wr->s->lb_value);
-            jk_printf(s, " elected=%" JK_UINT64_T_FMT, wr->s->elected);
-            jk_printf(s, " errors=%" JK_UINT32_T_FMT, wr->s->errors);
-            jk_printf(s, " clienterrors=%" JK_UINT32_T_FMT, wr->s->client_errors);
-            jk_printf(s, " transferred=%" JK_UINT64_T_FMT, wr->s->transferred);
-            jk_printf(s, " readed=%" JK_UINT64_T_FMT, wr->s->readed);
-            jk_printf(s, " busy=%u", wr->s->busy);
-            jk_printf(s, " maxbusy=%u", wr->s->max_busy);
-            if (wr->s->state == JK_LB_STATE_ERROR) {
-                int rs = lb->maintain_time - (int)difftime(now, lb->s->last_maintain_time);
-                if (rs < lb->recover_wait_time - (int)difftime(now, wr->s->error_time))
-                    rs += lb->maintain_time;
+        if (show_members) {
+            for (j = 0; j < lb->num_of_workers; j++) {
+                worker_record_t *wr = &(lb->lb_workers[j]);
+                ajp_worker_t *a = (ajp_worker_t *)wr->w->worker_private;
+                int rs = 0;
+                if (wr->s->state == JK_LB_STATE_ERROR) {
+                    rs = lb->maintain_time - (int)difftime(now, lb->s->last_maintain_time);
+                    if (rs < lb->recover_wait_time - (int)difftime(now, wr->s->error_time))
+                        rs += lb->maintain_time;
+                }
+                jk_puts(s, "Member:");
+                jk_printf(s, " name=%s", wr->s->name);
+                jk_printf(s, " type=%s", status_worker_type(wr->w->type));
+                jk_printf(s, " host=%s", a->host);
+                jk_printf(s, " port=%d", a->port);
+                jk_printf(s, " address=%s", jk_dump_hinfo(&a->worker_inet_addr, buf));
+                jk_printf(s, " activation=%s", jk_lb_get_activation(wr, l));
+                jk_printf(s, " lbfactor=%d", wr->s->lb_factor);
+                jk_printf(s, " route=\"%s\"", wr->s->route ? wr->s->route : "");
+                jk_printf(s, " redirect=\"%s\"", wr->s->redirect ? wr->s->redirect : "");
+                jk_printf(s, " domain=\"%s\"", wr->s->domain ? wr->s->domain : "");
+                jk_printf(s, " distance=%d", wr->s->distance);
+                jk_printf(s, " state=%s", jk_lb_get_state(wr, l));
+                jk_printf(s, " lbmult=%" JK_UINT64_T_FMT, wr->s->lb_mult);
+                jk_printf(s, " lbvalue=%" JK_UINT64_T_FMT, wr->s->lb_value);
+                jk_printf(s, " elected=%" JK_UINT64_T_FMT, wr->s->elected);
+                jk_printf(s, " errors=%" JK_UINT32_T_FMT, wr->s->errors);
+                jk_printf(s, " client_errors=%" JK_UINT32_T_FMT, wr->s->client_errors);
+                jk_printf(s, " transferred=%" JK_UINT64_T_FMT, wr->s->transferred);
+                jk_printf(s, " read=%" JK_UINT64_T_FMT, wr->s->readed);
+                jk_printf(s, " busy=%u", wr->s->busy);
+                jk_printf(s, " max_busy=%u", wr->s->max_busy);
+                jk_printf(s, " time_to_recover=%u", rs < 0 ? 0 : rs);
+                jk_puts(s, "\n");
             }
-            jk_printf(s, " time_to_recover=%u\n", rs < 0 ? 0 : rs);
         }
     }
     else if (aw) {
-        jk_printf(s, "Ajp:");
+        jk_puts(s, "AJP Worker:");
         jk_printf(s, " name=%s", name);
         jk_printf(s, " type=%s", status_worker_type(w->type));
         jk_printf(s, " host=%s", aw->host);
         jk_printf(s, " port=%d", aw->port);
-        jk_printf(s, " address=%s\n", jk_dump_hinfo(&aw->worker_inet_addr, buf));
+        jk_printf(s, " address=%s", jk_dump_hinfo(&aw->worker_inet_addr, buf));
+        jk_puts(s, "\n");
     }
     if (name)
-        display_maps_txt(s, s->uw_map, name, l);
+        display_maps_txt(s, s->uw_map, sw, name, l);
+    JK_TRACE_EXIT(l);
+}
+
+static void display_worker_prop(jk_ws_service_t *s, jk_worker_t *w,
+                                status_worker_t *sw, int show_members, int single,
+                                jk_logger_t *l)
+{
+    char buf[32];
+    const char *name = NULL;
+    ajp_worker_t *aw = NULL;
+    lb_worker_t *lb = NULL;
+
+    JK_TRACE_ENTER(l);
+    if (w->type == JK_LB_WORKER_TYPE) {
+        lb = (lb_worker_t *)w->worker_private;
+        name = lb->s->name;
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "%s lb worker '%s' as txt",
+                   single ? "showing" : "listing", name);
+    }
+    else if (w->type == JK_AJP13_WORKER_TYPE ||
+             w->type == JK_AJP14_WORKER_TYPE) {
+        aw = (ajp_worker_t *)w->worker_private;
+        name = aw->name;
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "%s ajp worker '%s' as txt",
+                   single ? "showing" : "listing", name);
+    }
+    else {
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "worker type not implemented");
+        JK_TRACE_EXIT(l);
+        return;
+    }
+
+    jk_print_prop_att_string(s, sw, NULL, "list", name);
+    if (lb) {
+        time_t now = time(NULL);
+        unsigned int good = 0;
+        unsigned int degraded = 0;
+        unsigned int bad = 0;
+        unsigned int j;
+
+        jk_shm_lock();
+        if (lb->sequence != lb->s->sequence)
+            jk_lb_pull(lb, l);
+        jk_shm_unlock();
+
+        for (j = 0; j < lb->num_of_workers; j++) {
+            worker_record_t *wr = &(lb->lb_workers[j]);
+            int rate;
+            rate = status_rate(wr, sw, l);
+            if (rate > 0 )
+               good++;
+            else if (rate < 0 )
+               bad++;
+            else
+               degraded++;
+        }
+
+        jk_print_prop_att_string(s, sw, name, "type", status_worker_type(w->type));
+        jk_print_prop_att_string(s, sw, name, "sticky_session", status_val_bool(lb->sticky_session));
+        jk_print_prop_att_string(s, sw, name, "sticky_session_force", status_val_bool(lb->sticky_session_force));
+        jk_print_prop_att_int(s, sw, name, "retries", lb->retries);
+        jk_print_prop_att_int(s, sw, name, "recover_time", lb->recover_wait_time);
+        jk_print_prop_att_string(s, sw, name, "method", jk_lb_get_method(lb, l));
+        jk_print_prop_att_string(s, sw, name, "lock", jk_lb_get_lock(lb, l));
+        jk_print_prop_att_int(s, sw, name, "member_count", lb->num_of_workers);
+        jk_print_prop_att_int(s, sw, name, "good", good);
+        jk_print_prop_att_int(s, sw, name, "degraded", degraded);
+        jk_print_prop_att_int(s, sw, name, "bad", bad);
+        jk_print_prop_att_int(s, sw, name, "busy", lb->s->busy);
+        jk_print_prop_att_int(s, sw, name, "max_busy", lb->s->max_busy);
+
+        if (show_members) {
+            for (j = 0; j < lb->num_of_workers; j++) {
+                worker_record_t *wr = &(lb->lb_workers[j]);
+                ajp_worker_t *a = (ajp_worker_t *)wr->w->worker_private;
+                int rs = 0;
+                if (wr->s->state == JK_LB_STATE_ERROR) {
+                    rs = lb->maintain_time - (int)difftime(now, lb->s->last_maintain_time);
+                    if (rs < lb->recover_wait_time - (int)difftime(now, wr->s->error_time))
+                        rs += lb->maintain_time;
+                }
+                jk_print_prop_att_string(s, sw, name, "balance_workers", wr->s->name);
+                jk_print_prop_att_string(s, sw, wr->s->name, "type", status_worker_type(wr->w->type));
+                jk_print_prop_att_string(s, sw, wr->s->name, "host", a->host);
+                jk_print_prop_att_int(s, sw, wr->s->name, "port", a->port);
+                jk_print_prop_att_string(s, sw, wr->s->name, "address", jk_dump_hinfo(&a->worker_inet_addr, buf));
+                jk_print_prop_att_string(s, sw, wr->s->name, "activation", jk_lb_get_activation(wr, l));
+                jk_print_prop_att_int(s, sw, wr->s->name, "lbfactor", wr->s->lb_factor);
+                jk_print_prop_att_string(s, sw, wr->s->name, "route", wr->s->route);
+                jk_print_prop_att_string(s, sw, wr->s->name, "redirect", wr->s->redirect);
+                jk_print_prop_att_string(s, sw, wr->s->name, "domain", wr->s->domain);
+                jk_print_prop_att_int(s, sw, wr->s->name, "distance", wr->s->distance);
+                jk_print_prop_att_string(s, sw, wr->s->name, "state", jk_lb_get_state(wr, l));
+                jk_print_prop_att_uint64(s, sw, wr->s->name, "lbmult", wr->s->lb_mult);
+                jk_print_prop_att_uint64(s, sw, wr->s->name, "lbvalue", wr->s->lb_value);
+                jk_print_prop_att_uint64(s, sw, wr->s->name, "elected", wr->s->elected);
+                jk_print_prop_att_uint32(s, sw, wr->s->name, "errors", wr->s->errors);
+                jk_print_prop_att_uint32(s, sw, wr->s->name, "client_errors", wr->s->client_errors);
+                jk_print_prop_att_uint64(s, sw, wr->s->name, "transferred", wr->s->transferred);
+                jk_print_prop_att_uint64(s, sw, wr->s->name, "read", wr->s->readed);
+                jk_print_prop_att_uint(s, sw, wr->s->name, "busy", wr->s->busy);
+                jk_print_prop_att_uint(s, sw, wr->s->name, "max_busy", wr->s->max_busy);
+                jk_print_prop_att_uint(s, sw, wr->s->name, "time_to_recover", rs < 0 ? 0 : rs);
+            }
+        }
+    }
+    else if (aw) {
+        jk_print_prop_att_string(s, sw, name, "type", status_worker_type(w->type));
+        jk_print_prop_att_string(s, sw, name, "host", aw->host);
+        jk_print_prop_att_int(s, sw, name, "port", aw->port);
+        jk_print_prop_att_string(s, sw, name, "address", jk_dump_hinfo(&aw->worker_inet_addr, buf));
+    }
+    if (name)
+        display_maps_prop(s, s->uw_map, sw, name, l);
     JK_TRACE_EXIT(l);
 }
 
@@ -1130,10 +1734,6 @@
     lb_worker_t *lb = NULL;
 
     JK_TRACE_ENTER(l);
-    jk_puts(s, "<hr/>\n");
-    status_write_uri(s, "Back to worker view", from,
-                     0, 0, refresh, NULL, NULL);
-    jk_puts(s, "<br/>\n");
     if (w->type == JK_LB_WORKER_TYPE) {
         lb = (lb_worker_t *)w->worker_private;
         name = lb->s->name;
@@ -1160,7 +1760,7 @@
             name, "</h3>\n", NULL);
 
     status_start_form(s, "GET", JK_STATUS_CMD_UPDATE,
-                      0, from, refresh, name, NULL);
+                      0, from, refresh, name, NULL, NULL);
 
     jk_putv(s, "<table>\n<tr><td>", JK_STATUS_ARG_LB_TEXT_RETRIES,
             ":</td><td><input name=\"",
@@ -1225,46 +1825,6 @@
     jk_puts(s, "</table>\n");
     jk_puts(s, "<br/><input type=\"submit\" value=\"Update Balancer\"/></form>\n");
 
-    jk_putv(s, "<hr/><h3>Edit load balancer member settings by type for ",
-            name, "</h3>\n", NULL);
-    jk_puts(s, "[<a href=\"");
-    status_write_uri(s, NULL, JK_STATUS_CMD_EDIT,
-                     0, from, refresh, name, NULL);
-    jk_putv(s, "&", JK_STATUS_ARG_LB_MEMBER_ATT, "=",
-            JK_STATUS_ARG_LBM_ACTIVATION, "\">",
-            JK_STATUS_ARG_LBM_TEXT_ACTIVATION, "</a>\n", NULL);
-    jk_puts(s, "|<a href=\"");
-    status_write_uri(s, NULL, JK_STATUS_CMD_EDIT,
-                     0, from, refresh, name, NULL);
-    jk_putv(s, "&", JK_STATUS_ARG_LB_MEMBER_ATT, "=",
-            JK_STATUS_ARG_LBM_FACTOR, "\">",
-            JK_STATUS_ARG_LBM_TEXT_FACTOR, "</a>\n", NULL);
-    jk_puts(s, "|<a href=\"");
-    status_write_uri(s, NULL, JK_STATUS_CMD_EDIT,
-                     0, from, refresh, name, NULL);
-    jk_putv(s, "&", JK_STATUS_ARG_LB_MEMBER_ATT, "=",
-            JK_STATUS_ARG_LBM_ROUTE, "\">",
-            JK_STATUS_ARG_LBM_TEXT_ROUTE, "</a>\n", NULL);
-    jk_puts(s, "|<a href=\"");
-    status_write_uri(s, NULL, JK_STATUS_CMD_EDIT,
-                     0, from, refresh, name, NULL);
-    jk_putv(s, "&", JK_STATUS_ARG_LB_MEMBER_ATT, "=",
-            JK_STATUS_ARG_LBM_REDIRECT, "\">",
-            JK_STATUS_ARG_LBM_TEXT_REDIRECT, "</a>\n", NULL);
-    jk_puts(s, "|<a href=\"");
-    status_write_uri(s, NULL, JK_STATUS_CMD_EDIT,
-                     0, from, refresh, name, NULL);
-    jk_putv(s, "&", JK_STATUS_ARG_LB_MEMBER_ATT, "=",
-            JK_STATUS_ARG_LBM_DOMAIN, "\">",
-            JK_STATUS_ARG_LBM_TEXT_DOMAIN, "</a>\n", NULL);
-    jk_puts(s, "|<a href=\"");
-    status_write_uri(s, NULL, JK_STATUS_CMD_EDIT,
-                     0, from, refresh, name, NULL);
-    jk_putv(s, "&", JK_STATUS_ARG_LB_MEMBER_ATT, "=",
-            JK_STATUS_ARG_LBM_DISTANCE, "\">",
-            JK_STATUS_ARG_LBM_TEXT_DISTANCE, "</a>\n", NULL);
-    jk_puts(s, "]<br/>\n");
-
     JK_TRACE_EXIT(l);
 }
 
@@ -1279,14 +1839,10 @@
                "producing edit form for sub worker '%s' of lb worker '%s'",
                wr->s->name, worker);
 
-    jk_puts(s, "<hr/>\n");
-    status_write_uri(s, "Back to worker view", from,
-                     0, 0, refresh, NULL, NULL);
-    jk_puts(s, "<br/>\n");
     jk_putv(s, "<hr/><h3>Edit worker settings for ",
             wr->s->name, "</h3>\n", NULL);
     status_start_form(s, "GET", JK_STATUS_CMD_UPDATE,
-                      0, from, refresh, worker, wr->s->name);
+                      0, from, refresh, worker, wr->s->name, NULL);
 
     jk_puts(s, "<table>\n");
     jk_putv(s, "<tr><td>", JK_STATUS_ARG_LBM_TEXT_ACTIVATION,
@@ -1347,14 +1903,10 @@
     unsigned int i;
 
     JK_TRACE_ENTER(l);
-    jk_puts(s, "<hr/>\n");
-    status_write_uri(s, "Back to worker view", from,
-                     0, 0, refresh, NULL, NULL);
-    jk_puts(s, "<br/>\n");
     if (!attribute) {
         jk_log(l, JK_LOG_WARNING,
                "missing request parameter '%s'",
-               JK_STATUS_ARG_LB_MEMBER_ATT);
+               JK_STATUS_ARG_OPTION);
         JK_TRACE_EXIT(l);
         return;
     }
@@ -1400,11 +1952,7 @@
                 name, "</h3>\n", NULL);
 
         status_start_form(s, "GET", JK_STATUS_CMD_UPDATE,
-                          0, from, refresh, name, NULL);
-
-        jk_putv(s, "<input type=\"hidden\" name=\"",
-                JK_STATUS_ARG_LB_MEMBER_ATT, "\" ", NULL);
-        jk_putv(s, "value=\"", attribute, "\"/>\n", NULL);
+                          0, from, refresh, name, NULL, attribute);
 
         jk_putv(s, "<table><tr>"
                 "<th>Balanced Worker</th><th>", aname, "</th>"
@@ -1498,7 +2046,7 @@
         jk_lb_pull(lb, l);
 
     i = status_get_int(JK_STATUS_ARG_LB_RETRIES,
-                       s->query_string, lb->retries);
+                       s->query_string, lb->retries, l);
     if (i != lb->retries && i > 0) {
         jk_log(l, JK_LOG_INFO,
                "setting 'retries' for lb worker '%s' to '%i'",
@@ -1506,7 +2054,7 @@
         lb->retries = i;
     }
     i = status_get_int(JK_STATUS_ARG_LB_RECOVER_TIME,
-                       s->query_string, lb->recover_wait_time);
+                       s->query_string, lb->recover_wait_time, l);
     if (i != lb->recover_wait_time && i > 0) {
         jk_log(l, JK_LOG_INFO,
                "setting 'recover_time' for lb worker '%s' to '%i'",
@@ -1514,7 +2062,7 @@
         lb->recover_wait_time = i;
     }
     i = status_get_bool(JK_STATUS_ARG_LB_STICKY,
-                        s->query_string, 0);
+                        s->query_string, 0, l);
     if (i != lb->sticky_session && i > 0) {
         jk_log(l, JK_LOG_INFO,
                "setting 'sticky_session' for lb worker '%s' to '%i'",
@@ -1522,7 +2070,7 @@
         lb->sticky_session = i;
     }
     i = status_get_bool(JK_STATUS_ARG_LB_STICKY_FORCE,
-                        s->query_string, 0);
+                        s->query_string, 0, l);
     if (i != lb->sticky_session_force && i > 0) {
         jk_log(l, JK_LOG_INFO,
                "setting 'sticky_session_force' for lb worker '%s' to '%i'",
@@ -1530,7 +2078,7 @@
         lb->sticky_session_force = i;
     }
     i = status_get_int(JK_STATUS_ARG_LB_METHOD,
-                       s->query_string, lb->lbmethod);
+                       s->query_string, lb->lbmethod, l);
     if (i != lb->lbmethod && i > 0 && i <= JK_LB_METHOD_MAX) {
         jk_log(l, JK_LOG_INFO,
                "setting 'method' for lb worker '%s' to '%i'",
@@ -1538,7 +2086,7 @@
         lb->lbmethod = i;
     }
     i = status_get_int(JK_STATUS_ARG_LB_LOCK,
-                       s->query_string, lb->lblock);
+                       s->query_string, lb->lblock, l);
     if (i != lb->lblock && i > 0 && i <= JK_LB_LOCK_MAX) {
         jk_log(l, JK_LOG_INFO,
                "setting 'lock' for lb worker '%s' to '%i'",
@@ -1565,7 +2113,7 @@
                wr->s->name, worker);
 
     i = status_get_int(JK_STATUS_ARG_LBM_ACTIVATION,
-                       s->query_string, wr->s->activation);
+                       s->query_string, wr->s->activation, l);
     if (i != wr->s->activation && i > 0 && i<= JK_LB_ACTIVATION_MAX) {
         jk_log(l, JK_LOG_INFO,
                "setting 'activation' for sub worker '%s' of lb worker '%s' to '%s'",
@@ -1574,7 +2122,7 @@
         rc |= 1;
     }
     i = status_get_int(JK_STATUS_ARG_LBM_FACTOR,
-                       s->query_string, wr->s->lb_factor);
+                       s->query_string, wr->s->lb_factor, l);
     if (i != wr->s->lb_factor && i > 0) {
         jk_log(l, JK_LOG_INFO,
                "setting 'lbfactor' for sub worker '%s' of lb worker '%s' to '%i'",
@@ -1584,7 +2132,7 @@
         rc |= 2;
     }
     if ((rv = status_get_arg(JK_STATUS_ARG_LBM_ROUTE,
-                             s->query_string, buf, sizeof(buf))) == JK_TRUE) {
+                             s->query_string, buf, sizeof(buf), l)) == JK_TRUE) {
         if (strncmp(wr->s->route, buf, JK_SHM_STR_SIZ)) {
             jk_log(l, JK_LOG_INFO,
                    "setting 'route' for sub worker '%s' of lb worker '%s' to '%s'",
@@ -1607,7 +2155,7 @@
         memset(wr->s->route, 0, JK_SHM_STR_SIZ);
     }
     if ((rv = status_get_arg(JK_STATUS_ARG_LBM_REDIRECT,
-                             s->query_string, buf, sizeof(buf))) == JK_TRUE) {
+                             s->query_string, buf, sizeof(buf), l)) == JK_TRUE) {
         if (strncmp(wr->s->redirect, buf, JK_SHM_STR_SIZ)) {
             jk_log(l, JK_LOG_INFO,
                    "setting 'redirect' for sub worker '%s' of lb worker '%s' to '%s'",
@@ -1622,7 +2170,7 @@
         memset(wr->s->redirect, 0, JK_SHM_STR_SIZ);
     }
     if ((rv = status_get_arg(JK_STATUS_ARG_LBM_DOMAIN,
-                             s->query_string, buf, sizeof(buf))) == JK_TRUE) {
+                             s->query_string, buf, sizeof(buf), l)) == JK_TRUE) {
         if (strncmp(wr->s->domain, buf, JK_SHM_STR_SIZ)) {
             jk_log(l, JK_LOG_INFO,
                    "setting 'domain' for sub worker '%s' of lb worker '%s' to '%s'",
@@ -1637,7 +2185,7 @@
         memset(wr->s->domain, 0, JK_SHM_STR_SIZ);
     }
     i = status_get_int(JK_STATUS_ARG_LBM_DISTANCE,
-                       s->query_string, wr->s->distance);
+                       s->query_string, wr->s->distance, l);
     if (i != wr->s->distance && i > 0) {
         jk_log(l, JK_LOG_INFO,
                "setting 'distance' for sub worker '%s' of lb worker '%s' to '%i'",
@@ -1664,7 +2212,7 @@
     if (!attribute) {
         jk_log(l, JK_LOG_WARNING,
                "missing request parameter '%s'",
-               JK_STATUS_ARG_LB_MEMBER_ATT);
+               JK_STATUS_ARG_OPTION);
         JK_TRACE_EXIT(l);
         return;
     }
@@ -1710,7 +2258,7 @@
             snprintf(vname, 32-1, "val%d", j);
 
             if (!strcmp(attribute, JK_STATUS_ARG_LBM_ACTIVATION)) {
-                i = status_get_int(vname, s->query_string, wr->s->activation);
+                i = status_get_int(vname, s->query_string, wr->s->activation, l);
                 if (i != wr->s->activation && i > 0 && i<= JK_LB_ACTIVATION_MAX) {
                     jk_log(l, JK_LOG_INFO,
                            "setting 'activation' for sub worker '%s' of lb worker '%s' to '%s'",
@@ -1720,7 +2268,7 @@
                 }
             }
             else if (!strcmp(attribute, JK_STATUS_ARG_LBM_FACTOR)) {
-                i = status_get_int(vname, s->query_string, wr->s->lb_factor);
+                i = status_get_int(vname, s->query_string, wr->s->lb_factor, l);
                 if (i != wr->s->lb_factor && i > 0) {
                     jk_log(l, JK_LOG_INFO,
                            "setting 'lbfactor' for sub worker '%s' of lb worker '%s' to '%i'",
@@ -1730,7 +2278,7 @@
                 }
             }
             else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DISTANCE)) {
-                i = status_get_int(vname, s->query_string, wr->s->distance);
+                i = status_get_int(vname, s->query_string, wr->s->distance, l);
                 if (i != wr->s->distance && i > 0) {
                     jk_log(l, JK_LOG_INFO,
                            "setting 'distance' for sub worker '%s' of lb worker '%s' to '%i'",
@@ -1739,7 +2287,7 @@
                 }
             }
             else {
-                int rv = status_get_arg(vname, s->query_string, buf, sizeof(buf));
+                int rv = status_get_arg(vname, s->query_string, buf, sizeof(buf), l);
                 if (!strcmp(attribute, JK_STATUS_ARG_LBM_ROUTE)) {
                     if (rv == JK_TRUE) {
                         if (strncmp(wr->s->route, buf, JK_SHM_STR_SIZ)) {
@@ -1795,7 +2343,7 @@
                                wr->s->name, name);
                         memset(wr->s->domain, 0, JK_SHM_STR_SIZ);
                     }
-    
+
                 }
             }
         }
@@ -1814,7 +2362,7 @@
 static void display_legend(jk_ws_service_t *s, status_worker_t *sw, jk_logger_t *l)
 {
     JK_TRACE_ENTER(l);
-    jk_puts(s, "<hr/><table>\n"
+    jk_puts(s, "<hr/><h2>Legend</h2><table>\n"
             "<tbody valign=\"baseline\">\n"
             "<tr><th>Name</th><td>Worker name</td></tr>\n"
             "<tr><th>Type</th><td>Worker type</td></tr>\n"
@@ -1823,7 +2371,7 @@
             "<tr><th>Act</th><td>Worker activation configuration</br>\n"
             "ACT=Active, DIS=Disabled, STP=Stopped</td></tr>\n"
             "<tr><th>Stat</th><td>Worker error status</br>\n"
-            "OK=OK, N/A=Not availabe, ERR=Error, REC=Recovering, BSY=Busy</td></tr>\n"
+            "OK=OK, N/A=Unknown, ERR=Error, REC=Recovering, BSY=Busy</td></tr>\n"
             "<tr><th>D</th><td>Worker distance</td></tr>\n"
             "<tr><th>F</th><td>Load Balancer factor</td></tr>\n"
             "<tr><th>M</th><td>Load Balancer multiplicity</td></tr>\n"
@@ -1840,50 +2388,79 @@
             "<tr><th>Rs</th><td>Recovery scheduled</td></tr>\n"
             "</tbody>\n"
             "</table>\n");
-    if (sw->css) {            
-        jk_putv(s, "<hr/><div class=\"footer\">", JK_STATUS_COPY,
-                "</div>\n", NULL);
-    }
-    else {
-        jk_putv(s, "<hr/><p align=\"center\"><small>", JK_STATUS_COPY,
-                "</small></p>\n", NULL);        
-    }
-                
+
     JK_TRACE_EXIT(l);
 }
 
-
-static int list_workers(jk_ws_service_t *s, status_worker_t *sw,
-                        int refresh, jk_logger_t *l)
+static int check_worker(jk_ws_service_t *s,
+                        const char *worker, const char *sub_worker,
+                        jk_logger_t *l)
 {
     unsigned int i;
     jk_worker_t *w = NULL;
 
     JK_TRACE_ENTER(l);
-    for (i = 0; i < sw->we->num_of_workers; i++) {
-        w = wc_get_worker_for_name(sw->we->worker_list[i], l);
-        if (!w) {
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+               "checking worker '%s' sub worker '%s'",
+               worker ? worker : "(null)", sub_worker ? sub_worker : "(null)");
+    if (!worker || !worker[0]) {
+        jk_log(l, JK_LOG_WARNING,
+               "NULL or EMPTY worker param");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    w = wc_get_worker_for_name(worker, l);
+    if (!w) {
+        jk_log(l, JK_LOG_WARNING,
+               "could not find worker '%s'",
+               worker);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    if (sub_worker && sub_worker[0]) {
+        lb_worker_t *lb = NULL;
+        worker_record_t *wr = NULL;
+        if (w->type != JK_LB_WORKER_TYPE) {
+            jk_log(l, JK_LOG_WARNING,
+                   "worker type has o sub worker");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+        lb = (lb_worker_t *)w->worker_private;
+        if (!lb) {
+            jk_log(l, JK_LOG_WARNING,
+                   "lb structure is (NULL)");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+        for (i = 0; i < (int)lb->num_of_workers; i++) {
+            wr = &(lb->lb_workers[i]);
+            if (strcmp(sub_worker, wr->s->name) == 0)
+                break;
+        }
+        if (!wr || i == (int)lb->num_of_workers) {
             jk_log(l, JK_LOG_WARNING,
                    "could not find worker '%s'",
-                   sw->we->worker_list[i]);
-            continue;
+                   sub_worker);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
         }
-        display_worker(s, w, refresh, 0, l);
     }
-    display_legend(s, sw, l);
-    
     JK_TRACE_EXIT(l);
     return JK_TRUE;
 }
 
-static int list_workers_xml(jk_ws_service_t *s, status_worker_t *sw,
-                            jk_logger_t *l)
+static void count_workers_xml(jk_ws_service_t *s, status_worker_t *sw,
+                             int *lb_cnt, int *ajp_cnt,
+                             jk_logger_t *l)
 {
     unsigned int i;
-    int has_lb = 0;
     jk_worker_t *w = NULL;
 
     JK_TRACE_ENTER(l);
+    *lb_cnt = 0;
+    *ajp_cnt = 0;
     for (i = 0; i < sw->we->num_of_workers; i++) {
         w = wc_get_worker_for_name(sw->we->worker_list[i], l);
         if (!w) {
@@ -1893,33 +2470,20 @@
             continue;
         }
         if (w->type == JK_LB_WORKER_TYPE) {
-            if (!has_lb)
-                jk_putv(s, "<", sw->ns, "balancers>\n", NULL);
-            has_lb = 1;
-            display_worker_xml(s, w, sw, 0, l);
-        }
-    }
-    if (has_lb)
-        jk_putv(s, "</", sw->ns, "balancers>\n", NULL);
-
-    for (i = 0; i < sw->we->num_of_workers; i++) {
-        w = wc_get_worker_for_name(sw->we->worker_list[i], l);
-        if (!w) {
-            jk_log(l, JK_LOG_WARNING,
-                   "could not find worker '%s'",
-                   sw->we->worker_list[i]);
-            continue;
+            (*lb_cnt)++;
         }
-        if (w->type != JK_LB_WORKER_TYPE) {
-            display_worker_xml(s, w, sw, 0, l);
+        else if (w->type == JK_AJP13_WORKER_TYPE ||
+                 w->type == JK_AJP14_WORKER_TYPE) {
+            (*ajp_cnt)++;
         }
     }
     JK_TRACE_EXIT(l);
-    return JK_TRUE;
 }
 
-static int list_workers_txt(jk_ws_service_t *s, status_worker_t *sw,
-                            jk_logger_t *l)
+static void list_workers_type_mime(jk_ws_service_t *s, status_worker_t *sw,

[... 864 lines stripped ...]


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org