2 Parses an Evergreen fieldmapper IDL file and builds a global registry of
3 objects representing that IDL.
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
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
19 class IDLException(osrf.ex.OSRFException):
22 class IDLParser(object):
24 # ------------------------------------------------------------
25 # static methods and variables for managing a global parser
26 # ------------------------------------------------------------
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
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:
43 parser.set_IDL(osrf.set.get('IDL'))
45 IDLParser._global_parser = parser
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
53 return IDLParser.get_parser().IDLObject[class_name]
55 # ------------------------------------------------------------
57 # ------------------------------------------------------------
62 def set_IDL(self, file):
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.
70 attr = node.attributes.get(name)
76 """Parses the IDL file and builds class, field, and link objects"""
78 doc = xml.dom.minidom.parse(self.idlFile)
79 root = doc.childNodes[0]
81 for child in root.childNodes:
83 if child.nodeType == child.ELEMENT_NODE:
85 # -----------------------------------------------------------------------
86 # 'child' is the main class node for a fieldmapper class.
87 # It has 'fields' and 'links' nodes as children.
88 # -----------------------------------------------------------------------
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),
100 self.IDLObject[obj.name] = obj
102 fields = [f for f in child.childNodes if f.nodeName == 'fields']
103 links = [f for f in child.childNodes if f.nodeName == 'links']
105 keys = self.parse_fields(obj, fields[0])
107 self.parse_links(obj, links[0])
109 osrf.net_obj.register_hint(obj.name, keys, 'array')
114 def parse_links(self, idlobj, links):
116 for link in [l for l in links.childNodes if l.nodeName == 'link']:
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')
123 idlobj.links.append(obj)
126 def parse_fields(self, idlobj, fields):
127 """Takes the fields node and parses the included field elements"""
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)
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:
139 for field in [l for l in fields.childNodes if l.nodeName == 'field']:
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)
153 keys[obj.position] = obj.name
155 osrf.log.log_warn("parse_fields(): position out of range. pos=%d : key-size=%d" % (obj.position, len(keys)))
158 idlobj.fields.append(obj)
164 class IDLClass(object):
165 def __init__(self, name, **kwargs):
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')
177 if self.virtual and self.virtual.lower() == 'true':
182 def get_field(self, field_name):
184 return [f for f in self.fields if f.name == field_name][0]
186 msg = "No field '%s' in IDL class '%s'" % (field_name, self.name)
187 osrf.log.log_error(msg)
188 #raise IDLException(msg)
190 class IDLField(object):
191 def __init__(self, idl_class, **kwargs):
193 @param idl_class The IDLClass object which owns this field
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')
204 if self.virtual and self.virtual.lower() == 'true':
210 class IDLLink(object):
211 def __init__(self, field, **kwargs):
213 @param field The IDLField object this link references
216 self.rel_type = kwargs.get('rel_type')
217 self.key = kwargs.get('key')
218 self.map = kwargs.get('map')