--- a/configurationengine/source/cone/confml/persistentconfml.py Fri Mar 12 08:30:17 2010 +0200
+++ b/configurationengine/source/cone/confml/persistentconfml.py Tue Aug 10 14:29:28 2010 +0300
@@ -13,9 +13,9 @@
#
# Description:
#
+import os
import re
import logging
-import xml.parsers.expat
try:
from cElementTree import ElementTree
except ImportError:
@@ -27,8 +27,8 @@
except ImportError:
from xml.etree import ElementTree
-""" cone specific imports """
-from cone.public import persistence, exceptions, api, utils, container
+# cone specific imports
+from cone.public import persistence, exceptions, api, utils, container, parsecontext
from cone.confml import model
CONFIGURATION_NAMESPACES = ["http://www.s60.com/xml/confml/2","http://www.s60.com/xml/confml/1"]
@@ -42,12 +42,29 @@
etree = ConfmlWriter().dumps(obj)
if indent:
persistence.indent(etree)
- return ElementTree.tostring(etree)
+ result = ElementTree.tostring(etree)
+
+ # To make the output the same in linux and windows
+ # (needed to make testing easier)
+ if os.linesep != '\r\n':
+ result = result.replace(os.linesep, '\r\n')
+
+ return result
def loads(xml):
return ConfmlReader().loads(xml)
+def add_parse_warning(msg, line, type='model.confml'):
+ parsecontext.get_confml_context().handle_problem(
+ api.Problem(msg,
+ severity = api.Problem.SEVERITY_WARNING,
+ type = type,
+ line = line))
+def add_unknown_element_warning(elem):
+ add_parse_warning("Unknown element '%s'" % elem.tag,
+ utils.etree.get_lineno(elem),
+ type='model.confml.unknown_element')
class ConfmlWriter(persistence.ConeWriter):
"""
@@ -69,7 +86,11 @@
@param xml: The xml which to read. reads only the first object.
"""
reader = get_reader_for_elem("configuration")
- etree = utils.etree.fromstring(xmlstr)
+ try:
+ etree = utils.etree.fromstring(xmlstr)
+ except exceptions.XmlParseError, e:
+ e.problem_type = 'xml.confml'
+ raise e
return reader.loads(etree)
@@ -105,7 +126,13 @@
elem.set("xmlns:xlink",self.xlink_namespace)
if self.schema_namespace:
elem.set("xmlns:xs",self.schema_namespace)
- elem.set("name",obj.get_name())
+ if obj.get_name():
+ elem.set("name", obj.get_name())
+ if obj.version != None:
+ elem.set("version", obj.version)
+ if obj.get_id():
+ elem.set('id', obj.get_id())
+
for child in obj._objects():
""" Make sure that the object is mapped to an object in this model """
mobj = child._get_mapper('confml').map_object(child)
@@ -137,8 +164,11 @@
self.schema_namespaces = SCHEMA_NAMESPACES
def loads(self, etree):
- configuration = model.ConfmlConfiguration("")
- configuration.set_name(etree.get("name") or 'unknown')
+ configuration = model.ConfmlConfiguration(name=etree.get("name"),
+ id=etree.get("id"),
+ version=etree.get("version"))
+ configuration.lineno = utils.etree.get_lineno(etree)
+ # configuration.set_name(etree.get("name") or 'unknown')
configuration.set_ref(etree.get("name") or 'unknown')
for elem in etree.getchildren():
# At the moment we ignore the namespace of elements
@@ -149,7 +179,7 @@
if obj:
configuration.add(obj)
except exceptions.ConePersistenceError,e:
- logging.getLogger('cone').warning("Could not parse element %s. Exception: %s" % (elem,e))
+ add_unknown_element_warning(elem)
continue
return configuration
@@ -202,6 +232,7 @@
def loads(self,etree):
metaelem = model.ConfmlMeta()
+ metaelem.lineno = utils.etree.get_lineno(etree)
for elem in etree.getchildren():
(namespace,elemname) = get_elemname(elem.tag)
attributes = {}
@@ -250,6 +281,7 @@
def loads(self,elem):
desc = model.ConfmlDescription(elem.text)
+ desc.lineno = utils.etree.get_lineno(elem)
return desc
class ConfigurationProxyWriter(ConfmlWriter):
@@ -295,8 +327,9 @@
"""
@param elem: The xml include elem
"""
-
- return api.ConfigurationProxy(self.parse_include(elem))
+ proxy = api.ConfigurationProxy(self.parse_include(elem))
+ # proxy.lineno = utils.etree.get_lineno(elem)
+ return proxy
def parse_include(self,include):
#print "Found include %s" % include.get('href').replace('#/','')
@@ -321,10 +354,17 @@
@param obj: The Configuration object
"""
elem = ElementTree.Element('feature',
- {'ref' : obj.get_ref(),
- 'name' : obj.get_name()})
+ {'ref' : obj.get_ref()})
+ if obj.get_name():
+ elem.set('name', obj.get_name())
if obj.get_type():
elem.set('type', obj.get_type())
+ if obj.get_id() != None:
+ elem.set('id', obj.get_id())
+ if obj.get_relevant() != None:
+ elem.set('relevant', obj.get_relevant())
+ if obj.get_constraint() != None:
+ elem.set('constraint', obj.get_constraint())
for child in obj._objects():
""" Make sure that the object is mapped to an object in this model """
mobj = child._get_mapper('confml').map_object(child)
@@ -360,7 +400,14 @@
feature = model.ConfmlFeature(elem.get('ref'))
if elem.get('name'):
feature.set_name(elem.get('name'))
+ if elem.get('id') != None:
+ feature.set_id(elem.get('id'))
+ if elem.get('relevant') != None:
+ feature.set_relevant(elem.get('relevant'))
+ if elem.get('constraint') != None:
+ feature.set_constraint(elem.get('constraint'))
feature.set_type(type)
+ feature.lineno = utils.etree.get_lineno(elem)
for elem in elem.getchildren():
# At the moment we ignore the namespace of elements
(namespace,elemname) = get_elemname(elem.tag)
@@ -369,7 +416,7 @@
obj = reader.loads(elem)
feature.add(obj)
except exceptions.ConePersistenceError,e:
- logging.getLogger('cone').warning("Could not parse element %s. Exception: %s" % (elem,e))
+ add_unknown_element_warning(elem)
continue
return feature
@@ -396,6 +443,9 @@
if obj.get_value() is not None: objdict['value'] = obj.get_value()
if obj.map is not None: objdict['map'] = obj.map
if obj.relevant is not None: objdict['relevant'] = obj.relevant
+ if obj.display_name is not None: objdict['displayName'] = obj.display_name
+ if obj.map_value is not None: objdict['mapValue'] = obj.map_value
+
elem = ElementTree.Element('option', objdict)
return elem
@@ -422,11 +472,16 @@
name = elem.get('name')
value = elem.get('value')
optmap = elem.get('map')
+
if value == None and optmap == None:
logging.getLogger('cone').warning("Encountered option with no value")
option = None
else:
- option = api.Option(name, value, map=optmap, relevant=elem.get('relevant'))
+ option = api.Option(name, value, map=optmap,
+ relevant=elem.get('relevant'),
+ map_value=elem.get('mapValue'),
+ display_name=elem.get('displayName'))
+ option.lineno = utils.etree.get_lineno(elem)
return option
@@ -471,6 +526,7 @@
"""
href = elem.get('{%s}href' % XLINK_NAMESPACES[0])
obj = model.ConfmlIcon(href)
+ obj.lineno = utils.etree.get_lineno(elem)
return obj
@@ -481,7 +537,7 @@
Class method to determine if this ConfmlWriter supports writing
of the given class name
"""
- if classname=="ConfmlProperty":
+ if classname=="Property":
return True
else:
return False
@@ -518,7 +574,8 @@
"""
@param elem: The xml include elem
"""
- option = model.ConfmlProperty(name=elem.get('name'),value=elem.get('value'), unit=elem.get('unit'))
+ option = api.Property(name=elem.get('name'),value=elem.get('value'), unit=elem.get('unit'))
+ option.lineno = utils.etree.get_lineno(elem)
return option
@@ -574,6 +631,7 @@
elem_name = utils.xml.split_tag_namespace(elem.tag)[1]
facet_class = self.MAPPING[elem_name]
obj = facet_class(elem.get('value'))
+ obj.lineno = utils.etree.get_lineno(elem)
return obj
@@ -584,9 +642,8 @@
Class method to determine if this ConfmlWriter supports writing
of the given class name
"""
- if classname=="Data":
- return True
- if classname=="DataContainer":
+ if classname=="Data" or \
+ classname=="DataContainer":
return True
else:
return False
@@ -597,14 +654,16 @@
"""
# Create a data hierarchy of the
elem = ElementTree.Element(obj.get_ref())
- if hasattr(obj,'get_value') and obj.get_value() and not obj.get_map():
+ if hasattr(obj,'get_map') and obj.get_map() is not None:
+ elem.set('map', obj.get_map())
+ elif hasattr(obj,'get_value') and obj.get_value() is not None:
elem.text = obj.get_value()
- elif hasattr(obj,'get_map') and obj.get_map():
- elem.set('map', obj.get_map())
if hasattr(obj,'template') and obj.template == True:
elem.set('template','true')
if hasattr(obj,'policy') and obj.policy != '':
elem.set('extensionPolicy',obj.policy)
+ if hasattr(obj,'empty') and obj.empty == True:
+ elem.set('empty','true')
for child in obj._objects():
writer = DataWriter()
childelem = writer.dumps(child)
@@ -634,13 +693,14 @@
(namespace,elemname) = get_elemname(elem.tag)
obj = api.DataContainer(elemname, container=True)
+ obj.lineno = utils.etree.get_lineno(elem)
for elem in elem.getchildren():
try:
reader = ElemReader(attr='data')
childobj = reader.loads(elem)
obj.add(childobj)
except exceptions.ConePersistenceError,e:
- logging.getLogger('cone').warning("Could not parse element %s. Exception: %s" % (elem,e))
+ add_unknown_element_warning(elem)
continue
return obj
@@ -663,8 +723,9 @@
@param obj: The Configuration object
"""
elem = ElementTree.Element('view',
- {'id' : obj.get_ref(),
- 'name' : obj.get_name()})
+ {'name' : obj.get_name()})
+ if obj.id != None:
+ elem.set('id', obj.id)
for child in obj._objects():
""" Make sure that the object is mapped to an object in this model """
mobj = child._get_mapper('confml').map_object(child)
@@ -696,6 +757,7 @@
vid = elem.get('id')
name = elem.get('name')
view = model.ConfmlView(name, id=vid)
+ view.lineno = utils.etree.get_lineno(elem)
for elem in elem.getchildren():
# At the moment we ignore the namespace of elements
(namespace,elemname) = get_elemname(elem.tag)
@@ -704,7 +766,7 @@
obj = reader.loads(elem)
view.add(obj)
except exceptions.ConePersistenceError,e:
- logging.getLogger('cone').warning("Could not parse element %s. Exception: %s" % (elem,e))
+ add_unknown_element_warning(elem)
continue
return view
@@ -727,6 +789,9 @@
"""
elem = ElementTree.Element('group',
{'name' : obj.get_name()})
+ if obj.get_id():
+ elem.set('id', obj.get_id())
+
for child in obj._objects():
""" Make sure that the object is mapped to an object in this model """
mobj = child._get_mapper('confml').map_object(child)
@@ -758,6 +823,9 @@
gname = elem.get('name')
gref = utils.resourceref.to_dref(gname).replace('.','_')
group = model.ConfmlGroup(gref, name=gname)
+ group.lineno = utils.etree.get_lineno(elem)
+ if elem.get('id'):
+ group.set_id(elem.get('id'))
for elem in elem.getchildren():
# At the moment we ignore the namespace of elements
(namespace,elemname) = get_elemname(elem.tag)
@@ -767,58 +835,11 @@
if obj != None:
group.add(obj)
except exceptions.ConePersistenceError,e:
- logging.getLogger('cone').warning("Could not parse element %s. Exception: %s" % (elem,e))
+ add_unknown_element_warning(elem)
continue
return group
-class GroupSettingWriter(ConfmlWriter):
- """
- """
- @classmethod
- def supported_class(cls, classname):
- """
- Class method to determine if this ConfmlWriter supports writing
- of the given class name
- """
- if classname=="FeatureLink":
- return True
- else:
- return False
-
- def dumps(self, obj):
- """
- @param obj: The Configuration object
- """
- ref = obj.fqr.replace('.','/')
- elem = ElementTree.Element('setting',
- {'ref' : ref})
- return elem
-
-class GroupSettingReader(ConfmlReader):
- """
- """
- @classmethod
- def supported_elem(cls, elemname, parent=None):
- """
- Class method to determine if this ConfmlWriter supports reading
- of the given elem name
- """
- if elemname=='setting' and parent=='group':
- return True
- else:
- return False
-
- def loads(self, elem):
- """
- @param elem: The xml include elem
- """
- ref = elem.get('ref') or ''
- ref = ref.replace('/','.')
- return api.FeatureLink(ref)
-
-
-
class ConfmlSettingWriter(ConfmlWriter):
@classmethod
def supported_class(cls, classname):
@@ -837,6 +858,7 @@
classname=="ConfmlTimeSetting" or \
classname=="ConfmlDateTimeSetting" or \
classname=="ConfmlDurationSetting" or \
+ classname=="ConfmlHexBinarySetting" or \
classname=="ConfmlFileSetting" or \
classname=="ConfmlFolderSetting" or \
classname=="FeatureSequence" or \
@@ -850,10 +872,20 @@
@param obj: The Configuration object
"""
elem = ElementTree.Element('setting',
- {'ref' : obj.get_ref(),
- 'name' : obj.get_name()})
+ {'ref' : obj.get_ref()})
+ self._set_setting_properties(elem, obj)
+ return elem
+
+ def _set_setting_properties(self, elem, obj):
+ """
+ Set the setting properties for the given elm from the given feature object
+ """
+ if obj.get_name():
+ elem.set('name', obj.get_name())
if obj.type:
elem.set('type', obj.get_type())
+ if obj.get_id():
+ elem.set('id', obj.get_id())
if hasattr(obj,'minOccurs'):
elem.set('minOccurs', str(obj.minOccurs))
if hasattr(obj,'maxOccurs'):
@@ -870,6 +902,8 @@
elem.set('mapKey', str(obj.mapKey))
if hasattr(obj,'mapValue') and obj.mapValue is not None:
elem.set('mapValue', str(obj.mapValue))
+ if hasattr(obj,'displayName') and obj.displayName is not None:
+ elem.set('displayName', str(obj.displayName))
for child in obj._objects():
""" Make sure that the object is mapped to an object in this model """
@@ -878,7 +912,6 @@
childelem = writer.dumps(child)
if childelem != None:
elem.append(childelem)
- return elem
class ConfmlSettingReader(ConfmlReader):
@@ -891,7 +924,7 @@
of the given elem name
"""
if parent and not (parent=='feature' or parent=='setting'):
- return False
+ return False
if elemname=='setting':
return True
else:
@@ -905,7 +938,8 @@
if typedef == 'sequence':
map_key = elem.get('mapKey')
map_value = elem.get('mapValue')
- feature = model.ConfmlSequenceSetting(elem.get('ref'), mapKey=map_key, mapValue=map_value)
+ display_name = elem.get('displayName')
+ feature = model.ConfmlSequenceSetting(elem.get('ref'), mapKey=map_key, mapValue=map_value, displayName=display_name)
elif typedef == 'int':
feature = model.ConfmlIntSetting(elem.get('ref'))
elif typedef == 'boolean':
@@ -930,14 +964,25 @@
feature = model.ConfmlDateTimeSetting(elem.get('ref'))
elif typedef == 'duration':
feature = model.ConfmlDurationSetting(elem.get('ref'))
+ elif typedef == 'hexBinary':
+ feature = model.ConfmlHexBinarySetting(elem.get('ref'))
else:
# Handle the default setting as int type
- feature = model.ConfmlSetting(elem.get('ref'), type=None)
+ feature = model.ConfmlSetting(elem.get('ref'), type=typedef)
+ feature.lineno = utils.etree.get_lineno(elem)
+ self._get_setting_properties(elem, feature)
+ return feature
+ def _get_setting_properties(self, elem, feature):
+ """
+ Get the setting properties for the given feature from the given xml elem
+ """
if elem.get('name'):
feature.set_name(elem.get('name'))
+ if elem.get('id'):
+ feature.set_id(elem.get('id'))
if elem.get('minOccurs'):
feature.minOccurs = int(elem.get('minOccurs'))
if elem.get('maxOccurs'):
@@ -960,12 +1005,63 @@
if obj != None:
feature.add(obj,container.APPEND)
else:
- logging.getLogger('cone').warning("Invalid child %s in %s" % (elem,feature.name))
+ add_parse_warning("Invalid child %s in %s" % (elem, feature.name),
+ utils.etree.get_lineno(elem))
except exceptions.ConePersistenceError,e:
- logging.getLogger('cone').warning("Could not parse element %s. Exception: %s" % (elem,e))
+ add_unknown_element_warning(elem)
continue
- return feature
+
+
+class GroupSettingWriter(ConfmlSettingWriter):
+ """
+ """
+ @classmethod
+ def supported_class(cls, classname):
+ """
+ Class method to determine if this ConfmlWriter supports writing
+ of the given class name
+ """
+ if classname=="FeatureLink" or \
+ classname=="ConfmlFeatureLink":
+ return True
+ else:
+ return False
+ def dumps(self, obj):
+ """
+ @param obj: The Configuration object
+ """
+ ref = obj.fqr.replace('.','/')
+ elem = ElementTree.Element('setting',
+ {'ref' : ref})
+ self._set_setting_properties(elem, obj)
+ return elem
+
+
+class GroupSettingReader(ConfmlSettingReader):
+ """
+ """
+ @classmethod
+ def supported_elem(cls, elemname, parent=None):
+ """
+ Class method to determine if this ConfmlWriter supports reading
+ of the given elem name
+ """
+ if elemname=='setting' and parent=='group':
+ return True
+ else:
+ return False
+
+ def loads(self, elem):
+ """
+ @param elem: The xml include elem
+ """
+ ref = elem.get('ref') or ''
+ ref = ref.replace('/','.')
+ feature_link = model.ConfmlFeatureLink(ref)
+ feature_link.lineno = utils.etree.get_lineno(elem)
+ self._get_setting_properties(elem, feature_link)
+ return feature_link
class ConfmlLocalPathWriter(ConfmlWriter):
@classmethod
@@ -1007,7 +1103,9 @@
"""
@param elem: The xml include elem
"""
- return model.ConfmlLocalPath(readOnly=elem.get('readOnly'))
+ obj = model.ConfmlLocalPath(readOnly=elem.get('readOnly'))
+ obj.lineno = utils.etree.get_lineno(elem)
+ return obj
class ConfmlTargetPathWriter(ConfmlWriter):
@@ -1050,7 +1148,9 @@
"""
@param elem: The xml include elem
"""
- return model.ConfmlTargetPath(readOnly=elem.get('readOnly'))
+ obj = model.ConfmlTargetPath(readOnly=elem.get('readOnly'))
+ obj.lineno = utils.etree.get_lineno(elem)
+ return obj
class DummyWriter(ConfmlWriter):
@@ -1094,13 +1194,14 @@
(namespace,elemname) = get_elemname(elem.tag)
obj = api.DataContainer(elemname, container=True)
+ obj.lineno = utils.etree.get_lineno(elem)
for elem in elem.getchildren():
try:
reader = ElemReader(attr='rfs')
childobj = reader.loads(elem)
obj.add(childobj)
except exceptions.ConePersistenceError,e:
- logging.getLogger('cone').warning("Could not parse element %s. Exception: %s" % (elem,e))
+ add_unknown_element_warning(elem)
continue
return obj
@@ -1118,10 +1219,15 @@
datavalue = None
if len(list(elem)) == 0:
datavalue = elem.text
- datatemplate = elem.get('template') == 'true' or self.template
- dataextensionpolicy = elem.get('extensionPolicy') or ''
- datamap = elem.get('map')
- obj = api.Data(ref=elemname,value=datavalue, template=datatemplate, attr=self.attr,policy=dataextensionpolicy,map=datamap)
+ obj = model.ConfmlData(
+ ref = elemname,
+ value = datavalue,
+ template = elem.get('template') == 'true' or self.template,
+ attr = self.attr,
+ policy = elem.get('extensionPolicy') or '',
+ map = elem.get('map'),
+ empty = elem.get('empty') == 'true')
+ obj.lineno = utils.etree.get_lineno(elem)
for elem in elem.getchildren():
try:
reader = ElemReader(**self.args)
@@ -1152,13 +1258,13 @@
def get_reader_for_elem(elemname, parent=None):
- for reader in ConfmlReader.__subclasses__():
+ for reader in utils.all_subclasses(ConfmlReader):
if reader.supported_elem(elemname,parent):
return reader()
raise exceptions.ConePersistenceError("No reader for given elem %s under %s found!" % (elemname, parent))
def get_writer_for_class(classname):
- for writer in ConfmlWriter.__subclasses__():
+ for writer in utils.all_subclasses(ConfmlWriter):
if writer.supported_class(classname):
return writer ()
raise exceptions.ConePersistenceError("No writer for given class found! %s" % classname)