7352f471b889953495f0316070b10ef226281e23
[plcapi.git] / PLC / Accessor.py
1 #
2 # Thierry Parmentelat - INRIA
3 #
4 #
5 # just a placeholder for storing accessor-related tag checkers
6 # this is filled by the accessors factory
7 #
8 # NOTE. If you ever come to manually delete a TagType that was created
9 # by the Factory, you need to restart your python instance / web server
10 # as the cached information then becomes wrong
11
12 from PLC.Logger import logger
13
14 from PLC.TagTypes import TagTypes, TagType
15 from PLC.Roles import Roles, Role
16
17 # implementation
18 class Accessor (object) :
19     """This is placeholder for storing accessor-related tag checkers.
20 Methods in this class are defined by the accessors factory
21
22 This is implemented as a singleton, so we can cache results over time"""
23
24     _instance = None
25
26     tag_locators={}
27
28     def __init__ (self, api):
29         self.api=api
30         # 'tagname'=>'tag_id'
31         self.cache={}
32         self.hash_name_to_role=dict ( [ (role['name'],role) for role in Roles(api)] )
33
34     def has_cache (self,tagname): return self.cache.has_key(tagname)
35     def get_cache (self,tagname): return self.cache[tagname]
36     def set_cache (self,tagname,tag_type): self.cache[tagname]=tag_type
37
38     def locate_or_create_tag (self, tagname, category, description, roles, enforce=False):
39         "search tag type from tagname & create if needed"
40
41         # cached ?
42         if self.has_cache (tagname):
43             return self.get_cache(tagname)
44         # search
45         tag_types = TagTypes (self.api, {'tagname':tagname})
46         if tag_types:
47             tag_type = tag_types[0]
48             # enforce should only be set by the 'service plc start accessors' sequence
49             if enforce:
50                 try:
51                     tag_type.update({'category':category,'description':description})
52                     tag_type.sync()
53                     roles_to_add = set(roles).difference(set(tag_type['roles']))
54                     for rolename in roles_to_add:
55                         tag_type.add_role(self.hash_name_to_role[rolename])
56                     roles_to_delete = set(tag_type['roles']).difference(set(roles))
57                     for rolename in roles_to_delete:
58                         tag_type.remove_role(self.hash_name_to_role[rolename])
59                 except:
60                     logger.exception("WARNING, Could not enforce tag type, tagname={}\n"
61                                      .format(tagname))
62
63                     
64         else:
65             # not found: create it
66             tag_type_fields = {'tagname':tagname,
67                                'category' :  category,
68                                'description' : description}
69             tag_type = TagType (self.api, tag_type_fields)
70             tag_type.sync()
71             for role in roles:
72                 try: 
73                     role_obj=Roles (self.api, role)[0]
74                     tag_type.add_role(role_obj)
75                 except:
76                     # xxx todo find a more appropriate way of notifying this
77                     logger.exception("Accessor.locate_or_create_tag: "
78                                      "Could not add role {} to tag_type {}"
79                                      .format(role,tagname))
80         self.set_cache(tagname,tag_type)
81         return tag_type
82
83     # a locator is a function that retrieves - or creates - a tag_type instance
84     @staticmethod
85     def register_tag_locator (name, tag_locator):
86         Accessor.tag_locators[name]=tag_locator
87
88     @staticmethod
89     def retrieve_tag_locator (name):
90         return Accessor.tag_locators[name]
91     
92     # this is designed to be part of the 'service plc start' sequence
93     # it ensures the creation of all the tagtypes defined 
94     # in the various accessors, and enforces consistency to the DB
95     # it's not easy to have define_accessors do this because at
96     # load-time as we do not have an instance of API yet
97     def run_all_tag_locators (self):
98         for (name, tag_locator) in Accessor.tag_locators.items():
99             tag_locator(self,enforce=True)
100
101 ####################
102 # make it a singleton so we can cache stuff in there over time
103 def AccessorSingleton (api):
104     if not Accessor._instance:
105         Accessor._instance = Accessor(api)
106     return Accessor._instance