Author: gsim
Date: Fri Apr 11 03:02:49 2008
New Revision: 647099

URL: http://svn.apache.org/viewvc?rev=647099&view=rev
Log:
QPID-913: committed patch from [EMAIL PROTECTED]


Added:
    incubator/qpid/trunk/qpid/python/commands/qpid-tool
    incubator/qpid/trunk/qpid/python/qpid/disp.py   (with props)
    incubator/qpid/trunk/qpid/python/qpid/managementdata.py   (with props)
Removed:
    incubator/qpid/trunk/qpid/python/mgmt-cli/
Modified:
    incubator/qpid/trunk/qpid/python/commands/qpid-route

Modified: incubator/qpid/trunk/qpid/python/commands/qpid-route
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/python/commands/qpid-route?rev=647099&r1=647098&r2=647099&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/python/commands/qpid-route (original)
+++ incubator/qpid/trunk/qpid/python/commands/qpid-route Fri Apr 11 03:02:49 
2008
@@ -160,6 +160,9 @@
                     print "Error closing bridge: %d - %s" % (res.status, 
res.statusText)
                     sys.exit (1)
                 if len (bridges) == 1:
+                    link = self.getLink ()
+                    if link == None:
+                        sys.exit (0)
                     if _verbose:
                         print "Last bridge on link, closing link..."
                     res = mc.syncCallMethod (self.mch, link.id, link.classKey, 
"close")
@@ -208,6 +211,7 @@
             elif _verbose:
                 print "Ok"
 
+        links = mc.syncGetObjects (self.mch, "link")
         for link in links:
             if _verbose:
                 print "Deleting Link: %s... " % link.address,

