]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/python/oils/utils/idl.py
logging error for now instead of throwing exception
[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.oilsParseIDL()
11 >>> # 'bre' is a network registry hint, or class ID in the IDL file
12 ... print oils.utils.idl.oilsGetIDLParser().IDLObject['bre'].tablename
13 biblio.record_entry
14 """
15 import osrf.net_obj
16 import osrf.log, osrf.set, osrf.ex
17
18 import sys, string, xml.dom.minidom
19 from oils.const import OILS_NS_OBJ, OILS_NS_PERSIST, OILS_NS_REPORTER
20
21 __global_parser = None
22
23 def oilsParseIDL():
24     global __global_parser
25     if __global_parser: return # no need to re-parse the IDL
26     idlParser = oilsIDLParser();
27     idlParser.setIDL(osrf.set.get('IDL'))
28     idlParser.parseIDL()
29     __global_parser = idlParser
30
31 def oilsGetIDLParser():
32     global __global_parser
33     return __global_parser
34
35 class oilsIDLParser(object):
36
37     def __init__(self):
38         self.IDLObject = {}
39
40     def setIDL(self, file):
41         osrf.log.log_info("setting IDL file to " + str(file))
42         self.idlFile = file
43
44     def __getAttr(self, node, name, ns=None):
45         """ Find the attribute value on a given node 
46             Namespace is ignored for now.. 
47             not sure if minidom has namespace support.
48             """
49         attr = node.attributes.get(name)
50         if attr:
51             return attr.nodeValue
52         return None
53
54     def parseIDL(self):
55         """Parses the IDL file and builds class objects"""
56
57         doc = xml.dom.minidom.parse(self.idlFile)
58         root = doc.childNodes[0]
59
60         for child in root.childNodes:
61         
62             if child.nodeType == child.ELEMENT_NODE:
63         
64                 # -----------------------------------------------------------------------
65                 # 'child' is the main class node for a fieldmapper class.
66                 # It has 'fields' and 'links' nodes as children.
67                 # -----------------------------------------------------------------------
68
69                 obj = IDLClass(
70                     self.__getAttr(child, 'id'),
71                     controller = self.__getAttr(child, 'controller'),
72                     fieldmapper = self.__getAttr(child, 'oils_obj:fieldmapper', OILS_NS_OBJ),
73                     virtual = self.__getAttr(child, 'oils_persist:virtual', OILS_NS_PERSIST),
74                     label = self.__getAttr(child, 'reporter:label', OILS_NS_REPORTER),
75                     tablename = self.__getAttr(child, 'oils_persist:tablename', OILS_NS_REPORTER),
76                 )
77
78
79                 self.IDLObject[obj.name] = obj
80
81                 fields = [f for f in child.childNodes if f.nodeName == 'fields']
82                 links = [f for f in child.childNodes if f.nodeName == 'links']
83                 keys = self.parseFields(obj, fields[0])
84                 if len(links) > 0:
85                     self.parse_links(obj, links[0])
86
87                 osrf.net_obj.register_hint(obj.name, keys, 'array')
88
89         doc.unlink()
90
91
92     def parse_links(self, idlobj, links):
93
94         for link in [l for l in links.childNodes if l.nodeName == 'link']:
95             obj = IDLLink(
96                 field = idlobj.get_field(self.__getAttr(link, 'field')),
97                 rel_type = self.__getAttr(link, 'rel_type'),
98                 key = self.__getAttr(link, 'key'),
99                 map = self.__getAttr(link, 'map')
100             )
101             idlobj.links.append(obj)
102
103
104     def parseFields(self, idlobj, fields):
105         """Takes the fields node and parses the included field elements"""
106
107         keys = []
108
109         idlobj.primary = self.__getAttr(fields, 'oils_persist:primary', OILS_NS_PERSIST)
110         idlobj.sequence =  self.__getAttr(fields, 'oils_persist:sequence', OILS_NS_PERSIST)
111
112         # pre-flesh the array of keys to accomodate random index insertions
113         for field in fields.childNodes:
114             if field.nodeType == field.ELEMENT_NODE:
115                 keys.append(None)
116         
117         for field in [l for l in fields.childNodes if l.nodeName == 'field']:
118
119             obj = IDLField(
120                 idlobj,
121                 name = self.__getAttr(field, 'name'),
122                 position = int(self.__getAttr(field, 'oils_obj:array_position', OILS_NS_OBJ)),
123                 virtual = self.__getAttr(field, 'oils_persist:virtual', OILS_NS_PERSIST),
124                 label = self.__getAttr(field, 'reporter:label', OILS_NS_REPORTER),
125                 rpt_datatype = self.__getAttr(field, 'reporter:datatype', OILS_NS_REPORTER),
126                 rpt_select = self.__getAttr(field, 'reporter:selector', OILS_NS_REPORTER),
127                 primitive = self.__getAttr(field, 'oils_persist:primitive', OILS_NS_PERSIST)
128             )
129
130             try:
131                 keys[obj.position] = obj.name
132             except Exception, e:
133                 osrf.log.log_error("parseFields(): position out of range.  pos=%d : key-size=%d" % (obj.position, len(keys)))
134                 raise e
135
136             idlobj.fields.append(obj)
137
138         return keys
139
140
141 class IDLException(osrf.ex.OSRFException):
142     pass
143
144 class IDLClass(object):
145     def __init__(self, name, **kwargs):
146         self.name = name
147         self.controller = kwargs.get('controller')
148         self.fieldmapper = kwargs.get('fieldmapper')
149         self.virtual = kwargs.get('virtual')
150         self.label = kwargs.get('label')
151         self.tablename = kwargs.get('tablename')
152         self.primary = kwargs.get('primary')
153         self.sequence = kwargs.get('sequence')
154         self.fields = []
155         self.links = []
156
157         if self.virtual and self.virtual.lower() == 'true':
158             self.virtul = True
159         else:
160             self.virtual = False
161
162     def get_field(self, field_name):
163         try:
164             return [f for f in self.fields if f.name == field_name][0]
165         except:
166             msg = "No field '%s' in IDL class '%s'" % (field_name, self.name)
167             osrf.log.log_error(msg)
168             #raise IDLException(msg)
169
170 class IDLField(object):
171     def __init__(self, idl_class, **kwargs):
172         '''
173             @param idl_class The IDLClass object which owns this field
174         '''
175         self.idl_class = idl_class
176         self.name = kwargs.get('name')
177         self.label = kwargs.get('label')
178         self.rpt_datatype = kwargs.get('rpt_datatype')
179         self.rpt_select = kwargs.get('rpt_select')
180         self.primitive = kwargs.get('primitive')
181         self.virtual = kwargs.get('virtual')
182         self.position = kwargs.get('position')
183
184         if self.virtual and self.virtual.lower() == 'true':
185             self.virtul = True
186         else:
187             self.virtual = False
188
189
190 class IDLLink(object):
191     def __init__(self, field, **kwargs):
192         '''
193             @param field The IDLField object this link references
194         '''
195         self.field = field
196         self.rel_type = kwargs.get('rel_type')
197         self.key = kwargs.get('key')
198         self.map = kwargs.get('map')
199
200