diff options
author | Ted Ross <tross@apache.org> | 2008-11-21 18:46:24 +0000 |
---|---|---|
committer | Ted Ross <tross@apache.org> | 2008-11-21 18:46:24 +0000 |
commit | 57c7e6d45483b94d4306eb93f285f4cbaa52bd57 (patch) | |
tree | 408000aaa36bffbb1410d0929b2704cba97fab9f /cpp/managementgen/qmfgen/schema.py | |
parent | 61523667e8589275138a66ad23fda254c66c7dfe (diff) | |
download | qpid-python-57c7e6d45483b94d4306eb93f285f4cbaa52bd57.tar.gz |
Renamed the python package for the qmf code generation as it conflicts
with the package for the qmf apis.
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@719671 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/managementgen/qmfgen/schema.py')
-rwxr-xr-x | cpp/managementgen/qmfgen/schema.py | 1339 |
1 files changed, 1339 insertions, 0 deletions
diff --git a/cpp/managementgen/qmfgen/schema.py b/cpp/managementgen/qmfgen/schema.py new file mode 100755 index 0000000000..692a474992 --- /dev/null +++ b/cpp/managementgen/qmfgen/schema.py @@ -0,0 +1,1339 @@ +# +# 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 xml.dom.minidom import parse, parseString, Node +from cStringIO import StringIO +import md5 + +class Hash: + """ Manage the hash of an XML sub-tree """ + def __init__(self, node): + self.md5Sum = md5.new() + self._compute(node) + + def addSubHash(self, hash): + """ Use this method to add the hash of a dependend-on XML fragment that is not in the sub-tree """ + self.md5Sum.update(hash.getDigest()) + + def getDigest(self): + return self.md5Sum.digest() + + def _compute(self, node): + attrs = node.attributes + self.md5Sum.update(node.nodeName) + + for idx in range(attrs.length): + self.md5Sum.update(attrs.item(idx).nodeName) + self.md5Sum.update(attrs.item(idx).nodeValue) + + for child in node.childNodes: + if child.nodeType == Node.ELEMENT_NODE: + self._compute(child) + + +#===================================================================================== +# +#===================================================================================== +class SchemaType: + def __init__ (self, node): + self.name = None + self.base = None + self.cpp = None + self.encode = None + self.decode = None + self.style = "normal" + self.accessor = None + self.init = "0" + self.perThread = False + self.byRef = False + + attrs = node.attributes + for idx in range (attrs.length): + key = attrs.item(idx).nodeName + val = attrs.item(idx).nodeValue + if key == 'name': + self.name = val + + elif key == 'base': + self.base = val + + elif key == 'cpp': + self.cpp = val + + elif key == 'encode': + self.encode = val + + elif key == 'decode': + self.decode = val + + elif key == 'style': + self.style = val + + elif key == 'accessor': + self.accessor = val + + elif key == 'init': + self.init = val + + elif key == 'perThread': + if val != 'y': + raise ValueError ("Expected 'y' in perThread attribute") + self.perThread = True + + elif key == 'byRef': + if val != 'y': + raise ValueError ("Expected 'y' in byRef attribute") + self.byRef = True + + else: + raise ValueError ("Unknown attribute in type '%s'" % key) + + if self.name == None or self.base == None or self.cpp == None or \ + self.encode == None or self.decode == None: + raise ValueError ("Missing required attribute(s) in type") + + if self.byRef: + self.asArg = "const " + self.cpp + "&" + else: + self.asArg = self.cpp + + def getName (self): + return self.name + + def genAccessor (self, stream, varName, changeFlag = None, optional = False): + if self.perThread: + prefix = "getThreadStats()->" + if self.style == "wm": + raise ValueError ("'wm' style types can't be per-thread") + else: + prefix = "" + if self.accessor == "direct": + stream.write (" inline void set_" + varName + " (" + self.asArg + " val) {\n"); + if not self.perThread: + stream.write (" ::qpid::sys::Mutex::ScopedLock mutex(accessLock);\n") + if self.style != "mma": + stream.write (" " + prefix + varName + " = val;\n") + if optional: + stream.write (" presenceMask[presenceByte_%s] |= presenceMask_%s;\n" % (varName, varName)) + if self.style == "wm": + stream.write (" if (" + varName + "Low > val)\n") + stream.write (" " + varName + "Low = val;\n") + stream.write (" if (" + varName + "High < val)\n") + stream.write (" " + varName + "High = val;\n") + if self.style == "mma": + stream.write (" " + prefix + varName + "Count++;\n") + stream.write (" " + prefix + varName + "Total += val;\n") + stream.write (" if (" + prefix + varName + "Min > val)\n") + stream.write (" " + prefix + varName + "Min = val;\n") + stream.write (" if (" + prefix + varName + "Max < val)\n") + stream.write (" " + prefix + varName + "Max = val;\n") + if changeFlag != None: + stream.write (" " + changeFlag + " = true;\n") + stream.write (" }\n") + if self.style != "mma": + stream.write (" inline " + self.asArg + " get_" + varName + "() {\n"); + if not self.perThread: + stream.write (" ::qpid::sys::Mutex::ScopedLock mutex(accessLock);\n") + stream.write (" return " + prefix + varName + ";\n") + stream.write (" }\n") + if optional: + stream.write (" inline void clr_" + varName + "() {\n") + stream.write (" presenceMask[presenceByte_%s] &= ~presenceMask_%s;\n" % (varName, varName)) + if changeFlag != None: + stream.write (" " + changeFlag + " = true;\n") + stream.write (" }\n") + stream.write (" inline bool isSet_" + varName + "() {\n") + stream.write (" return (presenceMask[presenceByte_%s] & presenceMask_%s) != 0;\n" % (varName, varName)) + stream.write (" }\n") + elif self.accessor == "counter": + stream.write (" inline void inc_" + varName + " (" + self.asArg + " by = 1) {\n"); + if not self.perThread: + stream.write (" ::qpid::sys::Mutex::ScopedLock mutex(accessLock);\n") + stream.write (" " + prefix + varName + " += by;\n") + if self.style == "wm": + stream.write (" if (" + varName + "High < " + varName + ")\n") + stream.write (" " + varName + "High = " + varName + ";\n") + if changeFlag != None: + stream.write (" " + changeFlag + " = true;\n") + stream.write (" }\n"); + stream.write (" inline void dec_" + varName + " (" + self.asArg + " by = 1) {\n"); + if not self.perThread: + stream.write (" ::qpid::sys::Mutex::ScopedLock mutex(accessLock);\n") + stream.write (" " + prefix + varName + " -= by;\n") + if self.style == "wm": + stream.write (" if (" + varName + "Low > " + varName + ")\n") + stream.write (" " + varName + "Low = " + varName + ";\n") + if changeFlag != None: + stream.write (" " + changeFlag + " = true;\n") + stream.write (" }\n"); + + def genHiLoStatResets (self, stream, varName): + if self.style == "wm": + stream.write (" " + varName + "High = " + varName + ";\n") + stream.write (" " + varName + "Low = " + varName + ";\n") + if self.style == "mma": + stream.write (" " + varName + "Count = 0;\n") + stream.write (" " + varName + "Total = 0;\n") + stream.write (" " + varName + "Min = std::numeric_limits<" + self.type.type.cpp + ">::max();\n") + stream.write (" " + varName + "Max = std::numeric_limits<" + self.type.type.cpp + ">::min();\n") + + def genPerThreadHiLoStatResets (self, stream, varName, cpptype): + if self.style == "mma": + stream.write (" threadStats->" + varName + "Count = 0;\n") + stream.write (" threadStats->" + varName + "Total = 0;\n") + stream.write (" threadStats->" + varName + "Min = std::numeric_limits<" + cpptype + ">::max();\n") + stream.write (" threadStats->" + varName + "Max = std::numeric_limits<" + cpptype + ">::min();\n") + + def genWrite (self, stream, varName, indent=" "): + if self.style != "mma": + stream.write (indent + self.encode.replace ("@", "buf").replace ("#", varName) + ";\n") + if self.style == "wm": + stream.write (indent + self.encode.replace ("@", "buf") \ + .replace ("#", varName + "High") + ";\n") + stream.write (indent + self.encode.replace ("@", "buf") \ + .replace ("#", varName + "Low") + ";\n") + if self.style == "mma": + stream.write (indent + self.encode.replace ("@", "buf") \ + .replace ("#", varName + "Count") + ";\n") + stream.write (indent + self.encode.replace ("@", "buf") \ + .replace ("#", varName + "Count ? " + varName + "Min : 0") + ";\n") + stream.write (indent + self.encode.replace ("@", "buf") \ + .replace ("#", varName + "Max") + ";\n") + stream.write (indent + self.encode.replace ("@", "buf") \ + .replace ("#", varName + "Count ? " + varName + "Total / " + + varName + "Count : 0") + ";\n") + + + def getReadCode (self, varName, bufName): + result = self.decode.replace ("@", bufName).replace ("#", varName) + return result + + def getWriteCode (self, varName, bufName): + result = self.encode.replace ("@", bufName).replace ("#", varName) + return result + +#===================================================================================== +# +#===================================================================================== +class TypeSpec: + def __init__ (self, file): + self.types = {} + dom = parse (file) + document = dom.documentElement + if document.tagName != 'schema-types': + raise ValueError ("Expected 'schema-types' in type file") + + for child in document.childNodes: + if child.nodeType == Node.ELEMENT_NODE: + if child.nodeName == 'type': + stype = SchemaType (child) + self.types[stype.getName ()] = stype + else: + raise ValueError ("Unknown type tag '%s'" % child.nodeName) + + def getType (self, name): + return self.types[name] + + +#===================================================================================== +# +#===================================================================================== +class Type: + def __init__ (self, name, typespec): + self.type = typespec.getType (name) + +#===================================================================================== +# +#===================================================================================== +class SchemaProperty: + def __init__ (self, node, typespec): + self.name = None + self.type = None + self.ref = None + self.access = "RO" + self.isIndex = 0 + self.isParentRef = 0 + self.isGeneralRef = 0 + self.isOptional = 0 + self.unit = None + self.min = None + self.max = None + self.maxLen = None + self.desc = None + + attrs = node.attributes + for idx in range (attrs.length): + key = attrs.item(idx).nodeName + val = attrs.item(idx).nodeValue + if key == 'name': + self.name = makeValidCppSymbol(val) + + elif key == 'type': + self.type = Type (val, typespec) + if self.type.type.accessor != 'direct': + raise ValueError ("Class properties must have a type with a direct accessor") + + elif key == 'references': + self.ref = val + + elif key == 'access': + self.access = val + + elif key == 'index': + if val != 'y': + raise ValueError ("Expected 'y' in index attribute") + self.isIndex = 1 + + elif key == 'parentRef': + if val != 'y': + raise ValueError ("Expected 'y' in parentRef attribute") + self.isParentRef = 1 + + elif key == 'isGeneralReference': + if val != 'y': + raise ValueError ("Expected 'y' in isGeneralReference attribute") + self.isGeneralRef = 1 + + elif key == 'optional': + if val != 'y': + raise ValueError ("Expected 'y' in optional attribute") + self.isOptional = 1 + + elif key == 'unit': + self.unit = val + + elif key == 'min': + self.min = val + + elif key == 'max': + self.max = val + + elif key == 'maxlen': + self.maxLen = val + + elif key == 'desc': + self.desc = val + + else: + raise ValueError ("Unknown attribute in property '%s'" % key) + + if self.access == "RC" and self.isOptional == 1: + raise ValueError ("Properties with ReadCreate access must not be optional (%s)" % self.name) + + if self.name == None: + raise ValueError ("Missing 'name' attribute in property") + if self.type == None: + raise ValueError ("Missing 'type' attribute in property") + + def getName (self): + return self.name + + def isConstructorArg (self): + if self.access == "RC" and self.isParentRef == 0: + return 1 + return 0 + + def genDeclaration (self, stream, prefix=" "): + stream.write (prefix + self.type.type.cpp + " " + self.name + ";\n") + + def genFormalParam (self, stream, variables): + stream.write (self.type.type.asArg + " _" + self.name) + + def genAccessor (self, stream): + self.type.type.genAccessor (stream, self.name, "configChanged", self.isOptional == 1) + + def genInitialize (self, stream, prefix="", indent=" "): + val = self.type.type.init + stream.write (indent + prefix + self.name + " = " + val + ";\n") + + def genSchema (self, stream): + stream.write (" ft = FieldTable ();\n") + stream.write (" ft.setString (NAME, \"" + self.name + "\");\n") + stream.write (" ft.setInt (TYPE, TYPE_" + self.type.type.base +");\n") + stream.write (" ft.setInt (ACCESS, ACCESS_" + self.access + ");\n") + stream.write (" ft.setInt (IS_INDEX, " + str (self.isIndex) + ");\n") + stream.write (" ft.setInt (IS_OPTIONAL, " + str (self.isOptional) + ");\n") + if self.unit != None: + stream.write (" ft.setString (UNIT, \"" + self.unit + "\");\n") + if self.min != None: + stream.write (" ft.setInt (MIN, " + self.min + ");\n") + if self.max != None: + stream.write (" ft.setInt (MAX, " + self.max + ");\n") + if self.maxLen != None: + stream.write (" ft.setInt (MAXLEN, " + self.maxLen + ");\n") + if self.desc != None: + stream.write (" ft.setString (DESC, \"" + self.desc + "\");\n") + stream.write (" buf.put (ft);\n\n") + + def genWrite (self, stream): + indent = " " + if self.isOptional: + stream.write(" if (presenceMask[presenceByte_%s] & presenceMask_%s) {\n" % (self.name, self.name)) + indent = " " + self.type.type.genWrite (stream, self.name, indent) + if self.isOptional: + stream.write(" }\n") + + +#===================================================================================== +# +#===================================================================================== +class SchemaStatistic: + def __init__ (self, node, typespec): + self.name = None + self.type = None + self.unit = None + self.desc = None + self.assign = None + + attrs = node.attributes + for idx in range (attrs.length): + key = attrs.item(idx).nodeName + val = attrs.item(idx).nodeValue + if key == 'name': + self.name = makeValidCppSymbol(val) + + elif key == 'type': + self.type = Type (val, typespec) + + elif key == 'unit': + self.unit = val + + elif key == 'desc': + self.desc = val + + elif key == 'assign': + self.assign = val + + else: + raise ValueError ("Unknown attribute in statistic '%s'" % key) + + if self.name == None: + raise ValueError ("Missing 'name' attribute in statistic") + if self.type == None: + raise ValueError ("Missing 'type' attribute in statistic") + + def getName (self): + return self.name + + def genDeclaration (self, stream, prefix=" "): + if self.type.type.style != "mma": + stream.write (prefix + self.type.type.cpp + " " + self.name + ";\n") + if self.type.type.style == 'wm': + stream.write (prefix + self.type.type.cpp + " " + self.name + "High;\n") + stream.write (prefix + self.type.type.cpp + " " + self.name + "Low;\n") + if self.type.type.style == "mma": + stream.write (prefix + self.type.type.cpp + " " + self.name + "Count;\n") + stream.write (prefix + "uint64_t " + self.name + "Total;\n") + stream.write (prefix + self.type.type.cpp + " " + self.name + "Min;\n") + stream.write (prefix + self.type.type.cpp + " " + self.name + "Max;\n") + + def genAccessor (self, stream): + self.type.type.genAccessor (stream, self.name, "instChanged") + + def genHiLoStatResets (self, stream): + self.type.type.genHiLoStatResets (stream, self.name) + + def genPerThreadHiLoStatResets (self, stream): + self.type.type.genPerThreadHiLoStatResets (stream, self.name, self.type.type.cpp) + + def genSchemaText (self, stream, name, desc): + stream.write (" ft = FieldTable ();\n") + stream.write (" ft.setString (NAME, \"" + name + "\");\n") + stream.write (" ft.setInt (TYPE, TYPE_" + self.type.type.base +");\n") + if self.unit != None: + stream.write (" ft.setString (UNIT, \"" + self.unit + "\");\n") + if desc != None: + stream.write (" ft.setString (DESC, \"" + desc + "\");\n") + stream.write (" buf.put (ft);\n\n") + + def genSchema (self, stream): + if self.type.type.style != "mma": + self.genSchemaText (stream, self.name, self.desc) + if self.type.type.style == "wm": + descHigh = self.desc + descLow = self.desc + if self.desc != None: + descHigh = descHigh + " (High)" + descLow = descLow + " (Low)" + self.genSchemaText (stream, self.name + "High", descHigh) + self.genSchemaText (stream, self.name + "Low", descLow) + if self.type.type.style == "mma": + descCount = self.desc + descMin = self.desc + descMax = self.desc + descAverage = self.desc + if self.desc != None: + descCount = descCount + " (Samples)" + descMin = descMin + " (Min)" + descMax = descMax + " (Max)" + descAverage = descAverage + " (Average)" + self.genSchemaText (stream, self.name + "Samples", descCount) + self.genSchemaText (stream, self.name + "Min", descMin) + self.genSchemaText (stream, self.name + "Max", descMax) + self.genSchemaText (stream, self.name + "Average", descAverage) + + def genAssign (self, stream): + if self.assign != None: + if self.type.type.perThread: + prefix = " threadStats->" + else: + prefix = "" + stream.write (" " + prefix + self.name + " = (" + self.type.type.cpp + + ") (" + self.assign + ");\n") + + def genWrite (self, stream): + if self.type.type.perThread: + self.type.type.genWrite (stream, "totals." + self.name) + else: + self.type.type.genWrite (stream, self.name) + + def genInitialize (self, stream, prefix="", indent=" "): + val = self.type.type.init + if self.type.type.style != "mma": + stream.write (indent + prefix + self.name + " = " + val + ";\n") + if self.type.type.style == "wm": + stream.write (indent + prefix + self.name + "High = " + val + ";\n") + stream.write (indent + prefix + self.name + "Low = " + val + ";\n") + if self.type.type.style == "mma": + stream.write (indent + prefix + self.name + "Count = 0;\n") + stream.write (indent + prefix + self.name + "Min = std::numeric_limits<" + self.type.type.cpp + ">::max();\n") + stream.write (indent + prefix + self.name + "Max = std::numeric_limits<" + self.type.type.cpp + ">::min();\n") + stream.write (indent + prefix + self.name + "Total = 0;\n") + + def genInitializeTotalPerThreadStats (self, stream): + if self.type.type.style == "mma": + stream.write (" totals->" + self.name + "Count = 0;\n") + stream.write (" totals->" + self.name + "Min = std::numeric_limits<" + self.type.type.cpp + ">::max();\n") + stream.write (" totals->" + self.name + "Max = std::numeric_limits<" + self.type.type.cpp + ">::min();\n") + stream.write (" totals->" + self.name + "Total = 0;\n") + else: + stream.write (" totals->" + self.name + " = 0;\n") + + def genAggregatePerThreadStats (self, stream): + if self.type.type.style == "mma": + stream.write (" totals->%sCount += threadStats->%sCount;\n" % (self.name, self.name)) + stream.write (" if (totals->%sMin > threadStats->%sMin)\n" % (self.name, self.name)) + stream.write (" totals->%sMin = threadStats->%sMin;\n" % (self.name, self.name)) + stream.write (" if (totals->%sMax < threadStats->%sMax)\n" % (self.name, self.name)) + stream.write (" totals->%sMax = threadStats->%sMax;\n" % (self.name, self.name)) + stream.write (" totals->%sTotal += threadStats->%sTotal;\n" % (self.name, self.name)) + else: + stream.write (" totals->%s += threadStats->%s;\n" % (self.name, self.name)) + +#===================================================================================== +# +#===================================================================================== +class SchemaArg: + def __init__ (self, node, typespec): + self.name = None + self.type = None + self.unit = None + self.dir = "I" + self.min = None + self.max = None + self.maxLen = None + self.desc = None + self.default = None + self.hash = Hash(node) + + attrs = node.attributes + for idx in range (attrs.length): + key = attrs.item(idx).nodeName + val = attrs.item(idx).nodeValue + if key == 'name': + self.name = makeValidCppSymbol(val) + + elif key == 'type': + self.type = Type (val, typespec) + + elif key == 'unit': + self.unit = val + + elif key == 'dir': + self.dir = val.upper () + + elif key == 'min': + self.min = val + + elif key == 'max': + self.max = val + + elif key == 'maxlen': + self.maxLen = val + + elif key == 'desc': + self.desc = val + + elif key == 'default': + self.default = val + + else: + raise ValueError ("Unknown attribute in arg '%s'" % key) + + if self.name == None: + raise ValueError ("Missing 'name' attribute in arg") + if self.type == None: + raise ValueError ("Missing 'type' attribute in arg") + + def getName (self): + return self.name + + def getDir (self): + return self.dir + + def genSchema (self, stream, event=False): + stream.write (" ft = FieldTable ();\n") + stream.write (" ft.setString (NAME, \"" + self.name + "\");\n") + stream.write (" ft.setInt (TYPE, TYPE_" + self.type.type.base +");\n") + if (not event): + stream.write (" ft.setString (DIR, \"" + self.dir + "\");\n") + if self.unit != None: + stream.write (" ft.setString (UNIT, \"" + self.unit + "\");\n") + if not event: + if self.min != None: + stream.write (" ft.setInt (MIN, " + self.min + ");\n") + if self.max != None: + stream.write (" ft.setInt (MAX, " + self.max + ");\n") + if self.maxLen != None: + stream.write (" ft.setInt (MAXLEN, " + self.maxLen + ");\n") + if self.default != None: + stream.write (" ft.setString (DEFAULT, \"" + self.default + "\");\n") + if self.desc != None: + stream.write (" ft.setString (DESC, \"" + self.desc + "\");\n") + stream.write (" buf.put (ft);\n\n") + + def genFormalParam (self, stream, variables): + stream.write ("%s _%s" % (self.type.type.asArg, self.name)) + +#===================================================================================== +# +#===================================================================================== +class SchemaMethod: + def __init__ (self, parent, node, typespec): + self.parent = parent + self.name = None + self.desc = None + self.args = [] + + attrs = node.attributes + for idx in range (attrs.length): + key = attrs.item(idx).nodeName + val = attrs.item(idx).nodeValue + if key == 'name': + self.name = makeValidCppSymbol(val) + + elif key == 'desc': + self.desc = val + + else: + raise ValueError ("Unknown attribute in method '%s'" % key) + + for child in node.childNodes: + if child.nodeType == Node.ELEMENT_NODE: + if child.nodeName == 'arg': + arg = SchemaArg (child, typespec) + self.args.append (arg) + else: + raise ValueError ("Unknown method tag '%s'" % child.nodeName) + + def getName (self): + return self.name + + def getFullName (self): + return capitalize(self.parent.getName()) + self.name[0:1].upper() +\ + self.name[1:] + + def getArgCount (self): + return len (self.args) + + #=================================================================================== + # Code Generation Functions. The names of these functions (minus the leading "gen") + # match the substitution keywords in the template files. + #=================================================================================== + def genNameUpper (self, stream, variables): + stream.write (self.getFullName ().upper ()) + + def genNameCamel (self, stream, variables): + stream.write (self.getFullName ()) + + def genOpenNamespaces (self, stream, variables): + self.parent.genOpenNamespaces(stream, variables) + + def genCloseNamespaces (self, stream, variables): + self.parent.genCloseNamespaces(stream, variables) + + def genArguments (self, stream, variables): + for arg in self.args: + ctype = arg.type.type.cpp + dirTag = arg.dir.lower() + "_" + stream.write (" " + ctype + " " + dirTag + arg.getName () + ";\n") + + def genNamePackageLower (self, stream, variables): + self.parent.genNamePackageLower(stream, variables) + + def genSchema (self, stream, variables): + stream.write (" ft = FieldTable ();\n") + stream.write (" ft.setString (NAME, \"" + self.name + "\");\n") + stream.write (" ft.setInt (ARGCOUNT, " + str (len (self.args)) + ");\n") + if self.desc != None: + stream.write (" ft.setString (DESC, \"" + self.desc + "\");\n") + stream.write (" buf.put (ft);\n\n") + for arg in self.args: + arg.genSchema (stream) + +#===================================================================================== +# +#===================================================================================== +class SchemaEvent: + def __init__ (self, package, node, typespec, argset): + self.packageName = package + self.name = None + self.desc = None + self.sevText = "inform" + self.args = [] + self.hash = Hash(node) + + attrs = node.attributes + for idx in range (attrs.length): + key = attrs.item(idx).nodeName + val = attrs.item(idx).nodeValue + if key == 'name': + self.name = val + + elif key == 'desc': + self.desc = val + + elif key == 'sev': + self.sevText = val + + elif key == 'args': + list = val.replace(" ", "").split(",") + for item in list: + if item not in argset.args: + raise Exception("undefined argument '%s' in event" % item) + self.args.append(argset.args[item]) + self.hash.addSubHash(argset.args[item].hash) + + else: + raise ValueError ("Unknown attribute in event '%s'" % key) + + if self.sevText == "emerg" : self.sev = 0 + elif self.sevText == "alert" : self.sev = 1 + elif self.sevText == "crit" : self.sev = 2 + elif self.sevText == "error" : self.sev = 3 + elif self.sevText == "warn" : self.sev = 4 + elif self.sevText == "notice" : self.sev = 5 + elif self.sevText == "inform" : self.sev = 6 + elif self.sevText == "debug" : self.sev = 7 + else: + raise ValueError("Unknown severity '%s' in event '%s'" % (self.sevText, self.name)) + + def getName (self): + return self.name + + def getNameCap(self): + return capitalize(self.name) + + def getFullName (self): + return capitalize(self.package + capitalize(self.name)) + + def getArgCount (self): + return len (self.args) + + def genArgCount (self, stream, variables): + stream.write("%d" % len(self.args)) + + def genArgDeclarations(self, stream, variables): + for arg in self.args: + if arg.type.type.byRef: + ref = "&" + else: + ref = "" + stream.write(" const %s%s %s;\n" % (arg.type.type.cpp, ref, arg.name)) + + def genCloseNamespaces (self, stream, variables): + for item in self.packageName.split("."): + stream.write ("}") + + def genConstructorArgs(self, stream, variables): + pre = "" + for arg in self.args: + if arg.type.type.byRef: + ref = "&" + else: + ref = "" + stream.write("%sconst %s%s _%s" % (pre, arg.type.type.cpp, ref, arg.name)) + pre = ",\n " + + def genConstructorInits(self, stream, variables): + pre = "" + for arg in self.args: + stream.write("%s%s(_%s)" % (pre, arg.name, arg.name)) + pre = ",\n " + + def genName(self, stream, variables): + stream.write(self.name) + + def genNameCap(self, stream, variables): + stream.write(capitalize(self.name)) + + def genNamespace (self, stream, variables): + stream.write("::".join(self.packageName.split("."))) + + def genNameLower(self, stream, variables): + stream.write(self.name.lower()) + + def genNameUpper(self, stream, variables): + stream.write(self.name.upper()) + + def genNamePackageLower(self, stream, variables): + stream.write(self.packageName.lower()) + + def genOpenNamespaces (self, stream, variables): + for item in self.packageName.split("."): + stream.write ("namespace %s {\n" % item) + + def genSeverity(self, stream, variables): + stream.write("%d" % self.sev) + + def genArgEncodes(self, stream, variables): + for arg in self.args: + stream.write(" " + arg.type.type.encode.replace("@", "buf").replace("#", arg.name) + ";\n") + + def genArgSchema(self, stream, variables): + for arg in self.args: + arg.genSchema(stream, True) + + def genSchemaMD5(self, stream, variables): + sum = self.hash.getDigest() + for idx in range (len (sum)): + if idx != 0: + stream.write (",") + stream.write (hex (ord (sum[idx]))) + + +class SchemaClass: + def __init__ (self, package, node, typespec, fragments, options): + self.packageName = package + self.properties = [] + self.statistics = [] + self.methods = [] + self.events = [] + self.options = options + self.hash = Hash(node) + + attrs = node.attributes + self.name = makeValidCppSymbol(attrs['name'].nodeValue) + + children = node.childNodes + for child in children: + if child.nodeType == Node.ELEMENT_NODE: + if child.nodeName == 'property': + sub = SchemaProperty (child, typespec) + self.properties.append (sub) + + elif child.nodeName == 'statistic': + sub = SchemaStatistic (child, typespec) + self.statistics.append (sub) + + elif child.nodeName == 'method': + sub = SchemaMethod (self, child, typespec) + self.methods.append (sub) + + elif child.nodeName == 'group': + self.expandFragment (child, fragments) + + else: + raise ValueError ("Unknown class tag '%s'" % child.nodeName) + + # Adjust the 'assign' attributes for each statistic + for stat in self.statistics: + if stat.assign != None and stat.type.type.perThread: + stat.assign = self.adjust (stat.assign, self.statistics) + + def adjust (self, text, statistics): + result = text + start = 0 + while True: + next = None + for stat in statistics: + pos = result.find (stat.name, start) + if pos != -1 and (next == None or pos < next[0]): + next = (pos, stat.name) + if next == None: + return result + pos = next[0] + result = result[0:pos] + "threadStats->" + result[pos:] + start = pos + 9 + len(next[1]) + + def expandFragment (self, node, fragments): + attrs = node.attributes + name = attrs['name'].nodeValue + for fragment in fragments: + if fragment.name == name: + self.hash.addSubHash(fragment.hash) + for config in fragment.properties: + self.properties.append (config) + for inst in fragment.statistics: + self.statistics.append (inst) + for method in fragment.methods: + self.methods.append (method) + for event in fragment.events: + self.events.append (event) + return + raise ValueError ("Undefined group '%s'" % name) + + def getName (self): + return self.name + + def getNameCap (self): + return capitalize(self.name) + + def getMethods (self): + return self.methods + + def getEvents (self): + return self.events + + def getPackageNameCap (self): + return capitalize(self.packageName) + + #=================================================================================== + # Code Generation Functions. The names of these functions (minus the leading "gen") + # match the substitution keywords in the template files. + #=================================================================================== + def testExistOptionals (self, variables): + for prop in self.properties: + if prop.isOptional == 1: + return True + return False + + def testExistPerThreadStats (self, variables): + for inst in self.statistics: + if inst.type.type.perThread: + return True + return False + + def testExistPerThreadAssign (self, variables): + for inst in self.statistics: + if inst.type.type.perThread and inst.assign != None: + return True + return False + + def testExistPerThreadResets (self, variables): + for inst in self.statistics: + if inst.type.type.perThread and inst.type.type.style == "mma": + return True + return False + + def testNoStatistics (self, variables): + return len (self.statistics) == 0 + + def genAccessorMethods (self, stream, variables): + for config in self.properties: + if config.access != "RC": + config.genAccessor (stream) + for inst in self.statistics: + if inst.assign == None: + inst.genAccessor (stream) + + def genCloseNamespaces (self, stream, variables): + for item in self.packageName.split("."): + stream.write ("}") + + def genConfigCount (self, stream, variables): + stream.write ("%d" % len (self.properties)) + + def genConfigDeclarations (self, stream, variables): + for element in self.properties: + element.genDeclaration (stream) + + def genConstructorArgs (self, stream, variables): + # Constructor args are config elements with read-create access + result = "" + for element in self.properties: + if element.isConstructorArg (): + stream.write (", ") + element.genFormalParam (stream, variables) + + def genConstructorInits (self, stream, variables): + for element in self.properties: + if element.isConstructorArg (): + stream.write ("," + element.getName () + "(_" + element.getName () + ")") + + def genDoMethodArgs (self, stream, variables): + methodCount = 0 + inArgCount = 0 + for method in self.methods: + methodCount = methodCount + 1 + for arg in method.args: + if arg.getDir () == "I" or arg.getDir () == "IO": + inArgCount = inArgCount + 1 + + if methodCount == 0: + stream.write ("string&, Buffer&, Buffer& outBuf") + else: + if inArgCount == 0: + stream.write ("string& methodName, Buffer&, Buffer& outBuf") + else: + stream.write ("string& methodName, Buffer& inBuf, Buffer& outBuf") + + def genHiLoStatResets (self, stream, variables): + for inst in self.statistics: + if not inst.type.type.perThread: + inst.genHiLoStatResets (stream) + + def genPerThreadHiLoStatResets (self, stream, variables): + for inst in self.statistics: + if inst.type.type.perThread: + inst.genPerThreadHiLoStatResets (stream) + + def genInitializeElements (self, stream, variables): + for prop in self.properties: + if not prop.isConstructorArg() and not prop.isParentRef: + prop.genInitialize(stream) + for inst in self.statistics: + if not inst.type.type.perThread: + inst.genInitialize (stream) + + def genInitializePerThreadElements (self, stream, variables): + for inst in self.statistics: + if inst.type.type.perThread: + inst.genInitialize (stream, "threadStats->", " ") + + def genInitializeTotalPerThreadStats (self, stream, variables): + for inst in self.statistics: + if inst.type.type.perThread: + inst.genInitializeTotalPerThreadStats (stream) + + def genAggregatePerThreadStats (self, stream, variables): + for inst in self.statistics: + if inst.type.type.perThread: + inst.genAggregatePerThreadStats (stream) + + def genInstCount (self, stream, variables): + count = 0 + for inst in self.statistics: + count = count + 1 + if inst.type.type.style == "wm": + count = count + 2 + if inst.type.type.style == "mma": + count = count + 3 + stream.write ("%d" % count) + + def genInstDeclarations (self, stream, variables): + for element in self.statistics: + if not element.type.type.perThread: + element.genDeclaration (stream) + + def genPerThreadDeclarations (self, stream, variables): + for element in self.statistics: + if element.type.type.perThread: + element.genDeclaration (stream, " ") + + def genNamespace (self, stream, variables): + stream.write("::".join(self.packageName.split("."))) + + def genMethodArgIncludes (self, stream, variables): + for method in self.methods: + if method.getArgCount () > 0: + stream.write ("#include \"Args" + method.getFullName () + ".h\"\n") + + def genMethodCount (self, stream, variables): + stream.write ("%d" % len (self.methods)) + + def genMethodHandlers (self, stream, variables): + for method in self.methods: + stream.write ("\n if (methodName == \"" + method.getName () + "\") {\n") + if method.getArgCount () == 0: + stream.write (" ::qpid::management::ArgsNone ioArgs;\n") + else: + stream.write (" Args" + method.getFullName () + " ioArgs;\n") + for arg in method.args: + if arg.getDir () == "I" or arg.getDir () == "IO": + stream.write (" " +\ + arg.type.type.getReadCode ("ioArgs." +\ + arg.dir.lower () + "_" +\ + arg.name, "inBuf") + ";\n") + + stream.write (" status = coreObject->ManagementMethod (METHOD_" +\ + method.getName().upper() + ", ioArgs, text);\n") + stream.write (" outBuf.putLong (status);\n") + stream.write (" outBuf.putMediumString(::qpid::management::Manageable::StatusText (status, text));\n") + for arg in method.args: + if arg.getDir () == "O" or arg.getDir () == "IO": + stream.write (" " +\ + arg.type.type.getWriteCode ("ioArgs." +\ + arg.dir.lower () + "_" +\ + arg.name, "outBuf") + ";\n") + stream.write (" return;\n }\n") + + def genOpenNamespaces (self, stream, variables): + for item in self.packageName.split("."): + stream.write ("namespace %s {\n" % item) + + def genPresenceMaskBytes (self, stream, variables): + count = 0 + for prop in self.properties: + if prop.isOptional == 1: + count += 1 + if count == 0: + stream.write("0") + else: + stream.write (str(((count - 1) / 8) + 1)) + + def genPresenceMaskConstants (self, stream, variables): + count = 0 + for prop in self.properties: + if prop.isOptional == 1: + stream.write(" static const uint8_t presenceByte_%s = %d;\n" % (prop.name, count / 8)) + stream.write(" static const uint8_t presenceMask_%s = %d;\n" % (prop.name, 1 << (count % 8))) + count += 1 + + def genPropertySchema (self, stream, variables): + for prop in self.properties: + prop.genSchema (stream) + + def genSetGeneralReferenceDeclaration (self, stream, variables): + for prop in self.properties: + if prop.isGeneralRef: + stream.write ("void setReference(::qpid::management::ObjectId objectId) { " + prop.name + " = objectId; }\n") + + def genStatisticSchema (self, stream, variables): + for stat in self.statistics: + stat.genSchema (stream) + + def genMethodIdDeclarations (self, stream, variables): + number = 1 + for method in self.methods: + stream.write (" static const uint32_t METHOD_" + method.getName().upper() +\ + " = %d;\n" % number) + number = number + 1 + + def genMethodSchema (self, stream, variables): + for method in self.methods: + method.genSchema (stream, variables) + + def genNameCap (self, stream, variables): + stream.write (capitalize(self.name)) + + def genNameLower (self, stream, variables): + stream.write (self.name.lower ()) + + def genNamePackageCap (self, stream, variables): + stream.write (self.getPackageNameCap ()) + + def genNamePackageLower (self, stream, variables): + stream.write (self.packageName.lower ()) + + def genNameUpper (self, stream, variables): + stream.write (self.name.upper ()) + + def genParentArg (self, stream, variables): + for config in self.properties: + if config.isParentRef == 1: + stream.write (", ::qpid::management::Manageable* _parent") + return + + def genParentRefAssignment (self, stream, variables): + for config in self.properties: + if config.isParentRef == 1: + stream.write (config.getName () + \ + " = _parent->GetManagementObject ()->getObjectId ();") + return + + def genSchemaMD5 (self, stream, variables): + sum = self.hash.getDigest() + for idx in range (len (sum)): + if idx != 0: + stream.write (",") + stream.write (hex (ord (sum[idx]))) + + def genAssign (self, stream, variables): + for inst in self.statistics: + if not inst.type.type.perThread: + inst.genAssign (stream) + + def genPerThreadAssign (self, stream, variables): + for inst in self.statistics: + if inst.type.type.perThread: + inst.genAssign (stream) + + def genWriteProperties (self, stream, variables): + for prop in self.properties: + prop.genWrite (stream) + + def genWriteStatistics (self, stream, variables): + for stat in self.statistics: + stat.genWrite (stream) + + +class SchemaEventArgs: + def __init__(self, package, node, typespec, fragments, options): + self.packageName = package + self.options = options + self.args = {} + + children = node.childNodes + for child in children: + if child.nodeType == Node.ELEMENT_NODE: + if child.nodeName == 'arg': + arg = SchemaArg(child, typespec) + self.args[arg.name] = arg + else: + raise Exception("Unknown tag '%s' in <eventArguments>" % child.nodeName) + +class SchemaPackage: + def __init__ (self, typefile, schemafile, options): + + self.classes = [] + self.fragments = [] + self.typespec = TypeSpec (typefile) + self.eventArgSet = None + self.events = [] + + dom = parse (schemafile) + document = dom.documentElement + if document.tagName != 'schema': + raise ValueError ("Expected 'schema' node") + attrs = document.attributes + pname = attrs['package'].nodeValue + namelist = pname.split('.') + self.packageName = ".".join(namelist) + + children = document.childNodes + for child in children: + if child.nodeType == Node.ELEMENT_NODE: + if child.nodeName == 'class': + cls = SchemaClass (self.packageName, child, self.typespec, + self.fragments, options) + self.classes.append (cls) + + elif child.nodeName == 'group': + cls = SchemaClass (self.packageName, child, self.typespec, + self.fragments, options) + self.fragments.append (cls) + + elif child.nodeName == 'eventArguments': + if self.eventArgSet: + raise Exception("Only one <eventArguments> may appear in a package") + self.eventArgSet = SchemaEventArgs(self.packageName, child, self.typespec, self.fragments, options) + + elif child.nodeName == 'event': + event = SchemaEvent(self.packageName, child, self.typespec, self.eventArgSet) + self.events.append(event) + + else: + raise ValueError ("Unknown schema tag '%s'" % child.nodeName) + + def getPackageName (self): + return self.packageName + + def getPackageNameCap (self): + return capitalize(self.packageName) + + def getPackageNameLower (self): + return self.packageName.lower() + + def getClasses (self): + return self.classes + + def getEvents(self): + return self.events + + def genCloseNamespaces (self, stream, variables): + for item in self.packageName.split("."): + stream.write ("}") + + def genNamespace (self, stream, variables): + stream.write("::".join(self.packageName.split("."))) + + def genOpenNamespaces (self, stream, variables): + for item in self.packageName.split("."): + stream.write ("namespace %s {\n" % item) + + def genPackageNameUpper (self, stream, variables): + up = "_".join(self.packageName.split(".")) + stream.write (up.upper()) + + def genNamePackageLower (self, stream, variables): + stream.write (self.packageName.lower ()) + + def genClassIncludes (self, stream, variables): + for _class in self.classes: + stream.write ("#include \"") + _class.genNameCap (stream, variables) + stream.write (".h\"\n") + for _event in self.events: + stream.write ("#include \"Event") + _event.genNameCap(stream, variables) + stream.write (".h\"\n") + + def genClassRegisters(self, stream, variables): + for _class in self.classes: + stream.write(" ") + _class.genNameCap(stream, variables) + stream.write("::registerSelf(agent);\n") + for _event in self.events: + stream.write(" Event") + _event.genNameCap(stream, variables) + stream.write("::registerSelf(agent);\n") + + +#===================================================================================== +# Utility Functions +#===================================================================================== + +# Create a valid C++ symbol from the input string so that it can be +# used in generated C++ source. For instance, change "qpid.mgmt" to +# "qpidMgmt". +# +# Input: Raw string (str) to process +# Output: String (str) suitable for use as a C++ symbol +# +# Limitations: Currently, only strips periods ('.') from strings, +# eventually should strip :'s and ,'s and ''s, oh my! +def makeValidCppSymbol(input): + output = str() + capitalize = False + + for char in input: + skip = False + + if char == ".": + capitalize = True + skip = True + + if not skip: + output += capitalize and char.upper() or char + + capitalize = False + + return output + +# Capitalize a string by /only/ forcing the first character to be +# uppercase. The rest of the string is left alone. This is different +# from str.capitalize(), which forces the first character to uppercase +# and the rest to lowercase. +# +# Input: A string (str) to capitalize +# Output: A string (str) with the first character as uppercase +def capitalize(input): + return input[0].upper() + input[1:] |