113 lines
3.2 KiB
Python
113 lines
3.2 KiB
Python
import weakref
|
|
import collections
|
|
|
|
from objectbroker.Persistence import Persistence,NoPersistence
|
|
|
|
class Serializer:
|
|
"""Base class for object serialization with support for persistence"""
|
|
|
|
def __init__(self, objStore, objCache = weakref.WeakValueDictionary() ):
|
|
self.__objStore = objStore
|
|
self.__objCache = objCache
|
|
|
|
|
|
def serialize(self, o):
|
|
slist = {}
|
|
state = self.objectToState( o, slist )
|
|
self.__objStore.save(state, slist)
|
|
|
|
def unserialize(self, pid):
|
|
o = self.objectFromCache( pid )
|
|
if o is None:
|
|
state = self.__objStore.load( pid )
|
|
o = self.stateToObject( state )
|
|
return o
|
|
|
|
def objectToState(self, o, states = {} ):
|
|
"""Create a state dict for an object <o>.
|
|
Returns the state dict.
|
|
After method returns, <states> will contain entries for all referenced persistent objects."""
|
|
|
|
if not isinstance(o, Persistence):
|
|
raise TypeError("needs to be based on Persistence class to be used as persistent object")
|
|
|
|
if Persistence._persistence_id( o ) in states:
|
|
return states[ Persistence._persistence_id( o ) ]
|
|
|
|
state = {}
|
|
state["pid"] = Persistence._persistence_id( o )
|
|
state["module"] = o.__class__.__module__
|
|
state["class"] = o.__class__.__name__
|
|
state["fields"] = {}
|
|
state["pfields"] = {}
|
|
|
|
nopersistence = self.collectClassAttribute(o.__class__,"NOPERSIST")
|
|
persistnone = self.collectClassAttribute(o.__class__,"PERSISTNONE")
|
|
|
|
states[ state["pid"] ] = state
|
|
|
|
d = object.__getattribute__(o, "__dict__")
|
|
for n in d.keys():
|
|
a = getattr( o, n )
|
|
if (not isinstance( a, collections.Callable)) or isinstance( a, object ):
|
|
if (isinstance( a, NoPersistence)) or (n in nopersistence):
|
|
state["fields"][n] = a
|
|
elif n in persistnone:
|
|
state["fields"][n] = None
|
|
elif (isinstance( a, Persistence)):
|
|
state["pfields"][n] = self.objectToState( a, states )["pid"]
|
|
else:
|
|
state["fields"][n] = a
|
|
|
|
return state
|
|
|
|
def stateToObject(self, state):
|
|
"""Returns an object that is constructed of the given state.
|
|
If the cache already holds a reference to an object with the same persistence id,
|
|
this reference is returned without any alternation of the object."""
|
|
|
|
o = self.objFromCache( state["pid"] )
|
|
if not o is None:
|
|
return o
|
|
|
|
m = __import__(state["module"],fromlist=[state["class"]])
|
|
cls = getattr(m, state["class"] )
|
|
o = cls.__new__(cls)
|
|
|
|
objToCache( o, state["pid"] )
|
|
|
|
for n in state["fields"]:
|
|
setattr( o, n, state["fields"][n] )
|
|
|
|
for n in state["pfields"]:
|
|
setattr( o, n, self.stateToObject( state["pfields"][n] ))
|
|
|
|
return o
|
|
|
|
def objFromCache(self, pid):
|
|
if not self.__objCache is None:
|
|
if pid in self.__objCache:
|
|
return self.__objCache[ pid ]
|
|
return None
|
|
|
|
def objToCache(self, o, pid = None):
|
|
if pid is None:
|
|
pid = Persistence._persistence_id( o )
|
|
|
|
if not self.__objCache is None:
|
|
if not pid in self.__objCache:
|
|
self.__objCache[ pid ] = o
|
|
|
|
def collectClassAttribute(self, c, name, default = set() ):
|
|
collection = default
|
|
classes = (self.__class__,) + self.__class__.__bases__
|
|
|
|
for clazz in classes:
|
|
if hasattr(clazz, name):
|
|
if isinstance( collection, dict ):
|
|
collection.update( getattr( clazz, name ) )
|
|
else:
|
|
collection = collection + getattr( clazz, name )
|
|
|
|
return collection
|