~hudson-openstack/nova/trunk

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/spread/publish.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.test.test_pb -*-
 
2
# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 
3
# See LICENSE for details.
 
4
 
 
5
"""
 
6
Persistently cached objects for PB.
 
7
 
 
8
Maintainer: Glyph Lefkowitz
 
9
 
 
10
Future Plans: None known.
 
11
"""
 
12
 
 
13
import time
 
14
 
 
15
from twisted.internet import defer
 
16
from twisted.spread import banana, jelly, flavors
 
17
 
 
18
 
 
19
class Publishable(flavors.Cacheable):
 
20
    """An object whose cached state persists across sessions.
 
21
    """
 
22
    def __init__(self, publishedID):
 
23
        self.republish()
 
24
        self.publishedID = publishedID
 
25
 
 
26
    def republish(self):
 
27
        """Set the timestamp to current and (TODO) update all observers.
 
28
        """
 
29
        self.timestamp = time.time()
 
30
 
 
31
    def view_getStateToPublish(self, perspective):
 
32
        '(internal)'
 
33
        return self.getStateToPublishFor(perspective)
 
34
    
 
35
    def getStateToPublishFor(self, perspective):
 
36
        """Implement me to special-case your state for a perspective.
 
37
        """
 
38
        return self.getStateToPublish()
 
39
 
 
40
    def getStateToPublish(self):
 
41
        """Implement me to return state to copy as part of the publish phase.
 
42
        """
 
43
        raise NotImplementedError("%s.getStateToPublishFor" % self.__class__)
 
44
 
 
45
    def getStateToCacheAndObserveFor(self, perspective, observer):
 
46
        """Get all necessary metadata to keep a clientside cache.
 
47
        """
 
48
        if perspective:
 
49
            pname = perspective.perspectiveName
 
50
            sname = perspective.getService().serviceName
 
51
        else:
 
52
            pname = "None"
 
53
            sname = "None"
 
54
 
 
55
        return {"remote": flavors.ViewPoint(perspective, self),
 
56
                "publishedID": self.publishedID,
 
57
                "perspective": pname,
 
58
                "service": sname,
 
59
                "timestamp": self.timestamp}
 
60
 
 
61
class RemotePublished(flavors.RemoteCache):
 
62
    """The local representation of remote Publishable object.
 
63
    """
 
64
    isActivated = 0
 
65
    _wasCleanWhenLoaded = 0
 
66
    def getFileName(self, ext='pub'):
 
67
        return ("%s-%s-%s.%s" %
 
68
                (self.service, self.perspective, str(self.publishedID), ext))
 
69
    
 
70
    def setCopyableState(self, state):
 
71
        self.__dict__.update(state)
 
72
        self._activationListeners = []
 
73
        try:
 
74
            dataFile = file(self.getFileName(), "rb")
 
75
            data = dataFile.read()
 
76
            dataFile.close()
 
77
        except IOError:
 
78
            recent = 0
 
79
        else:
 
80
            newself = jelly.unjelly(banana.decode(data))
 
81
            recent = (newself.timestamp == self.timestamp)
 
82
        if recent:
 
83
            self._cbGotUpdate(newself.__dict__)
 
84
            self._wasCleanWhenLoaded = 1
 
85
        else:
 
86
            self.remote.callRemote('getStateToPublish').addCallbacks(self._cbGotUpdate)
 
87
 
 
88
    def __getstate__(self):
 
89
        other = self.__dict__.copy()
 
90
        # Remove PB-specific attributes
 
91
        del other['broker']
 
92
        del other['remote']
 
93
        del other['luid']
 
94
        # remove my own runtime-tracking stuff
 
95
        del other['_activationListeners']
 
96
        del other['isActivated']
 
97
        return other
 
98
 
 
99
    def _cbGotUpdate(self, newState):
 
100
        self.__dict__.update(newState)
 
101
        self.isActivated = 1
 
102
        # send out notifications
 
103
        for listener in self._activationListeners:
 
104
            listener(self)
 
105
        self._activationListeners = []
 
106
        self.activated()
 
107
        dataFile = file(self.getFileName(), "wb")
 
108
        dataFile.write(banana.encode(jelly.jelly(self)))
 
109
        dataFile.close()
 
110
 
 
111
 
 
112
    def activated(self):
 
113
        """Implement this method if you want to be notified when your
 
114
        publishable subclass is activated.
 
115
        """
 
116
        
 
117
    def callWhenActivated(self, callback):
 
118
        """Externally register for notification when this publishable has received all relevant data.
 
119
        """
 
120
        if self.isActivated:
 
121
            callback(self)
 
122
        else:
 
123
            self._activationListeners.append(callback)
 
124
 
 
125
def whenReady(d):
 
126
    """
 
127
    Wrap a deferred returned from a pb method in another deferred that
 
128
    expects a RemotePublished as a result.  This will allow you to wait until
 
129
    the result is really available.
 
130
 
 
131
    Idiomatic usage would look like::
 
132
 
 
133
        publish.whenReady(serverObject.getMeAPublishable()).addCallback(lookAtThePublishable)
 
134
    """
 
135
    d2 = defer.Deferred()
 
136
    d.addCallbacks(_pubReady, d2.errback,
 
137
                   callbackArgs=(d2,))
 
138
    return d2
 
139
 
 
140
def _pubReady(result, d2):
 
141
    '(internal)'
 
142
    result.callWhenActivated(d2.callback)