configurationengine/source/cone/carbon/persistentjson.py
changeset 0 2e8eeb919028
child 3 e7e0ae78773e
equal deleted inserted replaced
-1:000000000000 0:2e8eeb919028
       
     1 #
       
     2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description:
       
    15 #
       
    16 ## 
       
    17 # @author Teemu Rytkonen
       
    18 import re
       
    19 import logging
       
    20 import simplejson
       
    21 
       
    22 """ cone specific imports """
       
    23 from cone.public import persistence, exceptions, api, utils, container
       
    24 from cone.carbon import model
       
    25 
       
    26 MODEL                    = model
       
    27 
       
    28 def dumps(obj, indent=True):
       
    29     """ Make sure that the object is mapped to an object in this model """
       
    30     mobj = obj._get_mapper('carbon').map_object(obj)
       
    31     writer = get_writer_for_class(mobj.__class__.__name__)
       
    32     dict = writer.dumps(mobj)
       
    33     # Return the data as dict, as it is urlencoded by client
       
    34     return dict
       
    35 
       
    36 def loads(jsonstr):
       
    37     return CarbonReader().loads(jsonstr)
       
    38 
       
    39 
       
    40 class CarbonResourceMapper(object):
       
    41     def __init__(self):
       
    42         self.CARBON_RESOURCE_TYPE_MAP = {'configurationroot' : self.map_carbon_configurationroot,
       
    43                              'configurationlayer' : self.map_carbon_configurationlayer,
       
    44                              'featurelist' : self.map_carbon_featurelist}
       
    45         self.CONFML_RESOURCE_TYPE_MAP = {'configurationroot' : self.map_confml_configurationroot,
       
    46                              'configurationlayer' : self.map_confml_configurationlayer,
       
    47                              'featurelist' : self.map_confml_featurelist}
       
    48 
       
    49     def map_carbon_resource(self, resourcepath):
       
    50         for resourceext in self.CARBON_RESOURCE_TYPE_MAP:
       
    51             if resourcepath.endswith(resourceext):
       
    52                 return self.CARBON_RESOURCE_TYPE_MAP[resourceext](resourcepath)
       
    53         return resourcepath
       
    54 
       
    55     def map_confml_resource(self, resourcetype, resourcepath):
       
    56         return self.CONFML_RESOURCE_TYPE_MAP[resourcetype](resourcepath)
       
    57 
       
    58     def map_carbon_configurationroot(self, resourcepath):
       
    59         return resourcepath.replace('.configurationroot', '.confml')
       
    60 
       
    61     def map_carbon_configurationlayer(self, resourcepath):
       
    62         return resourcepath.replace('.configurationlayer', '/root.confml')
       
    63 
       
    64     def map_carbon_featurelist(self, resourcepath):
       
    65         return "featurelists/%s" % resourcepath.replace('.featurelist', '.confml')
       
    66 
       
    67     def map_confml_configurationroot(self, resourcepath):
       
    68         return resourcepath.replace('.confml', '.configurationroot')
       
    69 
       
    70     def map_confml_configurationlayer(self, resourcepath):
       
    71         return resourcepath.replace('/root.confml', '.configurationlayer')
       
    72 
       
    73     def map_confml_featurelist(self, resourcepath):
       
    74         path = resourcepath.replace('featurelists/','').replace('.confml', '')
       
    75         version_identifier = 'WORKING'
       
    76         m = re.match('^(.*) \((.*)\)', path)
       
    77         # if the resourcepath does not have version information 
       
    78         # use default WORKING
       
    79         if m:
       
    80             path = m.group(1)
       
    81             version_identifier = m.group(2)
       
    82         return '%s (%s).featurelist' % (path, version_identifier)
       
    83 
       
    84 class ResourceListReader(persistence.ConeReader):
       
    85     """
       
    86     """ 
       
    87     def loads(self, jsonstr):
       
    88         """
       
    89         @param jsonstr: The json string to read. 
       
    90         """
       
    91         reslist = model.ResourceList()
       
    92         datadict = simplejson.loads(jsonstr)
       
    93         for configuration in datadict.get('configurations', []):
       
    94             reslist.add_resource(model.ConfigurationResource(**configuration))
       
    95         for featurelist in datadict.get('featurelists', []):
       
    96             reslist.add_resource(model.FeatureListResource(**featurelist))
       
    97         return reslist
       
    98 
       
    99 class HasResourceReader(persistence.ConeReader):
       
   100     """
       
   101     """ 
       
   102     def loads(self, jsonstr):
       
   103         """
       
   104         @param jsonstr: The json string to read. 
       
   105         """
       
   106         try:
       
   107             datadict = simplejson.loads(jsonstr)
       
   108             return datadict.get('has_resource',False)
       
   109         except ValueError,e:
       
   110             logging.getLogger('cone').error("Failed to parser json from %s" % jsonstr)
       
   111             raise e
       
   112 
       
   113 
       
   114 class CarbonWriter(persistence.ConeWriter):
       
   115     """
       
   116     """ 
       
   117     def dumps(self, obj):
       
   118         """
       
   119         @param obj: The object 
       
   120         """
       
   121         """ Make sure that the object is mapped to an object in this model """
       
   122         mobj = obj._get_mapper('carbon').map_object(obj)
       
   123         writer = get_writer_for_class(mobj.__class__.__name__)
       
   124         return writer.dumps(obj)
       
   125 
       
   126 
       
   127 class CarbonReader(persistence.ConeReader):
       
   128     """
       
   129     """ 
       
   130     def loads(self, jsonstr):
       
   131         """
       
   132         @param xml: The xml which to read. reads only the first object. 
       
   133         """
       
   134         try:
       
   135             datadict = simplejson.loads(jsonstr)
       
   136             for key in datadict:
       
   137                 reader = get_reader_for_elem(key)
       
   138                 return reader.loads(datadict[key])
       
   139         except (SyntaxError, ValueError),e:
       
   140             utils.log_exception(logging.getLogger('cone'), "Json string parse raised exception: %s!" % (e))
       
   141             raise exceptions.ParseError("Json string %s parse raised exception: %s!" % (jsonstr,e))
       
   142 
       
   143 class ConfigurationCreateWriter(CarbonWriter):
       
   144     @classmethod
       
   145     def supported_class(cls, classname):
       
   146         """
       
   147         Class method to determine if this CarbonWriter supports writing
       
   148         of the given class name
       
   149         """
       
   150         return False
       
   151 
       
   152     def dumps(self, obj):
       
   153         """
       
   154         @param obj: The Configuration object 
       
   155         """
       
   156         featurelists = []
       
   157         included = []
       
   158         # Remove the featurelists and configurations from the creation phase
       
   159 #        resmapper = CarbonResourceMapper()
       
   160 #        for confpath in obj.list_configurations():
       
   161 #            config = obj.get_configuration(confpath)
       
   162 #            if config.meta and config.meta.get('type') == 'featurelist':
       
   163 #                featurelists.append(resmapper.map_confml_resource('featurelist',confpath))
       
   164 #            elif config.meta and config.meta.get('type'):
       
   165 #                included.append(resmapper.map_confml_resource(config.meta.get('type'),confpath))
       
   166 #            else:
       
   167 #                # ignore configs that are not carbon configs
       
   168 #                pass
       
   169 
       
   170         configuration_dict = {'name' : obj.name,
       
   171                               'parent_path' : '',
       
   172                               'included' : included,
       
   173                               'description' : obj.desc or 'Needs description',
       
   174                               'configuration_type' : 'carbon',
       
   175                               'resource_type' : 'configuration',
       
   176                               'feature_lists' : featurelists, 
       
   177                                }
       
   178         
       
   179         return configuration_dict
       
   180 
       
   181 class ConfigurationWriter(CarbonWriter):
       
   182     @classmethod
       
   183     def supported_class(cls, classname):
       
   184         """
       
   185         Class method to determine if this CarbonWriter supports writing
       
   186         of the given class name
       
   187         """
       
   188         if classname=="CarbonConfiguration":
       
   189             return True
       
   190         else:
       
   191             return False
       
   192 
       
   193     def dumps(self, obj):
       
   194         if obj.meta:
       
   195             if obj.meta.get('type') == 'configurationroot':
       
   196                 return self.dumps_root(obj)
       
   197             elif obj.meta.get('type') == 'configurationlayer':
       
   198                 return self.dumps_layer(obj)
       
   199         raise Exception("Not supported CarbonConfigruration, %s" % obj)
       
   200 
       
   201     def dumps_root(self, obj):
       
   202         """
       
   203         @param obj: The Configuration object 
       
   204         """
       
   205         featurelists = []
       
   206         included = []
       
   207         resmapper = CarbonResourceMapper()
       
   208         for confpath in obj.list_configurations():
       
   209             config = obj.get_configuration(confpath)
       
   210             if config.meta:
       
   211                 if config.meta.get('type') == 'featurelist':
       
   212                     featurelists.append(resmapper.map_confml_resource('featurelist',confpath))
       
   213                 else:
       
   214                     included.append(resmapper.map_confml_resource(config.meta.get('type'),confpath))
       
   215             else:
       
   216                 # This default case could also be identified as error
       
   217                 included.append(confpath)
       
   218 
       
   219         configuration_dict = {'feature_lists': featurelists,
       
   220                              'parent_config': None, 
       
   221                              'configuration_name': obj.name, 
       
   222                              'version_identifier': obj.version_identifier, 
       
   223                              'included': included, 
       
   224                              'ref': obj.ref}
       
   225         
       
   226         return configuration_dict
       
   227 
       
   228     def dumps_layer(self, obj):
       
   229         """
       
   230         @param obj: The Configuration object 
       
   231         """
       
   232         configuration_dict = {'version_identifier': obj.version_identifier}
       
   233 
       
   234         datawriter = DataWriter()
       
   235         data = datawriter.dumps(obj)
       
   236         configuration_dict['data'] =  data
       
   237         
       
   238         return configuration_dict
       
   239 
       
   240 class ConfigurationRootReader(CarbonReader):
       
   241     """
       
   242     """ 
       
   243     @classmethod
       
   244     def supported_elem(cls, elemname, parent=None):
       
   245         """
       
   246         Class method to determine if this ConfmlWriter supports writing
       
   247         of the given elem name
       
   248         """
       
   249         if elemname=="configurationroot":
       
   250             return True
       
   251         else:
       
   252             return False
       
   253 
       
   254     def __init__(self):
       
   255         pass
       
   256 
       
   257     def loads(self, dict):
       
   258         """
       
   259         @param obj: The Configuration object 
       
   260         """
       
   261         name = dict.get('configuration_name')
       
   262         path = name + ".confml"
       
   263         conf = model.CarbonConfiguration(dict.get('ref'), path=path, type='configurationroot')
       
   264         conf.name = name
       
   265         conf.version = dict.get('version_identifier')
       
   266         resmapper = CarbonResourceMapper()
       
   267         
       
   268         """ Read the featurelists as included configurations """
       
   269         for fealist in dict.get('feature_lists',[]):
       
   270             conf.include_configuration(resmapper.map_carbon_resource(fealist))
       
   271         """ Read the included configurations """
       
   272         for includedconfig in dict.get('included',[]):
       
   273             conf.include_configuration(resmapper.map_carbon_resource(includedconfig))
       
   274         return conf
       
   275 
       
   276 class ConfigurationLayerReader(CarbonReader):
       
   277     """
       
   278     """ 
       
   279     @classmethod
       
   280     def supported_elem(cls, elemname, parent=None):
       
   281         """
       
   282         Class method to determine if this ConfmlWriter supports writing
       
   283         of the given elem name
       
   284         """
       
   285         if elemname=="configurationlayer":
       
   286             return True
       
   287         else:
       
   288             return False
       
   289 
       
   290     def __init__(self):
       
   291         pass
       
   292 
       
   293     def loads(self, dict):
       
   294         """
       
   295         @param obj: The Configuration object 
       
   296         """
       
   297         name = dict.get('configuration_name')
       
   298         path = name + ".confml"
       
   299         conf = model.CarbonConfiguration(dict.get('ref'), path=path, type='configurationlayer')
       
   300         conf.name = name
       
   301         
       
   302         conf.version = dict.get('version_identifier')
       
   303         
       
   304         """ Last read the data of this configuration and add it as a configuration """
       
   305         data_reader = DataReader()
       
   306         datacont = data_reader.loads(dict.get('data', {}))
       
   307         proxy = api.ConfigurationProxy(datacont.path)
       
   308         conf.add_configuration(proxy)
       
   309         proxy._set_obj(datacont)
       
   310         
       
   311         return conf
       
   312 
       
   313 class FeatureListCreateWriter(CarbonWriter):
       
   314     @classmethod
       
   315     def supported_class(cls, classname):
       
   316         """
       
   317         Feature list create writer is supported only explicitly
       
   318         """
       
   319         return False
       
   320 
       
   321     def dumps(self, obj):
       
   322         """
       
   323         @param obj: The FeatureList object 
       
   324         """
       
   325         """ Make sure that the object is mapped to an object in this model """
       
   326         mobj = obj._get_mapper('carbon').map_object(obj)
       
   327         featurelist_dict = {'type' : 'featurelist',
       
   328                             'flv_description' : mobj.desc or 'Needs description',
       
   329                             'version_identifier' : mobj.version_identifier
       
   330                             }
       
   331         if hasattr(mobj, 'responsible'):
       
   332             featurelist_dict['responsible'] = mobj.responsible
       
   333         return featurelist_dict
       
   334 
       
   335 class FeatureListWriter(CarbonWriter):
       
   336     @classmethod
       
   337     def supported_class(cls, classname):
       
   338         """
       
   339         Feature list create writer is supported only explicitly
       
   340         """
       
   341         if classname == 'FeatureList':
       
   342             return True
       
   343         else:
       
   344             return False
       
   345 
       
   346     def dumps(self, obj):
       
   347         """
       
   348         @param obj: The FeatureList object 
       
   349         """
       
   350 
       
   351         featurelist_dict = {
       
   352                             'type' : 'featurelist',
       
   353                             'name' : obj.name,
       
   354                             'flv_description' : obj.desc or 'Needs description',
       
   355                             'path' : obj.path,
       
   356                             'features' : []
       
   357                             }
       
   358         if obj.meta.get('version_identifier'):
       
   359             featurelist_dict['version_identifier'] = obj.meta.get('version_identifier')
       
   360         # add all features of the featurelist
       
   361         for fearef in obj.list_features():
       
   362             feature = obj.get_feature(fearef)
       
   363             writer = FeatureWriter()
       
   364             feadict = writer.dumps(feature)
       
   365             featurelist_dict['features'].append(feadict)
       
   366         
       
   367         return featurelist_dict
       
   368 
       
   369 class FeatureListReader(CarbonReader):
       
   370     """
       
   371     """ 
       
   372     @classmethod
       
   373     def supported_elem(cls, elemname, parent=None):
       
   374         """
       
   375         Class method to determine if this ConfmlWriter supports writing
       
   376         of the given elem name
       
   377         """
       
   378         if elemname=="featurelist":
       
   379             return True
       
   380         else:
       
   381             return False
       
   382 
       
   383     def __init__(self):
       
   384         pass
       
   385 
       
   386     def loads(self, dict):
       
   387         """
       
   388         @param obj: The Configuration object 
       
   389         """
       
   390         fealist_expanded            = dict.get('expanded')
       
   391         fealist_version             = dict.get('version_identifier')
       
   392         fealist_is_latest_version   = dict.get('is_latest_version')
       
   393         fealist_list_id             = dict.get('list_id')
       
   394         fealist_path                = dict.get('path')
       
   395         fealist_version_title       = dict.get('version_title')
       
   396         fealist_can_be_released     = dict.get('can_be_released')
       
   397         fealist_type                = dict.get('type')
       
   398         fealist_has_external_relations = dict.get('is_latest_version')
       
   399         
       
   400         # Create a configuration object from the featurelist
       
   401         conf = model.FeatureList(path='featurelists/'+fealist_version_title+'.confml')
       
   402         conf.meta.add('version_identifier', fealist_version)
       
   403         
       
   404         for feature in dict.get('features'):
       
   405             reader = FeatureReader()
       
   406             fea = reader.loads(feature)
       
   407             if fea != None:
       
   408                 conf.add_feature(fea)
       
   409         
       
   410         for feafqr in conf.list_all_features():
       
   411             # Add empty data object to featurelist configuration
       
   412             conf.add_data(api.Data(fqr=feafqr))
       
   413             
       
   414         return conf
       
   415 
       
   416 
       
   417 class FeatureWriter(CarbonWriter):
       
   418     CONFML_TO_CARBON_TYPE = {
       
   419                              'boolean'   : 'BOOLEAN',
       
   420                              'int'       : 'INTEGER',
       
   421                              'selection' : 'SELECTION',
       
   422                              'string'    : 'STRING',
       
   423                              None : None,
       
   424                              '' : ''
       
   425                              }
       
   426     @classmethod
       
   427     def supported_class(cls, classname):
       
   428         """
       
   429         Class method to determine if this ConfmlWriter supports writing
       
   430         of the given class name
       
   431         """
       
   432         if classname=="Feature" or\
       
   433             classname=="CarbonBooleanSetting" or\
       
   434             classname=="CarbonIntSetting" or\
       
   435             classname=="CarbonStringSetting" or\
       
   436             classname=="CarbonSelectSetting"or\
       
   437             classname=="CarbonSetting":
       
   438             return True
       
   439         else:
       
   440             return False
       
   441 
       
   442     def dumps(self, obj):
       
   443         """
       
   444         @param obj: The Feature object 
       
   445         """
       
   446         """ Make sure that the object is mapped to an object in this model """
       
   447         mobj = obj._get_mapper('carbon').map_object(obj)
       
   448         
       
   449         featuredict = {'type' : 'feature',
       
   450                        'status' : 'APPROVED',
       
   451                        'title' : mobj.name,
       
   452                        'ref' : mobj.ref,
       
   453                        'description' : mobj.desc or 'Needs description',
       
   454                        'responsible' : None,
       
   455                        'value_type' : self.CONFML_TO_CARBON_TYPE[mobj.type],
       
   456                        'children' : []}
       
   457         if featuredict['value_type'] != None:
       
   458             featuredict['type_object'] = 'carbon_feature_type_normal'
       
   459         if mobj.type == 'selection':
       
   460             featuredict['options'] = mobj.options.keys() 
       
   461 
       
   462         writer = FeatureWriter()
       
   463         for fearef in mobj.list_features():
       
   464             feaobj = obj.get_feature(fearef)
       
   465             childdict = writer.dumps(feaobj)
       
   466             featuredict['children'].append(childdict)
       
   467         return featuredict
       
   468 
       
   469 
       
   470 class FeatureReader(CarbonReader):
       
   471     """
       
   472     """ 
       
   473     @classmethod
       
   474     def supported_elem(cls, elemname, parent=None):
       
   475         """
       
   476         Class method to determine if this ConfmlWriter supports writing
       
   477         of the given elem name
       
   478         """
       
   479         if elemname=="features":
       
   480             return True
       
   481         else:
       
   482             return False
       
   483 
       
   484     def __init__(self):
       
   485         pass
       
   486 
       
   487     def loads(self, dict):
       
   488         """
       
   489         @param obj: The Configuration object 
       
   490         """
       
   491         id = dict.get('id')
       
   492         name = dict.get('title')
       
   493         ref = dict.get('ref')
       
   494         ref = utils.resourceref.to_objref(ref)
       
   495         status = dict.get('status')
       
   496         value_type = dict.get('value_type')
       
   497         description = dict.get('description')
       
   498         
       
   499         if value_type == 'boolean':
       
   500             fea = model.CarbonBooleanSetting(ref, type=value_type)
       
   501         elif value_type == 'integer':
       
   502             fea = model.CarbonIntSetting(ref, type=value_type)
       
   503         elif value_type == 'string':
       
   504             fea = model.CarbonStringSetting(ref, type=value_type)
       
   505         elif value_type == 'selection':
       
   506             fea = model.CarbonSelectionSetting(ref, type=value_type)
       
   507             for option in dict.get('options'):
       
   508                 fea.add_option(option,option)
       
   509         elif value_type == '':
       
   510             fea = model.CarbonFeature(ref, type=value_type)
       
   511         else:
       
   512             fea = model.CarbonFeature(ref)
       
   513 
       
   514         
       
   515         fea.name = name
       
   516         fea.status = status
       
   517         fea.desc = description
       
   518          
       
   519         for childdict in dict.get('children',[]):
       
   520             reader = FeatureReader()
       
   521             subfea = reader.loads(childdict)
       
   522             if subfea != None:
       
   523                 fea.add_feature(subfea)
       
   524         return fea
       
   525 
       
   526 class DataWriter(CarbonWriter):
       
   527     @classmethod
       
   528     def supported_class(cls, classname):
       
   529         """
       
   530         Class method to determine if this ConfmlWriter supports writing
       
   531         of the given class name
       
   532         """
       
   533         if  classname=="Data" or \
       
   534             classname=="DataContainer":
       
   535             return True
       
   536         else:
       
   537             return False
       
   538 
       
   539     def dumps(self, obj):
       
   540         """
       
   541         @param obj: The DataContainer object 
       
   542         """
       
   543         datadict = {}
       
   544         for dataelem in obj._traverse(type=api.Data):
       
   545             if dataelem.get_value() != None:
       
   546                 datadict[dataelem.get_fearef()] = map_confml2carbon_value(dataelem.get_value())
       
   547         return datadict
       
   548 
       
   549 
       
   550 class DataReader(CarbonReader):
       
   551     """
       
   552     """ 
       
   553     @classmethod
       
   554     def supported_elem(cls, elemname, parent=None):
       
   555         """
       
   556         Class method to determine if this ConfmlWriter supports writing
       
   557         of the given elem name
       
   558         """
       
   559         if elemname=="data":
       
   560             return True
       
   561         else:
       
   562             return False
       
   563 
       
   564     def __init__(self):
       
   565         pass
       
   566 
       
   567     def loads(self, dict):
       
   568         """
       
   569         @param obj: The Configuration object 
       
   570         """
       
   571         datacont  = api.Configuration('confml/data.confml')
       
   572         for dataref in dict.keys():
       
   573             # Ignore null values
       
   574             if dict[dataref]:
       
   575                 refs = []
       
   576                 for elem in dataref.split('.'):
       
   577                     refs.append(utils.resourceref.to_objref(elem))
       
   578                 newref = '.'.join(refs)
       
   579                 dataelem = api.Data(fqr=newref, value=map_carbon2confml_value(dict[dataref]))
       
   580                 datacont.add_data(dataelem)
       
   581         return datacont
       
   582 
       
   583 def map_carbon2confml_value(value):
       
   584     if value == 'DEFINED':
       
   585         return 'true'
       
   586     elif value == 'UNDEFINED':
       
   587         return 'false'
       
   588     else:
       
   589         return value
       
   590 
       
   591 def map_confml2carbon_value(value):
       
   592     if value == 'true':
       
   593         return 'DEFINED'
       
   594     elif value == 'false':
       
   595         return 'UNDEFINED'
       
   596     else:
       
   597         return value
       
   598 
       
   599 def get_reader_for_elem(elemname, parent=None):
       
   600     for reader in CarbonReader.__subclasses__():
       
   601         if reader.supported_elem(elemname,parent):
       
   602             return reader()
       
   603     raise exceptions.ConePersistenceError("No reader for given elem %s under %s found!" % (elemname, parent))
       
   604 
       
   605 def get_writer_for_class(classname):
       
   606     for writer in CarbonWriter.__subclasses__():
       
   607         if writer.supported_class(classname):
       
   608             return writer ()
       
   609     raise exceptions.ConePersistenceError("No writer for given class found! %s" % classname)