Welcome, guest | Sign In | My Account | Store | Cart
import re, time, xmlrpclib
from SimpleXMLRPCServer import *
import threading

class SomeState(object):
    def __init__(self):
        self.value = 0
        
    
CLASSES = [SomeState]
TIMEOUT = 60.0 * 5.0

class Timeout:
    pass
    
class InvalidId:
    pass
    
class ObjectManager(object):
    """ ObjectManager stores and  manages id-to-object mappings. It utilizes the 
    Borg pattern to avoid global variables.
    """
    shared_state = {"id2o" : {}}
    
    def __init__(self):
        self.__dict__ = self.shared_state
        
    def map(self, val, classes):
        """ Checks if a val is of a type found in classes and 
        then creates the mapping between the id of the value and
        a tuple constisting of the value itself and the current time.
        """
        if val.__class__ in classes:
            vid = id(val)
            self.id2o[vid] = (val, time.time())
            val = vid
        return val

    def lookup(self, vid, timeout):
        """ Lookups the passed vid in the o2id-mapping. If not found,
        a InvalidId exception is raised. If found, but the timeout kicks in, a 
        Timeout exception is raised. Otherwise the associated value is returned.
        """
        try:
            o, ts = self.id2o[vid]
            now = time.time()
            if now - ts > timeout:
                raise Timeout()
            self.id2o[vid] = (o, now)
            return o
        except KeyError:
            raise InvalidId()

            
def map(classes=CLASSES):
    """
    Registers a result value in the ObjectManager. The optional classes argument specifies
    the list of instances that are subject to mapping.
    """
    def f(func):
        def _map(self, *args, **kwargs):
            om = ObjectManager()
            res = func(self, *args, **kwargs)
            return om.map(res, classes)
        return _map
    return f
    
def lookup(poslist=[0], timeout=TIMEOUT):
    """
    Lookups the values at the indices listed in poslist in the ObjectManager.
    """    
    def f(func):
        def _lookup(self, *args, **kwargs):
            args = list(args)        
            om = ObjectManager()
            for pos in poslist:
                args[pos] = om.lookup(args[pos], timeout=timeout)
            return func(self, *args, **kwargs)
        return _lookup
    return f
    

def wrap(poslist=[0], timeout=TIMEOUT, classes=CLASSES):
    """
    Cobines lookup and map.
    """    
    def f(func):
        def _wrap(self, *args, **kwargs):
            args = list(args)        
            om = ObjectManager()
            for pos in poslist:
                args[pos] = om.lookup(args[pos], timeout=timeout)
            res = func(self, *args, **kwargs)
            return om.map(res, classes)
        return _wrap
    return f

    

class Test(object):
    
    @map()
    def init(self):
        return SomeState()
        
    @lookup()
    def add(self, state, amount):
        state.value += amount
        return state.value
    
    @wrap(timeout=1.0)
    def clone(self, state):
        ns = SomeState()
        ns.value = state.value
        return ns

    @lookup(poslist=[0,1])
    def equals(self, a, b):
        print a.value , b.value
        return a.value == b.value
        
    
def launch():
    server = SimpleXMLRPCServer(("localhost", 8000))
    server.register_instance(Test())
    server.serve_forever()

    
def main():
    server_thread = threading.Thread(target=launch)
    server_thread.setDaemon(True)   
    server_thread.start()
    # We need some time to start the server - this should be enough.
    time.sleep(4)
    t = xmlrpclib.ServerProxy("http://localhost:8000")
    
    # test mapping
    h = t.init()
    # test lookup
    h_value = t.add(h, 10)
    # test wrap
    cloned_h = t.clone(h)
    assert cloned_h != h
    cloned_h_value = t.add(cloned_h, 10)
    assert cloned_h_value == 20 and h_value == 10
    # test the timeout
    time.sleep(2)
    try:
        cloned_h = t.clone(h)
        assert False
    except xmlrpclib.Fault:
        pass
    # test the poslist 
    assert not t.equals(h, cloned_h)
    
if __name__ == "__main__":
    main()
    

History