Added: incubator/qpid/trunk/qpid/python/commands/qpid-tool
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/python/commands/qpid-tool?rev=647099&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/python/commands/qpid-tool (added)
+++ incubator/qpid/trunk/qpid/python/commands/qpid-tool Fri Apr 11 03:02:49 2008
@@ -0,0 +1,179 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import os
+import getopt
+import sys
+import socket
+from cmd                 import Cmd
+from qpid.managementdata import ManagementData
+from shlex               import split
+from qpid.disp           import Display
+from qpid.peer           import Closed
+
+class Mcli (Cmd):
+  """ Management Command Interpreter """
+  prompt = "qpid: "
+
+  def __init__ (self, dataObject, dispObject):
+    Cmd.__init__ (self)
+    self.dataObject = dataObject
+    self.dispObject = dispObject
+    
+  def emptyline (self):
+    pass
+
+  def do_help (self, data):
+    print "Management Tool for QPID"
+    print
+    print "Commands:"
+    print "    list                            - Print summary of existing 
objects by class"
+    print "    list <className>                - Print list of objects of the 
specified class"
+    print "    list <className> all            - Print contents of all objects 
of specified class"
+    print "    list <className> active         - Print contents of all 
non-deleted objects of specified class"
+    print "    list <list-of-IDs>              - Print contents of one or more 
objects (infer className)"
+    print "    list <className> <list-of-IDs>  - Print contents of one or more 
objects"
+    print "        list is space-separated, ranges may be specified (i.e. 
1004-1010)"
+    print "    call <ID> <methodName> [<args>] - Invoke a method on an object"
+    print "    schema                          - Print summary of object 
classes seen on the target"
+    print "    schema <className>              - Print details of an object 
class"
+    print "    set time-format short           - Select short timestamp format 
(default)"
+    print "    set time-format long            - Select long timestamp format"
+    print "    quit or ^D                      - Exit the program"
+    print
+
+  def complete_set (self, text, line, begidx, endidx):
+    """ Command completion for the 'set' command """
+    tokens = split (line)
+    if len (tokens) < 2:
+      return ["time-format "]
+    elif tokens[1] == "time-format":
+      if len (tokens) == 2:
+        return ["long", "short"]
+      elif len (tokens) == 3:
+        if "long".find (text) == 0:
+          return ["long"]
+        elif "short".find (text) == 0:
+          return ["short"]
+    elif "time-format".find (text) == 0:
+      return ["time-format "]
+    return []
+
+  def do_set (self, data):
+    tokens = split (data)
+    try:
+      if tokens[0] == "time-format":
+        self.dispObject.do_setTimeFormat (tokens[1])
+    except:
+      pass
+
+  def complete_schema (self, text, line, begidx, endidx):
+    tokens = split (line)
+    if len (tokens) > 2:
+      return []
+    return self.dataObject.classCompletions (text)
+
+  def do_schema (self, data):
+    self.dataObject.do_schema (data)
+
+  def complete_list (self, text, line, begidx, endidx):
+    tokens = split (line)
+    if len (tokens) > 2:
+      return []
+    return self.dataObject.classCompletions (text)
+
+  def do_list (self, data):
+    self.dataObject.do_list (data)
+
+  def do_call (self, data):
+    try:
+      self.dataObject.do_call (data)
+    except ValueError, e:
+      print "ValueError:", e
+
+  def do_EOF (self, data):
+    print "quit"
+    return True
+
+  def do_quit (self, data):
+    return True
+
+  def postcmd (self, stop, line):
+    return stop
+
+  def postloop (self):
+    print "Exiting..."
+    self.dataObject.close ()
+
+def Usage ():
+  print "Usage:", sys.argv[0], "[OPTIONS] [<target-host[:<tcp-port>]]"
+  print
+  print "Options:"
+  print "    -s [ --spec-file ] PATH (/usr/share/amqp/amqp.0-10-preview.xml)"
+  print
+  sys.exit (1)
+
+#=========================================================
+# Main Program
+#=========================================================
+
+# Get host name and port if specified on the command line
+try:
+  longOpts = ("spec-file=")
+  (optlist, cargs) = getopt.gnu_getopt (sys.argv[1:], 's:', longOpts)
+except:
+  Usage ()
+  sys.exit (1)
+
+_specpath = "/usr/share/amqp/amqp.0-10-preview.xml"
+_host     = "localhost"
+
+for opt in optlist:
+  if opt[0] == "-s" or opt[0] == "--spec-file":
+    _specpath = opt[1]
+
+if len (cargs) > 0:
+  _host = cargs[0]
+
+disp = Display ()
+
+# Attempt to make a connection to the target broker
+try:
+  data = ManagementData (disp, _host, specfile=_specpath)
+except socket.error, e:
+  print "Socket Error (%s):" % _host, e[1]
+  sys.exit (1)
+except Closed, e:
+  if str(e).find ("Exchange not found") != -1:
+    print "Management not enabled on broker:  Use '-m yes' option on broker 
startup."
+  sys.exit (1)
+except IOError, e:
+  print "IOError: %d - %s: %s" % (e.errno, e.strerror, e.filename)
+  sys.exit (1)
+
+# Instantiate the CLI interpreter and launch it.
+cli = Mcli (data, disp)
+print ("Management Tool for QPID")
+try:
+  cli.cmdloop ()
+except Closed, e:
+  print "Connection to Broker Lost:", e
+  sys.exit (1)

Added: incubator/qpid/trunk/qpid/python/qpid/disp.py
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/python/qpid/disp.py?rev=647099&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/python/qpid/disp.py (added)
+++ incubator/qpid/trunk/qpid/python/qpid/disp.py Fri Apr 11 03:02:49 2008
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from time import strftime, gmtime
+
+class Display:
+  """ Display formatting for QPID Management CLI """
+  
+  def __init__ (self):
+    self.tableSpacing    = 2
+    self.tablePrefix     = "    "
+    self.timestampFormat = "%X"
+
+  def table (self, title, heads, rows):
+    """ Print a formatted table with autosized columns """
+    print title
+    if len (rows) == 0:
+      return
+    colWidth = []
+    col      = 0
+    line     = self.tablePrefix
+    for head in heads:
+      width = len (head)
+      for row in rows:
+        cellWidth = len (str (row[col]))
+        if cellWidth > width:
+          width = cellWidth
+      colWidth.append (width + self.tableSpacing)
+      line = line + head
+      for i in range (colWidth[col] - len (head)):
+        line = line + " "
+      col = col + 1
+    print line
+    line = self.tablePrefix
+    for width in colWidth:
+      for i in range (width):
+        line = line + "="
+    print line
+
+    for row in rows:
+      line = self.tablePrefix
+      col  = 0
+      for width in colWidth:
+        line = line + str (row[col])
+        for i in range (width - len (str (row[col]))):
+          line = line + " "
+        col = col + 1
+      print line
+
+  def do_setTimeFormat (self, fmt):
+    """ Select timestamp format """
+    if fmt == "long":
+      self.timestampFormat = "%c"
+    elif fmt == "short":
+      self.timestampFormat = "%X"
+
+  def timestamp (self, nsec):
+    """ Format a nanosecond-since-the-epoch timestamp for printing """
+    return strftime (self.timestampFormat, gmtime (nsec / 1000000000))

