--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/configurationengine/source/cone/carbon/persistentjson.py Thu Mar 11 17:04:37 2010 +0200
@@ -0,0 +1,609 @@
+#
+# 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 "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:
+#
+##
+# @author Teemu Rytkonen
+import re
+import logging
+import simplejson
+
+""" cone specific imports """
+from cone.public import persistence, exceptions, api, utils, container
+from cone.carbon import model
+
+MODEL = model
+
+def dumps(obj, indent=True):
+ """ Make sure that the object is mapped to an object in this model """
+ mobj = obj._get_mapper('carbon').map_object(obj)
+ writer = get_writer_for_class(mobj.__class__.__name__)
+ dict = writer.dumps(mobj)
+ # Return the data as dict, as it is urlencoded by client
+ return dict
+
+def loads(jsonstr):
+ return CarbonReader().loads(jsonstr)
+
+
+class CarbonResourceMapper(object):
+ def __init__(self):
+ self.CARBON_RESOURCE_TYPE_MAP = {'configurationroot' : self.map_carbon_configurationroot,
+ 'configurationlayer' : self.map_carbon_configurationlayer,
+ 'featurelist' : self.map_carbon_featurelist}
+ self.CONFML_RESOURCE_TYPE_MAP = {'configurationroot' : self.map_confml_configurationroot,
+ 'configurationlayer' : self.map_confml_configurationlayer,
+ 'featurelist' : self.map_confml_featurelist}
+
+ def map_carbon_resource(self, resourcepath):
+ for resourceext in self.CARBON_RESOURCE_TYPE_MAP:
+ if resourcepath.endswith(resourceext):
+ return self.CARBON_RESOURCE_TYPE_MAP[resourceext](resourcepath)
+ return resourcepath
+
+ def map_confml_resource(self, resourcetype, resourcepath):
+ return self.CONFML_RESOURCE_TYPE_MAP[resourcetype](resourcepath)
+
+ def map_carbon_configurationroot(self, resourcepath):
+ return resourcepath.replace('.configurationroot', '.confml')
+
+ def map_carbon_configurationlayer(self, resourcepath):
+ return resourcepath.replace('.configurationlayer', '/root.confml')
+
+ def map_carbon_featurelist(self, resourcepath):
+ return "featurelists/%s" % resourcepath.replace('.featurelist', '.confml')
+
+ def map_confml_configurationroot(self, resourcepath):
+ return resourcepath.replace('.confml', '.configurationroot')
+
+ def map_confml_configurationlayer(self, resourcepath):
+ return resourcepath.replace('/root.confml', '.configurationlayer')
+
+ def map_confml_featurelist(self, resourcepath):
+ path = resourcepath.replace('featurelists/','').replace('.confml', '')
+ version_identifier = 'WORKING'
+ m = re.match('^(.*) \((.*)\)', path)
+ # if the resourcepath does not have version information
+ # use default WORKING
+ if m:
+ path = m.group(1)
+ version_identifier = m.group(2)
+ return '%s (%s).featurelist' % (path, version_identifier)
+
+class ResourceListReader(persistence.ConeReader):
+ """
+ """
+ def loads(self, jsonstr):
+ """
+ @param jsonstr: The json string to read.
+ """
+ reslist = model.ResourceList()
+ datadict = simplejson.loads(jsonstr)
+ for configuration in datadict.get('configurations', []):
+ reslist.add_resource(model.ConfigurationResource(**configuration))
+ for featurelist in datadict.get('featurelists', []):
+ reslist.add_resource(model.FeatureListResource(**featurelist))
+ return reslist
+
+class HasResourceReader(persistence.ConeReader):
+ """
+ """
+ def loads(self, jsonstr):
+ """
+ @param jsonstr: The json string to read.
+ """
+ try:
+ datadict = simplejson.loads(jsonstr)
+ return datadict.get('has_resource',False)
+ except ValueError,e:
+ logging.getLogger('cone').error("Failed to parser json from %s" % jsonstr)
+ raise e
+
+
+class CarbonWriter(persistence.ConeWriter):
+ """
+ """
+ def dumps(self, obj):
+ """
+ @param obj: The object
+ """
+ """ Make sure that the object is mapped to an object in this model """
+ mobj = obj._get_mapper('carbon').map_object(obj)
+ writer = get_writer_for_class(mobj.__class__.__name__)
+ return writer.dumps(obj)
+
+
+class CarbonReader(persistence.ConeReader):
+ """
+ """
+ def loads(self, jsonstr):
+ """
+ @param xml: The xml which to read. reads only the first object.
+ """
+ try:
+ datadict = simplejson.loads(jsonstr)
+ for key in datadict:
+ reader = get_reader_for_elem(key)
+ return reader.loads(datadict[key])
+ except (SyntaxError, ValueError),e:
+ utils.log_exception(logging.getLogger('cone'), "Json string parse raised exception: %s!" % (e))
+ raise exceptions.ParseError("Json string %s parse raised exception: %s!" % (jsonstr,e))
+
+class ConfigurationCreateWriter(CarbonWriter):
+ @classmethod
+ def supported_class(cls, classname):
+ """
+ Class method to determine if this CarbonWriter supports writing
+ of the given class name
+ """
+ return False
+
+ def dumps(self, obj):
+ """
+ @param obj: The Configuration object
+ """
+ featurelists = []
+ included = []
+ # Remove the featurelists and configurations from the creation phase
+# resmapper = CarbonResourceMapper()
+# for confpath in obj.list_configurations():
+# config = obj.get_configuration(confpath)
+# if config.meta and config.meta.get('type') == 'featurelist':
+# featurelists.append(resmapper.map_confml_resource('featurelist',confpath))
+# elif config.meta and config.meta.get('type'):
+# included.append(resmapper.map_confml_resource(config.meta.get('type'),confpath))
+# else:
+# # ignore configs that are not carbon configs
+# pass
+
+ configuration_dict = {'name' : obj.name,
+ 'parent_path' : '',
+ 'included' : included,
+ 'description' : obj.desc or 'Needs description',
+ 'configuration_type' : 'carbon',
+ 'resource_type' : 'configuration',
+ 'feature_lists' : featurelists,
+ }
+
+ return configuration_dict
+
+class ConfigurationWriter(CarbonWriter):
+ @classmethod
+ def supported_class(cls, classname):
+ """
+ Class method to determine if this CarbonWriter supports writing
+ of the given class name
+ """
+ if classname=="CarbonConfiguration":
+ return True
+ else:
+ return False
+
+ def dumps(self, obj):
+ if obj.meta:
+ if obj.meta.get('type') == 'configurationroot':
+ return self.dumps_root(obj)
+ elif obj.meta.get('type') == 'configurationlayer':
+ return self.dumps_layer(obj)
+ raise Exception("Not supported CarbonConfigruration, %s" % obj)
+
+ def dumps_root(self, obj):
+ """
+ @param obj: The Configuration object
+ """
+ featurelists = []
+ included = []
+ resmapper = CarbonResourceMapper()
+ for confpath in obj.list_configurations():
+ config = obj.get_configuration(confpath)
+ if config.meta:
+ if config.meta.get('type') == 'featurelist':
+ featurelists.append(resmapper.map_confml_resource('featurelist',confpath))
+ else:
+ included.append(resmapper.map_confml_resource(config.meta.get('type'),confpath))
+ else:
+ # This default case could also be identified as error
+ included.append(confpath)
+
+ configuration_dict = {'feature_lists': featurelists,
+ 'parent_config': None,
+ 'configuration_name': obj.name,
+ 'version_identifier': obj.version_identifier,
+ 'included': included,
+ 'ref': obj.ref}
+
+ return configuration_dict
+
+ def dumps_layer(self, obj):
+ """
+ @param obj: The Configuration object
+ """
+ configuration_dict = {'version_identifier': obj.version_identifier}
+
+ datawriter = DataWriter()
+ data = datawriter.dumps(obj)
+ configuration_dict['data'] = data
+
+ return configuration_dict
+
+class ConfigurationRootReader(CarbonReader):
+ """
+ """
+ @classmethod
+ def supported_elem(cls, elemname, parent=None):
+ """
+ Class method to determine if this ConfmlWriter supports writing
+ of the given elem name
+ """
+ if elemname=="configurationroot":
+ return True
+ else:
+ return False
+
+ def __init__(self):
+ pass
+
+ def loads(self, dict):
+ """
+ @param obj: The Configuration object
+ """
+ name = dict.get('configuration_name')
+ path = name + ".confml"
+ conf = model.CarbonConfiguration(dict.get('ref'), path=path, type='configurationroot')
+ conf.name = name
+ conf.version = dict.get('version_identifier')
+ resmapper = CarbonResourceMapper()
+
+ """ Read the featurelists as included configurations """
+ for fealist in dict.get('feature_lists',[]):
+ conf.include_configuration(resmapper.map_carbon_resource(fealist))
+ """ Read the included configurations """
+ for includedconfig in dict.get('included',[]):
+ conf.include_configuration(resmapper.map_carbon_resource(includedconfig))
+ return conf
+
+class ConfigurationLayerReader(CarbonReader):
+ """
+ """
+ @classmethod
+ def supported_elem(cls, elemname, parent=None):
+ """
+ Class method to determine if this ConfmlWriter supports writing
+ of the given elem name
+ """
+ if elemname=="configurationlayer":
+ return True
+ else:
+ return False
+
+ def __init__(self):
+ pass
+
+ def loads(self, dict):
+ """
+ @param obj: The Configuration object
+ """
+ name = dict.get('configuration_name')
+ path = name + ".confml"
+ conf = model.CarbonConfiguration(dict.get('ref'), path=path, type='configurationlayer')
+ conf.name = name
+
+ conf.version = dict.get('version_identifier')
+
+ """ Last read the data of this configuration and add it as a configuration """
+ data_reader = DataReader()
+ datacont = data_reader.loads(dict.get('data', {}))
+ proxy = api.ConfigurationProxy(datacont.path)
+ conf.add_configuration(proxy)
+ proxy._set_obj(datacont)
+
+ return conf
+
+class FeatureListCreateWriter(CarbonWriter):
+ @classmethod
+ def supported_class(cls, classname):
+ """
+ Feature list create writer is supported only explicitly
+ """
+ return False
+
+ def dumps(self, obj):
+ """
+ @param obj: The FeatureList object
+ """
+ """ Make sure that the object is mapped to an object in this model """
+ mobj = obj._get_mapper('carbon').map_object(obj)
+ featurelist_dict = {'type' : 'featurelist',
+ 'flv_description' : mobj.desc or 'Needs description',
+ 'version_identifier' : mobj.version_identifier
+ }
+ if hasattr(mobj, 'responsible'):
+ featurelist_dict['responsible'] = mobj.responsible
+ return featurelist_dict
+
+class FeatureListWriter(CarbonWriter):
+ @classmethod
+ def supported_class(cls, classname):
+ """
+ Feature list create writer is supported only explicitly
+ """
+ if classname == 'FeatureList':
+ return True
+ else:
+ return False
+
+ def dumps(self, obj):
+ """
+ @param obj: The FeatureList object
+ """
+
+ featurelist_dict = {
+ 'type' : 'featurelist',
+ 'name' : obj.name,
+ 'flv_description' : obj.desc or 'Needs description',
+ 'path' : obj.path,
+ 'features' : []
+ }
+ if obj.meta.get('version_identifier'):
+ featurelist_dict['version_identifier'] = obj.meta.get('version_identifier')
+ # add all features of the featurelist
+ for fearef in obj.list_features():
+ feature = obj.get_feature(fearef)
+ writer = FeatureWriter()
+ feadict = writer.dumps(feature)
+ featurelist_dict['features'].append(feadict)
+
+ return featurelist_dict
+
+class FeatureListReader(CarbonReader):
+ """
+ """
+ @classmethod
+ def supported_elem(cls, elemname, parent=None):
+ """
+ Class method to determine if this ConfmlWriter supports writing
+ of the given elem name
+ """
+ if elemname=="featurelist":
+ return True
+ else:
+ return False
+
+ def __init__(self):
+ pass
+
+ def loads(self, dict):
+ """
+ @param obj: The Configuration object
+ """
+ fealist_expanded = dict.get('expanded')
+ fealist_version = dict.get('version_identifier')
+ fealist_is_latest_version = dict.get('is_latest_version')
+ fealist_list_id = dict.get('list_id')
+ fealist_path = dict.get('path')
+ fealist_version_title = dict.get('version_title')
+ fealist_can_be_released = dict.get('can_be_released')
+ fealist_type = dict.get('type')
+ fealist_has_external_relations = dict.get('is_latest_version')
+
+ # Create a configuration object from the featurelist
+ conf = model.FeatureList(path='featurelists/'+fealist_version_title+'.confml')
+ conf.meta.add('version_identifier', fealist_version)
+
+ for feature in dict.get('features'):
+ reader = FeatureReader()
+ fea = reader.loads(feature)
+ if fea != None:
+ conf.add_feature(fea)
+
+ for feafqr in conf.list_all_features():
+ # Add empty data object to featurelist configuration
+ conf.add_data(api.Data(fqr=feafqr))
+
+ return conf
+
+
+class FeatureWriter(CarbonWriter):
+ CONFML_TO_CARBON_TYPE = {
+ 'boolean' : 'BOOLEAN',
+ 'int' : 'INTEGER',
+ 'selection' : 'SELECTION',
+ 'string' : 'STRING',
+ None : None,
+ '' : ''
+ }
+ @classmethod
+ def supported_class(cls, classname):
+ """
+ Class method to determine if this ConfmlWriter supports writing
+ of the given class name
+ """
+ if classname=="Feature" or\
+ classname=="CarbonBooleanSetting" or\
+ classname=="CarbonIntSetting" or\
+ classname=="CarbonStringSetting" or\
+ classname=="CarbonSelectSetting"or\
+ classname=="CarbonSetting":
+ return True
+ else:
+ return False
+
+ def dumps(self, obj):
+ """
+ @param obj: The Feature object
+ """
+ """ Make sure that the object is mapped to an object in this model """
+ mobj = obj._get_mapper('carbon').map_object(obj)
+
+ featuredict = {'type' : 'feature',
+ 'status' : 'APPROVED',
+ 'title' : mobj.name,
+ 'ref' : mobj.ref,
+ 'description' : mobj.desc or 'Needs description',
+ 'responsible' : None,
+ 'value_type' : self.CONFML_TO_CARBON_TYPE[mobj.type],
+ 'children' : []}
+ if featuredict['value_type'] != None:
+ featuredict['type_object'] = 'carbon_feature_type_normal'
+ if mobj.type == 'selection':
+ featuredict['options'] = mobj.options.keys()
+
+ writer = FeatureWriter()
+ for fearef in mobj.list_features():
+ feaobj = obj.get_feature(fearef)
+ childdict = writer.dumps(feaobj)
+ featuredict['children'].append(childdict)
+ return featuredict
+
+
+class FeatureReader(CarbonReader):
+ """
+ """
+ @classmethod
+ def supported_elem(cls, elemname, parent=None):
+ """
+ Class method to determine if this ConfmlWriter supports writing
+ of the given elem name
+ """
+ if elemname=="features":
+ return True
+ else:
+ return False
+
+ def __init__(self):
+ pass
+
+ def loads(self, dict):
+ """
+ @param obj: The Configuration object
+ """
+ id = dict.get('id')
+ name = dict.get('title')
+ ref = dict.get('ref')
+ ref = utils.resourceref.to_objref(ref)
+ status = dict.get('status')
+ value_type = dict.get('value_type')
+ description = dict.get('description')
+
+ if value_type == 'boolean':
+ fea = model.CarbonBooleanSetting(ref, type=value_type)
+ elif value_type == 'integer':
+ fea = model.CarbonIntSetting(ref, type=value_type)
+ elif value_type == 'string':
+ fea = model.CarbonStringSetting(ref, type=value_type)
+ elif value_type == 'selection':
+ fea = model.CarbonSelectionSetting(ref, type=value_type)
+ for option in dict.get('options'):
+ fea.add_option(option,option)
+ elif value_type == '':
+ fea = model.CarbonFeature(ref, type=value_type)
+ else:
+ fea = model.CarbonFeature(ref)
+
+
+ fea.name = name
+ fea.status = status
+ fea.desc = description
+
+ for childdict in dict.get('children',[]):
+ reader = FeatureReader()
+ subfea = reader.loads(childdict)
+ if subfea != None:
+ fea.add_feature(subfea)
+ return fea
+
+class DataWriter(CarbonWriter):
+ @classmethod
+ def supported_class(cls, classname):
+ """
+ Class method to determine if this ConfmlWriter supports writing
+ of the given class name
+ """
+ if classname=="Data" or \
+ classname=="DataContainer":
+ return True
+ else:
+ return False
+
+ def dumps(self, obj):
+ """
+ @param obj: The DataContainer object
+ """
+ datadict = {}
+ for dataelem in obj._traverse(type=api.Data):
+ if dataelem.get_value() != None:
+ datadict[dataelem.get_fearef()] = map_confml2carbon_value(dataelem.get_value())
+ return datadict
+
+
+class DataReader(CarbonReader):
+ """
+ """
+ @classmethod
+ def supported_elem(cls, elemname, parent=None):
+ """
+ Class method to determine if this ConfmlWriter supports writing
+ of the given elem name
+ """
+ if elemname=="data":
+ return True
+ else:
+ return False
+
+ def __init__(self):
+ pass
+
+ def loads(self, dict):
+ """
+ @param obj: The Configuration object
+ """
+ datacont = api.Configuration('confml/data.confml')
+ for dataref in dict.keys():
+ # Ignore null values
+ if dict[dataref]:
+ refs = []
+ for elem in dataref.split('.'):
+ refs.append(utils.resourceref.to_objref(elem))
+ newref = '.'.join(refs)
+ dataelem = api.Data(fqr=newref, value=map_carbon2confml_value(dict[dataref]))
+ datacont.add_data(dataelem)
+ return datacont
+
+def map_carbon2confml_value(value):
+ if value == 'DEFINED':
+ return 'true'
+ elif value == 'UNDEFINED':
+ return 'false'
+ else:
+ return value
+
+def map_confml2carbon_value(value):
+ if value == 'true':
+ return 'DEFINED'
+ elif value == 'false':
+ return 'UNDEFINED'
+ else:
+ return value
+
+def get_reader_for_elem(elemname, parent=None):
+ for reader in CarbonReader.__subclasses__():
+ 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 CarbonWriter.__subclasses__():
+ if writer.supported_class(classname):
+ return writer ()
+ raise exceptions.ConePersistenceError("No writer for given class found! %s" % classname)