Changeset 45

Show
Ignore:
Timestamp:
08/26/06 10:30:22 (2 years ago)
Author:
johnbywater
Message:

Added major performance improvement to dm/accesscontroller.py.

  • eliminated for statements (see new isRoleAuthorised() method for details)
    • performance of the access controller is now far more scalable

Changed various minor details whilst tuning performance.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/etc/domainmodel.conf.new

    r43 r45  
    11## Please Note: This file is a meant as a starting point for a configuration file for a 
    2 new dm application. It is also used to setup development of the dm package. 
     2#new dm application. It is also used to setup development of the dm package. 
    33 
    44[DEFAULT] 
     
    2020# plugin_data_dir: 
    2121#  * path to plugin filesystems 
    22 plugin_data_dir = /tmp/domainmodel_testing/plugin_data 
     22plugin_data_dir = /path/to/domainmdoel/var/plugin_data 
    2323 
    2424# domain_name: 
     
    3030# log_file: 
    3131#  * service log file 
    32 log_file = %(system_name)s.log 
     32log_file = /path/to/domainmodel/var/log/domainmodel.log 
    3333 
    3434# level: 
  • trunk/src/dm/accesscontrol.py

    r32 r45  
    11from dm.ioc import RequiredFeature 
    22from dm.exceptions import * 
     3from dm.dictionarywords import VISITOR_NAME 
    34 
    45class AbstractAccessController(object): 
     
    1011    debug      = RequiredFeature('Debug') 
    1112 
     13    def __init__(self): 
     14        self.visitor = None 
     15         
     16    def getVisitor(self): 
     17        if self.visitor == None: 
     18            visitorName = self.dictionary[VISITOR_NAME] 
     19            self.visitor = self.registry.persons[visitorName] 
     20        return self.visitor 
     21             
    1222    def isAuthorised(self, person=None, actionName='', protectedObject=None): 
     23        if not actionName: 
     24            return False 
     25        if not protectedObject: 
     26            return False 
    1327        self.setPerson(person) 
    14         self.actionName = actionName 
    15         self.protectedObject = protectedObject 
    16         if not self.validateInput(): 
    17             if self.debug: 
    18                 self.logger.debug("Access denied: Invalid input.") 
    19             return False 
     28        self.setAction(actionName) 
     29        self.setProtectedObject(protectedObject) 
    2030        if self.hasAuthorisedRole(): 
    2131            if self.debug: 
     
    3444            return False 
    3545 
    36     def setPerson(self, person): 
    37         if person == None: 
    38             personName = self.dictionary['visitor'] 
    39             person = self.registry.persons[personName] 
    40         self.person = person 
     46    def setPerson(self, person=None): 
     47        if person != None: 
     48            self.person = person 
     49        else: 
     50            self.person = self.getVisitor() 
    4151 
    42     def validateInput(self): 
    43         if not self.person: 
    44             if self.debug: 
    45                 self.logger.debug( 
    46                     "No person for access controller." 
    47                 ) 
    48             return False 
    49         if not self.actionName: 
    50             if self.debug: 
    51                 self.logger.debug( 
    52                     "No action name for access controller." 
    53                 ) 
    54             return False 
    55         if not self.actionName in self.registry.actions: 
    56             if self.debug: 
    57                 self.logger.debug( 
    58                     "Action name '%s' not registered." % self.actionName 
    59                 ) 
    60             return False 
     52    def setAction(self, actionName): 
     53        self.actionName = actionName 
    6154        self.action = self.registry.actions[self.actionName] 
    62         if not self.action: 
    63             if self.debug: 
    64                 self.logger.debug( 
    65                     "No action for access controller." 
    66                 ) 
    67             return False 
    68         if not self.protectedObject: 
    69             if self.debug: 
    70                 self.logger.debug( 
    71                     "No protected object for access controller." 
    72                 ) 
    73             return False 
    74         return True 
     55 
     56    def setProtectedObject(self, protectedObject): 
     57        self.protectedObject = protectedObject 
     58        self.makeProtectedNames() 
     59        self.setProtectionObject() 
    7560 
    7661    def hasAuthorisedRole(self): 
    7762        message = "Abstract method not implemented on: %s" % str(self) 
    7863        raise Exception(message) 
    79              
     64         
    8065    def isRoleAuthorised(self, role): 
     66        permission = self.protectionObject.permissions[self.action] 
     67        if role in permission.grants: 
     68            if self.debug: 
     69                msg = "Access by role authorised: '%s' to '%s' with '%s'." % (role.name, self.actionName, self.protectedObject) 
     70                self.logger.debug(msg) 
     71            return True 
     72        else: 
     73            if self.debug: 
     74                msg = "Access by role not authorised: '%s' to '%s' with '%s'." % (role.name, self.actionName, self.protectedObject) 
     75                self.logger.debug(msg) 
     76            return False 
     77         
     78    def ____isRoleAuthorised(self, role): 
    8179        for grant in role.grants: 
    8280            permission = grant.permission 
     
    9088        return False 
    9189         
     90    def makeProtectedNames(self): 
     91        self.protectedNames = [] 
     92        if self.protectedObject.__class__ == type: 
     93            className = self.protectedObject.__name__ 
     94            self.protectedNames.append(className) 
     95        else: 
     96            className = self.protectedObject.__class__.__name__ 
     97            keyValue = self.protectedObject.getRegisterKeyValue() 
     98            self.protectedNames.append(className + "." + str(keyValue)) 
     99            self.protectedNames.append(className) 
     100        if not self.protectedNames: 
     101            raise "No protected names derived from protection object." 
     102 
     103    def setProtectionObject(self): 
     104        protectionObjects = self.registry.protectionObjects 
     105        for name in self.protectedNames: 
     106            if name in protectionObjects: 
     107                self.protectionObject = protectionObjects[name] 
     108                return 
     109        raise "No protection object available for %s" % self.protectedNames 
     110 
    92111 
    93112class SystemAccessController(AbstractAccessController): 
     
    95114 
    96115    def hasAuthorisedRole(self): 
    97         if self.isPersonBarred(): 
    98             return False 
    99         if self.isPersonAuthorised(): 
    100             return True 
    101116        if self.isSystemRoleAuthorised(): 
    102117            return True 
     118        #if self.isPersonAuthorised(): 
     119        #    return True 
     120        #if self.isPersonBarred(): 
     121        #    return False 
    103122        return False 
    104123 
  • trunk/src/dm/db.py

    r2 r45  
    102102                else: 
    103103                    record = records 
     104            if debug: 
     105                logger.debug('Found %s record from database.' % (className)) 
    104106            return record 
    105107         
     
    129131            recordClass = self.getRecordClass(className) 
    130132            if self.isSelectById(kwds): 
    131                 return recordClass.selectByKeywordsWithId(**kwds) 
     133                records = recordClass.selectByKeywordsWithId(**kwds) 
    132134            elif self.isSelectByTimeInterval(kwds): 
    133                 return recordClass.selectByKeywordsWithTimeInterval(**kwds) 
     135                records = recordClass.selectByKeywordsWithTimeInterval(**kwds) 
    134136            else:     
    135                 return recordClass.selectByKeywords(**kwds) 
     137                records = recordClass.selectByKeywords(**kwds) 
     138            return records 
    136139 
    137140        def startsWith(self, className, value, attributeName, **kwds): 
     
    154157            else: 
    155158                records = self.getRecordClass(className).select() 
     159            if debug: 
     160                logger.debug('Listed %s records from database.' % (className)) 
    156161            return records 
    157162        
     
    437442            loadedList = dict() 
    438443        if not self.domainObject: 
    439             if debug: 
    440                 message = "Rebuilding domain object from db record: %s" % self 
    441                 logger.debug(message) 
    442444            obj = self.createDomainObject()  
    443445            self.domainObject = obj  
    444446            self.domainObject.record = self 
    445447            if debug: 
    446                 message = "Loading from db record: %s" % self 
     448                message = "Record returned newly instantiated %s." % self.getClassName() 
    447449                logger.debug(message) 
    448450            self.loadDomainObject(loadedList, sync=False) 
     
    451453                if not self.domainObject in loadedList: 
    452454                    if debug: 
    453                         message = "Reloading from db record: %s" % self 
     455                        message = "Record loads existing %s instance with values." % self.getClassName() 
    454456                        logger.debug(message) 
    455457                    self.loadDomainObject(loadedList) 
    456458                else: 
    457459                    if debug: 
    458                         message = "Cyclic reload avoided for db record: %s" % self 
     460                        message = "Loaded %s record avoids loading loop." % self.getClassName() 
    459461                        logger.debug(message) 
    460462            else:  
    461463                if debug: 
    462                     message = "Using cached db record values: %s" % self 
     464                    message = "Record returned %s with existing values." % self.getClassName() 
    463465                    logger.debug(message) 
    464466        return self.domainObject 
     
    473475        return domainObject 
    474476        
     477    def getClassName(self): 
     478        return self.__class__.__name__ 
     479         
    475480    def getDomainClass(self): 
    476481        "Returns mapper's synonymous domain model class."  
    477         className = self.__class__.__name__ 
     482        className = self.getClassName() 
    478483        registry = RequiredFeature('DomainRegistry') 
    479484        return registry.getDomainClass(className) 
     
    483488        if sync: 
    484489            if debug: 
    485                 message = "Synchronising db record with database. %s" % self 
     490                message = "Synchronising mapper values with RDBMS." 
    486491                logger.debug(message) 
    487492            self.sync() 
     493        elif sync: 
     494            if debug: 
     495                message = "Not synchronising mapper values with RDBMS." 
     496                logger.debug(message) 
     497        if debug: 
     498            message = "Loading domain object values from mapper." 
     499            logger.debug(message) 
    488500        self.domainObject.id = self.id 
    489501        for metaAttr in self.meta.attributes: 
     
    501513                setattr(self.domainObject, domName, mappedValue) 
    502514        loadedList[self.domainObject] = self.domainObject 
    503         if debug: 
    504             message = "Updated domain object from db record. %s" % self 
    505             logger.debug(message) 
    506515 
    507516    def saveDomainObject(self): 
    508517        "Sets attributes of record object from domain object." 
     518        isChanged = False 
    509519        for metaAttr in self.meta.attributes: 
    510             isChanged = False 
    511520            if metaAttr.isDomainObjectRef: 
    512521                domainObject = getattr(self.domainObject, metaAttr.domName) 
     
    525534                    setattr(self, metaAttr.dbName, domValue) 
    526535                    isChanged = True 
    527             if isChanged: 
    528                 if debug: 
    529                     message = "Updating database with db record: %s" % self 
    530                     logger.debug(message) 
    531                 self.syncUpdate() 
    532         if debug: 
    533             message = "Updated db record from domain object: %s" % self 
    534             logger.debug(message) 
     536        if isChanged: 
     537            if debug: 
     538                message = "Updating RDBMS with %s mapper value." % ( 
     539                    self.meta.domName 
     540                ) 
     541                logger.debug(message) 
     542            self.syncUpdate() 
    535543 
    536544    def coerceKwds(self, kwds): 
  • trunk/src/dm/dictionary.py

    r43 r45  
    4141        self[AUTH_COOKIE_NAME]    = '%s_auth' % self[SYSTEM_NAME] 
    4242        self[NO_AUTH_COOKIE_NAME] = '%s_no_auth' % self[SYSTEM_NAME] 
     43        self[LOG_LEVEL]           = 'INFO' 
    4344 
    4445    def makeConfigFilePath(self): 
  • trunk/src/dm/dom/accesscontrol.py

    r2 r45  
    55    "Registered granted permission. Associates a Role and a Permission." 
    66 
    7     isConstant  = True 
     7#    isConstant  = True 
    88    permission  = HasA('Permission') 
    99    role        = HasA('Role') 
     
    3434    isConstant  = True 
    3535    # define aggregates 
    36     permissions = HasMany('Permission', 'protectionObject')   
     36    permissions = AggregatesMany('Permission', 'protectionObject')   
    3737     
    3838    def initialise(self, register): 
     
    4141        for protectionObject in self.registry.protectionObjects:   
    4242            self.permissions.create(protectionObject) 
    43  
    44     def delete(self): 
    45         # delete aggregates 
    46         for permission in self.permissions:   
    47             permission.delete() 
    48         super(Action, self).delete() 
    4943 
    5044 
     
    5549    """ 
    5650 
     51#    isConstant  = True 
    5752    action           = HasA('Action') 
    5853    protectionObject = HasA('ProtectionObject') 
    59     grants           = HasMany('Grant', 'role')  # aggregates   
    60     personalGrants   = HasMany('PersonalGrant', 'person')  # aggregates   
    61     personalBars     = HasMany('PersonalBar', 'person')  # aggregates   
     54    grants           = AggregatesMany('Grant', 'role') 
     55    personalGrants   = AggregatesMany('PersonalGrant', 'person') 
     56    personalBars     = AggregatesMany('PersonalBar', 'person') 
    6257     
    63     def delete(self): 
    64         # delete aggregates 
    65         for grant in self.grants:   
    66             grant.delete() 
    67         for personalGrant in self.personalGrants:   
    68             personalGrant.delete() 
    69         for personalBar in self.personalBars:   
    70             personalBar.delete() 
    71         super(Permission, self).delete() 
    72  
    7358    def getLabelValue(self): 
    7459        return "%s-%s" % ( 
     
    8166    "Protects a protected object with a protected name." 
    8267 
    83     isConstant  = True 
    84     # define aggregates 
    85     permissions = HasMany('Permission', 'action') 
     68#    isConstant  = True 
     69    permissions = AggregatesMany('Permission', 'action') 
    8670 
    8771    def isProtector(self, protectedObject): 
     
    122106            self.permissions.create(action) 
    123107 
    124     def delete(self): 
    125         # delete aggregates  
    126         for permission in self.permissions:   
    127             permission.delete() 
    128         super(ProtectionObject, self).delete() 
    129  
  • trunk/src/dm/dom/base.py

    r29 r45  
    124124         
    125125    def __repr__(self): 
    126         count = self.count() 
    127126        className = self.__class__.__name__ 
    128127        typeName = self.typeName 
    129128        keyName = self.keyName 
    130         return "<%s count='%d' typeName='%s' keyName='%s'>" % ( 
    131             className, count, typeName, keyName) 
     129        return "<%s typeName='%s' keyName='%s'>" % ( 
     130            className, typeName, keyName 
     131        ) 
    132132 
    133133    def retrieveItem(self, key): 
     
    406406        if self.meta: 
    407407            for attr in self.meta.attributes: 
    408                 attrsRepr += " " + attr.createObjectRepr(self) 
     408                if attr.isValueRef: 
     409                    attrsRepr += " " + attr.createObjectRepr(self) 
    409410        className = self.__class__.__name__ 
    410411        return "<%s id='%s'%s>" % (className, str(self.id), attrsRepr) 
     
    489490            self.record = None 
    490491 
     492    def purgeAggregates(self): 
     493        for metaAttr in self.meta.attributes: 
     494            if metaAttr.isAggregation(): 
     495                if metaAttr.isList(): 
     496                    self.purgeAggregateList(metaAttr.name) 
     497 
     498    def purgeAggregateList(self, attrName): 
     499        aggregateRegister = getattr(self, attrName) 
     500        for aggregateObject in aggregateRegister: 
     501            aggregateObject.purge() 
     502 
    491503    def decacheItem(self): 
    492504        for register in self.registerCache.keys(): 
  • trunk/src/dm/dom/builder.py

    r2 r45  
    4343        self.registry.registerDomainClass(ProtectionObject) 
    4444 
     45        self.registry.grants = Grant.createRegister() 
    4546        self.registry.roles = Role.createRegister() 
    4647        self.registry.actions = Action.createRegister() 
     48        self.registry.permissions = Permission.createRegister() 
    4749        self.registry.protectionObjects = ProtectionObject.createRegister() 
    4850 
    4951        self.registry.loadBackgroundRegister(self.registry.roles) 
    5052        self.registry.loadBackgroundRegister(self.registry.actions) 
    51         self.registry.loadBackgroundRegister(self.registry.protectionObjects) 
    5253 
    5354    def loadPerson(self): 
     
    6263        self.registry.registerDomainClass(PersonalBar) 
    6364 
     65 
    6466    def loadSession(self): 
    6567        from dm.dom.session import Session 
  • trunk/src/dm/dom/meta.py

    r29 r45  
    246246class DomainObjectAssociation(MetaDomainAttr): 
    247247    "Associates domain objects with other domain objects." 
     248 
     249    def countChoices(self, domainObject): 
     250        if callable(self.getChoices): 
     251            return len(self.getChoices(domainObject)) 
     252        else: 
     253            return len(self.getAssociatedObjectRegister(domainObject)) 
    248254 
    249255    def getAllChoices(self, domainObject): 
     
    373379        return True 
    374380 
     381    def countChoices(self, domainObject): 
     382        associateRegister = self.getAssociatedObjectRegister(domainObject) 
     383        return len(associateRegister) 
     384 
    375385    def getAllChoices(self, domainObject): 
    376386        choices = [] 
  • trunk/src/dm/dom/plugin.py

    r2 r45  
    66    return domainRegistry.projects 
    77 
    8 #class Plugin(SimpleNamedObject): 
    98class Plugin(StandardObject): 
    109    "Registered plugin." 
  • trunk/src/dm/dom/state.py

    r2 r45  
    5858        def purgeObject(self, object): 
    5959            object.raisePurge() 
     60            object.purgeAggregates() 
    6061            object.decacheItem() 
    6162            object.state = None  
    6263            object.destroySelf() 
     64 
     65 
    6366 
    6467    def getBehaviour(self): 
  • trunk/src/dm/dom/stateful.py

    r2 r45  
    222222        self.page = page 
    223223        self.pageKeys = pageKeys 
     224 
     225    def countChoices(self, domainObject): 
     226        associateRegister = self.getAssociatedObjectRegister(domainObject) 
     227        return len(associateRegister) 
    224228 
    225229    def getAllChoices(self, domainObject): 
  • trunk/src/dm/view/manipulator.py

    r29 r45  
    8484        isFieldRequired = metaAttr.isRequired 
    8585        if metaAttr.isAssociateList: 
    86             choices = metaAttr.getAllChoices(self.domainObject) 
    87             field = djangoforms.SelectMultipleField( 
    88                 field_name=metaAttr.name, 
    89                 is_required=isFieldRequired, 
    90                 choices=choices, 
    91                 size=4, 
    92             ) 
    93         elif metaAttr.isDomainObjectRef: 
    94             choices = metaAttr.getAllChoices(self.domainObject) 
    95             choices = [('', '-- select option --')] + choices 
    96             if len(choices) <= 50: 
    97                 field = djangoforms.SelectField( 
     86            countChoices = metaAttr.countChoices(self.domainObject) 
     87            if countChoices <= 50: 
     88                choices = metaAttr.getAllChoices(self.domainObject) 
     89                field = djangoforms.SelectMultipleField( 
    9890                    field_name=metaAttr.name, 
    9991                    is_required=isFieldRequired, 
    10092                    choices=choices, 
     93                    size=4, 
    10194                ) 
    10295            else: 
    10396                field = djangoforms.TextField( 
    10497                    field_name=metaAttr.name, 
    105                     is_required=metaAttr.isRequired, 
     98                    is_required=isFieldRequired, 
     99                ) 
     100             
     101        elif metaAttr.isDomainObjectRef: 
     102            countChoices = metaAttr.countChoices(self.domainObject) 
     103            if countChoices <= 50: 
     104                choices = metaAttr.getAllChoices(self.domainObject) 
     105                choices = [('', '-- select option --')] + choices 
     106                field = djangoforms.SelectField( 
     107                    field_name=metaAttr.name, 
     108                    is_required=isFieldRequired, 
     109                    choices=choices, 
     110                ) 
     111            else: 
     112                field = djangoforms.TextField( 
     113                    field_name=metaAttr.name, 
     114                    is_required=isFieldRequired, 
    106115                ) 
    107116        elif metaAttr.isValueObject(): 
     
    109118                field = djangoforms.LargeTextField( 
    110119                    field_name=metaAttr.name, 
    111                     is_required=metaAttr.isRequired, 
     120                    is_required=isFieldRequired, 
    112121                ) 
    113122            elif metaAttr.typeName == 'Password': 
    114123                field = djangoforms.PasswordField( 
    115124                    field_name=metaAttr.name, 
    116                     is_required=metaAttr.isRequired, 
     125                    is_required=isFieldRequired, 
    117126                ) 
    118127            elif metaAttr.typeName == 'Integer': 
    119128                field = djangoforms.IntegerField( 
    120129                    field_name=metaAttr.name, 
    121                     is_required=metaAttr.isRequired, 
     130                    is_required=isFieldRequired, 
    122131                ) 
    123132            elif metaAttr.typeName == 'Url': 
    124133                field = djangoforms.URLField( 
    125134                    field_name=metaAttr.name, 
    126                     is_required=metaAttr.isRequired, 
     135                    is_required=isFieldRequired, 
    127136                ) 
    128137            elif metaAttr.typeName == 'DateTime': 
    129138                field = djangoforms.DatetimeField( 
    130139                    field_name=metaAttr.name, 
    131                     is_required=metaAttr.isRequired, 
     140                    is_required=isFieldRequired, 
    132141                ) 
    133142            elif metaAttr.typeName == 'Date': 
    134143                field = djangoforms.DateField( 
    135144                    field_name=metaAttr.name, 
    136                     is_required=metaAttr.isRequired, 
     145                    is_required=isFieldRequired, 
    137146                ) 
    138147            else: 
    139148                field = djangoforms.TextField( 
    140149                    field_name=metaAttr.name, 
    141                     is_required=metaAttr.isRequired, 
     150                    is_required=isFieldRequired, 
    142151                ) 
    143152        if field: