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, osrf.ses
17 import osrf.net_obj, osrf.log, osrf.ex, osrf.ses
18 from oils.const import OILS_NS_OBJ, OILS_NS_PERSIST, OILS_NS_REPORTER, OILS_APP_ACTOR
20 class IDLException(osrf.ex.OSRFException):
23 class IDLParser(object):
25 # ------------------------------------------------------------
26 # static methods and variables for managing a global parser
27 # ------------------------------------------------------------
32 ''' Returns the global IDL parser object '''
33 if IDLParser._global_parser is None:
34 raise IDLException("IDL has not been parsed")
35 return IDLParser._global_parser
39 ''' Finds the path to the IDL file from the OpenSRF settings
40 server, parses the IDL file, and uses the parsed data as
41 the global IDL repository '''
42 if IDLParser._global_parser is None:
44 idl_path = osrf.ses.ClientSession.atomic_request(
45 OILS_APP_ACTOR, 'opensrf.open-ils.fetch_idl.file')
46 parser.set_IDL(idl_path)
48 IDLParser._global_parser = parser
51 def get_class(class_name):
52 ''' Returns the IDLClass object with the given
53 network hint / IDL class name.
54 @param The class ID from the IDL
56 return IDLParser.get_parser().IDLObject[class_name]
58 # ------------------------------------------------------------
60 # ------------------------------------------------------------
65 def set_IDL(self, file):
68 def _get_attr(self, node, name, ns=None):
69 """ Find the attribute value on a given node
70 Namespace is ignored for now..
71 not sure if minidom has namespace support.
73 attr = node.attributes.get(name)
79 """Parses the IDL file and builds class, field, and link objects"""
81 doc = xml.dom.minidom.parse(self.idlFile)
82 root = doc.documentElement
84 for child in root.childNodes:
86 if child.nodeType == child.ELEMENT_NODE:
88 # -----------------------------------------------------------------------
89 # 'child' is the main class node for a fieldmapper class.
90 # It has 'fields' and 'links' nodes as children.
91 # -----------------------------------------------------------------------
94 self._get_attr(child, 'id'),
95 controller = self._get_attr(child, 'controller'),
96 fieldmapper = self._get_attr(child, 'oils_obj:fieldmapper', OILS_NS_OBJ),
97 virtual = self._get_attr(child, 'oils_persist:virtual', OILS_NS_PERSIST),
98 label = self._get_attr(child, 'reporter:label', OILS_NS_REPORTER),
99 tablename = self._get_attr(child, 'oils_persist:tablename', OILS_NS_REPORTER),
103 self.IDLObject[obj.name] = obj
105 fields = [f for f in child.childNodes if f.nodeName == 'fields']
106 links = [f for f in child.childNodes if f.nodeName == 'links']
108 keys = self.parse_fields(obj, fields[0])
110 self.parse_links(obj, links[0])
112 osrf.net_obj.register_hint(obj.name, keys, 'array')
117 def parse_links(self, idlobj, links):
119 for link in [l for l in links.childNodes if l.nodeName == 'link']:
121 field = idlobj.get_field(self._get_attr(link, 'field')),
122 rel_type = self._get_attr(link, 'rel_type'),
123 key = self._get_attr(link, 'key'),
124 map = self._get_attr(link, 'map')
126 idlobj.links.append(obj)
129 def parse_fields(self, idlobj, fields):
130 """Takes the fields node and parses the included field elements"""
134 idlobj.primary = self._get_attr(fields, 'oils_persist:primary', OILS_NS_PERSIST)
135 idlobj.sequence = self._get_attr(fields, 'oils_persist:sequence', OILS_NS_PERSIST)
137 # pre-flesh the array of keys to accomodate random index insertions
138 for field in fields.childNodes:
139 if field.nodeType == field.ELEMENT_NODE:
142 for field in [l for l in fields.childNodes if l.nodeName == 'field']:
146 name = self._get_attr(field, 'name'),
147 position = int(self._get_attr(field, 'oils_obj:array_position', OILS_NS_OBJ)),
148 virtual = self._get_attr(field, 'oils_persist:virtual', OILS_NS_PERSIST),
149 label = self._get_attr(field, 'reporter:label', OILS_NS_REPORTER),
150 rpt_datatype = self._get_attr(field, 'reporter:datatype', OILS_NS_REPORTER),
151 rpt_select = self._get_attr(field, 'reporter:selector', OILS_NS_REPORTER),
152 primitive = self._get_attr(field, 'oils_persist:primitive', OILS_NS_PERSIST)
156 keys[obj.position] = obj.name
158 osrf.log.log_error("parse_fields(): position out of range. pos=%d : key-size=%d" % (obj.position, len(keys)))
161 idlobj.fields.append(obj)
167 class IDLClass(object):
168 def __init__(self, name, **kwargs):
170 self.controller = kwargs.get('controller')
171 self.fieldmapper = kwargs.get('fieldmapper')
172 self.virtual = kwargs.get('virtual')
173 self.label = kwargs.get('label')
174 self.tablename = kwargs.get('tablename')
175 self.primary = kwargs.get('primary')
176 self.sequence = kwargs.get('sequence')
180 if self.virtual and self.virtual.lower() == 'true':
185 def get_field(self, field_name):
187 return [f for f in self.fields if f.name == field_name][0]
189 msg = "No field '%s' in IDL class '%s'" % (field_name, self.name)
190 osrf.log.log_warn(msg)
191 #raise IDLException(msg)
193 class IDLField(object):
194 def __init__(self, idl_class, **kwargs):
196 @param idl_class The IDLClass object which owns this field
198 self.idl_class = idl_class
199 self.name = kwargs.get('name')
200 self.label = kwargs.get('label')
201 self.rpt_datatype = kwargs.get('rpt_datatype')
202 self.rpt_select = kwargs.get('rpt_select')
203 self.primitive = kwargs.get('primitive')
204 self.virtual = kwargs.get('virtual')
205 self.position = kwargs.get('position')
207 if self.virtual and self.virtual.lower() == 'true':
213 class IDLLink(object):
214 def __init__(self, field, **kwargs):
216 @param field The IDLField object this link references
219 self.rel_type = kwargs.get('rel_type')
220 self.key = kwargs.get('key')
221 self.map = kwargs.get('map')