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