2 # Thierry Parmentelat - INRIA
5 # just a placeholder for storing accessor-related tag checkers
6 # this is filled by the accessors factory
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
12 from PLC.Logger import logger
14 from PLC.TagTypes import TagTypes, TagType
15 from PLC.Roles import Roles, Role
18 class Accessor(object):
20 This is a placeholder for storing accessor-related tag checkers.
21 Methods in this class are defined by the accessors factory
23 Class is implemented as a singleton, so we can cache results over time
30 def __init__(self, api):
34 self.hash_name_to_role = {role['name']: role for role in Roles(api)}
36 def has_cache(self, tagname):
37 return tagname in self.cache
39 def get_cache(self, tagname):
40 return self.cache[tagname]
42 def set_cache(self, tagname, tag_type):
43 self.cache[tagname] = tag_type
45 def locate_or_create_tag(self, tagname, category,
46 description, roles, enforce=False):
47 "search tag type from tagname & create if needed"
50 if self.has_cache(tagname):
51 return self.get_cache(tagname)
53 tag_types = TagTypes(self.api, {'tagname': tagname})
55 tag_type = tag_types[0]
56 # enforce should only be set by
57 # 'service plc start accessors' sequence
60 tag_type.update({'category': category,
61 'description': description})
63 roles_to_add = set(roles).difference(set(tag_type['roles']))
64 for rolename in roles_to_add:
65 tag_type.add_role(self.hash_name_to_role[rolename])
66 roles_to_delete = set(tag_type['roles']). difference(set(roles))
67 for rolename in roles_to_delete:
68 tag_type.remove_role(self.hash_name_to_role[rolename])
71 "WARNING, Could not enforce tag type, tagname={}\n"
76 # not found: create it
77 tag_type_fields = {'tagname': tagname,
79 'description': description}
80 tag_type = TagType(self.api, tag_type_fields)
84 role_obj = Roles(self.api, role)[0]
85 tag_type.add_role(role_obj)
87 # xxx todo find a more appropriate way of notifying this
88 logger.exception("Accessor.locate_or_create_tag: "
89 "Could not add role {} to tag_type {}"
90 .format(role,tagname))
91 self.set_cache(tagname, tag_type)
94 # a locator is a function that retrieves - or creates - a tag_type instance
96 def register_tag_locator(name, tag_locator):
97 Accessor.tag_locators[name] = tag_locator
100 def retrieve_tag_locator(name):
101 return Accessor.tag_locators[name]
103 # this is designed to be part of the 'service plc start' sequence
104 # it ensures the creation of all the tagtypes defined
105 # in the various accessors, and enforces consistency to the DB
106 # it's not easy to have define_accessors do this because at
107 # load-time as we do not have an instance of API yet
108 def run_all_tag_locators(self):
109 for (name, tag_locator) in list(Accessor.tag_locators.items()):
110 tag_locator(self, enforce=True)
113 # make it a singleton so we can cache stuff in there over time
114 def AccessorSingleton(api):
115 if not Accessor._instance:
116 Accessor._instance = Accessor(api)
117 return Accessor._instance