source: mauRepo/MolesManager/trunk/cedaMoles/MolesManager/views/moles2gui/__init__.py @ 8507

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/mauRepo/MolesManager/trunk/cedaMoles/MolesManager/views/moles2gui/__init__.py@8507
Revision 8507, 13.1 KB checked in by mnagni, 8 years ago (diff)

Incomplete - # 22534: Add versiojn number to the gui page
 http://team.ceda.ac.uk/trac/ceda/ticket/22534

Line 
1from json.encoder import JSONEncoder
2from json import loads
3import re
4import logging
5from abc import abstractmethod
6from ea_model.moles3_4.utilities.mo_organisation import MO_Organisation
7from ea_model.moles3_4.utilities.mo_individual import MO_Individual
8from cedaMoles.MolesManager.djencoder import escapeForJSON
9import operator
10import inspect
11from cedaMoles.libs.epb import isPrimitive
12
13"""
14    From now on we define:
15    - cedaObject any instances or class defined in from the CedaMoles3 model
16    - jsonObject any json representation generated by the CedaMolesGuiAdapter.encode method
17"""
18
19_encodeMapper = {'ea_model.iso_19108_2006_temporal_schema.temporal_objects.tm_instant.TM_Instant': 
20                    ('cedaMoles.MolesManager.views.moles2gui.om.instant', 'Instant'),
21                 'ea_model.iso_19108_2006_temporal_schema.temporal_objects.tm_period.TM_Period': 
22                    ('cedaMoles.MolesManager.views.moles2gui.om.period', 'Period'),                   
23                 'ea_model.moles3_4.utilities.mo_organisation.MO_Organisation': 
24                    ('cedaMoles.MolesManager.views.moles2gui.mo.party', 'Party'),
25                 'ea_model.moles3_4.utilities.mo_individual.MO_Individual': 
26                    ('cedaMoles.MolesManager.views.moles2gui.mo.party', 'Party'),
27                 'ea_model.moles3_4.utilities.mo_responsiblepartyinfo.MO_ResponsiblePartyInfo': 
28                    ('cedaMoles.MolesManager.views.moles2gui.mo.responsiblePartyInfo', 'ResponsiblePartyInfo'),
29                 'ea_model.ceda_metadatamodel.ceda_observation.ceda_observation.CEDA_Observation': 
30                    ('cedaMoles.MolesManager.views.moles2gui.ceda.observation', 'Observation')                   
31                 }
32
33def encodeCedaMoles2Json(cedaObj):
34    adapter = _encodeCedaMoles2Adapter(cedaObj);
35    if adapter is not None:
36        return _Moles2guiEncoder().encode(adapter)
37   
38    # Then is a non mapped class
39    return None
40
41def decodeJson2CedaMoles(json= None, moles3EPB = None, cedaMoleObj = None):
42    """
43        Updates the given a cedaObject using a jsonObject object.
44        If `moles3EPB` is given it overrride the value from `cedaMoleObj`
45       
46        **Parameters**
47            * json: a json string
48            * moles3EPB: an epb instance to retrieve the cedaObject by the json string
49            * cedaMoleObj: a cedaObject
50       
51        **Raise**
52            * Exception both `moles3EPB` and `cedaMoleObj` are `None`
53    """   
54    if (cedaMoleObj is None or moles3EPB is None) and json is None:
55        raise Exception("No sufficient parameters to exploit the request")
56       
57    adapter = _decodeJson2Adapter(json)       
58     
59    if adapter == json:
60        raise Exception("json string %s cannot be loaded") % json
61   
62    if cedaMoleObj is None:
63        cedaMoleObj = moles3EPB.search(dynamicallyLoadClass(adapter._module, adapter._clazz), adapter.id).first()
64    if cedaMoleObj is None:
65        return cedaMoleObj
66       
67    adapter.decode(cedaMoleObj)
68    return cedaMoleObj
69
70def dynamicallyLoadClass(modulePath, className):
71    mod = __import__(modulePath, fromlist=[className])
72    return getattr(mod, className)
73
74def dictByID(objList):
75    """
76        **Deprecated**
77        Returns a dictionary where the key is the object id
78    """   
79    ret = {}
80    for item in objList:
81        ret[item.id] = item
82    return ret
83
84class CedaMolesGuiAdapter(object):
85    internal = ['_module', '_clazz', '_adapter_module', '_adapter_clazz']
86    mapper = {}
87    acceptedTypes = []   
88
89    def __init__(self):
90        for item in self.mapper.items():
91            setattr(self, item[0], None)
92
93    @classmethod
94    def _cedaObjToAdapterMapping(cls, instance, cedaObject):
95        if type(cedaObject) in cls.acceptedTypes:       
96            for item in cls.mapper.items():
97                if item[0] == 'resultTime' and item[1] == 'resultTime':
98                    print item[0]
99                try:                       
100                    setattr(instance, item[0], getData(cedaObject, item[1]))
101                except Exception as e:
102                    print e
103
104    @classmethod
105    def _adapterToCedaObjMapping(cls, instance, cedaObj):
106        for item in cls.mapper.items():           
107            _setData(cedaObj, item[1], getattr(instance, item[0]))
108
109    def postCedaObjToAdapterMapping(self, cedaObject):
110        """
111        Refines the mapping done using the internal `mapper`.
112        If some mapping are possible only at a later moment override this method
113       
114        **Parameters**
115                * cedaObj: the Ceda object instance which has to be mapped to the adapter
116        """
117        pass
118   
119    def postAdapterToCedaObjMapping(self, cedaObject):
120        """
121        Refines the mapping done using the internal `mapper`.
122        If some mapping are possible only at a later moment override this method
123       
124        **Parameters**
125                * cedaObject: the Ceda object instance which has to be mapped from the adapter
126        """
127    pass
128
129    @classmethod
130    def cedaObjToAdapter(cls, cedaObject):
131        """
132        Injects a new attribute in a CedaMolesGuiAdapter. Using the 2 component `attributeMap` tuple,
133        the attribute has 
134        - name as attributeMap[0]
135        - attributeMap as the attribute in `cedaObject` speficied by attributeMap[1]
136           
137        **Parameters**
138            * cedaObject: a Ceda object instance
139        """
140        adapter = cls()
141        if type(cedaObject) not in cls.acceptedTypes:
142            raise Exception ("Not accepted type mapping")
143       
144        if cedaObject is not None:
145            setattr(adapter, 'id', None)
146            if hasattr(cedaObject, 'id'):
147                setattr(adapter, 'id', cedaObject.id)
148               
149            setattr(adapter, '_module', cedaObject.__module__)       
150            setattr(adapter, '_clazz', cedaObject.__class__.__name__)       
151        setattr(adapter, '_adapter_module', adapter.__module__)       
152        setattr(adapter, '_adapter_clazz', adapter.__class__.__name__)
153        cls._cedaObjToAdapterMapping(adapter, cedaObject)
154        adapter.postCedaObjToAdapterMapping(cedaObject)
155       
156        return adapter
157
158    def decode(self, cedaObject):       
159        if type(cedaObject) not in self.acceptedTypes:
160            raise Exception ("Not accepted type mapping")
161
162        self._adapterToCedaObjMapping(self, cedaObject)
163        self.postAdapterToCedaObjMapping(cedaObject)
164
165class _Moles2guiEncoder(JSONEncoder):
166
167    log = logging.getLogger('DJEncoder')
168   
169    def __init__(self):
170        self.__markers = {}
171        super(_Moles2guiEncoder, self).__init__()
172        self.__pattern = re.compile('\D\D__*')
173        self.__pattern2 = re.compile('\A\w+__id\Z')
174       
175
176    def default(self, obj):       
177        # Convert objects to a dictionary of their representation
178        d = {}
179   
180        if not hasattr(obj, "__dict__"):
181            return d
182   
183        for key in obj.__dict__.keys():
184            if key in CedaMolesGuiAdapter.internal or not (key.startswith("_") or self.__pattern.match(key) or self.__pattern2.match(key)):
185                d.update({key: getattr(obj, key)})
186       
187        for key, value in d.items():
188            if value is not None and id(value) in self.__markers and not isinstance(value, str) and not isinstance(value, int):
189                continue
190            else:
191                self.__markers[id(value)] = value
192                if isinstance(value, str) or isinstance(value, unicode):                   
193                    self.__markers[id(value)] = escapeForJSON(value)
194                else:
195                    self.__markers[id(value)] = value
196        return d
197
198def getData(obj, attrString):
199    """
200    Returns an attribute value from an object. It is similar to getattr() function
201    but in this case the `attr` parameter express a deeper argument than `obj.paramName`.
202    For instance, call drillData(obj, 'a.b.c[1].d') is aquivalent to call
203    obj.a.b.c[1].d
204
205    **Parameters**         
206            * obj: its an the instance from which the attribute is required
207            * attrString: an attributes dot separated string expression
208    """
209    if attrString is not None and isinstance(attrString, str):
210        return _drillData(obj, attrString.split('.'))
211
212def _setDataToAdapter(obj, attrString, value):
213    if attrString is None or not isinstance(attrString, str) or value is None:
214        return
215
216    ret = None
217    if isinstance(value, list):
218        ret = []
219        for item in value:
220            ret.append(_decodeJson2Adapter(item))
221    else:
222        ret = _decodeJson2Adapter(value)       
223    setattr(obj, attrString, ret)
224
225def _setData(obj, attrString, value):
226    if attrString is None or not isinstance(attrString, str):
227        return
228   
229    attrOwner = obj
230    attrName =  attrString
231   
232    items = attrString.split('.')             
233    if len(items[:-1]) > 0:
234        attrOwner = _drillData(obj, items[:-1], toAdapter = False)
235        attrName =  items[-1:][0].partition('[')[0]             
236
237    if attrOwner is not None and hasattr(attrOwner, attrName):
238        attr = getattr(attrOwner, attrName)
239        if isinstance(attr, list):
240            if len(value) == 0:
241                del attr[:]
242           
243            if not isinstance(value[0], CedaMolesGuiAdapter):
244                del attr[:]
245                if isinstance(value, list):
246                    attr.extend(value)
247                else:
248                    attr.append(value)
249            else:   
250                sorted(attr, key = operator.attrgetter('id'))
251                sorted(value, key = operator.attrgetter('id'))
252                for item in attr:
253                    for valueItem in value:
254                        if item.id == valueItem.id:
255                            valueItem.decode(item)                       
256        else:
257            setattr(attrOwner, attrName, value)       
258   
259def _drillData(obj, attr, toAdapter = True):
260    """
261        When the method is used by the cedaObjToAdapter the `toAdapter=True` condition
262        guarantees that an immediate conversion of the mapped classes is done.
263        When the method is used by the adapterTocedaObj the `toAdapter=False` condition
264        guarantees that no 'cedaObjToAdapter' conversion is done. 
265    """
266    if attr is None or len(attr) == 0:
267        return None
268   
269    item = attr[0]
270    newobj = None
271           
272    # is an array?
273    if re.search("\[\d+\]", item) is not None:
274        index = int(re.search("\[\d+\]", item).group(0).replace('[', '').replace(']', ''))
275        parName = item.partition('[')[0]
276        if hasattr(obj, parName) and isinstance(getattr(obj, parName), list):
277            objattr = getattr(obj, parName)
278            if index < len(objattr):
279                newobj = objattr[index]
280            else:
281                return None
282        else:
283            raise Exception ("Parameter call exception. Param:%s" % item) 
284       
285    # is a dictionary?
286    elif re.search("\['\w+\'\]", item) is not None:           
287        key = re.search("\['\w+\'\]", item).group(0).replace('[\'', '').replace('\']', '')
288        parName = item.partition('[')[0]       
289        if hasattr(obj, parName) and isinstance(getattr(obj, parName), dict):
290            objattr = getattr(obj, parName)
291        if objattr.has_key(key):
292            newobj = objattr[key]
293       
294    # is just a simple attribute
295    else:
296        if hasattr(obj, item):
297            newobj = getattr(obj, item)
298   
299    #is the last attr's item?
300    if len(attr) > 1:       
301        return _drillData(newobj, attr[1:], toAdapter)
302   
303    if not toAdapter:
304        return newobj
305
306    if isinstance(newobj, list):
307        ret = []
308        for item in newobj:               
309            ret.append(_encodeCedaMoles2Adapter(item))
310        return ret
311    else:
312        return _encodeCedaMoles2Adapter(newobj)             
313   
314def _encodeCedaMoles2Adapter(cedaObj):
315    if isPrimitive(cedaObj):
316        return cedaObj
317   
318    # Is a mapped class?
319    key = "%s.%s" % (cedaObj.__module__, cedaObj.__class__.__name__)
320    if _encodeMapper.has_key(key):   
321        module, clazz = _encodeMapper[key]
322        encoder = dynamicallyLoadClass(module, clazz)
323        return encoder.cedaObjToAdapter(cedaObj)
324
325   
326    # Then is a non mapped class
327    return None
328
329def _decodeJson2Adapter(json):
330    decJson = json
331   
332    if isPrimitive(decJson) and not isinstance(decJson, str):
333        return decJson
334   
335    if not isinstance(json, dict):
336        try:
337            decJson = loads(json)
338        except:
339            return decJson
340   
341    adapter = dynamicallyLoadClass(decJson['_adapter_module'], decJson['_adapter_clazz'])()
342    setattr(adapter, '_module', decJson['_module'])
343    setattr(adapter, '_clazz', decJson['_clazz'])
344    setattr(adapter, '_adapter_module', decJson['_adapter_module'])
345    setattr(adapter, '_adapter_clazz', decJson['_adapter_clazz'])
346    setattr(adapter, 'id', decJson['id'])
347    for item in adapter.mapper.items():
348        _setDataToAdapter(adapter, item[0], decJson[item[0]])
349    return adapter
350
351def unicodeToString(text):
352    if isinstance(text, unicode):
353        return str(text)
354    return text
355
356def hasAttrNotNone(obj, name):
357    return hasattr(obj, name) and getattr(obj, name) is not None
Note: See TracBrowser for help on using the repository browser.