Ignore:
Timestamp:
02/04/09 10:38:41 (11 years ago)
Author:
pjkersha
Message:

Moved function condition classes into cond module

File:
1 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/authz/xacml/cond.py

    r5159 r5162  
     1"""XACML cond module contains condition function classes and class factories 
     2 
     3NERC DataGrid Project 
     4""" 
     5__author__ = "P J Kershaw" 
     6__date__ = "02/04/09" 
     7__copyright__ = "(C) 2009 Science and Technology Facilities Council" 
     8__contact__ = "Philip.Kershaw@stfc.ac.uk" 
     9__license__ = "BSD - see LICENSE file in top-level directory" 
     10__contact__ = "Philip.Kershaw@stfc.ac.uk" 
     11__revision__ = "$Id$" 
     12class FunctionBase(XacmlBase): 
     13    FUNCTION_NS = "urn:oasis:names:tc:xacml:1.0:function:" 
     14     
     15    def __init__(self,  
     16                 functionName,  
     17                 functionId=None,  
     18                 paramType=None, 
     19                 paramIsBag=False, 
     20                 numParams=0,  
     21                 minParams=0, 
     22                 returnType='',  
     23                 returnsBag=False): 
     24           
     25        self.functionName = functionName 
     26        self.functionId = functionId 
     27        self.returnType = None 
     28        self.returnsBag = False 
     29     
     30        self.singleType = True; 
     31     
     32        self.paramType = paramType 
     33        self.paramIsBag = paramIsBag 
     34        self.numParams = numParams 
     35        self.minParams = minParams 
     36         
     37   
     38    def _setFunctionName(self, functionName): 
     39          if functionName not in self.__class__.supportedIdentifiers: 
     40              functionList = ', '.join(self.__class__.supportedIdentifiers) 
     41              raise TypeError("Function name [%s] is not on of the recognised " 
     42                              "types: %s" % (functionName, functionList)) 
     43          self._functionName = functionName 
     44           
     45    def _getFunctionName(self): 
     46          return getattr(self, '_functionName', None) 
     47     
     48    functionName = property(fset=_setFunctionName, 
     49                                    fget=_getFunctionName) 
     50           
     51    def checkInputs(self, inputs): 
     52        '''Checks that the given inputs are of the right types, in the right  
     53        order, and are the right number for this function to evaluate.''' 
     54        raise NotImplementedError() 
     55             
     56    def checkInputsNoBag(self, inputs): 
     57        '''Checks that the given inputs are of the right types, in the right  
     58        order, and are the right number for this function to evaluate.''' 
     59        raise NotImplementedError() 
     60  
     61    def evaluate(self, inputs, context): 
     62        '''Evaluates the Function using the given inputs.''' 
     63        raise NotImplementedError() 
     64      
     65    def evalArgs(self, params, context, args): 
     66        '''Evaluates each of the parameters, in order, filling in the argument 
     67        array with the resulting values. If any error occurs, this method 
     68        returns the error, otherwise null is returned, signalling that 
     69        evaluation was successful for all inputs, and the resulting argument 
     70        list can be used. 
     71         
     72        @param params a list of Evaluatable objects representing the parameters 
     73        to evaluate 
     74        @param context the representation of the request 
     75        @param args an array as long as the params list that will, on return,  
     76        contain the AttributeValues generated from evaluating all parameters 
     77 
     78        @return None if no errors were encountered, otherwise 
     79        an EvaluationResult representing the error 
     80        ''' 
     81        index = 0 
     82 
     83        for eval in params: 
     84            # get and evaluate the next parameter 
     85            result = eval.evaluate(context) 
     86 
     87            # If there was an error, pass it back... 
     88            if result.indeterminate(): 
     89                return result 
     90 
     91            # ...otherwise save it and keep going 
     92            args[index] = result.getAttributeValue() 
     93            index += 1 
     94             
     95        return None 
     96 
     97# TODO: Condition classes - minimal implementation until opportunity to fully  
     98# implement    
     99class Function(XacmlBase): 
     100    def __init__(self, *arg, **kw): 
     101        raise NotImplementedError() 
     102 
     103    @classmethod 
     104    def getInstance(cls, root): 
     105        raise NotImplementedError() 
     106 
     107class BagFunction(FunctionBase): 
     108    def __init__(self, *arg, **kw): 
     109        raise NotImplementedError() 
     110 
     111class SetFunction(FunctionBase): 
     112    def __init__(self, *arg, **kw): 
     113        raise NotImplementedError() 
     114        
     115class ConditionBagFunction(BagFunction): 
     116    def __init__(self, *arg, **kw): 
     117        raise NotImplementedError() 
     118         
     119class ConditionSetFunction(FunctionBase): 
     120    def __init__(self, *arg, **kw): 
     121        raise NotImplementedError() 
     122         
     123class HigherOrderFunction(Function): 
     124    def __init__(self, *arg, **kw): 
     125        raise NotImplementedError() 
     126 
     127# TODO: Function classes - minimal implementation until opportunity to fully  
     128# implement                                     
     129class LogicalFunction(FunctionBase): 
     130 
     131    def __init__(self, *arg, **kw): 
     132        raise NotImplementedError() 
     133 
     134class NOfFunction(FunctionBase): 
     135     
     136    def __init__(self, *arg, **kw): 
     137        raise NotImplementedError() 
     138         
     139class NotFunction(FunctionBase): 
     140     
     141    def __init__(self, *arg, **kw): 
     142        raise NotImplementedError() 
     143         
     144class ComparisonFunction(FunctionBase): 
     145     
     146    def __init__(self, *arg, **kw): 
     147        raise NotImplementedError() 
     148 
     149class MatchFunction(FunctionBase): 
     150    NAME_REGEXP_STRING_MATCH = \ 
     151          "urn:oasis:names:tc:xacml:1.0:function:regexp-string-match" 
     152    NAME_RFC822NAME_MATCH = \ 
     153          "urn:oasis:names:tc:xacml:1.0:function:rfc822Name-match" 
     154    NAME_X500NAME_MATCH = \ 
     155          "urn:oasis:names:tc:xacml:1.0:function:x500Name-match"      
     156 
     157    supportedIdentifiers = (NAME_REGEXP_STRING_MATCH,  
     158                            NAME_RFC822NAME_MATCH, 
     159                            NAME_X500NAME_MATCH) 
     160     
     161    lut = { 
     162          NAME_REGEXP_STRING_MATCH: 'regexpStringMatch', 
     163          NAME_RFC822NAME_MATCH:    'rfc822NameMatch', 
     164          NAME_X500NAME_MATCH:      'x500NameMatch' 
     165    } 
     166     
     167    def __init__(self, functionName, **kw): 
     168          super(MatchFunction, self).__init__(functionName, **kw) 
     169 
     170    def regexpStringMatch(self, regex, val): 
     171          return re.match(regex, val) is not None 
     172     
     173    def rfc822NameMatch(self, *inputs): 
     174        raise NotImplementedError() 
     175     
     176    def x500NameMatch(self, *inputs): 
     177        raise NotImplementedError() 
     178     
     179    def evaluate(self, inputs, context): 
     180          matchFunction = getattr(self, MatchFunction.lut[self.functionName]) 
     181          match = matchFunction(self, *inputs) 
     182          if match: 
     183                return EvaluationResult(status=Status.STATUS_OK) 
     184 
     185 
     186class EqualFunction(FunctionBase): 
     187    supportedIdentifiers = ( 
     188          "urn:oasis:names:tc:xacml:1.0:function:anyURI-equal", 
     189          "urn:oasis:names:tc:xacml:1.0:function:base64Binary-equal", 
     190          "urn:oasis:names:tc:xacml:1.0:function:boolean-equal", 
     191          "urn:oasis:names:tc:xacml:1.0:function:date-equal", 
     192          "urn:oasis:names:tc:xacml:1.0:function:dateTime-equal", 
     193          "urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-equal", 
     194          "urn:oasis:names:tc:xacml:1.0:function:double-equal", 
     195          "urn:oasis:names:tc:xacml:1.0:function:hexBinary-equal", 
     196          "urn:oasis:names:tc:xacml:1.0:function:integer-equal", 
     197          "urn:oasis:names:tc:xacml:1.0:function:rfc822Name-equal", 
     198          "urn:oasis:names:tc:xacml:1.0:function:string-equal", 
     199          "urn:oasis:names:tc:xacml:1.0:function:time-equal", 
     200          "urn:oasis:names:tc:xacml:1.0:function:x500Name-equal", 
     201          "urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-equal" 
     202    ) 
     203 
     204    (NAME_ANYURI_EQUAL, 
     205    NAME_BASE64BINARY_EQUAL, 
     206    NAME_BOOLEAN_EQUAL, 
     207    NAME_DATE_EQUAL, 
     208    NAME_DATETIME_EQUAL, 
     209    NAME_DAYTIME_DURATION_EQUAL, 
     210    NAME_DOUBLE_EQUAL, 
     211    NAME_HEXBINARY_EQUAL, 
     212    NAME_INTEGER_EQUAL, 
     213    NAME_RFC822NAME_EQUAL, 
     214    NAME_STRING_EQUAL, 
     215    NAME_TIME_EQUAL, 
     216    NAME_X500NAME_EQUAL, 
     217    NAME_YEARMONTH_DURATION_EQUAL) = supportedIdentifiers 
     218 
     219    lut = { 
     220          NAME_STRING_EQUAL: 'stringEqual' 
     221    } 
     222     
     223    typeMap = {NAME_STRING_EQUAL: basestring} 
     224     
     225    def __init__(self, functionName, **kw): 
     226          super(EqualFunction, self).__init__(functionName, **kw) 
     227 
     228    def evaluate(self, inputs, evaluationCtx): 
     229        function = EqualFunction.lut.get(self.functionName) 
     230        if function is None: 
     231            if self.functionName in supportedIdentifiers: 
     232                raise NotImplementedError("No implementation is available for " 
     233                                          "%s" % self.functionName)             
     234            else: 
     235                raise AttributeError('function name "%s" not recognised ' 
     236                                     'for %s' % (self.functionName, 
     237                                                 self.__class__.__name__)) 
     238                                   
     239        return getattr(self, function)(inputs, evaluationCtx) 
     240     
     241    def stringEqual(self, inputs, evaluationCtx): 
     242        result = self.evalArgs(inputs, context, argValues) 
     243        if result is not None: 
     244            return result 
     245           
     246        return EvaluationResult(argValues[0] == argValues[1]) 
     247     
     248    def getArgumentType(functionName): 
     249        datatype = EqualFunction.typeMap.get(functionName); 
     250        if datatype is None: 
     251            raise AttributeError("Not a standard function: %s" % functionName) 
     252           
     253        return datatype 
     254 
     255class AddFunction(FunctionBase): 
     256     
     257    def __init__(self, *arg, **kw): 
     258        raise NotImplementedError() 
     259             
     260class SubtractFunction(FunctionBase): 
     261     
     262    def __init__(self, *arg, **kw): 
     263        raise NotImplementedError() 
     264             
     265class MultiplyFunction(FunctionBase): 
     266     
     267    def __init__(self, *arg, **kw): 
     268        raise NotImplementedError() 
     269             
     270class DivideFunction(FunctionBase): 
     271     
     272    def __init__(self, *arg, **kw): 
     273        raise NotImplementedError() 
     274             
     275class ModFunction(FunctionBase): 
     276     
     277    def __init__(self, *arg, **kw): 
     278        raise NotImplementedError() 
     279 
     280class AbsFunction(FunctionBase): 
     281     
     282    def __init__(self, *arg, **kw): 
     283        raise NotImplementedError() 
     284 
     285class RoundFunction(FunctionBase): 
     286     
     287    def __init__(self, *arg, **kw): 
     288        raise NotImplementedError() 
     289 
     290class FloorFunction(FunctionBase): 
     291     
     292    def __init__(self, *arg, **kw): 
     293        raise NotImplementedError() 
     294 
     295class DateMathFunction(FunctionBase): 
     296     
     297    def __init__(self, *arg, **kw): 
     298        raise NotImplementedError() 
     299 
     300class GeneralBagFunction(BagFunction): 
     301     
     302    def __init__(self, *arg, **kw): 
     303        raise NotImplementedError() 
     304 
     305class NumericConvertFunction(FunctionBase): 
     306     
     307    def __init__(self, *arg, **kw): 
     308        raise NotImplementedError() 
     309 
     310class StringNormalizeFunction(FunctionBase): 
     311     
     312    def __init__(self, *arg, **kw): 
     313        raise NotImplementedError() 
     314 
     315class GeneralSetFunction(SetFunction): 
     316     
     317    def __init__(self, *arg, **kw): 
     318        raise NotImplementedError() 
     319     
     320class MapFunction(Function):         
     321    supportedIdentifiers = () 
     322    NAME_MAP = FunctionBase.FUNCTION_NS + "map" 
     323     
     324    def __init__(self, *arg, **kw): 
     325        raise NotImplementedError() 
     326 
     327    @classmethod 
     328    def getInstance(cls, root): 
     329        raise NotImplementedError() 
     330     
     331class FunctionProxy(): 
     332 
     333    def getInstance(self, root): 
     334        raise NotImplementedError() 
     335 
     336class MapFunctionProxy(FunctionProxy): 
     337 
     338    def getInstance(self, root): 
     339        return MapFunction.getInstance(root) 
     340 
     341 
     342class UnknownIdentifierException(Exception): 
     343    pass 
     344 
     345class FunctionTypeException(Exception): 
     346    pass 
     347 
     348class ParsingException(Exception): 
     349    pass 
     350 
     351class FunctionFactory(XacmlBase): 
     352    '''Factory used to create all functions. There are three kinds of factories: 
     353    general, condition, and target. These provide functions that can be used 
     354    anywhere, only in a condition's root and only in a target (respectively). 
     355     
     356    Note that all functions, except for abstract functions, are singletons, so 
     357    any instance that is added to a factory will be the same one returned 
     358    from the create methods. This is done because most functions don't have 
     359    state, so there is no need to have more than one, or to spend the time 
     360    creating multiple instances that all do the same thing.''' 
     361 
     362    defaultFactoryProxy = StandardFunctionFactory()                  
     363             
     364    @classmethod 
     365    def getTargetInstance(cls): 
     366        '''Returns the default FunctionFactory that will only provide those 
     367        functions that are usable in Target matching. 
     368         
     369        @return a FunctionFactory for target functions''' 
     370        return cls.defaultFactoryProxy.getTargetFactory() 
     371        
     372    @classmethod  
     373    def getConditionInstance(cls):  
     374        '''Returns the default FunctionFactory that provides access to all the 
     375        functions. These Functions are a superset of the Condition functions. 
     376         
     377        @return a FunctionFactory for all functions 
     378        ''' 
     379        return cls.defaultFactoryProxy.getConditionFactory() 
     380     
     381    @classmethod 
     382    def getGeneralInstance(cls):  
     383        '''Sets the default factory. Note that this is just a place holder for 
     384        now, and will be replaced with a more useful mechanism soon.''' 
     385        return cls.defaultFactoryProxy.getGeneralFactory() 
     386     
     387     
     388    def addFunction(self, function): 
     389        '''Adds the function to the factory. Most functions have no state, so 
     390        the singleton model used here is typically desirable. The factory will 
     391        not enforce the requirement that a Target or Condition matching  
     392        function must be boolean. 
     393         
     394        @param function the Function to add to the factory 
     395        ''' 
     396        raise NotImplementedError() 
     397         
     398    def addAbstractFunction(self, functionProxy, identity): 
     399        '''Adds the abstract function proxy to the factory. This is used for 
     400        those functions which have state, or change behaviour (for instance 
     401        the standard map function, which changes its return type based on 
     402        how it is used).  
     403         
     404        @param proxy the FunctionProxy to add to the factory 
     405        @param identity the function's identifier 
     406        ''' 
     407        raise NotImplementedError()         
     408     
     409    def getSupportedFunctions(self): 
     410        '''Returns the function identifiers supported by this factory. 
     411         
     412        @return a Set of Strings''' 
     413        raise NotImplementedError() 
     414 
     415    def createFunction(self, identity): 
     416        '''Tries to get an instance of the specified function. 
     417         
     418        @param identity the name of the function 
     419        '''        
     420        raise NotImplementedError() 
     421     
     422    def createAbstractFunction(self, identity, root): 
     423        '''Tries to get an instance of the specified abstract function. 
     424         
     425        @param identity the name of the function 
     426        @param root the DOM root containing info used to create the function 
     427        ''' 
     428        raise NotImplementedError() 
     429 
     430 
     431class FunctionFactoryProxy(XacmlBase): 
     432    '''A simple proxy interface used to install new FunctionFactorys. 
     433    The three kinds of factory (Target, Condition, and General) are tied 
     434    together in this interface because implementors writing new factories 
     435    should always implement all three types and provide them together''' 
     436    def getTargetFactory(): 
     437        raise NotImplementedError() 
     438 
     439    def getConditionFactory(): 
     440        raise NotImplementedError() 
     441 
     442    def getGeneralFactory(): 
     443        raise NotImplementedError() 
     444 
     445 
     446class BasicFunctionFactoryProxy(FunctionFactoryProxy): 
     447    '''A simple utility class that manages triples of function factories.''' 
     448     
     449    # the triple of factories 
     450    targetFactory = None 
     451    conditionFactory = None 
     452    generalFactory = None 
     453 
     454    def __init__(targetFactory, conditionFactory, generalFactory):  
     455        '''Creates a new proxy. 
     456         
     457        @param targetFactory the target factory provided by this proxy 
     458        @param conditionFactory the target condition provided by this proxy 
     459        @param generalFactory the general factory provided by this proxy 
     460        ''' 
     461        self.targetFactory = targetFactory 
     462        self.conditionFactory = conditionFactory 
     463        self.generalFactory = generalFactory 
     464     
     465    def getTargetFactory(): 
     466        return targetFactory 
     467 
     468    def getConditionFactory(): 
     469        return conditionFactory 
     470 
     471    def getGeneralFactory(): 
     472        return generalFactory 
     473     
     474 
     475class BaseFunctionFactory(FunctionFactory): 
     476    '''This is a basic implementation of <code>FunctionFactory</code>. It 
     477    implements the insertion and retrieval methods, but it doesn't actually 
     478    setup the factory with any functions. It also assumes a certain model 
     479    with regard to the different kinds of functions (Target, Condition, and 
     480    General). For this reason, you may want to re-use this class, or you  
     481    may want to extend FunctionFactory directly, if you're writing a new 
     482    factory implementation. 
     483     
     484    Note that while this class is thread-safe on all creation methods, it 
     485    is not safe to add support for a new function while creating an instance 
     486    of a function. This follows from the assumption that most people will 
     487    initialize these factories up-front, and then start processing without 
     488    ever modifying the factories. If you need these mutual operations to 
     489    be thread-safe, then you should write a wrapper class that implements 
     490    the right synchronization. 
     491    ''' 
     492     
     493    def __init__(self,  
     494                 superset=None,  
     495                 supportedFunctions=[], 
     496                 supportedAbstractFunctions={}): 
     497        '''Sets a "superset factory". This is useful since 
     498        the different function factories (Target, Condition, and General) 
     499        have a superset relationship (Condition functions are a superset 
     500        of Target functions, etc.). Adding a function to this factory will 
     501        automatically add the same function to the superset factory. 
     502 
     503        Constructor that defines the initial functions supported by this 
     504        factory but doesn't use a superset factory. 
     505 
     506        Constructor that defines the initial functions supported by this 
     507        factory but doesn't use a superset factory. 
     508 
     509        Constructor that defines the initial functions supported by this 
     510        factory and uses a superset factory. Note that the functions 
     511        supplied here are not propagated up to the superset factory, so 
     512        you must either make sure the superset factory is correctly 
     513        initialized or use BaseFunctionFactory(FunctionFactory) 
     514        and then manually add each function. 
     515        
     516        @param supportedFunctions a Set of Functions 
     517        @param supportedAbstractFunctions a mapping from URI to 
     518                                          FunctionProxy 
     519         
     520        @param supportedFunctions a Set of Functions 
     521        @param supportedAbstractFunctions a mapping from URI to FunctionProxy 
     522         
     523        @param superset the superset factory or None''' 
     524         
     525        # the backing maps for the Function objects 
     526        self.functionMap = {} 
     527     
     528        # the superset factory chained to this factory 
     529        self.superset = superset 
     530      
     531        for function in supportedFunctions: 
     532            self.functionMap[function.functionId] = function 
     533         
     534        for id in supportedAbstractFunctions.keys(): 
     535            proxy = supportedAbstractFunctions.get(id) 
     536            self.functionMap[id] = proxy 
     537  
     538    def addFunction(self, function): 
     539        '''Adds the function to the factory. Most functions have no state, so 
     540        the singleton model used here is typically desirable. The factory will 
     541        not enforce the requirement that a Target or Condition matching  
     542        function must be boolean. 
     543         
     544        @param function the Function to add to the factory 
     545        @raise TypeError if the function's identifier is already used or if the 
     546        function is non-boolean (when this is a Target or Condition factory) 
     547        ''' 
     548        id = function.functionId 
     549 
     550        # make sure this doesn't already exist 
     551        if id in self.functionMap: 
     552            raise TypeError("function %s already exists" % id) 
     553 
     554        # add to the superset factory 
     555        if self.superset != None: 
     556            self.superset.addFunction(function) 
     557 
     558        # Add to this factory 
     559        self.functionMap[id] = function 
     560     
     561         
     562    def addAbstractFunction(self, proxy, id): 
     563        '''Adds the abstract function proxy to the factory. This is used for 
     564        those functions which have state, or change behaviour (for instance 
     565        the standard map function, which changes its return type based on 
     566        how it is used).  
     567         
     568        @param proxy: the FunctionProxy to add to the factory 
     569        @param id: the function's identifier 
     570         
     571        @raise TypeError if the function's identifier is already used''' 
     572 
     573        # make sure this doesn't already exist 
     574        if id in self.functionMap: 
     575            raise TypeError("function already exists") 
     576 
     577        # add to the superset factory 
     578        if self.superset != None: 
     579            self.superset.addAbstractFunction(proxy, id) 
     580 
     581        # finally, add to this factory 
     582        functionMap[id] = proxy 
     583     
     584 
     585    def getSupportedFunctions(self):  
     586        '''Returns the function identifiers supported by this factory. 
     587         
     588        @return a list of strings''' 
     589     
     590        functions = self.functionMap.keys() 
     591 
     592        if self.superset != None: 
     593            functions += self.superset.getSupportedFunctions() 
     594 
     595        return functions 
     596     
     597 
     598    def createFunction(self, identity): 
     599        '''Tries to get an instance of the specified function. 
     600         
     601        @param identity the name of the function 
     602         
     603        @throws UnknownIdentifierException if the name isn't known 
     604        @throws FunctionTypeException if the name is known to map to an 
     605                                      abstract function, and should therefore 
     606                                      be created through createAbstractFunction 
     607        ''' 
     608        entry = self.functionMap.get(identity) 
     609        if entry is not None: 
     610            if isinstance(entry, Function):  
     611                return entry 
     612            else: 
     613                # this is actually a proxy, which means the other create 
     614                # method should have been called 
     615                raise FunctionTypeException("function is abstract")     
     616        else: 
     617            # we couldn't find a match 
     618            raise UnknownIdentifierException("functions of type %s are not " 
     619                                             "supported by this factory" %  
     620                                             identity)         
     621     
     622     
     623    def createAbstractFunction(identity, root): 
     624        '''Tries to get an instance of the specified abstract function. 
     625         
     626        @param identity the name of the function 
     627        @param root the DOM root containing info used to create the function 
     628        @param xpathVersion the version specified in the containing policy, or 
     629                            None if no version was specified 
     630         
     631        @throws UnknownIdentifierException if the name isn't known 
     632        @throws FunctionTypeException if the name is known to map to a 
     633                                      concrete function, and should therefore 
     634                                      be created through createFunction 
     635        @throws ParsingException if the function can't be created with the 
     636                                 given inputs''' 
     637     
     638        entry = self.functionMap.get(identity) 
     639        if entry is not None: 
     640            if isinstance(entry, FunctionProxy):  
     641                try:  
     642                    return entry.getInstance(root) 
     643                 
     644                except Exception, e: 
     645                    raise ParsingException("Couldn't create abstract function " 
     646                                           "%s: %s" % identity, e)       
     647            else: 
     648                # this is actually a concrete function, which means that 
     649                # the other create method should have been called 
     650                raise FunctionTypeException("function is concrete") 
     651             
     652        else: 
     653            raise UnknownIdentifierException("Abstract functions of type %s " 
     654                                             "are not supported by this " 
     655                                             "factory" % identity) 
     656 
     657 
     658class StandardFunctionFactory(BaseFunctionFactory): 
     659    '''This factory supports the standard set of functions specified in XACML 
     660    1.0 and 1.1. It is the default factory used by the system, and imposes 
     661    a singleton pattern insuring that there is only ever one instance of 
     662    this class. 
     663    <p> 
     664    Note that because this supports only the standard functions, this 
     665    factory does not allow the addition of any other functions. If you call 
     666    addFunction on an instance of this class, an exception 
     667    will be thrown. If you need a standard factory that is modifiable, 
     668    you can either create a new BaseFunctionFactory (or some 
     669    other implementation of FunctionFactory) populated with 
     670    the standard functions from getStandardFunctions or 
     671    you can use getNewFactoryProxy to get a proxy containing 
     672    a new, modifiable set of factories.''' 
     673 
     674 
     675    # the three singleton instances 
     676    targetFactory = None 
     677    conditionFactory = None 
     678    generalFactory = None 
     679 
     680    # the three function sets/maps that we use internally 
     681    targetFunctions = None 
     682    conditionFunctions = None 
     683    generalFunctions = None 
     684 
     685    targetAbstractFunctions = None 
     686    conditionAbstractFunctions = None 
     687    generalAbstractFunctions = None 
     688 
     689    # the set/map used by each singleton factory instance 
     690    supportedFunctions = None 
     691    supportedAbstractFunctions = None 
     692 
     693     
     694    def __init__(self, supportedFunctions, supportedAbstractFunctions):  
     695        '''Creates a new StandardFunctionFactory, making sure that the default 
     696        maps are initialized correctly. Standard factories can't be modified, 
     697        so there is no notion of supersetting since that's only used for 
     698        correctly propagating new functions.''' 
     699        super(StandardFunctionFactory, self).__init__(supportedFunctions,  
     700                                                    supportedAbstractFunctions) 
     701 
     702        self.supportedFunctions = supportedFunctions 
     703        self.supportedAbstractFunctions = supportedAbstractFunctions 
     704     
     705 
     706     
     707     
     708    def _initTargetFunctions(self):  
     709        '''Private initializer for the target functions. This is only ever 
     710        called once.''' 
     711        log.info("Initializing standard Target functions") 
     712 
     713        # Emulate a list with unique items using a dict with only the keys set 
     714        StandardFunctionFactory.targetFunctions = {} 
     715 
     716        # add EqualFunction 
     717        StandardFunctionFactory.targetFunctions.fromkeys( 
     718                                    EqualFunction.supportedIdentifiers) 
     719 
     720        # add LogicalFunction 
     721        StandardFunctionFactory.targetFunctions.fromkeys( 
     722                                    LogicalFunction.supportedIdentifiers) 
     723         
     724        # add NOfFunction 
     725        StandardFunctionFactory.targetFunctions.fromkeys( 
     726                                    NOfFunction.supportedIdentifiers) 
     727         
     728        # add NotFunction 
     729        StandardFunctionFactory.targetFunctions.fromkeys( 
     730                                    NotFunction.supportedIdentifiers) 
     731         
     732        # add ComparisonFunction 
     733        StandardFunctionFactory.targetFunctions.fromkeys( 
     734                                    ComparisonFunction.supportedIdentifiers) 
     735 
     736        # add MatchFunction 
     737        StandardFunctionFactory.targetFunctions.fromkeys( 
     738                                    MatchFunction.supportedIdentifiers) 
     739 
     740        StandardFunctionFactory.targetAbstractFunctions = {} 
     741     
     742     
     743    def _initConditionFunctions(self):  
     744        '''Private initializer for the condition functions. This is only ever 
     745        called once.''' 
     746        log.info("Initializing standard Condition functions") 
     747 
     748        if StandardFunctionFactory.targetFunctions is None: 
     749            self._initTargetFunctions() 
     750 
     751        StandardFunctionFactory.conditionFunctions = \ 
     752            StandardFunctionFactory.targetFunctions.copy() 
     753 
     754        # add condition functions from BagFunction 
     755        conditionFunctions.fromkeys(ConditionBagFunction.supportedIdentifiers) 
     756         
     757        # add condition functions from SetFunction 
     758        conditionFunctions.fromkeys(ConditionSetFunction.supportedIdentifiers) 
     759         
     760        # add condition functions from HigherOrderFunction 
     761        conditionFunctions.fromkeys(HigherOrderFunction.supportedIdentifiers) 
     762 
     763        StandardFunctionFactory.conditionAbstractFunctions = \ 
     764            StandardFunctionFactory.targetAbstractFunctions.copy() 
     765     
     766 
     767    def _initGeneralFunctions(self):      
     768        '''Private initializer for the general functions. This is only ever 
     769        called once.''' 
     770     
     771        log.info("Initializing standard General functions") 
     772 
     773        if StandardFunctionFactory.conditionFunctions is None: 
     774            self._initConditionFunctions() 
     775 
     776        StandardFunctionFactory.generalFunctions = \ 
     777            StandardFunctionFactory.conditionFunctions.copy() 
     778 
     779        # add AddFunction 
     780        StandardFunctionFactory.generalFunctions.fromkeys( 
     781            AddFunction.supportedIdentifiers) 
     782             
     783        # add SubtractFunction 
     784        StandardFunctionFactory.generalFunctions.fromkeys( 
     785            SubtractFunction.supportedIdentifiers) 
     786             
     787        # add MultiplyFunction 
     788        StandardFunctionFactory.generalFunctions.fromkeys( 
     789            MultiplyFunction.supportedIdentifiers) 
     790             
     791        # add DivideFunction 
     792        StandardFunctionFactory.generalFunctions.fromkeys( 
     793            DivideFunction.supportedIdentifiers) 
     794             
     795        # add ModFunction 
     796        StandardFunctionFactory.generalFunctions.fromkeys( 
     797            ModFunction.supportedIdentifiers) 
     798         
     799        # add AbsFunction 
     800        StandardFunctionFactory.generalFunctions.fromkeys( 
     801            AbsFunction.supportedIdentifiers) 
     802             
     803        # add RoundFunction 
     804        StandardFunctionFactory.generalFunctions.fromkeys( 
     805            RoundFunction.supportedIdentifiers) 
     806             
     807        # add FloorFunction 
     808        StandardFunctionFactory.generalFunctions.fromkeys( 
     809            FloorFunction.supportedIdentifiers) 
     810         
     811        # add DateMathFunction 
     812        StandardFunctionFactory.generalFunctions.fromkeys( 
     813            DateMathFunction.supportedIdentifiers) 
     814             
     815        # add general functions from BagFunction 
     816        StandardFunctionFactory.generalFunctions.fromkeys( 
     817            GeneralBagFunction.supportedIdentifiers) 
     818             
     819        # add NumericConvertFunction 
     820        StandardFunctionFactory.generalFunctions.fromkeys( 
     821            NumericConvertFunction.supportedIdentifiers) 
     822             
     823        # add StringNormalizeFunction 
     824        StandardFunctionFactory.generalFunctions.fromkeys( 
     825            StringNormalizeFunction.supportedIdentifiers) 
     826         
     827        # add general functions from SetFunction 
     828        StandardFunctionFactory.generalFunctions.fromkeys( 
     829            GeneralSetFunction.supportedIdentifiers) 
     830             
     831        StandardFunctionFactory.generalAbstractFunctions = \ 
     832            StandardFunctionFactory.conditionAbstractFunctions.copy() 
     833 
     834        # Add the map function's proxy 
     835        StandardFunctionFactory.generalAbstractFunctions[ 
     836                                    MapFunction.NAME_MAP] = MapFunctionProxy() 
     837     
     838    @classmethod  
     839    def getTargetFactory(cls):  
     840        '''Returns a FunctionFactory that will only provide those functions  
     841        that are usable in Target matching. This method enforces a singleton 
     842        model, meaning that this always returns the same instance, creating 
     843        the factory if it hasn't been requested before. This is the default 
     844        model used by the FunctionFactory, ensuring quick 
     845        access to this factory. 
     846         
     847        @return a FunctionFactory for target functions''' 
     848        if StandardFunctionFactory.targetFactory is None:  
     849            if StandardFunctionFactory.targetFunctions is None: 
     850                StandardFunctionFactory._initTargetFunctions() 
     851                 
     852            if StandardFunctionFactory.targetFactory is None: 
     853                StandardFunctionFactory.targetFactory=StandardFunctionFactory( 
     854                            StandardFunctionFactory.targetFunctions, 
     855                            StandardFunctionFactory.targetAbstractFunctions) 
     856         
     857        return StandardFunctionFactory.targetFactory 
     858 
     859     
     860    @classmethod 
     861    def getConditionFactory(cls):  
     862        '''Returns a FuntionFactory that will only provide those functions that 
     863        are usable in the root of the Condition. These Functions are a 
     864        superset of the Target functions. This method enforces a singleton 
     865        model, meaning that this always returns the same instance, creating 
     866        the factory if it hasn't been requested before. This is the default 
     867        model used by the FunctionFactory, ensuring quick 
     868        access to this factory. 
     869     
     870        @return a FunctionFactory for condition functions 
     871        ''' 
     872        if StandardFunctionFactory.conditionFactory is None: 
     873            if StandardFunctionFactory.conditionFunctions is None: 
     874                StandardFunctionFactory._initConditionFunctions() 
     875                 
     876            if StandardFunctionFactory.conditionFactory is None: 
     877                StandardFunctionFactory.conditionFactory = \ 
     878                    StandardFunctionFactory( 
     879                           StandardFunctionFactory.conditionFunctions, 
     880                           StandardFunctionFactory.conditionAbstractFunctions)        
     881 
     882        return StandardFunctionFactory.conditionFactory 
     883     
     884 
     885    @classmethod 
     886    def getGeneralFactory(cls):  
     887        '''Returns a FunctionFactory that provides access to all the functions. 
     888        These Functions are a superset of the Condition functions. This method 
     889        enforces a singleton model, meaning that this always returns the same 
     890        instance, creating the factory if it hasn't been requested before. 
     891        This is the default model used by the FunctionFactory, 
     892        ensuring quick access to this factory. 
     893         
     894        @return a FunctionFactory for all functions''' 
     895     
     896        if StandardFunctionFactory.generalFactory is None: 
     897            if StandardFunctionFactory.generalFunctions is None: 
     898                StandardFunctionFactory._initGeneralFunctions() 
     899                 
     900                StandardFunctionFactory.generalFactory = \ 
     901                    StandardFunctionFactory( 
     902                            StandardFunctionFactory.generalFunctions, 
     903                            StandardFunctionFactory.generalAbstractFunctions) 
     904                 
     905        return StandardFunctionFactory.generalFactory 
     906 
     907 
     908    def getStandardFunctions(self): 
     909        '''Returns the set of functions that this standard factory supports. 
     910         
     911        @return a Set of Functions''' 
     912        return tuple(self.supportedFunctions.keys()) 
     913         
     914    def getStandardAbstractFunctions(self): 
     915        '''Returns the set of abstract functions that this standard factory 
     916        supports as a mapping of identifier to proxy. 
     917         
     918        @return a Map mapping URIs to FunctionProxys''' 
     919        return tuple(self.supportedAbstractFunctions.keys()) 
     920     
     921     
     922    @classmethod 
     923    def getNewFactoryProxy(cls):  
     924        '''A convenience method that returns a proxy containing newly created 
     925        instances of BaseFunctionFactorys that are correctly 
     926        supersetted and contain the standard functions and abstract functions. 
     927        These factories allow adding support for new functions. 
     928         
     929        @return a new proxy containing new factories supporting the standard 
     930        functions''' 
     931         
     932        general = StandardFunctionFactory.getGeneralFactory() 
     933             
     934        newGeneral=BaseFunctionFactory(general.getStandardFunctions(), 
     935                                       general.getStandardAbstractFunctions()) 
     936 
     937        condition = StandardFunctionFactory.getConditionFactory() 
     938         
     939        newCondition = BaseFunctionFactory(newGeneral, 
     940                                    condition.getStandardFunctions(), 
     941                                    condition.getStandardAbstractFunctions()) 
     942 
     943        target = StandardFunctionFactory.getTargetFactory() 
     944        newTarget = BaseFunctionFactory(newCondition, 
     945                                    target.getStandardFunctions(), 
     946                                    target.getStandardAbstractFunctions()) 
     947 
     948        return BasicFunctionFactoryProxy(newTarget, newCondition, newGeneral) 
     949     
     950 
     951     
     952     
     953    def addFunction(self, function): 
     954        '''Always throws an exception, since support for new functions may not  
     955        be added to a standard factory. 
     956         
     957        @param function the Function to add to the factory        
     958        @raise NotImplementedError''' 
     959     
     960        raise NotImplementedError("a standard factory cannot support new " 
     961                                  "functions") 
     962     
     963     
     964    def addAbstractFunction(self, proxy, identity): 
     965        '''Always throws an exception, since support for new functions may not  
     966        be added to a standard factory. 
     967         
     968        @param proxy the FunctionProxy to add to the factory 
     969        @param identity the function's identifier 
     970         
     971        @raise NotImplementedError always''' 
     972        raise NotImplementedError("a standard factory cannot support new " 
     973                                  "functions") 
Note: See TracChangeset for help on using the changeset viewer.