#!/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