Propchange: incubator/qpid/trunk/qpid/python/qpid/disp.py
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/qpid/trunk/qpid/python/qpid/managementdata.py
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/python/qpid/managementdata.py?rev=647099&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/python/qpid/managementdata.py (added)
+++ incubator/qpid/trunk/qpid/python/qpid/managementdata.py Fri Apr 11 03:02:49 
2008
@@ -0,0 +1,621 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import qpid
+import socket
+from qpid.management import managementChannel, managementClient
+from threading       import Lock
+from disp            import Display
+from shlex           import split
+from qpid.client     import Client
+
+class Broker:
+  def __init__ (self, text):
+    colon = text.find (":")
+    if colon == -1:
+      host = text
+      self.port = 5672
+    else:
+      host = text[:colon]
+      self.port = int (text[colon+1:])
+    self.host = socket.gethostbyname (host)
+
+  def name (self):
+    return self.host + ":" + str (self.port)
+
+class ManagementData:
+
+  #
+  # Data Structure:
+  #
+  # Please note that this data structure holds only the most recent
+  # configuration and instrumentation data for each object.  It does
+  # not hold the detailed historical data that is sent from the broker.
+  # The only historical data it keeps are the high and low watermarks
+  # for hi-lo statistics.
+  #
+  #    tables        :== {class-key}
+  #                        {<obj-id>}
+  #                          (timestamp, config-record, inst-record)
+  #    class-key     :== (<package-name>, <class-name>, <class-hash>)
+  #    timestamp     :== (<last-interval-time>, <create-time>, <delete-time>)
+  #    config-record :== [element]
+  #    inst-record   :== [element]
+  #    element       :== (<element-name>, <element-value>)
+  #
+
+  def registerObjId (self, objId):
+    if self.baseId == 0:
+      if objId & 0x8000000000000000L == 0:
+        self.baseId = objId - 1000
+
+  def displayObjId (self, objId):
+    if objId & 0x8000000000000000L == 0:
+      return objId - self.baseId
+    return (objId & 0x7fffffffffffffffL) + 5000
+
+  def rawObjId (self, displayId):
+    if displayId < 5000:
+      return displayId + self.baseId
+    return displayId - 5000 + 0x8000000000000000L
+
+  def displayClassName (self, cls):
+    (packageName, className, hash) = cls
+    return packageName + "." + className
+
+  def dataHandler (self, context, className, list, timestamps):
+    """ Callback for configuration and instrumentation data updates """
+    self.lock.acquire ()
+    try:
+      # If this class has not been seen before, create an empty dictionary to
+      # hold objects of this class
+      if className not in self.tables:
+        self.tables[className] = {}
+
+      # Register the ID so a more friendly presentation can be displayed
+      id = long (list[0][1])
+      self.registerObjId (id)
+
+      # If this object hasn't been seen before, create a new object record with
+      # the timestamps and empty lists for configuration and instrumentation 
data.
+      if id not in self.tables[className]:
+        self.tables[className][id] = (timestamps, [], [])
+
+      (unused, oldConf, oldInst) = self.tables[className][id]
+
+      # For config updates, simply replace old config list with the new one.
+      if   context == 0: #config
+        self.tables[className][id] = (timestamps, list, oldInst)
+
+      # For instrumentation updates, carry the minimum and maximum values for
+      # "hi-lo" stats forward.
+      elif context == 1: #inst
+        if len (oldInst) == 0:
+          newInst = list
+        else:
+          newInst = []
+          for idx in range (len (list)):
+            (key, value) = list[idx]
+            if key.find ("High") == len (key) - 4:
+              if oldInst[idx][1] > value:
+                value = oldInst[idx][1]
+            if key.find ("Low") == len (key) - 3:
+              if oldInst[idx][1] < value:
+                value = oldInst[idx][1]
+            newInst.append ((key, value))
+        self.tables[className][id] = (timestamps, oldConf, newInst)
+      
+    finally:
+      self.lock.release ()
+
+  def ctrlHandler (self, context, op, data):
+    if op == self.mclient.CTRL_BROKER_INFO:
+      pass
+
+  def configHandler (self, context, className, list, timestamps):
+    self.dataHandler (0, className, list, timestamps);
+
+  def instHandler (self, context, className, list, timestamps):
+    self.dataHandler (1, className, list, timestamps);
+
+  def methodReply (self, broker, sequence, status, sText, args):
+    """ Callback for method-reply messages """
+    self.lock.acquire ()
+    try:
+      line = "Call Result: " + self.methodsPending[sequence] + \
+             "  " + str (status) + " (" + sText + ")"
+      print line, args
+      del self.methodsPending[sequence]
+    finally:
+      self.lock.release ()
+
+  def schemaHandler (self, context, className, configs, insts, methods, 
events):
+    """ Callback for schema updates """
+    if className not in self.schema:
+      self.schema[className] = (configs, insts, methods, events)
+
+  def __init__ (self, disp, host, username="guest", password="guest",
+                specfile="../../specs/amqp.0-10-preview.xml"):
+    self.spec           = qpid.spec.load (specfile)
+    self.lock           = Lock ()
+    self.tables         = {}
+    self.schema         = {}
+    self.baseId         = 0
+    self.disp           = disp
+    self.lastUnit       = None
+    self.methodSeq      = 1
+    self.methodsPending = {}
+
+    self.broker = Broker (host)
+    self.client = Client (self.broker.host, self.broker.port, self.spec)
+    self.client.start ({"LOGIN": username, "PASSWORD": password})
+    self.channel = self.client.channel (1)
+
+    self.mclient = managementClient (self.spec, self.ctrlHandler, 
self.configHandler,
+                                     self.instHandler, self.methodReply)
+    self.mclient.schemaListener (self.schemaHandler)
+    self.mch = self.mclient.addChannel (self.channel)
+
+  def close (self):
+    self.mclient.removeChannel (self.mch)
+
+  def refName (self, oid):
+    if oid == 0:
+      return "NULL"
+    return str (self.displayObjId (oid))
+
+  def valueDisplay (self, classKey, key, value):
+    for kind in range (2):
+      schema = self.schema[classKey][kind]
+      for item in schema:
+        if item[0] == key:
+          typecode = item[1]
+          unit     = item[2]
+          if (typecode >= 1 and typecode <= 5) or typecode >= 12:  # numerics
+            if unit == None or unit == self.lastUnit:
+              return str (value)
+            else:
+              self.lastUnit = unit
+              suffix = ""
+              if value != 1:
+                suffix = "s"
+              return str (value) + " " + unit + suffix
+          elif typecode == 6 or typecode == 7: # strings
+            return value
+          elif typecode == 8:
+            if value == 0:
+              return "--"
+            return self.disp.timestamp (value)
+          elif typecode == 9:
+            return str (value)
+          elif typecode == 10:
+            return self.refName (value)
+          elif typecode == 11:
+            if value == 0:
+              return "False"
+            else:
+              return "True"
+          elif typecode == 14:
+            return str (UUID (bytes=value))
+          elif typecode == 15:
+            return str (value)
+    return "*type-error*"
+
+  def getObjIndex (self, className, config):
+    """ Concatenate the values from index columns to form a unique object name 
"""
+    result = ""
+    schemaConfig = self.schema[className][0]
+    for item in schemaConfig:
+      if item[5] == 1 and item[0] != "id":
+        if result != "":
+          result = result + "."
+        for key,val in config:
+          if key == item[0]:
+            result = result + self.valueDisplay (className, key, val)
+    return result
+
+  def getClassKey (self, className):
+    dotPos = className.find(".")
+    if dotPos == -1:
+      for key in self.schema:
+        if key[1] == className:
+          return key
+    else:
+      package = className[0:dotPos]
+      name    = className[dotPos + 1:]
+      for key in self.schema:
+        if key[0] == package and key[1] == name:
+          return key
+    return None
+
+  def classCompletions (self, prefix):
+    """ Provide a list of candidate class names for command completion """
+    self.lock.acquire ()
+    complist = []
+    try:
+      for name in self.tables:
+        if name.find (prefix) == 0:
+          complist.append (name)
+    finally:
+      self.lock.release ()
+    return complist
+
+  def typeName (self, typecode):
+    """ Convert type-codes to printable strings """
+    if   typecode == 1:
+      return "uint8"
+    elif typecode == 2:
+      return "uint16"
+    elif typecode == 3:
+      return "uint32"
+    elif typecode == 4:
+      return "uint64"
+    elif typecode == 5:
+      return "bool"
+    elif typecode == 6:
+      return "short-string"
+    elif typecode == 7:
+      return "long-string"
+    elif typecode == 8:
+      return "abs-time"
+    elif typecode == 9:
+      return "delta-time"
+    elif typecode == 10:
+      return "reference"
+    elif typecode == 11:
+      return "boolean"
+    elif typecode == 12:
+      return "float"
+    elif typecode == 13:
+      return "double"
+    elif typecode == 14:
+      return "uuid"
+    elif typecode == 15:
+      return "field-table"
+    else:
+      raise ValueError ("Invalid type code: %d" % typecode)
+
+  def accessName (self, code):
+    """ Convert element access codes to printable strings """
+    if code == 1:
+      return "ReadCreate"
+    elif code == 2:
+      return "ReadWrite"
+    elif code == 3:
+      return "ReadOnly"
+    else:
+      raise ValueError ("Invalid access code: %d" %code)
+
+  def notNone (self, text):
+    if text == None:
+      return ""
+    else:
+      return text
+
+  def isOid (self, id):
+    for char in str (id):
+      if not char.isdigit () and not char == '-':
+        return False
+    return True
+
+  def listOfIds (self, classKey, tokens):
+    """ Generate a tuple of object ids for a classname based on command 
tokens. """
+    list = []
+    if tokens[0] == "all":
+      for id in self.tables[classKey]:
+        list.append (self.displayObjId (id))
+
+    elif tokens[0] == "active":
+      for id in self.tables[classKey]:
+        if self.tables[classKey][id][0][2] == 0:
+          list.append (self.displayObjId (id))
+
+    else:
+      for token in tokens:
+        if self.isOid (token):
+          if token.find ("-") != -1:
+            ids = token.split("-", 2)
+            for id in range (int (ids[0]), int (ids[1]) + 1):
+              if self.getClassForId (self.rawObjId (long (id))) == classKey:
+                list.append (id)
+          else:
+            list.append (token)
+
+    list.sort ()
+    result = ()
+    for item in list:
+      result = result + (item,)
+    return result
+
+  def listClasses (self):
+    """ Generate a display of the list of classes """
+    self.lock.acquire ()
+    try:
+      rows = []
+      sorted = self.tables.keys ()
+      sorted.sort ()
+      for name in sorted:
+        active  = 0
+        deleted = 0
+        for record in self.tables[name]:
+          isdel = False
+          ts    = self.tables[name][record][0]
+          if ts[2] > 0:
+            isdel = True
+          if isdel:
+            deleted = deleted + 1
+          else:
+            active = active + 1
+        rows.append ((self.displayClassName (name), active, deleted))
+      if len (rows) != 0:
+        self.disp.table ("Management Object Types:",
+                         ("ObjectType", "Active", "Deleted"), rows)
+      else:
+        print "Waiting for next periodic update"
+    finally:
+      self.lock.release ()
+
+  def listObjects (self, className):
+    """ Generate a display of a list of objects in a class """
+    self.lock.acquire ()
+    try:
+      classKey = self.getClassKey (className)
+      if classKey == None:
+        print ("Object type %s not known" % className)
+      else:
+        rows = []
+        if classKey in self.tables:
+          sorted = self.tables[classKey].keys ()
+          sorted.sort ()
+          for objId in sorted:
+            (ts, config, inst) = self.tables[classKey][objId]
+            createTime  = self.disp.timestamp (ts[1])
+            destroyTime = "-"
+            if ts[2] > 0:
+              destroyTime = self.disp.timestamp (ts[2])
+            objIndex = self.getObjIndex (classKey, config)
+            row = (self.refName (objId), createTime, destroyTime, objIndex)
+            rows.append (row)
+          self.disp.table ("Objects of type %s.%s" % (classKey[0], 
classKey[1]),
+                           ("ID", "Created", "Destroyed", "Index"),
+                           rows)
+    finally:
+      self.lock.release ()
+
+  def showObjects (self, tokens):
+    """ Generate a display of object data for a particular class """
+    self.lock.acquire ()
+    try:
+      self.lastUnit = None
+      if self.isOid (tokens[0]):
+        if tokens[0].find ("-") != -1:
+          rootId = int (tokens[0][0:tokens[0].find ("-")])
+        else:
+          rootId = int (tokens[0])
+
+        classKey  = self.getClassForId (self.rawObjId (rootId))
+        remaining = tokens
+        if classKey == None:
+          print "Id not known: %d" % int (tokens[0])
+          raise ValueError ()
+      else:
+        classKey  = self.getClassKey (tokens[0])
+        remaining = tokens[1:]
+        if classKey not in self.tables:
+          print "Class not known: %s" % tokens[0]
+          raise ValueError ()
+
+      userIds = self.listOfIds (classKey, remaining)
+      if len (userIds) == 0:
+        print "No object IDs supplied"
+        raise ValueError ()
+
+      ids = []
+      for id in userIds:
+        if self.getClassForId (self.rawObjId (long (id))) == classKey:
+          ids.append (self.rawObjId (long (id)))
+
+      rows = []
+      timestamp = None
+      config = self.tables[classKey][ids[0]][1]
+      for eIdx in range (len (config)):
+        key = config[eIdx][0]
+        if key != "id":
+          row   = ("config", key)
+          for id in ids:
+            if timestamp == None or \
+               timestamp < self.tables[classKey][id][0][0]:
+              timestamp = self.tables[classKey][id][0][0]
+            (key, value) = self.tables[classKey][id][1][eIdx]
+            row = row + (self.valueDisplay (classKey, key, value),)
+          rows.append (row)
+
+      inst = self.tables[classKey][ids[0]][2]
+      for eIdx in range (len (inst)):
+        key = inst[eIdx][0]
+        if key != "id":
+          row = ("inst", key)
+          for id in ids:
+            (key, value) = self.tables[classKey][id][2][eIdx]
+            row = row + (self.valueDisplay (classKey, key, value),)
+          rows.append (row)
+
+      titleRow = ("Type", "Element")
+      for id in ids:
+        titleRow = titleRow + (self.refName (id),)
+      caption = "Object of type %s.%s:" % (classKey[0], classKey[1])
+      if timestamp != None:
+        caption = caption + " (last sample time: " + self.disp.timestamp 
(timestamp) + ")"
+      self.disp.table (caption, titleRow, rows)
+
+    except:
+      pass
+    self.lock.release ()
+
+  def schemaSummary (self):
+    """ Generate a display of the list of classes in the schema """
+    self.lock.acquire ()
+    try:
+      rows = []
+      sorted = self.schema.keys ()
+      sorted.sort ()
+      for classKey in sorted:
+        tuple = self.schema[classKey]
+        className = classKey[0] + "." + classKey[1]
+        row = (className, len (tuple[0]), len (tuple[1]), len (tuple[2]), len 
(tuple[3]))
+        rows.append (row)
+      self.disp.table ("Classes in Schema:",
+                       ("Class", "ConfigElements", "InstElements", "Methods", 
"Events"),
+                       rows)
+    finally:
+      self.lock.release ()
+
+  def schemaTable (self, className):
+    """ Generate a display of details of the schema of a particular class """
+    self.lock.acquire ()
+    try:
+      classKey = self.getClassKey (className)
+      if classKey == None:
+        print ("Class name %s not known" % className)
+        raise ValueError ()
+
+      rows = []
+      for config in self.schema[classKey][0]:
+        name     = config[0]
+        if name != "id":
+          typename = self.typeName(config[1])
+          unit     = self.notNone (config[2])
+          desc     = self.notNone (config[3])
+          access   = self.accessName (config[4])
+          extra    = ""
+          if config[5] == 1:
+            extra = extra + "index "
+          if config[6] != None:
+            extra = extra + "Min: " + str (config[6])
+          if config[7] != None:
+            extra = extra + "Max: " + str (config[7])
+          if config[8] != None:
+            extra = extra + "MaxLen: " + str (config[8])
+          rows.append ((name, typename, unit, access, extra, desc))
+        
+      for config in self.schema[classKey][1]:
+        name     = config[0]
+        if name != "id":
+          typename = self.typeName(config[1])
+          unit     = self.notNone (config[2])
+          desc     = self.notNone (config[3])
+          rows.append ((name, typename, unit, "", "", desc))
+
+      titles = ("Element", "Type", "Unit", "Access", "Notes", "Description")
+      self.disp.table ("Schema for class '%s.%s':" % (classKey[0], 
classKey[1]), titles, rows)
+
+      for mname in self.schema[classKey][2]:
+        (mdesc, args) = self.schema[classKey][2][mname]
+        caption = "\nMethod '%s' %s" % (mname, self.notNone (mdesc))
+        rows = []
+        for arg in args:
+          name     = arg[0]
+          typename = self.typeName (arg[1])
+          dir      = arg[2]
+          unit     = self.notNone (arg[3])
+          desc     = self.notNone (arg[4])
+          extra    = ""
+          if arg[5] != None:
+            extra = extra + "Min: " + str (arg[5])
+          if arg[6] != None:
+            extra = extra + "Max: " + str (arg[6])
+          if arg[7] != None:
+            extra = extra + "MaxLen: " + str (arg[7])
+          if arg[8] != None:
+            extra = extra + "Default: " + str (arg[8])
+          rows.append ((name, typename, dir, unit, extra, desc))
+        titles = ("Argument", "Type", "Direction", "Unit", "Notes", 
"Description")
+        self.disp.table (caption, titles, rows)
+
+    except:
+      pass
+    self.lock.release ()
+
+  def getClassForId (self, objId):
+    """ Given an object ID, return the class key for the referenced object """
+    for classKey in self.tables:
+      if objId in self.tables[classKey]:
+        return classKey
+    return None
+
+  def callMethod (self, userOid, methodName, args):
+    self.lock.acquire ()
+    methodOk = True
+    try:
+      classKey = self.getClassForId (self.rawObjId (userOid))
+      if classKey == None:
+        raise ValueError ()
+
+      if methodName not in self.schema[classKey][2]:
+        print "Method '%s' not valid for class '%s.%s'" % (methodName, 
classKey[0], classKey[1])
+        raise ValueError ()
+
+      schemaMethod = self.schema[classKey][2][methodName]
+      if len (args) != len (schemaMethod[1]):
+        print "Wrong number of method args: Need %d, Got %d" % (len 
(schemaMethod[1]), len (args))
+        raise ValueError ()
+
+      namedArgs = {}
+      for idx in range (len (args)):
+        namedArgs[schemaMethod[1][idx][0]] = args[idx]
+
+      self.methodSeq = self.methodSeq + 1
+      self.methodsPending[self.methodSeq] = methodName
+    except:
+      methodOk = False
+    self.lock.release ()
+    if methodOk:
+#      try:
+        self.mclient.callMethod (self.mch, self.methodSeq, self.rawObjId 
(userOid), classKey,
+                                 methodName, namedArgs)
+#      except ValueError, e:
+#        print "Error invoking method:", e
+
+  def do_list (self, data):
+    tokens = data.split ()
+    if len (tokens) == 0:
+      self.listClasses ()
+    elif len (tokens) == 1 and not self.isOid (tokens[0]):
+      self.listObjects (data)
+    else:
+      self.showObjects (tokens)
+
+  def do_schema (self, data):
+    if data == "":
+      self.schemaSummary ()
+    else:
+      self.schemaTable (data)
+
+  def do_call (self, data):
+    tokens = data.split ()
+    if len (tokens) < 2:
+      print "Not enough arguments supplied"
+      return
+    
+    userOid    = long (tokens[0])
+    methodName = tokens[1]
+    args       = tokens[2:]
+    self.callMethod (userOid, methodName, args)

Propchange: incubator/qpid/trunk/qpid/python/qpid/managementdata.py
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to