Changeset 5375


Ignore:
Timestamp:
10/06/09 15:50:45 (10 years ago)
Author:
pjkersha
Message:

Refactored XACML code:

  • fixes to Policy.getInstance parser method
  • moving Factory and Evaluatable classes from cond module into their own modules
Location:
TI12-security/trunk/python/ndg.security.common/ndg/security/common/authz/xacml
Files:
3 added
2 edited

Legend:

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

    r5168 r5375  
    1414log = logging.getLogger(__name__) 
    1515 
    16 #from ndg.security.common.authz.xacml.cond import FunctionFactory 
     16from elementtree import ElementTree 
     17 
     18from ndg.security.common.authz.xacml.factory import FunctionFactory, \ 
     19    UnknownIdentifierException, FunctionTypeException 
     20     
    1721import ndg.security.common.authz.xacml.cond 
    18 class FunctionFactory: 
    19     pass 
     22#class FunctionFactory: 
     23#    pass 
    2024 
    2125 
     
    6771     
    6872    @classmethod 
    69     def getInstance(cls, root): 
     73    def getInstance(cls, root=None, source=None): 
     74        """ 
     75        @type root: ElementTree.Element 
     76        @param root: ElementTree root element 
     77        @type source: basestring / file like object 
     78        @param source: file path or file like object source of data 
     79        """ 
     80        if root is None: 
     81            if source is None: 
     82                raise AttributeError('"root" or "source" keywords must be ' 
     83                                     'provided') 
     84                 
     85            elem = ElementTree.parse(source) 
     86            root = elem.getroot() 
    7087         
    7188        for elem in root: 
    7289            localName = getLocalName(elem) 
    7390            if localName == 'Description': 
    74                 description = elem.text 
     91                description = elem.text.strip() 
    7592                 
    7693            elif localName == 'Target': 
     
    8198             
    8299        policy = cls(id=root.attrib['PolicyId'],  
    83                      ruleCombiningAlg=root.attrib['RuleCombiningAlg'], 
     100                     ruleCombiningAlg=root.attrib['RuleCombiningAlgId'], 
    84101                     description=description, 
    85102                     target=target, 
     
    155172     
    156173class AttributeDesignator(XacmlBase): 
    157     ACTION_TARGET, ENVIRONMENT_TARGET, RESOURCE_TARGET, SUBJECT_TARGET=range(4) 
    158  
     174    elemNames = [n+'AttributeDesignator' for n in ('Action', 'Environment', 
     175                                                  'Resource', 'Subject')] 
     176    targetCodes = range(4) 
     177    targetLUT = dict(zip(elemNames, targetCodes)) 
     178     
     179    (ACTION_TARGET,  
     180    ENVIRONMENT_TARGET,  
     181    RESOURCE_TARGET,  
     182    SUBJECT_TARGET) = targetCodes 
     183     
    159184    def __init__(self, target, type, id, mustBePresent=False, issuer=None): 
    160           self.target = target 
    161           self.type = type 
    162           self.id = id 
    163           self.mustBePresent = mustBePresent 
    164           self.issuer = issuer 
    165  
    166     def getInstance(self): 
    167         pass 
     185        if target not in AttributeDesignator.targetCodes: 
     186            raise AttributeError("Target code must be one of %r; input code " 
     187                                 "is %r" % (AttributeDesignator.targetCodes, 
     188                                            target)) 
     189        self.target = target 
     190        self.type = type 
     191        self.id = id 
     192        self.mustBePresent = mustBePresent 
     193        self.issuer = issuer 
     194 
     195    @classmethod 
     196    def getInstance(cls, elem, target): 
     197        """Create a new instance from an ElementTree element 
     198        @type elem: ElementTree.Element 
     199        @param elem: AttributeDesignator XML element 
     200        @type target: int 
     201        @param target: target code 
     202        @rtype: AttributeDesignator 
     203        @return: new AttributeDesignator instance 
     204        """ 
     205        localName = getLocalName(elem) 
     206        if localName not in cls.elemNames: 
     207            raise AttributeError("Element name [%s] is not a recognised " 
     208                                 "AttributeDesignator name %r" %  
     209                                 (localName, cls.elemNames)) 
     210             
     211         
     212        if target not in cls.targetCodes: 
     213            raise AttributeError("Target code [%d] is not a recognised " 
     214                                 "AttributeDesignator target code %r" %  
     215                                 (localName, cls.targetCodes)) 
     216             
     217        id = elem.attrib['AttributeId'] 
     218        type = elem.attrib['DataType'] 
     219        mustBePresent=elem.attrib.get('mustBePresent','false').lower()=='true' 
     220        issuer = elem.attrib.get('issuer') 
     221        return cls(target, type, id, mustBePresent=mustBePresent,issuer=issuer) 
     222     
    168223     
    169224class TargetMatch(XacmlBase): 
     
    192247        @raise TypeError if the input type isn't a valid value 
    193248        ''' 
     249        if type not in self.__class__.types: 
     250            raise TypeError("Type is [%d] but it must be one of %r" %  
     251                            (type, self.__class__.types)) 
    194252        self.type = type 
    195253        self.function = function 
     
    225283        ''' 
    226284 
    227         action = ["Subject", "Resource", "Action"].index(prefix) 
    228         if action not in cls.types: 
     285        type = ["Subject", "Resource", "Action"].index(prefix) 
     286        if type not in cls.types: 
    229287            raise TypeError("Unknown TargetMatch type: %s" % prefix) 
    230288 
     
    249307            localName = getLocalName(elem) 
    250308 
    251             if name == prefix + "AttributeDesignator": 
    252                 eval = AttributeDesignator.getInstance(node, type) 
     309            if localName == prefix + "AttributeDesignator": 
     310                eval = AttributeDesignator.getInstance(elem, type) 
    253311                 
    254             elif name == "AttributeSelector": 
    255                 eval = AttributeSelector.getInstance(node) 
     312            elif localName == "AttributeSelector": 
     313                eval = AttributeSelector.getInstance(elem) 
    256314                 
    257             elif name == "AttributeValue": 
     315            elif localName == "AttributeValue": 
    258316                try: 
    259                     attrValue = attrFactory.createValue(node) 
     317                    attrValue = attrFactory.createValue(elem) 
    260318                except UnknownIdentifierException, e: 
    261319                    raise ParsingException("Unknown Attribute Type: %s" % e) 
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/authz/xacml/cond.py

    r5168 r5375  
    1 """XACML cond module contains condition function classes and class factories 
     1"""XACML cond module contains condition function classes 
    22 
    33NERC DataGrid Project 
     
    1313log = logging.getLogger(__name__) 
    1414 
    15 from ndg.security.common.utils import UniqList 
     15from ndg.security.common.authz.xacml.cond.eval import Evaluatable 
    1616from ndg.security.common.authz.xacml.attr import AnyURIAttribute, \ 
    1717    Base64BinaryAttribute, BooleanAttribute, DateAttribute, DateTimeAttribute,\ 
     
    1919    IntegerAttribute, RFC822NameAttribute, StringAttribute, TimeAttribute, \ 
    2020    X500NameAttribute, YearMonthDurationAttribute 
    21  
    22  
    23 class Evaluatable(object): 
    24     '''Generic interface that is implemented by all objects that can appear in 
    25     an ApplyType. This lets the evaluation code of Apply and 
    26     functions iterate through their members and evaluate them, working only 
    27     on the returned values or errors.''' 
    28      
    29     def evaluate(self, context): 
    30         '''Evaluates the object using the given context, and either returns an 
    31         error or a resulting value. 
    32      
    33         @param context the representation of the request 
    34         @return the result of evaluation''' 
    35         raise NotImplementedError() 
    36  
    37     def getType(self): 
    38         '''Get the type of this object.  This may be the data type of an 
    39         Attribute or the return type of an 
    40         AttributeDesignator, etc. 
    41      
    42         @return the type of data represented by this object''' 
    43         raise NotImplementedError() 
    44  
    45     def evaluatesToBag(self): 
    46         '''Tells whether evaluation will return a bag or a single value. 
    47      
    48         @return true if evaluation will return a bag, false otherwise''' 
    49         raise NotImplementedError() 
    50  
    51     def getChildren(self): 
    52         '''Returns all children, in order, of this element in the Condition 
    53         tree, or en empty set if this element has no children. In XACML 1.x, 
    54         only the ApplyType ever has children. 
    55      
    56         @return a list of Evaluatables''' 
    57         raise NotImplementedError() 
    58  
    59     def encode(self, output, indenter=None): 
    60         '''Encodes this Evaluatable into its XML representation and 
    61         writes this encoding to the given OutputStream with 
    62         indentation. 
    63      
    64         @param output a stream into which the XML-encoded data is written 
    65         @param indenter an object that creates indentation strings''' 
    66         raise NotImplementedError() 
    6721 
    6822 
     
    555509    def __init__(self, functionName, argumentType=None, **kw): 
    556510        if kw.get('functionId') is None: 
    557             kw['functionId'] = 0 
     511            kw['functionId'] = functionName 
    558512             
    559513        if kw.get('paramType') is None: 
     
    679633    def getInstance(self, root): 
    680634        return MapFunction.getInstance(root) 
    681  
    682  
    683 class UnknownIdentifierException(Exception): 
    684     pass 
    685  
    686 class FunctionTypeException(Exception): 
    687     pass 
    688  
    689 class ParsingException(Exception): 
    690     pass 
    691  
    692  
    693 class FunctionFactoryProxy(object): 
    694     '''A simple proxy interface used to install new <FunctionFactory>s. 
    695     The three kinds of factory (Target, Condition, and General) are tied 
    696     together in this interface because implementors writing new factories 
    697     should always implement all three types and provide them together''' 
    698      
    699     @classmethod 
    700     def getTargetFactory(cls): 
    701         raise NotImplementedError() 
    702  
    703     @classmethod 
    704     def getConditionFactory(cls): 
    705         raise NotImplementedError() 
    706  
    707     @classmethod 
    708     def getGeneralFactory(cls): 
    709         raise NotImplementedError() 
    710  
    711  
    712 class FunctionFactory(object): 
    713     '''Factory used to create all functions. There are three kinds of factories: 
    714     general, condition, and target. These provide functions that can be used 
    715     anywhere, only in a condition's root and only in a target (respectively). 
    716      
    717     Note that all functions, except for abstract functions, are singletons, so 
    718     any instance that is added to a factory will be the same one returned 
    719     from the create methods. This is done because most functions don't have 
    720     state, so there is no need to have more than one, or to spend the time 
    721     creating multiple instances that all do the same thing.''' 
    722  
    723     class defaultFactoryProxy(FunctionFactoryProxy): 
    724         @classmethod 
    725         def getTargetFactory(cls): 
    726             return StandardFunctionFactory.getTargetFactory() 
    727      
    728         @classmethod 
    729         def getConditionFactory(cls): 
    730             return StandardFunctionFactory.getConditionFactory() 
    731      
    732         @classmethod 
    733         def getGeneralFactory(cls): 
    734             return StandardFunctionFactory.getGeneralFactory()                  
    735              
    736     @classmethod 
    737     def getTargetInstance(cls): 
    738         '''Returns the default FunctionFactory that will only provide those 
    739         functions that are usable in Target matching. 
    740          
    741         @return a FunctionFactory for target functions''' 
    742         return cls.defaultFactoryProxy.getTargetFactory() 
    743         
    744     @classmethod  
    745     def getConditionInstance(cls):  
    746         '''Returns the default FunctionFactory that provides access to all the 
    747         functions. These Functions are a superset of the Condition functions. 
    748          
    749         @return a FunctionFactory for all functions 
    750         ''' 
    751         return cls.defaultFactoryProxy.getConditionFactory() 
    752      
    753     @classmethod 
    754     def getGeneralInstance(cls):  
    755         '''Sets the default factory. Note that this is just a place holder for 
    756         now, and will be replaced with a more useful mechanism soon.''' 
    757         return cls.defaultFactoryProxy.getGeneralFactory() 
    758      
    759      
    760     def addFunction(self, function): 
    761         '''Adds the function to the factory. Most functions have no state, so 
    762         the singleton model used here is typically desirable. The factory will 
    763         not enforce the requirement that a Target or Condition matching  
    764         function must be boolean. 
    765          
    766         @param function the Function to add to the factory 
    767         ''' 
    768         raise NotImplementedError() 
    769          
    770     def addAbstractFunction(self, functionProxy, identity): 
    771         '''Adds the abstract function proxy to the factory. This is used for 
    772         those functions which have state, or change behaviour (for instance 
    773         the standard map function, which changes its return type based on 
    774         how it is used).  
    775          
    776         @param proxy the FunctionProxy to add to the factory 
    777         @param identity the function's identifier 
    778         ''' 
    779         raise NotImplementedError()         
    780      
    781     def getSupportedFunctions(self): 
    782         '''Returns the function identifiers supported by this factory. 
    783          
    784         @return a Set of Strings''' 
    785         raise NotImplementedError() 
    786  
    787     def createFunction(self, identity): 
    788         '''Tries to get an instance of the specified function. 
    789          
    790         @param identity the name of the function 
    791         '''        
    792         raise NotImplementedError() 
    793      
    794     def createAbstractFunction(self, identity, root): 
    795         '''Tries to get an instance of the specified abstract function. 
    796          
    797         @param identity the name of the function 
    798         @param root the DOM root containing info used to create the function 
    799         ''' 
    800         raise NotImplementedError() 
    801  
    802  
    803 class BasicFunctionFactoryProxy(FunctionFactoryProxy): 
    804     '''A simple utility class that manages triples of function factories.''' 
    805      
    806     # the triple of factories 
    807     targetFactory = None 
    808     conditionFactory = None 
    809     generalFactory = None 
    810  
    811     def __init__(targetFactory, conditionFactory, generalFactory):  
    812         '''Creates a new proxy. 
    813          
    814         @param targetFactory the target factory provided by this proxy 
    815         @param conditionFactory the target condition provided by this proxy 
    816         @param generalFactory the general factory provided by this proxy 
    817         ''' 
    818         self.targetFactory = targetFactory 
    819         self.conditionFactory = conditionFactory 
    820         self.generalFactory = generalFactory 
    821      
    822     def getTargetFactory(): 
    823         return targetFactory 
    824  
    825     def getConditionFactory(): 
    826         return conditionFactory 
    827  
    828     def getGeneralFactory(): 
    829         return generalFactory 
    830      
    831  
    832 class BaseFunctionFactory(FunctionFactory): 
    833     '''This is a basic implementation of <code>FunctionFactory</code>. It 
    834     implements the insertion and retrieval methods, but it doesn't actually 
    835     setup the factory with any functions. It also assumes a certain model 
    836     with regard to the different kinds of functions (Target, Condition, and 
    837     General). For this reason, you may want to re-use this class, or you  
    838     may want to extend FunctionFactory directly, if you're writing a new 
    839     factory implementation. 
    840      
    841     Note that while this class is thread-safe on all creation methods, it 
    842     is not safe to add support for a new function while creating an instance 
    843     of a function. This follows from the assumption that most people will 
    844     initialize these factories up-front, and then start processing without 
    845     ever modifying the factories. If you need these mutual operations to 
    846     be thread-safe, then you should write a wrapper class that implements 
    847     the right synchronization. 
    848     ''' 
    849      
    850     def __init__(self,  
    851                  superset=None,  
    852                  supportedFunctions=[], 
    853                  supportedAbstractFunctions={}): 
    854         '''Sets a "superset factory". This is useful since 
    855         the different function factories (Target, Condition, and General) 
    856         have a superset relationship (Condition functions are a superset 
    857         of Target functions, etc.). Adding a function to this factory will 
    858         automatically add the same function to the superset factory. 
    859  
    860         Constructor that defines the initial functions supported by this 
    861         factory but doesn't use a superset factory. 
    862  
    863         Constructor that defines the initial functions supported by this 
    864         factory but doesn't use a superset factory. 
    865  
    866         Constructor that defines the initial functions supported by this 
    867         factory and uses a superset factory. Note that the functions 
    868         supplied here are not propagated up to the superset factory, so 
    869         you must either make sure the superset factory is correctly 
    870         initialized or use BaseFunctionFactory(FunctionFactory) 
    871         and then manually add each function. 
    872         
    873         @param supportedFunctions a Set of Functions 
    874         @param supportedAbstractFunctions a mapping from URI to 
    875                                           FunctionProxy 
    876          
    877         @param supportedFunctions a Set of Functions 
    878         @param supportedAbstractFunctions a mapping from URI to FunctionProxy 
    879          
    880         @param superset the superset factory or None''' 
    881          
    882         # the backing maps for the Function objects 
    883         self.functionMap = {} 
    884      
    885         # the superset factory chained to this factory 
    886         self.superset = superset 
    887       
    888         for function in supportedFunctions: 
    889             if function.functionId not in self.functionMap: 
    890                 self.functionMap[function.functionId] = function 
    891          
    892         for id in supportedAbstractFunctions.keys(): 
    893             proxy = supportedAbstractFunctions.get(id) 
    894             self.functionMap[id] = proxy 
    895   
    896     def addFunction(self, function): 
    897         '''Adds the function to the factory. Most functions have no state, so 
    898         the singleton model used here is typically desirable. The factory will 
    899         not enforce the requirement that a Target or Condition matching  
    900         function must be boolean. 
    901          
    902         @param function the Function to add to the factory 
    903         @raise TypeError if the function's identifier is already used or if the 
    904         function is non-boolean (when this is a Target or Condition factory) 
    905         ''' 
    906         id = function.functionId 
    907  
    908         # make sure this doesn't already exist 
    909         if id in self.functionMap: 
    910             raise TypeError("function %s already exists" % id) 
    911  
    912         # add to the superset factory 
    913         if self.superset != None: 
    914             self.superset.addFunction(function) 
    915  
    916         # Add to this factory 
    917         self.functionMap[id] = function 
    918      
    919          
    920     def addAbstractFunction(self, proxy, id): 
    921         '''Adds the abstract function proxy to the factory. This is used for 
    922         those functions which have state, or change behaviour (for instance 
    923         the standard map function, which changes its return type based on 
    924         how it is used).  
    925          
    926         @param proxy: the FunctionProxy to add to the factory 
    927         @param id: the function's identifier 
    928          
    929         @raise TypeError if the function's identifier is already used''' 
    930  
    931         # make sure this doesn't already exist 
    932         if id in self.functionMap: 
    933             raise TypeError("function already exists") 
    934  
    935         # add to the superset factory 
    936         if self.superset != None: 
    937             self.superset.addAbstractFunction(proxy, id) 
    938  
    939         # finally, add to this factory 
    940         functionMap[id] = proxy 
    941      
    942  
    943     def getSupportedFunctions(self):  
    944         '''Returns the function identifiers supported by this factory. 
    945          
    946         @return a list of strings''' 
    947      
    948         functions = self.functionMap.keys() 
    949  
    950         if self.superset != None: 
    951             functions += self.superset.getSupportedFunctions() 
    952  
    953         return functions 
    954      
    955  
    956     def createFunction(self, identity): 
    957         '''Tries to get an instance of the specified function. 
    958          
    959         @param identity the name of the function 
    960          
    961         @throws UnknownIdentifierException if the name isn't known 
    962         @throws FunctionTypeException if the name is known to map to an 
    963                                       abstract function, and should therefore 
    964                                       be created through createAbstractFunction 
    965         ''' 
    966         entry = self.functionMap.get(identity) 
    967         if entry is not None: 
    968             if isinstance(entry, Function):  
    969                 return entry 
    970             else: 
    971                 # this is actually a proxy, which means the other create 
    972                 # method should have been called 
    973                 raise FunctionTypeException("function is abstract")     
    974         else: 
    975             # we couldn't find a match 
    976             raise UnknownIdentifierException("functions of type %s are not " 
    977                                              "supported by this factory" %  
    978                                              identity)         
    979      
    980      
    981     def createAbstractFunction(identity, root): 
    982         '''Tries to get an instance of the specified abstract function. 
    983          
    984         @param identity the name of the function 
    985         @param root the DOM root containing info used to create the function 
    986         @param xpathVersion the version specified in the containing policy, or 
    987                             None if no version was specified 
    988          
    989         @throws UnknownIdentifierException if the name isn't known 
    990         @throws FunctionTypeException if the name is known to map to a 
    991                                       concrete function, and should therefore 
    992                                       be created through createFunction 
    993         @throws ParsingException if the function can't be created with the 
    994                                  given inputs''' 
    995      
    996         entry = self.functionMap.get(identity) 
    997         if entry is not None: 
    998             if isinstance(entry, FunctionProxy):  
    999                 try:  
    1000                     return entry.getInstance(root) 
    1001                  
    1002                 except Exception, e: 
    1003                     raise ParsingException("Couldn't create abstract function " 
    1004                                            "%s: %s" % identity, e)       
    1005             else: 
    1006                 # this is actually a concrete function, which means that 
    1007                 # the other create method should have been called 
    1008                 raise FunctionTypeException("function is concrete") 
    1009              
    1010         else: 
    1011             raise UnknownIdentifierException("Abstract functions of type %s " 
    1012                                              "are not supported by this " 
    1013                                              "factory" % identity) 
    1014  
    1015 getSupportedFunctions = lambda cls: [cls(i) for i in cls.supportedIdentifiers] 
    1016  
    1017 class StandardFunctionFactory(BaseFunctionFactory): 
    1018     '''This factory supports the standard set of functions specified in XACML 
    1019     1.0 and 1.1. It is the default factory used by the system, and imposes 
    1020     a singleton pattern insuring that there is only ever one instance of 
    1021     this class. 
    1022     <p> 
    1023     Note that because this supports only the standard functions, this 
    1024     factory does not allow the addition of any other functions. If you call 
    1025     addFunction on an instance of this class, an exception 
    1026     will be thrown. If you need a standard factory that is modifiable, 
    1027     you can either create a new BaseFunctionFactory (or some 
    1028     other implementation of FunctionFactory) populated with 
    1029     the standard functions from getStandardFunctions or 
    1030     you can use getNewFactoryProxy to get a proxy containing 
    1031     a new, modifiable set of factories.''' 
    1032  
    1033  
    1034     # the three singleton instances 
    1035     targetFactory = None 
    1036     conditionFactory = None 
    1037     generalFactory = None 
    1038  
    1039     # the three function sets/maps that we use internally 
    1040     targetFunctions = None 
    1041     conditionFunctions = None 
    1042     generalFunctions = None 
    1043  
    1044     targetAbstractFunctions = None 
    1045     conditionAbstractFunctions = None 
    1046     generalAbstractFunctions = None 
    1047  
    1048     # the set/map used by each singleton factory instance 
    1049     supportedFunctions = None 
    1050     supportedAbstractFunctions = None 
    1051  
    1052      
    1053     def __init__(self, supportedFunctions, supportedAbstractFunctions):  
    1054         '''Creates a new StandardFunctionFactory, making sure that the default 
    1055         maps are initialized correctly. Standard factories can't be modified, 
    1056         so there is no notion of supersetting since that's only used for 
    1057         correctly propagating new functions.''' 
    1058         super(StandardFunctionFactory, self).__init__( 
    1059                         supportedFunctions=supportedFunctions,  
    1060                         supportedAbstractFunctions=supportedAbstractFunctions) 
    1061  
    1062         self.supportedFunctions = supportedFunctions 
    1063         self.supportedAbstractFunctions = supportedAbstractFunctions 
    1064      
    1065     @classmethod 
    1066     def _initTargetFunctions(cls):  
    1067         '''Private initializer for the target functions. This is only ever 
    1068         called once.''' 
    1069         log.info("Initializing standard Target functions") 
    1070  
    1071         cls.targetFunctions = UniqList() 
    1072  
    1073         # add EqualFunction 
    1074         cls.targetFunctions.extend(getSupportedFunctions(EqualFunction)) 
    1075  
    1076         # add LogicalFunction 
    1077         cls.targetFunctions.extend(getSupportedFunctions(LogicalFunction)) 
    1078          
    1079         # add NOfFunction 
    1080         cls.targetFunctions.extend(getSupportedFunctions(NOfFunction)) 
    1081          
    1082         # add NotFunction 
    1083         cls.targetFunctions.extend(getSupportedFunctions(NotFunction)) 
    1084          
    1085         # add ComparisonFunction 
    1086         cls.targetFunctions.extend(getSupportedFunctions(ComparisonFunction)) 
    1087  
    1088         # add MatchFunction 
    1089         cls.targetFunctions.extend(getSupportedFunctions(MatchFunction)) 
    1090  
    1091         cls.targetAbstractFunctions = {} 
    1092      
    1093     @classmethod 
    1094     def _initConditionFunctions(cls):  
    1095         '''Private initializer for the condition functions. This is only ever 
    1096         called once.''' 
    1097         log.info("Initializing standard Condition functions") 
    1098  
    1099         if cls.targetFunctions is None: 
    1100             self._initTargetFunctions() 
    1101  
    1102         cls.conditionFunctions = cls.targetFunctions.copy() 
    1103  
    1104         # add condition functions from BagFunction 
    1105         conditionFunctions.extend(getSupportedFunctions(ConditionBagFunction)) 
    1106          
    1107         # add condition functions from SetFunction 
    1108         conditionFunctions.extend(getSupportedFunctions(ConditionSetFunction)) 
    1109          
    1110         # add condition functions from HigherOrderFunction 
    1111         conditionFunctions.extend(getSupportedFunctions(HigherOrderFunction)) 
    1112  
    1113         cls.conditionAbstractFunctions = cls.targetAbstractFunctions.copy() 
    1114      
    1115     @classmethod 
    1116     def _initGeneralFunctions(cls):      
    1117         '''Private initializer for the general functions. This is only ever 
    1118         called once.''' 
    1119      
    1120         log.info("Initializing standard General functions") 
    1121  
    1122         if cls.conditionFunctions is None: 
    1123             self._initConditionFunctions() 
    1124  
    1125         cls.generalFunctions = cls.conditionFunctions.copy() 
    1126  
    1127         # add AddFunction 
    1128         cls.generalFunctions.extend(getSupportedFunctions(AddFunction)) 
    1129              
    1130         # add SubtractFunction 
    1131         cls.generalFunctions.extend(getSupportedFunctions(SubtractFunction)) 
    1132              
    1133         # add MultiplyFunction 
    1134         cls.generalFunctions.extend(getSupportedFunctions(MultiplyFunction)) 
    1135              
    1136         # add DivideFunction 
    1137         cls.generalFunctions.extend(getSupportedFunctions(DivideFunction)) 
    1138              
    1139         # add ModFunction 
    1140         cls.generalFunctions.extend(getSupportedFunctions(ModFunction)) 
    1141          
    1142         # add AbsFunction 
    1143         cls.generalFunctions.extend(getSupportedFunctions(AbsFunction)) 
    1144              
    1145         # add RoundFunction 
    1146         cls.generalFunctions.extend(getSupportedFunctions(RoundFunction)) 
    1147              
    1148         # add FloorFunction 
    1149         cls.generalFunctions.extend(getSupportedFunctions(FloorFunction)) 
    1150          
    1151         # add DateMathFunction 
    1152         cls.generalFunctions.extend(getSupportedFunctions(DateMathFunction)) 
    1153              
    1154         # add general functions from BagFunction 
    1155         cls.generalFunctions.extend(getSupportedFunctions(GeneralBagFunction)) 
    1156              
    1157         # add NumericConvertFunction 
    1158         cls.generalFunctions.extend(getSupportedFunctions( 
    1159                                                     NumericConvertFunction)) 
    1160              
    1161         # add StringNormalizeFunction 
    1162         cls.generalFunctions.extend(getSupportedFunctions( 
    1163                                                     StringNormalizeFunction)) 
    1164          
    1165         # add general functions from SetFunction 
    1166         cls.generalFunctions.extend(getSupportedFunctions(GeneralSetFunction)) 
    1167              
    1168         cls.generalAbstractFunctions = cls.conditionAbstractFunctions.copy() 
    1169  
    1170         # Add the map function's proxy 
    1171         cls.generalAbstractFunctions[MapFunction.NAME_MAP] = MapFunctionProxy() 
    1172      
    1173     @classmethod  
    1174     def getTargetFactory(cls):  
    1175         '''Returns a FunctionFactory that will only provide those functions  
    1176         that are usable in Target matching. This method enforces a singleton 
    1177         model, meaning that this always returns the same instance, creating 
    1178         the factory if it hasn't been requested before. This is the default 
    1179         model used by the FunctionFactory, ensuring quick 
    1180         access to this factory. 
    1181          
    1182         @return a FunctionFactory for target functions''' 
    1183         if cls.targetFactory is None:  
    1184             if cls.targetFunctions is None: 
    1185                 cls._initTargetFunctions() 
    1186                  
    1187             if cls.targetFactory is None: 
    1188                 cls.targetFactory=cls(cls.targetFunctions, 
    1189                                       cls.targetAbstractFunctions) 
    1190          
    1191         return cls.targetFactory 
    1192  
    1193      
    1194     @classmethod 
    1195     def getConditionFactory(cls):  
    1196         '''Returns a FuntionFactory that will only provide those functions that 
    1197         are usable in the root of the Condition. These Functions are a 
    1198         superset of the Target functions. This method enforces a singleton 
    1199         model, meaning that this always returns the same instance, creating 
    1200         the factory if it hasn't been requested before. This is the default 
    1201         model used by the FunctionFactory, ensuring quick 
    1202         access to this factory. 
    1203      
    1204         @return a FunctionFactory for condition functions 
    1205         ''' 
    1206         if cls.conditionFactory is None: 
    1207             if cls.conditionFunctions is None: 
    1208                 cls._initConditionFunctions() 
    1209                  
    1210             if cls.conditionFactory is None: 
    1211                 cls.conditionFactory = cls(cls.conditionFunctions, 
    1212                                            cls.conditionAbstractFunctions)        
    1213  
    1214         return cls.conditionFactory 
    1215      
    1216  
    1217     @classmethod 
    1218     def getGeneralFactory(cls):  
    1219         '''Returns a FunctionFactory that provides access to all the functions. 
    1220         These Functions are a superset of the Condition functions. This method 
    1221         enforces a singleton model, meaning that this always returns the same 
    1222         instance, creating the factory if it hasn't been requested before. 
    1223         This is the default model used by the FunctionFactory, 
    1224         ensuring quick access to this factory. 
    1225          
    1226         @return a FunctionFactory for all functions''' 
    1227      
    1228         if cls.generalFactory is None: 
    1229             if cls.generalFunctions is None: 
    1230                 cls._initGeneralFunctions() 
    1231                  
    1232                 cls.generalFactory = cls(cls.generalFunctions, 
    1233                                          cls.generalAbstractFunctions) 
    1234                  
    1235         return cls.generalFactory 
    1236  
    1237  
    1238     def getStandardFunctions(self): 
    1239         '''Returns the set of functions that this standard factory supports. 
    1240          
    1241         @return a Set of Functions''' 
    1242         return tuple(self.supportedFunctions.keys()) 
    1243          
    1244     def getStandardAbstractFunctions(self): 
    1245         '''Returns the set of abstract functions that this standard factory 
    1246         supports as a mapping of identifier to proxy. 
    1247          
    1248         @return a Map mapping URIs to FunctionProxys''' 
    1249         return tuple(self.supportedAbstractFunctions.keys()) 
    1250      
    1251      
    1252     @classmethod 
    1253     def getNewFactoryProxy(cls):  
    1254         '''A convenience method that returns a proxy containing newly created 
    1255         instances of BaseFunctionFactorys that are correctly 
    1256         supersetted and contain the standard functions and abstract functions. 
    1257         These factories allow adding support for new functions. 
    1258          
    1259         @return a new proxy containing new factories supporting the standard 
    1260         functions''' 
    1261          
    1262         general = cls.getGeneralFactory() 
    1263              
    1264         newGeneral=BaseFunctionFactory(general.getStandardFunctions(), 
    1265                                        general.getStandardAbstractFunctions()) 
    1266  
    1267         condition = cls.getConditionFactory() 
    1268          
    1269         newCondition = BaseFunctionFactory(newGeneral, 
    1270                                     condition.getStandardFunctions(), 
    1271                                     condition.getStandardAbstractFunctions()) 
    1272  
    1273         target = cls.getTargetFactory() 
    1274         newTarget = BaseFunctionFactory(newCondition, 
    1275                                     target.getStandardFunctions(), 
    1276                                     target.getStandardAbstractFunctions()) 
    1277  
    1278         return BasicFunctionFactoryProxy(newTarget, newCondition, newGeneral) 
    1279      
    1280     def addFunction(self, function): 
    1281         '''Always throws an exception, since support for new functions may not  
    1282         be added to a standard factory. 
    1283          
    1284         @param function the Function to add to the factory        
    1285         @raise NotImplementedError''' 
    1286      
    1287         raise NotImplementedError("a standard factory cannot support new " 
    1288                                   "functions") 
    1289      
    1290      
    1291     def addAbstractFunction(self, proxy, identity): 
    1292         '''Always throws an exception, since support for new functions may not  
    1293         be added to a standard factory. 
    1294          
    1295         @param proxy the FunctionProxy to add to the factory 
    1296         @param identity the function's identifier 
    1297          
    1298         @raise NotImplementedError always''' 
    1299         raise NotImplementedError("a standard factory cannot support new " 
    1300                                   "functions") 
Note: See TracChangeset for help on using the changeset viewer.