]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/python/oils/utils/idl.py
def3b2452e488dbcb882d3fd71e9ba0a72a8754f
[Evergreen.git] / Open-ILS / src / python / oils / utils / idl.py
1 """
2 Parses an Evergreen fieldmapper IDL file and builds a global registry of
3 objects representing that IDL.
4
5 Typical usage:
6
7 >>> import osrf.system
8 >>> import oils.utils.idl
9 >>> osrf.system.connect('/openils/conf/opensrf_core.xml', 'config.opensrf')
10 >>> oils.utils.idl.IDLParser.parse()
11 >>> # 'bre' is a network registry hint, or class ID in the IDL file
12 ... print oils.utils.idl.IDLParser.get_class('bre').tablename
13 biblio.record_entry
14 """
15 import sys, string, xml.dom.minidom
16 import osrf.net_obj, osrf.log, osrf.set, osrf.ex
17 from oils.const import OILS_NS_OBJ, OILS_NS_PERSIST, OILS_NS_REPORTER
18
19 class IDLException(osrf.ex.OSRFException):
20     pass
21
22 class IDLParser(object):
23
24     # ------------------------------------------------------------
25     # static methods and variables for managing a global parser
26     # ------------------------------------------------------------
27     _global_parser = None
28
29     @staticmethod
30     def get_parser():
31         ''' Returns the global IDL parser object '''
32         if IDLParser._global_parser is None:
33             raise IDLException("IDL has not been parsed")
34         return IDLParser._global_parser
35
36     @staticmethod
37     def parse():
38         ''' Finds the path to the IDL file from the OpenSRF settings 
39             server, parses the IDL file, and uses the parsed data as
40             the global IDL repository '''
41         if IDLParser._global_parser is None:
42             parser = IDLParser()
43             parser.set_IDL(osrf.set.get('IDL'))
44             parser.parse_IDL()
45             IDLParser._global_parser = parser
46
47     @staticmethod
48     def get_class(class_name):
49         ''' Returns the IDLClass object with the given 
50             network hint / IDL class name.
51             @param The class ID from the IDL
52             '''
53         return IDLParser.get_parser().IDLObject[class_name]
54
55     # ------------------------------------------------------------
56     # instance methods
57     # ------------------------------------------------------------
58
59     def __init__(self):
60         self.IDLObject = {}
61
62     def set_IDL(self, file):
63         self.idlFile = file
64
65     def _get_attr(self, node, name, ns=None):
66         """ Find the attribute value on a given node 
67             Namespace is ignored for now.. 
68             not sure if minidom has namespace support.
69             """
70         attr = node.attributes.get(name)
71         if attr:
72             return attr.nodeValue
73         return None
74
75     def parse_IDL(self):
76         """Parses the IDL file and builds class, field, and link objects"""
77
78         doc = xml.dom.minidom.parse(self.idlFile)
79         root = doc.childNodes[0]
80
81         for child in root.childNodes:
82         
83             if child.nodeType == child.ELEMENT_NODE:
84         
85                 # -----------------------------------------------------------------------
86                 # 'child' is the main class node for a fieldmapper class.
87                 # It has 'fields' and 'links' nodes as children.
88                 # -----------------------------------------------------------------------
89
90                 obj = IDLClass(
91                     self._get_attr(child, 'id'),
92                     controller = self._get_attr(child, 'controller'),
93                     fieldmapper = self._get_attr(child, 'oils_obj:fieldmapper', OILS_NS_OBJ),
94                     virtual = self._get_attr(child, 'oils_persist:virtual', OILS_NS_PERSIST),
95                     label = self._get_attr(child, 'reporter:label', OILS_NS_REPORTER),
96                     tablename = self._get_attr(child, 'oils_persist:tablename', OILS_NS_REPORTER),
97                 )
98
99
100                 self.IDLObject[obj.name] = obj
101
102                 fields = [f for f in child.childNodes if f.nodeName == 'fields']
103                 links = [f for f in child.childNodes if f.nodeName == 'links']
104
105                 keys = self.parse_fields(obj, fields[0])
106                 if len(links) > 0:
107                     self.parse_links(obj, links[0])
108
109                 osrf.net_obj.register_hint(obj.name, keys, 'array')
110
111         doc.unlink()
112
113
114     def parse_links(self, idlobj, links):
115
116         for link in [l for l in links.childNodes if l.nodeName == 'link']:
117             obj = IDLLink(
118                 field = idlobj.get_field(self._get_attr(link, 'field')),
119                 rel_type = self._get_attr(link, 'rel_type'),
120                 key = self._get_attr(link, 'key'),
121                 map = self._get_attr(link, 'map')
122             )
123             idlobj.links.append(obj)
124
125
126     def parse_fields(self, idlobj, fields):
127         """Takes the fields node and parses the included field elements"""
128
129         keys = []
130
131         idlobj.primary = self._get_attr(fields, 'oils_persist:primary', OILS_NS_PERSIST)
132         idlobj.sequence =  self._get_attr(fields, 'oils_persist:sequence', OILS_NS_PERSIST)
133
134         # pre-flesh the array of keys to accomodate random index insertions
135         for field in fields.childNodes:
136             if field.nodeType == field.ELEMENT_NODE:
137                 keys.append(None)
138         
139         for field in [l for l in fields.childNodes if l.nodeName == 'field']:
140
141             obj = IDLField(
142                 idlobj,
143                 name = self._get_attr(field, 'name'),
144                 position = int(self._get_attr(field, 'oils_obj:array_position', OILS_NS_OBJ)),
145                 virtual = self._get_attr(field, 'oils_persist:virtual', OILS_NS_PERSIST),
146                 label = self._get_attr(field, 'reporter:label', OILS_NS_REPORTER),
147                 rpt_datatype = self._get_attr(field, 'reporter:datatype', OILS_NS_REPORTER),
148                 rpt_select = self._get_attr(field, 'reporter:selector', OILS_NS_REPORTER),
149                 primitive = self._get_attr(field, 'oils_persist:primitive', OILS_NS_PERSIST)
150             )
151
152             try:
153                 keys[obj.position] = obj.name
154             except Exception, e:
155                 osrf.log.log_error("parse_fields(): position out of range.  pos=%d : key-size=%d" % (obj.position, len(keys)))
156                 raise e
157
158             idlobj.fields.append(obj)
159
160         return keys
161
162
163
164 class IDLClass(object):
165     def __init__(self, name, **kwargs):
166         self.name = name
167         self.controller = kwargs.get('controller')
168         self.fieldmapper = kwargs.get('fieldmapper')
169         self.virtual = kwargs.get('virtual')
170         self.label = kwargs.get('label')
171         self.tablename = kwargs.get('tablename')
172         self.primary = kwargs.get('primary')
173         self.sequence = kwargs.get('sequence')
174         self.fields = []
175         self.links = []
176
177         if self.virtual and self.virtual.lower() == 'true':
178             self.virtual = True
179         else:
180             self.virtual = False
181
182     def get_field(self, field_name):
183         try:
184             return [f for f in self.fields if f.name == field_name][0]
185         except:
186             msg = "No field '%s' in IDL class '%s'" % (field_name, self.name)
187             osrf.log.log_warn(msg)
188             #raise IDLException(msg)
189
190 class IDLField(object):
191     def __init__(self, idl_class, **kwargs):
192         '''
193             @param idl_class The IDLClass object which owns this field
194         '''
195         self.idl_class = idl_class
196         self.name = kwargs.get('name')
197         self.label = kwargs.get('label')
198         self.rpt_datatype = kwargs.get('rpt_datatype')
199         self.rpt_select = kwargs.get('rpt_select')
200         self.primitive = kwargs.get('primitive')
201         self.virtual = kwargs.get('virtual')
202         self.position = kwargs.get('position')
203
204         if self.virtual and self.virtual.lower() == 'true':
205             self.virtual = True
206         else:
207             self.virtual = False
208
209
210 class IDLLink(object):
211     def __init__(self, field, **kwargs):
212         '''
213             @param field The IDLField object this link references
214         '''
215         self.field = field
216         self.rel_type = kwargs.get('rel_type')
217         self.key = kwargs.get('key')
218         self.map = kwargs.get('map')
219
220