Source code for linotp.lib.app_globals

# -*- coding: utf-8 -*-
#
#    LinOTP - the open source solution for two factor authentication
#    Copyright (C) 2010 - 2014 LSE Leading Security Experts GmbH
#
#    This file is part of LinOTP server.
#
#    This program is free software: you can redistribute it and/or
#    modify it under the terms of the GNU Affero General Public
#    License, version 3, as published by the Free Software Foundation.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the
#               GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#
#    E-mail: linotp@lsexperts.de
#    Contact: www.linotp.org
#    Support: www.lsexperts.de
#

"""The application's Globals object"""
import threading
import copy
import logging

from linotp.lib.security.provider import SecurityProvider


log = logging.getLogger(__name__)

[docs]class Globals(object): """Globals acts as a container for objects available throughout the life of the application """ def __init__(self): """One instance of Globals is created during application initialization and is available during requests via the 'app_globals' variable """ self.rwl = RWLock() self.rwl2 = RWLock() self.resolverLock = RWLock() self.rcount = 0 self.config = {} self.config_incomplete = False self.configLock = RWLock() secLock = RWLock() self.tokenprefixes = {} self.tokenclasses = {} self.security_provider = SecurityProvider(secLock) self.resolver_clazzes = {} self.resolver_types = {}
[docs] def setResolverClasses(self, resolver_clazzes=None): ''' setter to hold the reference to all resolver class objects ''' if resolver_clazzes is not None: self.resolver_clazzes = resolver_clazzes
[docs] def getResolverClasses(self): return self.resolver_clazzes
[docs] def setResolverTypes(self, resolver_types=None): """ setter to hold the reference to all resolver class names """ if resolver_types is not None: self.resolver_types = resolver_types
[docs] def getResolverTypes(self): return self.resolver_types
[docs] def getConfig(self): ''' retrieve (the deep copy of) the actual config ''' self.configLock.acquire_read() try: config = copy.deepcopy(self.config) finally: self.configLock.release() return config
[docs] def setTokenclasses(self, tcl): self.tokenclasses = tcl return
[docs] def getTokenclasses(self): return self.tokenclasses
[docs] def setTokenprefixes(self, tpl): self.tokenprefixes = tpl return
[docs] def getTokenprefixes(self): return self.tokenprefixes
[docs] def setConfig(self, config, replace=False): ''' set the app global config for linotp ''' err = None self.configLock.acquire_write() try: ty = type(config).__name__ if ty != 'dict': self.configLock.release() err = 'cannot set global config from object ' + ty else: conf = copy.deepcopy(config) if replace == True: self.config = conf else: self.config.update(conf) finally: self.configLock.release() if err is not None: raise Exception(err) return
[docs] def isConfigComplet(self): ret = True self.configLock.acquire_read() try: ret = self.config_incomplete finally: self.configLock.release() return ret
[docs] def setConfigIncomplete(self, val=False): ''' set the app global config for linotp ''' self.configLock.acquire_write() try: self.config_incomplete = val finally: self.configLock.release() return
[docs] def delConfig(self, conf): ''' delete one entry in the appl_globals ''' self.configLock.acquire_write() try: ty = type(conf).__name__ if ty == 'list' or ty == 'dict': for k in conf: if self.config.has_key(k): del self.config[k] elif ty == 'str' or ty == 'unicode': if self.config.has_key(conf): del self.config[conf] finally: self.configLock.release() return
[docs] def getLock(self): return self.rwl
[docs] def setConfigReadLock(self): self.rcount = self.rcount + 1 self.rwl2.acquire_read() return self.rcount
[docs] def setConfigWriteLock(self): self.rcount = self.rcount + 1 self.rwl2.acquire_write() return self.rcount
[docs] def releaseConfigLock(self): self.rcount = self.rcount - 1 self.rwl2.release() return self.rcount ### #Python offers a number of useful synchronization primitives in the threading and Queue modules. #One that is missing, however, is a simple reader-writer lock (RWLock). A RWLock allows improved #concurrency over a simple mutex, and is useful for objects that have high read-to-write ratios #like database caches. # #Surprisingly, I haven t been able to find any implementation of these semantics, so I rolled my #own in a module rwlock.py to implement a RWLock class, along with lock promotion/demotion. Hopefully #it can be added to the standard library threading module. #This code is hereby placed in the public domain. # # from # http://majid.info/blog/a-reader-writer-lock-for-python/ # # # Simple reader-writer locks in Python # Many readers can hold the lock XOR one and only one writer # # ### # #version = """$Id: 04-1.html,v 1.3 2006/12/05 17:45:12 majid Exp $"""
[docs]class RWLock: """ A simple reader-writer lock Several readers can hold the lock simultaneously, XOR one writer. Write locks have priority over reads to prevent write starvation. """ def __init__(self): self.rwlock = 0 self.writers_waiting = 0 self.monitor = threading.Lock() self.readers_ok = threading.Condition(self.monitor) self.writers_ok = threading.Condition(self.monitor)
[docs] def acquire_read(self): """Acquire a read lock. Several threads can hold this typeof lock. It is exclusive with write locks. """ self.monitor.acquire() while self.rwlock < 0 or self.writers_waiting: self.readers_ok.wait() self.rwlock += 1 self.monitor.release()
[docs] def acquire_write(self): """Acquire a write lock. Only one thread can hold this lock, and only when no read locks are also held. """ self.monitor.acquire() while self.rwlock != 0: self.writers_waiting += 1 self.writers_ok.wait() self.writers_waiting -= 1 self.rwlock = -1 self.monitor.release()
[docs] def promote(self): """Promote an already-acquired read lock to a write lock WARNING: it is very easy to deadlock with this method""" self.monitor.acquire() self.rwlock -= 1 while self.rwlock != 0: self.writers_waiting += 1 self.writers_ok.wait() self.writers_waiting -= 1 self.rwlock = -1 self.monitor.release()
[docs] def demote(self): """Demote an already-acquired write lock to a read lock""" self.monitor.acquire() self.rwlock = 1 self.readers_ok.notifyAll() self.monitor.release()
[docs] def release(self): """Release a lock, whether read or write.""" self.monitor.acquire() if self.rwlock < 0: self.rwlock = 0 else: self.rwlock -= 1 wake_writers = self.writers_waiting and self.rwlock == 0 wake_readers = self.writers_waiting == 0 self.monitor.release() if wake_writers: self.writers_ok.acquire() self.writers_ok.notify() self.writers_ok.release() elif wake_readers: self.readers_ok.acquire() self.readers_ok.notifyAll() self.readers_ok.release()