Changeset 5162 for TI12-security


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

Moved function condition classes into cond module

Location:
TI12-security/trunk/python/ndg.security.common/ndg/security/common/authz/xacml
Files:
1 deleted
2 edited

Legend:

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

    r5161 r5162  
    1 """XACML Policy Decision Point module 
     1"""XACML Package 
    22 
    33NERC DataGrid Project 
     
    354354        raise NotImplementedError() 
    355355     
    356        
    357 class FunctionBase(XacmlBase): 
    358     FUNCTION_NS = "urn:oasis:names:tc:xacml:1.0:function:" 
    359      
    360     def __init__(self,  
    361                  functionName,  
    362                  functionId=None,  
    363                  paramType=None, 
    364                  paramIsBag=False, 
    365                  numParams=0,  
    366                  minParams=0, 
    367                  returnType='',  
    368                  returnsBag=False): 
    369            
    370         self.functionName = functionName 
    371         self.functionId = functionId 
    372         self.returnType = None 
    373         self.returnsBag = False 
    374      
    375         self.singleType = True; 
    376      
    377         self.paramType = paramType 
    378         self.paramIsBag = paramIsBag 
    379         self.numParams = numParams 
    380         self.minParams = minParams 
    381          
    382    
    383     def _setFunctionName(self, functionName): 
    384           if functionName not in self.__class__.supportedIdentifiers: 
    385               functionList = ', '.join(self.__class__.supportedIdentifiers) 
    386               raise TypeError("Function name [%s] is not on of the recognised " 
    387                               "types: %s" % (functionName, functionList)) 
    388           self._functionName = functionName 
    389            
    390     def _getFunctionName(self): 
    391           return getattr(self, '_functionName', None) 
    392      
    393     functionName = property(fset=_setFunctionName, 
    394                                     fget=_getFunctionName) 
    395            
    396     def checkInputs(self, inputs): 
    397         '''Checks that the given inputs are of the right types, in the right  
    398         order, and are the right number for this function to evaluate.''' 
    399         raise NotImplementedError() 
    400              
    401     def checkInputsNoBag(self, inputs): 
    402         '''Checks that the given inputs are of the right types, in the right  
    403         order, and are the right number for this function to evaluate.''' 
    404         raise NotImplementedError() 
    405   
    406     def evaluate(self, inputs, context): 
    407         '''Evaluates the Function using the given inputs.''' 
    408         raise NotImplementedError() 
    409       
    410     def evalArgs(self, params, context, args): 
    411         '''Evaluates each of the parameters, in order, filling in the argument 
    412         array with the resulting values. If any error occurs, this method 
    413         returns the error, otherwise null is returned, signalling that 
    414         evaluation was successful for all inputs, and the resulting argument 
    415         list can be used. 
    416          
    417         @param params a list of Evaluatable objects representing the parameters 
    418         to evaluate 
    419         @param context the representation of the request 
    420         @param args an array as long as the params list that will, on return,  
    421         contain the AttributeValues generated from evaluating all parameters 
    422  
    423         @return None if no errors were encountered, otherwise 
    424         an EvaluationResult representing the error 
    425         ''' 
    426         index = 0 
    427  
    428         for eval in params: 
    429             # get and evaluate the next parameter 
    430             result = eval.evaluate(context) 
    431  
    432             # If there was an error, pass it back... 
    433             if result.indeterminate(): 
    434                 return result 
    435  
    436             # ...otherwise save it and keep going 
    437             args[index] = result.getAttributeValue() 
    438             index += 1 
    439              
    440         return None 
    441  
    442 # TODO: Condition classes - minimal implementation until opportunity to fully  
    443 # implement    
    444 class Function(XacmlBase): 
    445     def __init__(self, *arg, **kw): 
    446         raise NotImplementedError() 
    447  
    448     @classmethod 
    449     def getInstance(cls, root): 
    450         raise NotImplementedError() 
    451  
    452 class BagFunction(FunctionBase): 
    453     def __init__(self, *arg, **kw): 
    454         raise NotImplementedError() 
    455  
    456 class SetFunction(FunctionBase): 
    457     def __init__(self, *arg, **kw): 
    458         raise NotImplementedError() 
    459         
    460 class ConditionBagFunction(BagFunction): 
    461     def __init__(self, *arg, **kw): 
    462         raise NotImplementedError() 
    463          
    464 class ConditionSetFunction(FunctionBase): 
    465     def __init__(self, *arg, **kw): 
    466         raise NotImplementedError() 
    467          
    468 class HigherOrderFunction(Function): 
    469     def __init__(self, *arg, **kw): 
    470         raise NotImplementedError() 
    471  
    472 # TODO: Function classes - minimal implementation until opportunity to fully  
    473 # implement                                     
    474 class LogicalFunction(FunctionBase): 
    475  
    476     def __init__(self, *arg, **kw): 
    477         raise NotImplementedError() 
    478  
    479 class NOfFunction(FunctionBase): 
    480      
    481     def __init__(self, *arg, **kw): 
    482         raise NotImplementedError() 
    483          
    484 class NotFunction(FunctionBase): 
    485      
    486     def __init__(self, *arg, **kw): 
    487         raise NotImplementedError() 
    488          
    489 class ComparisonFunction(FunctionBase): 
    490      
    491     def __init__(self, *arg, **kw): 
    492         raise NotImplementedError() 
    493  
    494 class MatchFunction(FunctionBase): 
    495     NAME_REGEXP_STRING_MATCH = \ 
    496           "urn:oasis:names:tc:xacml:1.0:function:regexp-string-match" 
    497     NAME_RFC822NAME_MATCH = \ 
    498           "urn:oasis:names:tc:xacml:1.0:function:rfc822Name-match" 
    499     NAME_X500NAME_MATCH = \ 
    500           "urn:oasis:names:tc:xacml:1.0:function:x500Name-match"      
    501  
    502     supportedIdentifiers = (NAME_REGEXP_STRING_MATCH,  
    503                             NAME_RFC822NAME_MATCH, 
    504                             NAME_X500NAME_MATCH) 
    505      
    506     lut = { 
    507           NAME_REGEXP_STRING_MATCH: 'regexpStringMatch', 
    508           NAME_RFC822NAME_MATCH:    'rfc822NameMatch', 
    509           NAME_X500NAME_MATCH:      'x500NameMatch' 
    510     } 
    511      
    512     def __init__(self, functionName, **kw): 
    513           super(MatchFunction, self).__init__(functionName, **kw) 
    514  
    515     def regexpStringMatch(self, regex, val): 
    516           return re.match(regex, val) is not None 
    517      
    518     def rfc822NameMatch(self, *inputs): 
    519         raise NotImplementedError() 
    520      
    521     def x500NameMatch(self, *inputs): 
    522         raise NotImplementedError() 
    523      
    524     def evaluate(self, inputs, context): 
    525           matchFunction = getattr(self, MatchFunction.lut[self.functionName]) 
    526           match = matchFunction(self, *inputs) 
    527           if match: 
    528                 return EvaluationResult(status=Status.STATUS_OK) 
    529  
    530  
    531 class EqualFunction(FunctionBase): 
    532     supportedIdentifiers = ( 
    533           "urn:oasis:names:tc:xacml:1.0:function:anyURI-equal", 
    534           "urn:oasis:names:tc:xacml:1.0:function:base64Binary-equal", 
    535           "urn:oasis:names:tc:xacml:1.0:function:boolean-equal", 
    536           "urn:oasis:names:tc:xacml:1.0:function:date-equal", 
    537           "urn:oasis:names:tc:xacml:1.0:function:dateTime-equal", 
    538           "urn:oasis:names:tc:xacml:1.0:function:dayTimeDuration-equal", 
    539           "urn:oasis:names:tc:xacml:1.0:function:double-equal", 
    540           "urn:oasis:names:tc:xacml:1.0:function:hexBinary-equal", 
    541           "urn:oasis:names:tc:xacml:1.0:function:integer-equal", 
    542           "urn:oasis:names:tc:xacml:1.0:function:rfc822Name-equal", 
    543           "urn:oasis:names:tc:xacml:1.0:function:string-equal", 
    544           "urn:oasis:names:tc:xacml:1.0:function:time-equal", 
    545           "urn:oasis:names:tc:xacml:1.0:function:x500Name-equal", 
    546           "urn:oasis:names:tc:xacml:1.0:function:yearMonthDuration-equal" 
    547     ) 
    548  
    549     (NAME_ANYURI_EQUAL, 
    550     NAME_BASE64BINARY_EQUAL, 
    551     NAME_BOOLEAN_EQUAL, 
    552     NAME_DATE_EQUAL, 
    553     NAME_DATETIME_EQUAL, 
    554     NAME_DAYTIME_DURATION_EQUAL, 
    555     NAME_DOUBLE_EQUAL, 
    556     NAME_HEXBINARY_EQUAL, 
    557     NAME_INTEGER_EQUAL, 
    558     NAME_RFC822NAME_EQUAL, 
    559     NAME_STRING_EQUAL, 
    560     NAME_TIME_EQUAL, 
    561     NAME_X500NAME_EQUAL, 
    562     NAME_YEARMONTH_DURATION_EQUAL) = supportedIdentifiers 
    563  
    564     lut = { 
    565           NAME_STRING_EQUAL: 'stringEqual' 
    566     } 
    567      
    568     typeMap = {NAME_STRING_EQUAL: basestring} 
    569      
    570     def __init__(self, functionName, **kw): 
    571           super(EqualFunction, self).__init__(functionName, **kw) 
    572  
    573     def evaluate(self, inputs, evaluationCtx): 
    574         function = EqualFunction.lut.get(self.functionName) 
    575         if function is None: 
    576             if self.functionName in supportedIdentifiers: 
    577                 raise NotImplementedError("No implementation is available for " 
    578                                           "%s" % self.functionName)             
    579             else: 
    580                 raise AttributeError('function name "%s" not recognised ' 
    581                                      'for %s' % (self.functionName, 
    582                                                  self.__class__.__name__)) 
    583                                    
    584         return getattr(self, function)(inputs, evaluationCtx) 
    585      
    586     def stringEqual(self, inputs, evaluationCtx): 
    587         result = self.evalArgs(inputs, context, argValues) 
    588         if result is not None: 
    589             return result 
    590            
    591         return EvaluationResult(argValues[0] == argValues[1]) 
    592      
    593     def getArgumentType(functionName): 
    594         datatype = EqualFunction.typeMap.get(functionName); 
    595         if datatype is None: 
    596             raise AttributeError("Not a standard function: %s" % functionName) 
    597            
    598         return datatype 
    599  
    600 class AddFunction(FunctionBase): 
    601      
    602     def __init__(self, *arg, **kw): 
    603         raise NotImplementedError() 
    604              
    605 class SubtractFunction(FunctionBase): 
    606      
    607     def __init__(self, *arg, **kw): 
    608         raise NotImplementedError() 
    609              
    610 class MultiplyFunction(FunctionBase): 
    611      
    612     def __init__(self, *arg, **kw): 
    613         raise NotImplementedError() 
    614              
    615 class DivideFunction(FunctionBase): 
    616      
    617     def __init__(self, *arg, **kw): 
    618         raise NotImplementedError() 
    619              
    620 class ModFunction(FunctionBase): 
    621      
    622     def __init__(self, *arg, **kw): 
    623         raise NotImplementedError() 
    624  
    625 class AbsFunction(FunctionBase): 
    626      
    627     def __init__(self, *arg, **kw): 
    628         raise NotImplementedError() 
    629  
    630 class RoundFunction(FunctionBase): 
    631      
    632     def __init__(self, *arg, **kw): 
    633         raise NotImplementedError() 
    634  
    635 class FloorFunction(FunctionBase): 
    636      
    637     def __init__(self, *arg, **kw): 
    638         raise NotImplementedError() 
    639  
    640 class DateMathFunction(FunctionBase): 
    641      
    642     def __init__(self, *arg, **kw): 
    643         raise NotImplementedError() 
    644  
    645 class GeneralBagFunction(BagFunction): 
    646      
    647     def __init__(self, *arg, **kw): 
    648         raise NotImplementedError() 
    649  
    650 class NumericConvertFunction(FunctionBase): 
    651      
    652     def __init__(self, *arg, **kw): 
    653         raise NotImplementedError() 
    654  
    655 class StringNormalizeFunction(FunctionBase): 
    656      
    657     def __init__(self, *arg, **kw): 
    658         raise NotImplementedError() 
    659  
    660 class GeneralSetFunction(SetFunction): 
    661      
    662     def __init__(self, *arg, **kw): 
    663         raise NotImplementedError() 
    664      
    665 class MapFunction(Function):         
    666     supportedIdentifiers = () 
    667     NAME_MAP = FunctionBase.FUNCTION_NS + "map" 
    668      
    669     def __init__(self, *arg, **kw): 
    670         raise NotImplementedError() 
    671  
    672     @classmethod 
    673     def getInstance(cls, root): 
    674         raise NotImplementedError() 
    675      
    676 class FunctionProxy(): 
    677  
    678     def getInstance(self, root): 
    679         raise NotImplementedError() 
    680  
    681 class MapFunctionProxy(FunctionProxy): 
    682  
    683     def getInstance(self, root): 
    684         return MapFunction.getInstance(root) 
    685  
    686  
    687 class UnknownIdentifierException(Exception): 
    688     pass 
    689  
    690 class FunctionTypeException(Exception): 
    691     pass 
    692  
    693 class ParsingException(Exception): 
    694     pass 
    695  
    696 class FunctionFactory(XacmlBase): 
    697     '''Factory used to create all functions. There are three kinds of factories: 
    698     general, condition, and target. These provide functions that can be used 
    699     anywhere, only in a condition's root and only in a target (respectively). 
    700      
    701     Note that all functions, except for abstract functions, are singletons, so 
    702     any instance that is added to a factory will be the same one returned 
    703     from the create methods. This is done because most functions don't have 
    704     state, so there is no need to have more than one, or to spend the time 
    705     creating multiple instances that all do the same thing.''' 
    706  
    707     defaultFactoryProxy = StandardFunctionFactory()                  
    708              
    709     @classmethod 
    710     def getTargetInstance(cls): 
    711         '''Returns the default FunctionFactory that will only provide those 
    712         functions that are usable in Target matching. 
    713          
    714         @return a FunctionFactory for target functions''' 
    715         return cls.defaultFactoryProxy.getTargetFactory() 
    716         
    717     @classmethod  
    718     def getConditionInstance(cls):  
    719         '''Returns the default FunctionFactory that provides access to all the 
    720         functions. These Functions are a superset of the Condition functions. 
    721          
    722         @return a FunctionFactory for all functions 
    723         ''' 
    724         return cls.defaultFactoryProxy.getConditionFactory() 
    725      
    726     @classmethod 
    727     def getGeneralInstance(cls):  
    728         '''Sets the default factory. Note that this is just a place holder for 
    729         now, and will be replaced with a more useful mechanism soon.''' 
    730         return cls.defaultFactoryProxy.getGeneralFactory() 
    731      
    732      
    733     def addFunction(self, function): 
    734         '''Adds the function to the factory. Most functions have no state, so 
    735         the singleton model used here is typically desirable. The factory will 
    736         not enforce the requirement that a Target or Condition matching  
    737         function must be boolean. 
    738          
    739         @param function the Function to add to the factory 
    740         ''' 
    741         raise NotImplementedError() 
    742          
    743     def addAbstractFunction(self, functionProxy, identity): 
    744         '''Adds the abstract function proxy to the factory. This is used for 
    745         those functions which have state, or change behaviour (for instance 
    746         the standard map function, which changes its return type based on 
    747         how it is used).  
    748          
    749         @param proxy the FunctionProxy to add to the factory 
    750         @param identity the function's identifier 
    751         ''' 
    752         raise NotImplementedError()         
    753      
    754     def getSupportedFunctions(self): 
    755         '''Returns the function identifiers supported by this factory. 
    756          
    757         @return a Set of Strings''' 
    758         raise NotImplementedError() 
    759  
    760     def createFunction(self, identity): 
    761         '''Tries to get an instance of the specified function. 
    762          
    763         @param identity the name of the function 
    764         '''        
    765         raise NotImplementedError() 
    766      
    767     def createAbstractFunction(self, identity, root): 
    768         '''Tries to get an instance of the specified abstract function. 
    769          
    770         @param identity the name of the function 
    771         @param root the DOM root containing info used to create the function 
    772         ''' 
    773         raise NotImplementedError() 
    774  
    775  
    776 class FunctionFactoryProxy(XacmlBase): 
    777     '''A simple proxy interface used to install new FunctionFactorys. 
    778     The three kinds of factory (Target, Condition, and General) are tied 
    779     together in this interface because implementors writing new factories 
    780     should always implement all three types and provide them together''' 
    781     def getTargetFactory(): 
    782         raise NotImplementedError() 
    783  
    784     def getConditionFactory(): 
    785         raise NotImplementedError() 
    786  
    787     def getGeneralFactory(): 
    788         raise NotImplementedError() 
    789  
    790  
    791 class BasicFunctionFactoryProxy(FunctionFactoryProxy): 
    792     '''A simple utility class that manages triples of function factories.''' 
    793      
    794     # the triple of factories 
    795     targetFactory = None 
    796     conditionFactory = None 
    797     generalFactory = None 
    798  
    799     def __init__(targetFactory, conditionFactory, generalFactory):  
    800         '''Creates a new proxy. 
    801          
    802         @param targetFactory the target factory provided by this proxy 
    803         @param conditionFactory the target condition provided by this proxy 
    804         @param generalFactory the general factory provided by this proxy 
    805         ''' 
    806         self.targetFactory = targetFactory 
    807         self.conditionFactory = conditionFactory 
    808         self.generalFactory = generalFactory 
    809      
    810     def getTargetFactory(): 
    811         return targetFactory 
    812  
    813     def getConditionFactory(): 
    814         return conditionFactory 
    815  
    816     def getGeneralFactory(): 
    817         return generalFactory 
    818      
    819  
    820 class BaseFunctionFactory(FunctionFactory): 
    821     '''This is a basic implementation of <code>FunctionFactory</code>. It 
    822     implements the insertion and retrieval methods, but it doesn't actually 
    823     setup the factory with any functions. It also assumes a certain model 
    824     with regard to the different kinds of functions (Target, Condition, and 
    825     General). For this reason, you may want to re-use this class, or you  
    826     may want to extend FunctionFactory directly, if you're writing a new 
    827     factory implementation. 
    828      
    829     Note that while this class is thread-safe on all creation methods, it 
    830     is not safe to add support for a new function while creating an instance 
    831     of a function. This follows from the assumption that most people will 
    832     initialize these factories up-front, and then start processing without 
    833     ever modifying the factories. If you need these mutual operations to 
    834     be thread-safe, then you should write a wrapper class that implements 
    835     the right synchronization. 
    836     ''' 
    837      
    838     def __init__(self,  
    839                  superset=None,  
    840                  supportedFunctions=[], 
    841                  supportedAbstractFunctions={}): 
    842         '''Sets a "superset factory". This is useful since 
    843         the different function factories (Target, Condition, and General) 
    844         have a superset relationship (Condition functions are a superset 
    845         of Target functions, etc.). Adding a function to this factory will 
    846         automatically add the same function to the superset factory. 
    847  
    848         Constructor that defines the initial functions supported by this 
    849         factory but doesn't use a superset factory. 
    850  
    851         Constructor that defines the initial functions supported by this 
    852         factory but doesn't use a superset factory. 
    853  
    854         Constructor that defines the initial functions supported by this 
    855         factory and uses a superset factory. Note that the functions 
    856         supplied here are not propagated up to the superset factory, so 
    857         you must either make sure the superset factory is correctly 
    858         initialized or use BaseFunctionFactory(FunctionFactory) 
    859         and then manually add each function. 
    860         
    861         @param supportedFunctions a Set of Functions 
    862         @param supportedAbstractFunctions a mapping from URI to 
    863                                           FunctionProxy 
    864          
    865         @param supportedFunctions a Set of Functions 
    866         @param supportedAbstractFunctions a mapping from URI to FunctionProxy 
    867          
    868         @param superset the superset factory or None''' 
    869          
    870         # the backing maps for the Function objects 
    871         self.functionMap = {} 
    872      
    873         # the superset factory chained to this factory 
    874         self.superset = superset 
    875       
    876         for function in supportedFunctions: 
    877             self.functionMap[function.functionId] = function 
    878          
    879         for id in supportedAbstractFunctions.keys(): 
    880             proxy = supportedAbstractFunctions.get(id) 
    881             self.functionMap[id] = proxy 
    882   
    883     def addFunction(self, function): 
    884         '''Adds the function to the factory. Most functions have no state, so 
    885         the singleton model used here is typically desirable. The factory will 
    886         not enforce the requirement that a Target or Condition matching  
    887         function must be boolean. 
    888          
    889         @param function the Function to add to the factory 
    890         @raise TypeError if the function's identifier is already used or if the 
    891         function is non-boolean (when this is a Target or Condition factory) 
    892         ''' 
    893         id = function.functionId 
    894  
    895         # make sure this doesn't already exist 
    896         if id in self.functionMap: 
    897             raise TypeError("function %s already exists" % id) 
    898  
    899         # add to the superset factory 
    900         if self.superset != None: 
    901             self.superset.addFunction(function) 
    902  
    903         # Add to this factory 
    904         self.functionMap[id] = function 
    905      
    906          
    907     def addAbstractFunction(self, proxy, id): 
    908         '''Adds the abstract function proxy to the factory. This is used for 
    909         those functions which have state, or change behaviour (for instance 
    910         the standard map function, which changes its return type based on 
    911         how it is used).  
    912          
    913         @param proxy: the FunctionProxy to add to the factory 
    914         @param id: the function's identifier 
    915          
    916         @raise TypeError if the function's identifier is already used''' 
    917  
    918         # make sure this doesn't already exist 
    919         if id in self.functionMap: 
    920             raise TypeError("function already exists") 
    921  
    922         # add to the superset factory 
    923         if self.superset != None: 
    924             self.superset.addAbstractFunction(proxy, id) 
    925  
    926         # finally, add to this factory 
    927         functionMap[id] = proxy 
    928      
    929  
    930     def getSupportedFunctions(self):  
    931         '''Returns the function identifiers supported by this factory. 
    932          
    933         @return a list of strings''' 
    934      
    935         functions = self.functionMap.keys() 
    936  
    937         if self.superset != None: 
    938             functions += self.superset.getSupportedFunctions() 
    939  
    940         return functions 
    941      
    942  
    943     def createFunction(self, identity): 
    944         '''Tries to get an instance of the specified function. 
    945          
    946         @param identity the name of the function 
    947          
    948         @throws UnknownIdentifierException if the name isn't known 
    949         @throws FunctionTypeException if the name is known to map to an 
    950                                       abstract function, and should therefore 
    951                                       be created through createAbstractFunction 
    952         ''' 
    953         entry = self.functionMap.get(identity) 
    954         if entry is not None: 
    955             if isinstance(entry, Function):  
    956                 return entry 
    957             else: 
    958                 # this is actually a proxy, which means the other create 
    959                 # method should have been called 
    960                 raise FunctionTypeException("function is abstract")     
    961         else: 
    962             # we couldn't find a match 
    963             raise UnknownIdentifierException("functions of type %s are not " 
    964                                              "supported by this factory" %  
    965                                              identity)         
    966      
    967      
    968     def createAbstractFunction(identity, root): 
    969         '''Tries to get an instance of the specified abstract function. 
    970          
    971         @param identity the name of the function 
    972         @param root the DOM root containing info used to create the function 
    973         @param xpathVersion the version specified in the containing policy, or 
    974                             None if no version was specified 
    975          
    976         @throws UnknownIdentifierException if the name isn't known 
    977         @throws FunctionTypeException if the name is known to map to a 
    978                                       concrete function, and should therefore 
    979                                       be created through createFunction 
    980         @throws ParsingException if the function can't be created with the 
    981                                  given inputs''' 
    982      
    983         entry = self.functionMap.get(identity) 
    984         if entry is not None: 
    985             if isinstance(entry, FunctionProxy):  
    986                 try:  
    987                     return entry.getInstance(root) 
    988                  
    989                 except Exception, e: 
    990                     raise ParsingException("Couldn't create abstract function " 
    991                                            "%s: %s" % identity, e)       
    992             else: 
    993                 # this is actually a concrete function, which means that 
    994                 # the other create method should have been called 
    995                 raise FunctionTypeException("function is concrete") 
    996              
    997         else: 
    998             raise UnknownIdentifierException("Abstract functions of type %s " 
    999                                              "are not supported by this " 
    1000                                              "factory" % identity) 
    1001  
    1002  
    1003 class StandardFunctionFactory(BaseFunctionFactory): 
    1004     '''This factory supports the standard set of functions specified in XACML 
    1005     1.0 and 1.1. It is the default factory used by the system, and imposes 
    1006     a singleton pattern insuring that there is only ever one instance of 
    1007     this class. 
    1008     <p> 
    1009     Note that because this supports only the standard functions, this 
    1010     factory does not allow the addition of any other functions. If you call 
    1011     addFunction on an instance of this class, an exception 
    1012     will be thrown. If you need a standard factory that is modifiable, 
    1013     you can either create a new BaseFunctionFactory (or some 
    1014     other implementation of FunctionFactory) populated with 
    1015     the standard functions from getStandardFunctions or 
    1016     you can use getNewFactoryProxy to get a proxy containing 
    1017     a new, modifiable set of factories.''' 
    1018  
    1019  
    1020     # the three singleton instances 
    1021     targetFactory = None 
    1022     conditionFactory = None 
    1023     generalFactory = None 
    1024  
    1025     # the three function sets/maps that we use internally 
    1026     targetFunctions = None 
    1027     conditionFunctions = None 
    1028     generalFunctions = None 
    1029  
    1030     targetAbstractFunctions = None 
    1031     conditionAbstractFunctions = None 
    1032     generalAbstractFunctions = None 
    1033  
    1034     # the set/map used by each singleton factory instance 
    1035     supportedFunctions = None 
    1036     supportedAbstractFunctions = None 
    1037  
    1038      
    1039     def __init__(self, supportedFunctions, supportedAbstractFunctions):  
    1040         '''Creates a new StandardFunctionFactory, making sure that the default 
    1041         maps are initialized correctly. Standard factories can't be modified, 
    1042         so there is no notion of supersetting since that's only used for 
    1043         correctly propagating new functions.''' 
    1044         super(StandardFunctionFactory, self).__init__(supportedFunctions,  
    1045                                                     supportedAbstractFunctions) 
    1046  
    1047         self.supportedFunctions = supportedFunctions 
    1048         self.supportedAbstractFunctions = supportedAbstractFunctions 
    1049      
    1050  
    1051      
    1052      
    1053     def _initTargetFunctions(self):  
    1054         '''Private initializer for the target functions. This is only ever 
    1055         called once.''' 
    1056         log.info("Initializing standard Target functions") 
    1057  
    1058         # Emulate a list with unique items using a dict with only the keys set 
    1059         StandardFunctionFactory.targetFunctions = {} 
    1060  
    1061         # add EqualFunction 
    1062         StandardFunctionFactory.targetFunctions.fromkeys( 
    1063                                     EqualFunction.supportedIdentifiers) 
    1064  
    1065         # add LogicalFunction 
    1066         StandardFunctionFactory.targetFunctions.fromkeys( 
    1067                                     LogicalFunction.supportedIdentifiers) 
    1068          
    1069         # add NOfFunction 
    1070         StandardFunctionFactory.targetFunctions.fromkeys( 
    1071                                     NOfFunction.supportedIdentifiers) 
    1072          
    1073         # add NotFunction 
    1074         StandardFunctionFactory.targetFunctions.fromkeys( 
    1075                                     NotFunction.supportedIdentifiers) 
    1076          
    1077         # add ComparisonFunction 
    1078         StandardFunctionFactory.targetFunctions.fromkeys( 
    1079                                     ComparisonFunction.supportedIdentifiers) 
    1080  
    1081         # add MatchFunction 
    1082         StandardFunctionFactory.targetFunctions.fromkeys( 
    1083                                     MatchFunction.supportedIdentifiers) 
    1084  
    1085         StandardFunctionFactory.targetAbstractFunctions = {} 
    1086      
    1087      
    1088     def _initConditionFunctions(self):  
    1089         '''Private initializer for the condition functions. This is only ever 
    1090         called once.''' 
    1091         log.info("Initializing standard Condition functions") 
    1092  
    1093         if StandardFunctionFactory.targetFunctions is None: 
    1094             self._initTargetFunctions() 
    1095  
    1096         StandardFunctionFactory.conditionFunctions = \ 
    1097             StandardFunctionFactory.targetFunctions.copy() 
    1098  
    1099         # add condition functions from BagFunction 
    1100         conditionFunctions.fromkeys(ConditionBagFunction.supportedIdentifiers) 
    1101          
    1102         # add condition functions from SetFunction 
    1103         conditionFunctions.fromkeys(ConditionSetFunction.supportedIdentifiers) 
    1104          
    1105         # add condition functions from HigherOrderFunction 
    1106         conditionFunctions.fromkeys(HigherOrderFunction.supportedIdentifiers) 
    1107  
    1108         StandardFunctionFactory.conditionAbstractFunctions = \ 
    1109             StandardFunctionFactory.targetAbstractFunctions.copy() 
    1110      
    1111  
    1112     def _initGeneralFunctions(self):      
    1113         '''Private initializer for the general functions. This is only ever 
    1114         called once.''' 
    1115      
    1116         log.info("Initializing standard General functions") 
    1117  
    1118         if StandardFunctionFactory.conditionFunctions is None: 
    1119             self._initConditionFunctions() 
    1120  
    1121         StandardFunctionFactory.generalFunctions = \ 
    1122             StandardFunctionFactory.conditionFunctions.copy() 
    1123  
    1124         # add AddFunction 
    1125         StandardFunctionFactory.generalFunctions.fromkeys( 
    1126             AddFunction.supportedIdentifiers) 
    1127              
    1128         # add SubtractFunction 
    1129         StandardFunctionFactory.generalFunctions.fromkeys( 
    1130             SubtractFunction.supportedIdentifiers) 
    1131              
    1132         # add MultiplyFunction 
    1133         StandardFunctionFactory.generalFunctions.fromkeys( 
    1134             MultiplyFunction.supportedIdentifiers) 
    1135              
    1136         # add DivideFunction 
    1137         StandardFunctionFactory.generalFunctions.fromkeys( 
    1138             DivideFunction.supportedIdentifiers) 
    1139              
    1140         # add ModFunction 
    1141         StandardFunctionFactory.generalFunctions.fromkeys( 
    1142             ModFunction.supportedIdentifiers) 
    1143          
    1144         # add AbsFunction 
    1145         StandardFunctionFactory.generalFunctions.fromkeys( 
    1146             AbsFunction.supportedIdentifiers) 
    1147              
    1148         # add RoundFunction 
    1149         StandardFunctionFactory.generalFunctions.fromkeys( 
    1150             RoundFunction.supportedIdentifiers) 
    1151              
    1152         # add FloorFunction 
    1153         StandardFunctionFactory.generalFunctions.fromkeys( 
    1154             FloorFunction.supportedIdentifiers) 
    1155          
    1156         # add DateMathFunction 
    1157         StandardFunctionFactory.generalFunctions.fromkeys( 
    1158             DateMathFunction.supportedIdentifiers) 
    1159              
    1160         # add general functions from BagFunction 
    1161         StandardFunctionFactory.generalFunctions.fromkeys( 
    1162             GeneralBagFunction.supportedIdentifiers) 
    1163              
    1164         # add NumericConvertFunction 
    1165         StandardFunctionFactory.generalFunctions.fromkeys( 
    1166             NumericConvertFunction.supportedIdentifiers) 
    1167              
    1168         # add StringNormalizeFunction 
    1169         StandardFunctionFactory.generalFunctions.fromkeys( 
    1170             StringNormalizeFunction.supportedIdentifiers) 
    1171          
    1172         # add general functions from SetFunction 
    1173         StandardFunctionFactory.generalFunctions.fromkeys( 
    1174             GeneralSetFunction.supportedIdentifiers) 
    1175              
    1176         StandardFunctionFactory.generalAbstractFunctions = \ 
    1177             StandardFunctionFactory.conditionAbstractFunctions.copy() 
    1178  
    1179         # Add the map function's proxy 
    1180         StandardFunctionFactory.generalAbstractFunctions[ 
    1181                                     MapFunction.NAME_MAP] = MapFunctionProxy() 
    1182      
    1183     @classmethod  
    1184     def getTargetFactory(cls):  
    1185         '''Returns a FunctionFactory that will only provide those functions  
    1186         that are usable in Target matching. This method enforces a singleton 
    1187         model, meaning that this always returns the same instance, creating 
    1188         the factory if it hasn't been requested before. This is the default 
    1189         model used by the FunctionFactory, ensuring quick 
    1190         access to this factory. 
    1191          
    1192         @return a FunctionFactory for target functions''' 
    1193         if StandardFunctionFactory.targetFactory is None:  
    1194             if StandardFunctionFactory.targetFunctions is None: 
    1195                 StandardFunctionFactory._initTargetFunctions() 
    1196                  
    1197             if StandardFunctionFactory.targetFactory is None: 
    1198                 StandardFunctionFactory.targetFactory=StandardFunctionFactory( 
    1199                             StandardFunctionFactory.targetFunctions, 
    1200                             StandardFunctionFactory.targetAbstractFunctions) 
    1201          
    1202         return StandardFunctionFactory.targetFactory 
    1203  
    1204      
    1205     @classmethod 
    1206     def getConditionFactory(cls):  
    1207         '''Returns a FuntionFactory that will only provide those functions that 
    1208         are usable in the root of the Condition. These Functions are a 
    1209         superset of the Target functions. This method enforces a singleton 
    1210         model, meaning that this always returns the same instance, creating 
    1211         the factory if it hasn't been requested before. This is the default 
    1212         model used by the FunctionFactory, ensuring quick 
    1213         access to this factory. 
    1214      
    1215         @return a FunctionFactory for condition functions 
    1216         ''' 
    1217         if StandardFunctionFactory.conditionFactory is None: 
    1218             if StandardFunctionFactory.conditionFunctions is None: 
    1219                 StandardFunctionFactory._initConditionFunctions() 
    1220                  
    1221             if StandardFunctionFactory.conditionFactory is None: 
    1222                 StandardFunctionFactory.conditionFactory = \ 
    1223                     StandardFunctionFactory( 
    1224                            StandardFunctionFactory.conditionFunctions, 
    1225                            StandardFunctionFactory.conditionAbstractFunctions)        
    1226  
    1227         return StandardFunctionFactory.conditionFactory 
    1228      
    1229  
    1230     @classmethod 
    1231     def getGeneralFactory(cls):  
    1232         '''Returns a FunctionFactory that provides access to all the functions. 
    1233         These Functions are a superset of the Condition functions. This method 
    1234         enforces a singleton model, meaning that this always returns the same 
    1235         instance, creating the factory if it hasn't been requested before. 
    1236         This is the default model used by the FunctionFactory, 
    1237         ensuring quick access to this factory. 
    1238          
    1239         @return a FunctionFactory for all functions''' 
    1240      
    1241         if StandardFunctionFactory.generalFactory is None: 
    1242             if StandardFunctionFactory.generalFunctions is None: 
    1243                 StandardFunctionFactory._initGeneralFunctions() 
    1244                  
    1245                 StandardFunctionFactory.generalFactory = \ 
    1246                     StandardFunctionFactory( 
    1247                             StandardFunctionFactory.generalFunctions, 
    1248                             StandardFunctionFactory.generalAbstractFunctions) 
    1249                  
    1250         return StandardFunctionFactory.generalFactory 
    1251  
    1252  
    1253     def getStandardFunctions(self): 
    1254         '''Returns the set of functions that this standard factory supports. 
    1255          
    1256         @return a Set of Functions''' 
    1257         return tuple(self.supportedFunctions.keys()) 
    1258          
    1259     def getStandardAbstractFunctions(self): 
    1260         '''Returns the set of abstract functions that this standard factory 
    1261         supports as a mapping of identifier to proxy. 
    1262          
    1263         @return a Map mapping URIs to FunctionProxys''' 
    1264         return tuple(self.supportedAbstractFunctions.keys()) 
    1265      
    1266      
    1267     @classmethod 
    1268     def getNewFactoryProxy(cls):  
    1269         '''A convenience method that returns a proxy containing newly created 
    1270         instances of BaseFunctionFactorys that are correctly 
    1271         supersetted and contain the standard functions and abstract functions. 
    1272         These factories allow adding support for new functions. 
    1273          
    1274         @return a new proxy containing new factories supporting the standard 
    1275         functions''' 
    1276          
    1277         general = StandardFunctionFactory.getGeneralFactory() 
    1278              
    1279         newGeneral=BaseFunctionFactory(general.getStandardFunctions(), 
    1280                                        general.getStandardAbstractFunctions()) 
    1281  
    1282         condition = StandardFunctionFactory.getConditionFactory() 
    1283          
    1284         newCondition = BaseFunctionFactory(newGeneral, 
    1285                                     condition.getStandardFunctions(), 
    1286                                     condition.getStandardAbstractFunctions()) 
    1287  
    1288         target = StandardFunctionFactory.getTargetFactory() 
    1289         newTarget = BaseFunctionFactory(newCondition, 
    1290                                     target.getStandardFunctions(), 
    1291                                     target.getStandardAbstractFunctions()) 
    1292  
    1293         return BasicFunctionFactoryProxy(newTarget, newCondition, newGeneral) 
    1294      
    1295  
    1296      
    1297      
    1298     def addFunction(self, function): 
    1299         '''Always throws an exception, since support for new functions may not  
    1300         be added to a standard factory. 
    1301          
    1302         @param function the Function to add to the factory        
    1303         @raise NotImplementedError''' 
    1304      
    1305         raise NotImplementedError("a standard factory cannot support new " 
    1306                                   "functions") 
    1307      
    1308      
    1309     def addAbstractFunction(self, proxy, identity): 
    1310         '''Always throws an exception, since support for new functions may not  
    1311         be added to a standard factory. 
    1312          
    1313         @param proxy the FunctionProxy to add to the factory 
    1314         @param identity the function's identifier 
    1315          
    1316         @raise NotImplementedError always''' 
    1317         raise NotImplementedError("a standard factory cannot support new " 
    1318                                   "functions") 
    1319  
    1320356     
    1321357class Status(XacmlBase): 
  • 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.