#
# 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
from cone.carbon.resourcemapper import CarbonResourceMapper
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 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 + "/root.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', {}))
conf.add_configuration(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'] = 's60_feature'
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_name in dict.get('options'):
fea.create_option(option_name, option_name)
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)