#============================================================================
#Name : configuration_model.py
#Part of : Helium
#Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
#All rights reserved.
#This component and the accompanying materials are made available
#under the terms of the License "Eclipse Public License v1.0"
#which accompanies this distribution, and is available
#at the URL "http://www.eclipse.org/legal/epl-v10.html".
#
#Initial Contributors:
#Nokia Corporation - initial contribution.
#
#Contributors:
#
#Description:
#===============================================================================
import amara
import logging
import types
import copy
_logger = logging.getLogger('configurationmodel')
#logging.basicConfig(level=logging.DEBUG)
_handler = logging.StreamHandler()
_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
_logger.addHandler(_handler)
class PropertyDef(object):
""" The model definition of a property. """
def __init__(self, property_node):
""" Initialization. """
if not hasattr(property_node, 'name'):
raise Exception("Name is not defined for '" + str(property_node) + "'")
if not hasattr(property_node, 'type'):
raise Exception("Type is not defined for '" + str(property_node.name) + "'")
if not hasattr(property_node, 'description'):
raise Exception("Description is not defined for '" + str(property_node.name) + "'")
self.name = str(property_node.name)
self.editStatus = str(property_node.editStatus)
self.type = str(property_node.type)
self.description = str(property_node.description).strip()
if len(self.description) == 0:
_logger.log(logging.ERROR, "Description has no content for '" + str(property_node.name) + "'")
if hasattr(property_node, 'deprecated'):
self.deprecated = str(property_node.deprecated)
def __repr__(self):
return self.name
def __str__(self):
return self.name
class GroupDef(object):
""" The model definition of a group of properties. """
def __init__(self, group_node):
""" Initialization. """
self.name = str(group_node.name)
self.description = str(group_node.description)
self.properties = {}
self.propref = []
for property_ in group_node.propertyRef:
self.properties[str(property_)] = property_.usage
def check_config(self, config, items):
""" Checks that the set of properties in a group are properly defined. """
defined_props = [p for p in self.properties.keys() if config.has_key(p)]
if len(defined_props) > 0:
required_props = [p for p in self.properties.keys() if self.properties[p] == 'required']
required_not_defined_props = set(required_props).difference(set(defined_props))
for undefined_property in required_not_defined_props:
items.append(UndefinedRequiredInGroupItem((self.name, undefined_property)))
class DataModel(object):
""" A model of the configuration properties. """
def __init__(self, modelpath):
""" Initialization. """
doc = amara.parse(open(modelpath, 'r'))
self.properties = {}
self.required_props = []
for property_ in doc.heliumDataModel.property:
self.properties[str(property_.name)] = PropertyDef(property_)
self.nongroupedproperties = copy.copy(self.properties)
self.groups = {}
for group in doc.heliumDataModel.group:
groupobj = GroupDef(group)
self.groups[str(group.name)] = groupobj
for prop in groupobj.properties:
groupobj.propref.append(self.properties[prop])
if prop in self.nongroupedproperties:
del self.nongroupedproperties[prop]
groupobj.propref.sort()
required_props_in_group = [p for p in group.propertyRef if p.usage == 'required']
for required_prop in required_props_in_group:
self.required_props.append(required_prop)
if not self.properties.has_key(str(required_prop)):
raise Exception("Required property " + str(required_prop) + " is not defined!")
def validate_config(self, config):
""" Validate the Ant configuration against the model. """
items = []
self._check_deprecated_properties(config, items)
self._check_undefined_properties(config, items)
self._check_undefined_properties_in_groups(config, items)
self._check_type_validation(config, items)
self._check_defined_properties_not_in_groups(config, items)
return items
def validate_config_at_startup(self, config):
""" Validate the Ant configuration against the model at build startup. """
items = []
for p in self.required_props:
if not config.has_key(str(p)):
print "Required property " + str(p) + " is not defined!"
return items
def _check_deprecated_properties(self, config, items):
""" Check that deprecated properties not being used. """
deprecated_props = [p for p in self.properties.values() if hasattr(p, 'deprecated')]
for deprecated_prop in deprecated_props:
_logger.debug('Checking deprecated property: ' + str(deprecated_prop))
if config.has_key(str(deprecated_prop)):
items.append(UsingDeprecatedItem(deprecated_prop))
def _check_undefined_properties(self, config, items):
""" Check for any defined properties that are not in the model. """
undefined_properties = [p for p in config.keys() if p not in self.properties]
undefined_properties.sort()
for undefined_property in undefined_properties:
items.append(MissingFromDataModelItem(undefined_property))
def _check_undefined_properties_in_groups(self, config, items):
for group in self.groups.values():
_logger.debug('Checking group: %s' % group.name)
group.check_config(config, items)
def _check_defined_properties_not_in_groups(self, config, items):
gp = []
for group in self.groups.values():
gp = gp + group.properties.keys()
for p in self.properties.values():
if not str(p) in gp:
raise Exception(str(p) + ' not in a group')
def _check_type_validation(self, config, items):
prop_string = [p for p in self.properties.values() if p.type == 'string']
prop_integer = [p for p in self.properties.values() if p.type == 'integer']
prop_boolean = [p for p in self.properties.values() if p.type == 'boolean']
prop_flag = [p for p in self.properties.values() if p.type == 'flag']
for prop in prop_integer:
if config.has_key(str(prop)):
if not config[str(prop)].isdigit():
items.append(WrongTypeItem(("integer", prop)))
for prop in prop_boolean:
if config.has_key(str(prop)) :
if not (config[str(prop)] == 'false' or 'true'):
items.append(WrongTypeItem(("boolean", prop)))
for prop in prop_string:
if config.has_key(str(prop)):
if len(config[str(prop)]) == 0:
items.append(WrongTypeItem(("string", prop)))
class Item(object):
level = logging.INFO
message = ''
def __init__(self, values):
""" Initialization. """
self.values = values
def log(self, logger):
logger.log(self.level, str(self))
def __str__(self):
return self.message % self.values
class MissingFromDataModelItem(Item):
level = logging.INFO
message = 'Property not in data model: %s'
class UsingDeprecatedItem(Item):
level = logging.WARNING
message = 'Deprecated property used: %s'
class UndefinedRequiredInGroupItem(Item):
level = logging.WARNING
message = 'Required property in %s group is not defined: %s'
class WrongTypeItem(Item):
level = logging.WARNING
message = 'Invalid %s value: %s'