#!/usr/bin/python # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at # trunk/opends/resource/legal-notices/OpenDS.LICENSE # or https://OpenDS.dev.java.net/OpenDS.LICENSE. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at # trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, # add the following below this CDDL HEADER, with the fields enclosed # information: # Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. # Global variable containing the list of servers ("Server" class instances) deployed # Define ChangelogServer class class OIDDict: """OIDDict is a dictionary class that help lookup OID <-> litteral name of both objeclasses, and attributtypes""" def __init__(self, schema=None): self.attrDict = {} self.objDict = {} self.sup = {} self.may = {} self.must = {} self.allmay = [] self.allmust = [] def _getOID(self, line): """given a schema entry definition for objectclass/attributtype return the tuple (OID,List of names) the List of aliases starts from list of names[1:] when exist. for ex : attributeTypes: ( 2.5.4.4 NAME ( 'sn' 'surname' ) SUP name X-ORIGIN 'RFC 4519' ) (2.5.4.4,['sn','surname'] More details : https://www.opends.org/wiki/page/AttributeTypeDescriptionFormat """ pNdx = line.find('(') nNdx = line.find('NAME',pNdx) OID = line[pNdx+1:nNdx].strip() # populate the NAME to OID : "dict" dictionary NAMES = self._getStr(line,'NAME') if NAMES: if line.startswith('objectClasses:'): # TODO encoded schema is not handled for now self.objDict.update({OID:NAMES}) for name in NAMES: self.objDict.update({name:OID}) elif line.startswith('attributeTypes:'): # TODO encoded schema is not handled for now self.attrDict.update({OID:NAMES}) for name in NAMES: self.attrDict.update({name:OID}) # populate SUP and MUST / MAY, : "sup", "may", "must" dictionaries if line.startswith('objectClasses:'): r = self._getStr(line,'SUP') if r: self.sup.update({NAMES[0]:r}) r = self._getStr(line,'MUST') if r: self.must.update({NAMES[0]:r}) for m in r: if not m in self.allmust: self.allmust.append(m) r = self._getStr(line,'MAY') if r: self.may.update({NAMES[0]:r}) for m in r: if not m in self.allmay: self.allmay.append(m) return OID, NAMES def _getStr(self, line, myStr, right=None): """extract a list of attributes for a given myStr section. The section should contain () when multivalued. If another section comes after it starts with a Upercase. example MUST (sn cn) MAY ( description ... ) line : line to parse myStr : name of the section ex(MAY) right : right boundary, if None, function will figure out end of section""" left = line.find(myStr) if left == -1: return None if not right: right = len(line) lpNdx = line.find('(', left) if lpNdx > 0: spaces=line[left+len(myStr) : lpNdx] if len(spaces.strip()) == 0: right = line.find(')',lpNdx) left = lpNdx + 1 else: left = left+len(myStr)+1 else: left = left+len(myStr) strs = line[left:right] realStrs = [] for s in strs.split(' '): if len(s) > 0: if s[0] >= 'A' and s[0] <= 'Z': break elif s[0] != '$' and s[0] != '|': if s[0] == '\'' and s[-1] == '\'': s = s[1:-1] realStrs.append(s.lower()) return realStrs def getMust(self, objectclassname): """will return the attributes the objectclassname MUST implement""" if self.must.has_key(objectclassname): ret = self.must.get(objectclassname) else: ret = [] for h in self.getHierarchy(objectclassname): # avoiding duplication of MUSTs ret.extend([e for e in self.getMust(h) if ret.count(e) == 0]) return ret def getMay(self, objectclassname): """will return the attributes the objectclassname MAY implement""" if self.may.has_key(objectclassname): ret = self.may.get(objectclassname) else: ret = [] for h in self.getHierarchy(objectclassname): # avoiding duplication of MAYs ret.extend([e for e in self.getMay(h) if ret.count(e) == 0]) return ret def getSup(self, objectclassname): """will return the objectclassname that this objectclassname inherit""" if objectclassname == 'top': return None else: ret = self.sup.get(objectclassname) return ret[0] def getHierarchy(self, objectclassname): hierachy = [] up = self.getSup(objectclassname) while up: if hierachy.count(up) == 0: hierachy.append(up) up = self.getSup(up) return hierachy def parseSchema(self, ref_content): """get the schema as a string lookit up line by line, extracting OID/literal name for objectclasses and attributetypes only.""" lines=[] line='' for f in ref_content.splitlines(): if len(line) == 0 and \ not (f.startswith("objectClasses") or \ f.startswith("attributeTypes")): # not handled for now continue elif len(line) > 0 and len(f) > 0 and f[0].isspace(): # line continuation aggregated into 'line' line += f[1:] elif f.startswith("objectClasses") or f.startswith("attributeTypes"): if len(line) > 0: lines.append(line) # populate the OID <-> Names dictionary self._getOID(line) line = f[:-1] line = f if len(line) > 0: # parsing the last line self._getOID(line) lines.append(line) f=open('/tmp/lines.ldif','w') f.write('\n'.join(lines)) f.close() if __name__ == '__main__': """get example schema.ldif file with : ldapsearch -b 'cn=schema' -Dcn=directory\ manager -s base -wpassword objectclass=* objectClasses attributeTypes > /tmp/schema.ldif """ objectClassesFileName='/tmp/schema.ldif' f = open(objectClassesFileName) fc = f.readlines() f.close() oidDict = OIDDict() oidDict.parseSchema(''.join(fc)) print '[ Objectclasses dictionary ]'.center(80, '-') for k,v in oidDict.objDict.items(): print "%s\t%s"%(k,v) print '[ AttributeTypes dictionary ]'.center(80, '-') for k,v in oidDict.attrDict.items(): print "%s\t%s"%(k,v) print '[ must ]'.center(80, '-') for k,v in oidDict.must.items(): print "%s\t%s"%(k,v) print '[ may ]'.center(80, '-') for k,v in oidDict.may.items(): print "%s\t%s"%(k,v) print '[ sup ]'.center(80, '-') for k,v in oidDict.sup.items(): print "%s\t%s"%(k,v) for cn in ['rFC822LocalPart','inetOrgPerson','top','doMain','2.5.6.7','BLAH']: print cn.center(80, '-') try: print 'SUP'.center(40,'.') print 'SUP',oidDict.getSup(cn) print 'HIERARCHY',oidDict.getHierarchy(cn) print 'MUST'.center(40,'.') print 'MUST',oidDict.getMust(cn) print 'MAY'.center(40,'.') print 'MAY',oidDict.getMay(cn) except Exception, e: print e.message print '[ all must ]'.center(80,'-') mustSize = 0 for m in oidDict.allmust: mustSize += len(m) print 'got %s MUSTs size = %sKb' % (len(oidDict.allmust),mustSize/1024.0) print oidDict.allmust print '[ all may ]'.center(80,'-') maySize = 0 for m in oidDict.allmay: maySize += len(m) print 'got %s MAYs size = %sKb' % (len(oidDict.allmay),maySize/1024.0) print oidDict.allmay