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 # in case we're calling parse_IDL directly
82 if not IDLParser._global_parser:
83 IDLParser._global_parser = self
85 doc = xml.dom.minidom.parse(self.idlFile)
86 root = doc.documentElement
88 for child in root.childNodes:
90 if child.nodeType == child.ELEMENT_NODE and child.nodeName == 'class':
92 # -----------------------------------------------------------------------
93 # 'child' is the main class node for a fieldmapper class.
94 # It has 'fields' and 'links' nodes as children.
95 # -----------------------------------------------------------------------
98 self._get_attr(child, 'id'),
99 controller = self._get_attr(child, 'controller'),
100 fieldmapper = self._get_attr(child, 'oils_obj:fieldmapper', OILS_NS_OBJ),
101 virtual = self._get_attr(child, 'oils_persist:virtual', OILS_NS_PERSIST),
102 label = self._get_attr(child, 'reporter:label', OILS_NS_REPORTER),
103 tablename = self._get_attr(child, 'oils_persist:tablename', OILS_NS_REPORTER),
107 self.IDLObject[obj.name] = obj
109 fields = [f for f in child.childNodes if f.nodeName == 'fields']
110 links = [f for f in child.childNodes if f.nodeName == 'links']
112 fields = self.parse_fields(obj, fields[0])
114 self.parse_links(obj, links[0])
116 osrf.net_obj.register_hint(obj.name, [f.name for f in fields], 'array')
121 def parse_links(self, idlobj, links):
123 for link in [l for l in links.childNodes if l.nodeName == 'link']:
125 field = idlobj.get_field(self._get_attr(link, 'field')),
126 rel_type = self._get_attr(link, 'rel_type'),
127 key = self._get_attr(link, 'key'),
128 map = self._get_attr(link, 'map')
130 idlobj.links.append(obj)
133 def parse_fields(self, idlobj, fields):
134 """Takes the fields node and parses the included field elements"""
136 idlobj.primary = self._get_attr(fields, 'oils_persist:primary', OILS_NS_PERSIST)
137 idlobj.sequence = self._get_attr(fields, 'oils_persist:sequence', OILS_NS_PERSIST)
140 for field in [l for l in fields.childNodes if l.nodeName == 'field']:
142 name = self._get_attr(field, 'name')
144 if name in ['isnew', 'ischanged', 'isdeleted']:
151 virtual = self._get_attr(field, 'oils_persist:virtual', OILS_NS_PERSIST),
152 label = self._get_attr(field, 'reporter:label', OILS_NS_REPORTER),
153 rpt_datatype = self._get_attr(field, 'reporter:datatype', OILS_NS_REPORTER),
154 rpt_select = self._get_attr(field, 'reporter:selector', OILS_NS_REPORTER),
155 primitive = self._get_attr(field, 'oils_persist:primitive', OILS_NS_PERSIST)
158 idlobj.fields.append(obj)
161 for name in ['isnew', 'ischanged', 'isdeleted']:
162 obj = IDLField(idlobj,
167 idlobj.fields.append(obj)
174 class IDLClass(object):
175 def __init__(self, name, **kwargs):
177 self.controller = kwargs.get('controller')
178 self.fieldmapper = kwargs.get('fieldmapper')
179 self.virtual = kwargs.get('virtual')
180 self.label = kwargs.get('label')
181 self.tablename = kwargs.get('tablename')
182 self.primary = kwargs.get('primary')
183 self.sequence = kwargs.get('sequence')
187 if self.virtual and self.virtual.lower() == 'true':
192 def get_field(self, field_name):
194 return [f for f in self.fields if f.name == field_name][0]
196 msg = "No field '%s' in IDL class '%s'" % (field_name, self.name)
197 osrf.log.log_warn(msg)
198 #raise IDLException(msg)
200 class IDLField(object):
201 def __init__(self, idl_class, **kwargs):
203 @param idl_class The IDLClass object which owns this field
205 self.idl_class = idl_class
206 self.name = kwargs.get('name')
207 self.label = kwargs.get('label')
208 self.rpt_datatype = kwargs.get('rpt_datatype')
209 self.rpt_select = kwargs.get('rpt_select')
210 self.primitive = kwargs.get('primitive')
211 self.virtual = kwargs.get('virtual')
212 self.position = kwargs.get('position')
214 if self.virtual and self.virtual.lower() == 'true':
220 class IDLLink(object):
221 def __init__(self, field, **kwargs):
223 @param field The IDLField object this link references
226 self.rel_type = kwargs.get('rel_type')
227 self.key = kwargs.get('key')
228 self.map = kwargs.get('map')