Initial import to Tizen
[profile/ivi/python-twisted.git] / doc / core / howto / pb-copyable.html
1 <?xml version="1.0" encoding="utf-8"?><!DOCTYPE html  PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN'  'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
2   <head>
3 <title>Twisted Documentation: PB Copyable: Passing Complex Types</title>
4 <link href="stylesheet.css" rel="stylesheet" type="text/css"/>
5   </head>
6
7   <body bgcolor="white">
8     <h1 class="title">PB Copyable: Passing Complex Types</h1>
9     <div class="toc"><ol><li><a href="#auto0">Overview</a></li><li><a href="#auto1">Motivation</a></li><li><a href="#auto2">Passing Objects</a></li><ul><li><a href="#auto3">Security Options</a></li><li><a href="#auto4">What class to use?</a></li></ul><li><a href="#auto5">pb.Copyable</a></li><ul><li><a href="#auto6">Controlling the Copied State</a></li><li><a href="#auto7">Things To Watch Out For</a></li><li><a href="#auto8">More Information</a></li></ul><li><a href="#auto9">pb.Cacheable</a></li><ul><li><a href="#auto10">Example</a></li><li><a href="#auto11">More Information</a></li></ul></ol></div>
10     <div class="content">
11 <span/>
12
13 <h2>Overview<a name="auto0"/></h2>
14
15 <p>This chapter focuses on how to use PB to pass complex types (specifically
16 class instances) to and from a remote process. The first section is on
17 simply copying the contents of an object to a remote process (<code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.Copyable.html" title="twisted.spread.pb.Copyable">pb.Copyable</a></code>). The second covers how
18 to copy those contents once, then update them later when they change (<code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.Cacheable.html" title="twisted.spread.pb.Cacheable">Cacheable</a></code>).</p>
19
20 <h2>Motivation<a name="auto1"/></h2>
21
22 <p>From the <a href="pb-usage.html" shape="rect">previous chapter</a>, you've seen how to
23 pass basic types to a remote process, by using them in the arguments or
24 return values of a <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.RemoteReference.callRemote.html" title="twisted.spread.pb.RemoteReference.callRemote">callRemote</a></code> function. However,
25 if you've experimented with it, you may have discovered problems when trying
26 to pass anything more complicated than a primitive int/list/dict/string
27 type, or another <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.Referenceable.html" title="twisted.spread.pb.Referenceable">pb.Referenceable</a></code> object. At some point you want
28 to pass entire objects between processes, instead of having to reduce them
29 down to dictionaries on one end and then re-instantiating them on the
30 other.</p>
31
32 <h2>Passing Objects<a name="auto2"/></h2>
33
34 <p>The most obvious and straightforward way to send an object to a remote
35 process is with something like the following code. It also happens that this
36 code doesn't work, as will be explained below.</p>
37
38 <pre class="python"><p class="py-linenumber">1
39 2
40 3
41 4
42 5
43 6
44 </p><span class="py-src-keyword">class</span> <span class="py-src-identifier">LilyPond</span>:
45   <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">frogs</span>):
46     <span class="py-src-variable">self</span>.<span class="py-src-variable">frogs</span> = <span class="py-src-variable">frogs</span>
47
48 <span class="py-src-variable">pond</span> = <span class="py-src-variable">LilyPond</span>(<span class="py-src-number">12</span>)
49 <span class="py-src-variable">ref</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;sendPond&quot;</span>, <span class="py-src-variable">pond</span>)
50 </pre>
51
52 <p>If you try to run this, you might hope that a suitable remote end which
53 implements the <code>remote_sendPond</code> method would see that method get
54 invoked with an instance from the <code>LilyPond</code> class. But instead,
55 you'll encounter the dreaded <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.jelly.InsecureJelly.html" title="twisted.spread.jelly.InsecureJelly">InsecureJelly</a></code> exception. This is
56 Twisted's way of telling you that you've violated a security restriction,
57 and that the receiving end refuses to accept your object.</p>
58
59 <h3>Security Options<a name="auto3"/></h3>
60
61 <p>What's the big deal? What's wrong with just copying a class into another
62 process' namespace?</p>
63
64 <p>Reversing the question might make it easier to see the issue: what is the
65 problem with accepting a stranger's request to create an arbitrary object in
66 your local namespace? The real question is how much power you are granting
67 them: what actions can they convince you to take on the basis of the bytes
68 they are sending you over that remote connection.</p>
69
70 <p>Objects generally represent more power than basic types like strings and
71 dictionaries because they also contain (or reference) code, which can modify
72 other data structures when executed. Once previously-trusted data is
73 subverted, the rest of the program is compromised.</p>
74
75 <p>The built-in Python <q>batteries included</q> classes are relatively
76 tame, but you still wouldn't want to let a foreign program use them to
77 create arbitrary objects in your namespace or on your computer. Imagine a
78 protocol that involved sending a file-like object with a <code>read()</code>
79 method that was supposed to used later to retrieve a document. Then imagine
80 what if that object were created with 
81  <code>os.fdopen(&quot;~/.gnupg/secring.gpg&quot;)</code>. Or an instance of 
82  <code>telnetlib.Telnet(&quot;localhost&quot;, &quot;chargen&quot;)</code>. </p>
83
84 <p>Classes you've written for your own program are likely to have far more
85 power. They may run code during <code>__init__</code>, or even have special
86 meaning simply because of their existence. A program might have 
87  <code>User</code> objects to represent user accounts, and have a rule that
88 says all <code>User</code> objects in the system are referenced when
89 authorizing a login session. (In this system, <code>User.__init__</code>
90 would probably add the object to a global list of known users). The simple
91 act of creating an object would give access to somebody. If you could be
92 tricked into creating a bad object, an unauthorized user would get
93 access.</p>
94
95 <p>So object creation needs to be part of a system's security design. The
96 dotted line between <q>trusted inside</q> and <q>untrusted outside</q> needs
97 to describe what may be done in response to outside events. One of those
98 events is the receipt of an object through a PB remote procedure call, which
99 is a request to create an object in your <q>inside</q> namespace. The
100 question is what to do in response to it. For this reason, you must
101 explicitly specify what remote classes will be accepted, and how their
102 local representatives are to be created.</p>
103
104 <h3>What class to use?<a name="auto4"/></h3>
105
106 <p>Another basic question to answer before we can do anything useful with an
107 incoming serialized object is: what class should we create? The simplistic
108 answer is to create the <q>same kind</q> that was serialized on the sender's
109 end of the wire, but this is not as easy or as straightforward as you might
110 think. Remember that the request is coming from a different program, using a
111 potentially different set of class libraries. In fact, since PB has also
112 been implemented in Java, Emacs-Lisp, and other languages, there's no
113 guarantee that the sender is even running Python! All we know on the
114 receiving end is a list of two things which describe the instance they are
115 trying to send us: the name of the class, and a representation of the
116 contents of the object.</p>
117
118
119 <p>PB lets you specify the mapping from remote class names to local classes
120 with the <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.jelly.setUnjellyableForClass.html" title="twisted.spread.jelly.setUnjellyableForClass">setUnjellyableForClass</a></code> function 
121 <a href="#footnote-1" title="Note that, in this context, unjelly is a verb with the opposite meaning of jelly. The verb to jelly means to serialize an object or data structure into a sequence of bytes (or other primitive transmittable/storable representation), while to unjelly means to unserialize the bytestream into a live object in the receiver's memory space. Unjellyable is a noun, (not an adjective), referring to the the class that serves as a destination or recipient of the unjellying process. A is unjellyable into B means that a serialized representation A (of some remote object) can be unserialized into a local object of type B. It is these objects B that are the Unjellyable second argument of the setUnjellyableForClass function. In particular, unjellyable does not mean cannot be jellied. Unpersistable means not persistable, but unjelly, unserialize, and unpickle mean to reverse the operations of jellying, serializing, and pickling."><super>1</super></a>.
122
123
124 This function takes a remote/sender class reference (either the
125 fully-qualified name as used by the sending end, or a class object from
126 which the name can be extracted), and a local/recipient class (used to
127 create the local representation for incoming serialized objects). Whenever
128 the remote end sends an object, the class name that they transmit is looked
129 up in the table controlled by this function. If a matching class is found,
130 it is used to create the local object. If not, you get the 
131  <code>InsecureJelly</code> exception.</p>
132
133 <p>In general you expect both ends to share the same codebase: either you
134 control the program that is running on both ends of the wire, or both
135 programs share some kind of common language that is implemented in code
136 which exists on both ends. You wouldn't expect them to send you an object of
137 the MyFooziWhatZit class unless you also had a definition for that class. So
138 it is reasonable for the Jelly layer to reject all incoming classes except
139 the ones that you have explicitly marked with 
140  <code>setUnjellyableForClass</code>. But keep in mind that the sender's idea
141 of a <code>User</code> object might differ from the recipient's, either
142 through namespace collisions between unrelated packages, version skew
143 between nodes that haven't been updated at the same rate, or a malicious
144 intruder trying to cause your code to fail in some interesting or
145 potentially vulnerable way.</p>
146
147
148 <h2>pb.Copyable<a name="auto5"/></h2>
149
150 <p>Ok, enough of this theory. How do you send a fully-fledged object from
151 one side to the other?</p>
152
153 <div class="py-listing"><pre><p class="py-linenumber"> 1
154  2
155  3
156  4
157  5
158  6
159  7
160  8
161  9
162 10
163 11
164 12
165 13
166 14
167 15
168 16
169 17
170 18
171 19
172 20
173 21
174 22
175 23
176 24
177 25
178 26
179 27
180 28
181 29
182 30
183 31
184 32
185 33
186 34
187 35
188 36
189 37
190 38
191 39
192 40
193 41
194 42
195 43
196 44
197 45
198 46
199 47
200 48
201 49
202 50
203 51
204 52
205 53
206 54
207 55
208 56
209 57
210 </p><span class="py-src-comment">#!/usr/bin/env python</span>
211
212 <span class="py-src-comment"># Copyright (c) Twisted Matrix Laboratories.</span>
213 <span class="py-src-comment"># See LICENSE for details.</span>
214
215 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>, <span class="py-src-variable">jelly</span>
216 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">log</span>
217 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
218
219 <span class="py-src-keyword">class</span> <span class="py-src-identifier">LilyPond</span>:
220     <span class="py-src-keyword">def</span> <span class="py-src-identifier">setStuff</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">color</span>, <span class="py-src-parameter">numFrogs</span>):
221         <span class="py-src-variable">self</span>.<span class="py-src-variable">color</span> = <span class="py-src-variable">color</span>
222         <span class="py-src-variable">self</span>.<span class="py-src-variable">numFrogs</span> = <span class="py-src-variable">numFrogs</span>
223     <span class="py-src-keyword">def</span> <span class="py-src-identifier">countFrogs</span>(<span class="py-src-parameter">self</span>):
224         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;%d frogs&quot;</span> % <span class="py-src-variable">self</span>.<span class="py-src-variable">numFrogs</span>
225
226 <span class="py-src-keyword">class</span> <span class="py-src-identifier">CopyPond</span>(<span class="py-src-parameter">LilyPond</span>, <span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Copyable</span>):
227     <span class="py-src-keyword">pass</span>
228
229 <span class="py-src-keyword">class</span> <span class="py-src-identifier">Sender</span>:
230     <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">pond</span>):
231         <span class="py-src-variable">self</span>.<span class="py-src-variable">pond</span> = <span class="py-src-variable">pond</span>
232
233     <span class="py-src-keyword">def</span> <span class="py-src-identifier">got_obj</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">remote</span>):
234         <span class="py-src-variable">self</span>.<span class="py-src-variable">remote</span> = <span class="py-src-variable">remote</span>
235         <span class="py-src-variable">d</span> = <span class="py-src-variable">remote</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;takePond&quot;</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">pond</span>)
236         <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">ok</span>).<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">notOk</span>)
237
238     <span class="py-src-keyword">def</span> <span class="py-src-identifier">ok</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">response</span>):
239         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;pond arrived&quot;</span>, <span class="py-src-variable">response</span>
240         <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
241     <span class="py-src-keyword">def</span> <span class="py-src-identifier">notOk</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">failure</span>):
242         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;error during takePond:&quot;</span>
243         <span class="py-src-keyword">if</span> <span class="py-src-variable">failure</span>.<span class="py-src-variable">type</span> == <span class="py-src-variable">jelly</span>.<span class="py-src-variable">InsecureJelly</span>:
244             <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; InsecureJelly&quot;</span>
245         <span class="py-src-keyword">else</span>:
246             <span class="py-src-keyword">print</span> <span class="py-src-variable">failure</span>
247         <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
248         <span class="py-src-keyword">return</span> <span class="py-src-variable">None</span>
249
250 <span class="py-src-keyword">def</span> <span class="py-src-identifier">main</span>():
251     <span class="py-src-keyword">from</span> <span class="py-src-variable">copy_sender</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">CopyPond</span>  <span class="py-src-comment"># so it's not __main__.CopyPond</span>
252     <span class="py-src-variable">pond</span> = <span class="py-src-variable">CopyPond</span>()
253     <span class="py-src-variable">pond</span>.<span class="py-src-variable">setStuff</span>(<span class="py-src-string">&quot;green&quot;</span>, <span class="py-src-number">7</span>)
254     <span class="py-src-variable">pond</span>.<span class="py-src-variable">countFrogs</span>()
255     <span class="py-src-comment"># class name:</span>
256     <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;.&quot;</span>.<span class="py-src-variable">join</span>([<span class="py-src-variable">pond</span>.<span class="py-src-variable">__class__</span>.<span class="py-src-variable">__module__</span>, <span class="py-src-variable">pond</span>.<span class="py-src-variable">__class__</span>.<span class="py-src-variable">__name__</span>])
257
258     <span class="py-src-variable">sender</span> = <span class="py-src-variable">Sender</span>(<span class="py-src-variable">pond</span>)
259     <span class="py-src-variable">factory</span> = <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBClientFactory</span>()
260     <span class="py-src-variable">reactor</span>.<span class="py-src-variable">connectTCP</span>(<span class="py-src-string">&quot;localhost&quot;</span>, <span class="py-src-number">8800</span>, <span class="py-src-variable">factory</span>)
261     <span class="py-src-variable">deferred</span> = <span class="py-src-variable">factory</span>.<span class="py-src-variable">getRootObject</span>()
262     <span class="py-src-variable">deferred</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">sender</span>.<span class="py-src-variable">got_obj</span>)
263     <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
264
265 <span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
266     <span class="py-src-variable">main</span>()
267 </pre><div class="caption">Source listing - <a href="listings/pb/copy_sender.py"><span class="filename">listings/pb/copy_sender.py</span></a></div></div>
268 <div class="py-listing"><pre><p class="py-linenumber"> 1
269  2
270  3
271  4
272  5
273  6
274  7
275  8
276  9
277 10
278 11
279 12
280 13
281 14
282 15
283 16
284 17
285 18
286 19
287 20
288 21
289 22
290 23
291 24
292 25
293 26
294 27
295 28
296 29
297 30
298 31
299 32
300 33
301 34
302 35
303 36
304 37
305 38
306 39
307 40
308 41
309 </p><span class="py-src-comment"># Copyright (c) Twisted Matrix Laboratories.</span>
310 <span class="py-src-comment"># See LICENSE for details.</span>
311
312 <span class="py-src-string">&quot;&quot;&quot;
313 PB copy receiver example.
314
315 This is a Twisted Application Configuration (tac) file.  Run with e.g.
316    twistd -ny copy_receiver.tac
317
318 See the twistd(1) man page or
319 http://twistedmatrix.com/documents/current/howto/application for details.
320 &quot;&quot;&quot;</span>
321
322 <span class="py-src-keyword">import</span> <span class="py-src-variable">sys</span>
323 <span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
324     <span class="py-src-keyword">print</span> <span class="py-src-variable">__doc__</span>
325     <span class="py-src-variable">sys</span>.<span class="py-src-variable">exit</span>(<span class="py-src-number">1</span>)
326
327 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">service</span>, <span class="py-src-variable">internet</span>
328 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
329 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
330 <span class="py-src-keyword">from</span> <span class="py-src-variable">copy_sender</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">LilyPond</span>, <span class="py-src-variable">CopyPond</span>
331
332 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">log</span>
333 <span class="py-src-comment">#log.startLogging(sys.stdout)</span>
334
335 <span class="py-src-keyword">class</span> <span class="py-src-identifier">ReceiverPond</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">RemoteCopy</span>, <span class="py-src-parameter">LilyPond</span>):
336     <span class="py-src-keyword">pass</span>
337 <span class="py-src-variable">pb</span>.<span class="py-src-variable">setUnjellyableForClass</span>(<span class="py-src-variable">CopyPond</span>, <span class="py-src-variable">ReceiverPond</span>)
338
339 <span class="py-src-keyword">class</span> <span class="py-src-identifier">Receiver</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Root</span>):
340     <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_takePond</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">pond</span>):
341         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; got pond:&quot;</span>, <span class="py-src-variable">pond</span>
342         <span class="py-src-variable">pond</span>.<span class="py-src-variable">countFrogs</span>()
343         <span class="py-src-keyword">return</span> <span class="py-src-string">&quot;safe and sound&quot;</span> <span class="py-src-comment"># positive acknowledgement</span>
344     <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_shutdown</span>(<span class="py-src-parameter">self</span>):
345         <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
346
347 <span class="py-src-variable">application</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">Application</span>(<span class="py-src-string">&quot;copy_receiver&quot;</span>)
348 <span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-number">8800</span>, <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBServerFactory</span>(<span class="py-src-variable">Receiver</span>())).<span class="py-src-variable">setServiceParent</span>(
349     <span class="py-src-variable">service</span>.<span class="py-src-variable">IServiceCollection</span>(<span class="py-src-variable">application</span>))
350 </pre><div class="caption">Source listing - <a href="listings/pb/copy_receiver.tac"><span class="filename">listings/pb/copy_receiver.tac</span></a></div></div>
351
352 <p>The sending side has a class called <code>LilyPond</code>. To make this
353 eligble for transport through <code>callRemote</code> (either as an
354 argument, a return value, or something referenced by either of those [like a
355 dictionary value]), it must inherit from one of the four <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.Serializable.html" title="twisted.spread.pb.Serializable">Serializable</a></code> classes. In this section,
356 we focus on <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.Copyable.html" title="twisted.spread.pb.Copyable">Copyable</a></code>.
357 The copyable subclass of <code>LilyPond</code> is called 
358  <code>CopyPond</code>. We create an instance of it and send it through 
359  <code>callRemote</code> as an argument to the receiver's 
360  <code>remote_takePond</code> method. The Jelly layer will serialize
361 (<q>jelly</q>) that object as an instance with a class name of
362 <q>copy_sender.CopyPond</q> and some chunk of data that represents the
363 object's state. <code>pond.__class__.__module__</code> and 
364  <code>pond.__class__.__name__</code> are used to derive the class name
365 string. The object's <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.flavors.Copyable.getStateToCopy.html" title="twisted.spread.flavors.Copyable.getStateToCopy">getStateToCopy</a></code> method is
366 used to get the state: this is provided by <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.Copyable.html" title="twisted.spread.pb.Copyable">pb.Copyable</a></code>, and the default just retrieves 
367  <code>self.__dict__</code>. This works just like the optional 
368  <code>__getstate__</code> method used by <code>pickle</code>. The pair of
369 name and state are sent over the wire to the receiver.</p>
370
371 <p>The receiving end defines a local class named <code>ReceiverPond</code>
372 to represent incoming <code>LilyPond</code> instances. This class derives
373 from the sender's <code>LilyPond</code> class (with a fully-qualified name
374 of <code>copy_sender.LilyPond</code>), which specifies how we expect it to
375 behave. We trust that this is the same <code>LilyPond</code> class as the
376 sender used. (At the very least, we hope ours will be able to accept a state
377 created by theirs). It also inherits from <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.RemoteCopy.html" title="twisted.spread.pb.RemoteCopy">pb.RemoteCopy</a></code>, which is a requirement for all
378 classes that act in this local-representative role (those which are given to
379 the second argument of <code>setUnjellyableForClass</code>). 
380  <code>RemoteCopy</code> provides the methods that tell the Jelly layer how
381 to create the local object from the incoming serialized state.</p>
382
383 <p>Then <code>setUnjellyableForClass</code> is used to register the two
384 classes. This has two effects: instances of the remote class (the first
385 argument) will be allowed in through the security layer, and instances of
386 the local class (the second argument) will be used to contain the state that
387 is transmitted when the sender serializes the remote object.</p>
388
389 <p>When the receiver unserializes (<q>unjellies</q>) the object, it will
390 create an instance of the local <code>ReceiverPond</code> class, and hand
391 the transmitted state (usually in the form of a dictionary) to that object's 
392  <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.flavors.RemoteCopy.setCopyableState.html" title="twisted.spread.flavors.RemoteCopy.setCopyableState">setCopyableState</a></code> method.
393 This acts just like the <code>__setstate__</code> method that 
394  <code>pickle</code> uses when unserializing an object. 
395  <code>getStateToCopy</code>/<code>setCopyableState</code> are distinct from 
396  <code>__getstate__</code>/<code>__setstate__</code> to allow objects to be
397 persisted (across time) differently than they are transmitted (across
398 [memory]space).</p>
399
400 <p>When this is run, it produces the following output:</p>
401
402 <pre class="shell" xml:space="preserve">
403 [-] twisted.spread.pb.PBServerFactory starting on 8800
404 [-] Starting factory &lt;twisted.spread.pb.PBServerFactory instance at
405 0x406159cc&gt;
406 [Broker,0,127.0.0.1]  got pond: &lt;__builtin__.ReceiverPond instance at
407 0x406ec5ec&gt;
408 [Broker,0,127.0.0.1] 7 frogs
409 </pre>
410
411 <pre class="shell" xml:space="preserve">
412 $ ./copy_sender.py
413 7 frogs
414 copy_sender.CopyPond
415 pond arrived safe and sound
416 Main loop terminated.
417 $
418 </pre>
419
420
421
422 <h3>Controlling the Copied State<a name="auto6"/></h3>
423
424 <p>By overriding <code>getStateToCopy</code> and 
425  <code>setCopyableState</code>, you can control how the object is transmitted
426 over the wire. For example, you might want perform some data-reduction:
427 pre-compute some results instead of sending all the raw data over the wire.
428 Or you could replace references to a local object on the sender's side with
429 markers before sending, then upon receipt replace those markers with
430 references to a receiver-side proxy that could perform the same operations
431 against a local cache of data.</p>
432
433 <p>Another good use for <code>getStateToCopy</code> is to implement 
434 <q>local-only</q> attributes: data that is only accessible by the local
435 process, not to any remote users. For example, a <code>.password</code>
436 attribute could be removed from the object state before sending to a remote
437 system. Combined with the fact that <code>Copyable</code> objects return
438 unchanged from a round trip, this could be used to build a
439 challenge-response system (in fact PB does this with 
440  <code>pb.Referenceable</code> objects to implement authorization as
441 described <a href="pb-cred.html" shape="rect">here</a>).</p>
442
443 <p>Whatever <code>getStateToCopy</code> returns from the sending object will
444 be serialized and sent over the wire; <code>setCopyableState</code> gets
445 whatever comes over the wire and is responsible for setting up the state of
446 the object it lives in.</p>
447
448
449 <div class="py-listing"><pre><p class="py-linenumber"> 1
450  2
451  3
452  4
453  5
454  6
455  7
456  8
457  9
458 10
459 11
460 12
461 13
462 14
463 15
464 16
465 17
466 18
467 19
468 20
469 21
470 22
471 23
472 24
473 25
474 26
475 27
476 28
477 29
478 </p><span class="py-src-comment">#!/usr/bin/env python</span>
479
480 <span class="py-src-comment"># Copyright (c) Twisted Matrix Laboratories.</span>
481 <span class="py-src-comment"># See LICENSE for details.</span>
482
483 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
484
485 <span class="py-src-keyword">class</span> <span class="py-src-identifier">FrogPond</span>:
486     <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">numFrogs</span>, <span class="py-src-parameter">numToads</span>):
487         <span class="py-src-variable">self</span>.<span class="py-src-variable">numFrogs</span> = <span class="py-src-variable">numFrogs</span>
488         <span class="py-src-variable">self</span>.<span class="py-src-variable">numToads</span> = <span class="py-src-variable">numToads</span>
489     <span class="py-src-keyword">def</span> <span class="py-src-identifier">count</span>(<span class="py-src-parameter">self</span>):
490         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">numFrogs</span> + <span class="py-src-variable">self</span>.<span class="py-src-variable">numToads</span>
491
492 <span class="py-src-keyword">class</span> <span class="py-src-identifier">SenderPond</span>(<span class="py-src-parameter">FrogPond</span>, <span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Copyable</span>):
493     <span class="py-src-keyword">def</span> <span class="py-src-identifier">getStateToCopy</span>(<span class="py-src-parameter">self</span>):
494         <span class="py-src-variable">d</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">__dict__</span>.<span class="py-src-variable">copy</span>()
495         <span class="py-src-variable">d</span>[<span class="py-src-string">'frogsAndToads'</span>] = <span class="py-src-variable">d</span>[<span class="py-src-string">'numFrogs'</span>] + <span class="py-src-variable">d</span>[<span class="py-src-string">'numToads'</span>]
496         <span class="py-src-keyword">del</span> <span class="py-src-variable">d</span>[<span class="py-src-string">'numFrogs'</span>]
497         <span class="py-src-keyword">del</span> <span class="py-src-variable">d</span>[<span class="py-src-string">'numToads'</span>]
498         <span class="py-src-keyword">return</span> <span class="py-src-variable">d</span>
499
500 <span class="py-src-keyword">class</span> <span class="py-src-identifier">ReceiverPond</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">RemoteCopy</span>):
501     <span class="py-src-keyword">def</span> <span class="py-src-identifier">setCopyableState</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">state</span>):
502         <span class="py-src-variable">self</span>.<span class="py-src-variable">__dict__</span> = <span class="py-src-variable">state</span>
503     <span class="py-src-keyword">def</span> <span class="py-src-identifier">count</span>(<span class="py-src-parameter">self</span>):
504         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">frogsAndToads</span>
505
506 <span class="py-src-variable">pb</span>.<span class="py-src-variable">setUnjellyableForClass</span>(<span class="py-src-variable">SenderPond</span>, <span class="py-src-variable">ReceiverPond</span>)
507 </pre><div class="caption">Source listing - <a href="listings/pb/copy2_classes.py"><span class="filename">listings/pb/copy2_classes.py</span></a></div></div>
508 <div class="py-listing"><pre><p class="py-linenumber"> 1
509  2
510  3
511  4
512  5
513  6
514  7
515  8
516  9
517 10
518 11
519 12
520 13
521 14
522 15
523 16
524 17
525 18
526 19
527 20
528 21
529 22
530 23
531 24
532 25
533 26
534 27
535 28
536 29
537 30
538 31
539 32
540 33
541 34
542 35
543 36
544 37
545 38
546 39
547 40
548 41
549 42
550 43
551 44
552 </p><span class="py-src-comment">#!/usr/bin/env python</span>
553
554 <span class="py-src-comment"># Copyright (c) Twisted Matrix Laboratories.</span>
555 <span class="py-src-comment"># See LICENSE for details.</span>
556
557 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>, <span class="py-src-variable">jelly</span>
558 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">log</span>
559 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
560 <span class="py-src-keyword">from</span> <span class="py-src-variable">copy2_classes</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">SenderPond</span>
561
562 <span class="py-src-keyword">class</span> <span class="py-src-identifier">Sender</span>:
563     <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">pond</span>):
564         <span class="py-src-variable">self</span>.<span class="py-src-variable">pond</span> = <span class="py-src-variable">pond</span>
565
566     <span class="py-src-keyword">def</span> <span class="py-src-identifier">got_obj</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">obj</span>):
567         <span class="py-src-variable">d</span> = <span class="py-src-variable">obj</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;takePond&quot;</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">pond</span>)
568         <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">ok</span>).<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">notOk</span>)
569
570     <span class="py-src-keyword">def</span> <span class="py-src-identifier">ok</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">response</span>):
571         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;pond arrived&quot;</span>, <span class="py-src-variable">response</span>
572         <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
573     <span class="py-src-keyword">def</span> <span class="py-src-identifier">notOk</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">failure</span>):
574         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;error during takePond:&quot;</span>
575         <span class="py-src-keyword">if</span> <span class="py-src-variable">failure</span>.<span class="py-src-variable">type</span> == <span class="py-src-variable">jelly</span>.<span class="py-src-variable">InsecureJelly</span>:
576             <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; InsecureJelly&quot;</span>
577         <span class="py-src-keyword">else</span>:
578             <span class="py-src-keyword">print</span> <span class="py-src-variable">failure</span>
579         <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
580         <span class="py-src-keyword">return</span> <span class="py-src-variable">None</span>
581
582 <span class="py-src-keyword">def</span> <span class="py-src-identifier">main</span>():
583     <span class="py-src-variable">pond</span> = <span class="py-src-variable">SenderPond</span>(<span class="py-src-number">3</span>, <span class="py-src-number">4</span>)
584     <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;count %d&quot;</span> % <span class="py-src-variable">pond</span>.<span class="py-src-variable">count</span>()
585
586     <span class="py-src-variable">sender</span> = <span class="py-src-variable">Sender</span>(<span class="py-src-variable">pond</span>)
587     <span class="py-src-variable">factory</span> = <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBClientFactory</span>()
588     <span class="py-src-variable">reactor</span>.<span class="py-src-variable">connectTCP</span>(<span class="py-src-string">&quot;localhost&quot;</span>, <span class="py-src-number">8800</span>, <span class="py-src-variable">factory</span>)
589     <span class="py-src-variable">deferred</span> = <span class="py-src-variable">factory</span>.<span class="py-src-variable">getRootObject</span>()
590     <span class="py-src-variable">deferred</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">sender</span>.<span class="py-src-variable">got_obj</span>)
591     <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
592
593 <span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
594     <span class="py-src-variable">main</span>()
595 </pre><div class="caption">Source listing - <a href="listings/pb/copy2_sender.py"><span class="filename">listings/pb/copy2_sender.py</span></a></div></div>
596 <div class="py-listing"><pre><p class="py-linenumber"> 1
597  2
598  3
599  4
600  5
601  6
602  7
603  8
604  9
605 10
606 11
607 12
608 13
609 14
610 15
611 16
612 17
613 18
614 19
615 20
616 21
617 </p><span class="py-src-comment">#!/usr/bin/env python</span>
618
619 <span class="py-src-comment"># Copyright (c) Twisted Matrix Laboratories.</span>
620 <span class="py-src-comment"># See LICENSE for details.</span>
621
622 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">service</span>, <span class="py-src-variable">internet</span>
623 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
624 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
625 <span class="py-src-keyword">import</span> <span class="py-src-variable">copy2_classes</span> <span class="py-src-comment"># needed to get ReceiverPond registered with Jelly</span>
626
627 <span class="py-src-keyword">class</span> <span class="py-src-identifier">Receiver</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Root</span>):
628     <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_takePond</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">pond</span>):
629         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; got pond:&quot;</span>, <span class="py-src-variable">pond</span>
630         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; count %d&quot;</span> % <span class="py-src-variable">pond</span>.<span class="py-src-variable">count</span>()
631         <span class="py-src-keyword">return</span> <span class="py-src-string">&quot;safe and sound&quot;</span> <span class="py-src-comment"># positive acknowledgement</span>
632     <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_shutdown</span>(<span class="py-src-parameter">self</span>):
633         <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
634
635 <span class="py-src-variable">application</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">Application</span>(<span class="py-src-string">&quot;copy_receiver&quot;</span>)
636 <span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-number">8800</span>, <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBServerFactory</span>(<span class="py-src-variable">Receiver</span>())).<span class="py-src-variable">setServiceParent</span>(
637     <span class="py-src-variable">service</span>.<span class="py-src-variable">IServiceCollection</span>(<span class="py-src-variable">application</span>))
638 </pre><div class="caption">Source listing - <a href="listings/pb/copy2_receiver.py"><span class="filename">listings/pb/copy2_receiver.py</span></a></div></div>
639
640 <p>In this example, the classes are defined in a separate source file, which
641 also sets up the binding between them. The <code>SenderPond</code> and 
642 <code>ReceiverPond</code> are unrelated save for this binding: they happen
643 to implement the same methods, but use different internal instance variables
644 to accomplish them.</p>
645
646 <p>The recipient of the object doesn't even have to import the class
647 definition into their namespace. It is sufficient that they import the class
648 definition (and thus execute the <code>setUnjellyableForClass</code>
649 statement). The Jelly layer remembers the class definition until a matching
650 object is received. The sender of the object needs the definition, of
651 course, to create the object in the first place.</p>
652
653 <p>When run, the <code>copy2</code> example emits the following:</p>
654
655 <pre class="shell" xml:space="preserve">
656 $ twistd -n -y copy2_receiver.py
657 [-] twisted.spread.pb.PBServerFactory starting on 8800
658 [-] Starting factory &lt;twisted.spread.pb.PBServerFactory instance at
659 0x40604b4c&gt;
660 [Broker,0,127.0.0.1]  got pond: &lt;copy2_classes.ReceiverPond instance at
661 0x406eb2ac&gt;
662 [Broker,0,127.0.0.1]  count 7
663 </pre>
664
665 <pre class="shell" xml:space="preserve">
666 $ ./copy2_sender.py
667 count 7
668 pond arrived safe and sound
669 Main loop terminated.
670 </pre>
671
672
673
674 <h3>Things To Watch Out For<a name="auto7"/></h3>
675
676 <ul>
677
678   <li>The first argument to <code>setUnjellyableForClass</code> must refer
679   to the class <em>as known by the sender</em>. The sender has no way of
680   knowing about how your local <code>import</code> statements are set up,
681   and Python's flexible namespace semantics allow you to access the same
682   class through a variety of different names. You must match whatever the
683   sender does. Having both ends import the class from a separate file, using
684   a canonical module name (no <q>sibiling imports</q>), is a good way to get
685   this right, especially when both the sending and the receiving classes are
686   defined together, with the <code>setUnjellyableForClass</code> immediately
687   following them.</li>
688
689   <li>The class that is sent must inherit from <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.Copyable.html" title="twisted.spread.pb.Copyable">pb.Copyable</a></code>. The class that is registered to
690   receive it must inherit from <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.RemoteCopy.html" title="twisted.spread.pb.RemoteCopy">pb.RemoteCopy</a></code><a href="#footnote-2" title="pb.RemoteCopy is actually defined in twisted.spread.flavors, but pb.RemoteCopy is the preferred way to access it"><super>2</super></a>. </li>
691
692   <li>The same class can be used to send and receive. Just have it inherit
693   from both <code>pb.Copyable</code> and <code>pb.RemoteCopy</code>. This
694   will also make it possible to send the same class symmetrically back and
695   forth over the wire. But don't get confused about when it is coming (and
696   using <code>setCopyableState</code>) versus when it is going (using
697   <code>getStateToCopy</code>).</li>
698
699   <li><code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.jelly.InsecureJelly.html" title="twisted.spread.jelly.InsecureJelly">InsecureJelly</a></code>
700   exceptions are raised by the receiving end. They will be delivered
701   asynchronously to an <code>errback</code> handler. If you do not add one
702   to the <code>Deferred</code> returned by <code>callRemote</code>, then you
703   will never receive notification of the problem. </li>
704
705   <li>The class that is derived from <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.RemoteCopy.html" title="twisted.spread.pb.RemoteCopy">pb.RemoteCopy</a></code> will be created using a
706   constructor <code>__init__</code> method that takes no arguments. All
707   setup must be performed in the <code>setCopyableState</code> method. As
708   the docstring on <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.RemoteCopy.html" title="twisted.spread.pb.RemoteCopy">RemoteCopy</a></code> says, don't implement a
709   constructor that requires arguments in a subclass of
710   <code>RemoteCopy</code>.</li>
711
712
713
714
715
716 </ul>
717
718 <h3>More Information<a name="auto8"/></h3>
719
720 <ul>
721
722   <li> <code>pb.Copyable</code> is mostly implemented
723   in <code>twisted.spread.flavors</code>, and the docstrings there are
724   the best source of additional information.</li>
725
726   <li><code>Copyable</code> is also used in <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.distrib.html" title="twisted.web.distrib">twisted.web.distrib</a></code> to deliver HTTP requests to other
727   programs for rendering, allowing subtrees of URL space to be delegated to
728   multiple programs (on multiple machines).</li>
729
730   <li><code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.manhole.explorer.html" title="twisted.manhole.explorer">twisted.manhole.explorer</a></code> also uses
731   <code>Copyable</code> to distribute debugging information from the program
732   under test to the debugging tool.</li>
733
734 </ul>
735
736
737 <h2>pb.Cacheable<a name="auto9"/></h2>
738
739 <p>Sometimes the object you want to send to the remote process is big and
740 slow. <q>big</q> means it takes a lot of data (storage, network bandwidth,
741 processing) to represent its state. <q>slow</q> means that state doesn't
742 change very frequently. It may be more efficient to send the full state only
743 once, the first time it is needed, then afterwards only send the differences
744 or changes in state whenever it is modified. The <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.Cacheable.html" title="twisted.spread.pb.Cacheable">pb.Cacheable</a></code> class provides a framework to
745 implement this.</p>
746
747 <p><code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.Cacheable.html" title="twisted.spread.pb.Cacheable">pb.Cacheable</a></code> is derived
748 from <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.Copyable.html" title="twisted.spread.pb.Copyable">pb.Copyable</a></code>, so it is
749 based upon the idea of an object's state being captured on the sending side,
750 and then turned into a new object on the receiving side. This is extended to
751 have an object <q>publishing</q> on the sending side (derived from <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.Cacheable.html" title="twisted.spread.pb.Cacheable">pb.Cacheable</a></code>), matched with one
752 <q>observing</q> on the receiving side (derived from <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.RemoteCache.html" title="twisted.spread.pb.RemoteCache">pb.RemoteCache</a></code>).</p>
753
754 <p>To effectively use <code>pb.Cacheable</code>, you need to isolate changes
755 to your object into accessor functions (specifically <q>setter</q>
756 functions). Your object needs to get control <em>every</em> single time some
757 attribute is changed<a href="#footnote-3" title="Of course you could be clever and add a hook to __setattr__, along with magical change-announcing subclasses of the usual builtin types, to detect changes that result from normal = set operations. The semi-magical property attributes that were introduced in Python 2.2 could be useful too. The result might be hard to maintain or extend, though."><super>3</super></a>.</p>
758
759 <p>You derive your sender-side class from <code>pb.Cacheable</code>, and you
760 add two methods: <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.flavors.Cacheable.getStateToCacheAndObserveFor.html" title="twisted.spread.flavors.Cacheable.getStateToCacheAndObserveFor">getStateToCacheAndObserveFor</a></code>
761 and <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.flavors.Cacheable.stoppedObserving.html" title="twisted.spread.flavors.Cacheable.stoppedObserving">stoppedObserving</a></code>. The first
762 is called when a remote caching reference is first created, and retrieves
763 the data with which the cache is first filled. It also provides an
764 object called the <q>observer</q> <a href="#footnote-4" title="This is actually a RemoteCacheObserver, but it isn't very useful to subclass or modify, so simply treat it as a little demon that sits in your pb.Cacheable class and helps you distribute change notifications. The only useful thing to do with it is to run its callRemote method, which acts just like a normal pb.Referenceable's method of the same name."><super>4</super></a> that points at that receiver-side cache. Every time the state of the object
765 is changed, you give a message to the observer, informing them of the
766 change. The other method, <code>stoppedObserving</code>, is called when the
767 remote cache goes away, so that you can stop sending updates.</p>
768
769 <p>On the receiver end, you make your cache class inherit from <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.RemoteCache.html" title="twisted.spread.pb.RemoteCache">pb.RemoteCache</a></code>, and implement the 
770  <code>setCopyableState</code> as you would for a <code>pb.RemoteCopy</code>
771 object. In addition, you must implement methods to receive the updates sent
772 to the observer by the <code>pb.Cacheable</code>: these methods should have
773 names that start with <code>observe_</code>, and match the 
774  <code>callRemote</code> invocations from the sender side just as the usual 
775  <code>remote_*</code> and <code>perspective_*</code> methods match normal 
776  <code>callRemote</code> calls. </p>
777
778 <p>The first time a reference to the <code>pb.Cacheable</code> object is
779 sent to any particular recipient, a sender-side Observer will be created for
780 it, and the <code>getStateToCacheAndObserveFor</code> method will be called
781 to get the current state and register the Observer. The state which that
782 returns is sent to the remote end and turned into a local representation
783 using <code>setCopyableState</code> just like <code>pb.RemoteCopy</code>,
784 described above (in fact it inherits from that class). </p>
785
786 <p>After that, your <q>setter</q> functions on the sender side should call 
787  <code>callRemote</code> on the Observer, which causes <code>observe_*</code>
788 methods to run on the receiver, which are then supposed to update the
789 receiver-local (cached) state.</p>
790
791 <p>When the receiver stops following the cached object and the last
792 reference goes away, the <code>pb.RemoteCache</code> object can be freed.
793 Just before it dies, it tells the sender side it no longer cares about the
794 original object. When <em>that</em> reference count goes to zero, the
795 Observer goes away and the <code>pb.Cacheable</code> object can stop
796 announcing every change that takes place. The <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.flavors.Cacheable.stoppedObserving.html" title="twisted.spread.flavors.Cacheable.stoppedObserving">stoppedObserving</a></code> method is
797 used to tell the <code>pb.Cacheable</code> that the Observer has gone
798 away.</p>
799
800 <p>With the <code>pb.Cacheable</code> and <code>pb.RemoteCache</code>
801 classes in place, bound together by a call to 
802  <code>pb.setUnjellyableForClass</code>, all that remains is to pass a
803 reference to your <code>pb.Cacheable</code> over the wire to the remote end.
804 The corresponding <code>pb.RemoteCache</code> object will automatically be
805 created, and the matching methods will be used to keep the receiver-side
806 slave object in sync with the sender-side master object.</p>
807
808 <h3>Example<a name="auto10"/></h3>
809
810 <p>Here is a complete example, in which the <code>MasterDuckPond</code> is
811 controlled by the sending side, and the <code>SlaveDuckPond</code> is a
812 cache that tracks changes to the master:</p>
813
814 <div class="py-listing"><pre><p class="py-linenumber"> 1
815  2
816  3
817  4
818  5
819  6
820  7
821  8
822  9
823 10
824 11
825 12
826 13
827 14
828 15
829 16
830 17
831 18
832 19
833 20
834 21
835 22
836 23
837 24
838 25
839 26
840 27
841 28
842 29
843 30
844 31
845 32
846 33
847 34
848 35
849 36
850 37
851 38
852 39
853 40
854 41
855 42
856 43
857 </p><span class="py-src-comment">#!/usr/bin/env python</span>
858
859 <span class="py-src-comment"># Copyright (c) Twisted Matrix Laboratories.</span>
860 <span class="py-src-comment"># See LICENSE for details.</span>
861
862 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
863
864 <span class="py-src-keyword">class</span> <span class="py-src-identifier">MasterDuckPond</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Cacheable</span>):
865     <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">ducks</span>):
866         <span class="py-src-variable">self</span>.<span class="py-src-variable">observers</span> = []
867         <span class="py-src-variable">self</span>.<span class="py-src-variable">ducks</span> = <span class="py-src-variable">ducks</span>
868     <span class="py-src-keyword">def</span> <span class="py-src-identifier">count</span>(<span class="py-src-parameter">self</span>):
869         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;I have [%d] ducks&quot;</span> % <span class="py-src-variable">len</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">ducks</span>)
870     <span class="py-src-keyword">def</span> <span class="py-src-identifier">addDuck</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">duck</span>):
871         <span class="py-src-variable">self</span>.<span class="py-src-variable">ducks</span>.<span class="py-src-variable">append</span>(<span class="py-src-variable">duck</span>)
872         <span class="py-src-keyword">for</span> <span class="py-src-variable">o</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">observers</span>: <span class="py-src-variable">o</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">'addDuck'</span>, <span class="py-src-variable">duck</span>)
873     <span class="py-src-keyword">def</span> <span class="py-src-identifier">removeDuck</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">duck</span>):
874         <span class="py-src-variable">self</span>.<span class="py-src-variable">ducks</span>.<span class="py-src-variable">remove</span>(<span class="py-src-variable">duck</span>)
875         <span class="py-src-keyword">for</span> <span class="py-src-variable">o</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">observers</span>: <span class="py-src-variable">o</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">'removeDuck'</span>, <span class="py-src-variable">duck</span>)
876     <span class="py-src-keyword">def</span> <span class="py-src-identifier">getStateToCacheAndObserveFor</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">perspective</span>, <span class="py-src-parameter">observer</span>):
877         <span class="py-src-variable">self</span>.<span class="py-src-variable">observers</span>.<span class="py-src-variable">append</span>(<span class="py-src-variable">observer</span>)
878         <span class="py-src-comment"># you should ignore pb.Cacheable-specific state, like self.observers</span>
879         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">ducks</span> <span class="py-src-comment"># in this case, just a list of ducks</span>
880     <span class="py-src-keyword">def</span> <span class="py-src-identifier">stoppedObserving</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">perspective</span>, <span class="py-src-parameter">observer</span>):
881         <span class="py-src-variable">self</span>.<span class="py-src-variable">observers</span>.<span class="py-src-variable">remove</span>(<span class="py-src-variable">observer</span>)
882
883 <span class="py-src-keyword">class</span> <span class="py-src-identifier">SlaveDuckPond</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">RemoteCache</span>):
884     <span class="py-src-comment"># This is a cache of a remote MasterDuckPond</span>
885     <span class="py-src-keyword">def</span> <span class="py-src-identifier">count</span>(<span class="py-src-parameter">self</span>):
886         <span class="py-src-keyword">return</span> <span class="py-src-variable">len</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">cacheducks</span>)
887     <span class="py-src-keyword">def</span> <span class="py-src-identifier">getDucks</span>(<span class="py-src-parameter">self</span>):
888         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">cacheducks</span>
889     <span class="py-src-keyword">def</span> <span class="py-src-identifier">setCopyableState</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">state</span>):
890         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; cache - sitting, er, setting ducks&quot;</span>
891         <span class="py-src-variable">self</span>.<span class="py-src-variable">cacheducks</span> = <span class="py-src-variable">state</span>
892     <span class="py-src-keyword">def</span> <span class="py-src-identifier">observe_addDuck</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">newDuck</span>):
893         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; cache - addDuck&quot;</span>
894         <span class="py-src-variable">self</span>.<span class="py-src-variable">cacheducks</span>.<span class="py-src-variable">append</span>(<span class="py-src-variable">newDuck</span>)
895     <span class="py-src-keyword">def</span> <span class="py-src-identifier">observe_removeDuck</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">deadDuck</span>):
896         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; cache - removeDuck&quot;</span>
897         <span class="py-src-variable">self</span>.<span class="py-src-variable">cacheducks</span>.<span class="py-src-variable">remove</span>(<span class="py-src-variable">deadDuck</span>)
898
899 <span class="py-src-variable">pb</span>.<span class="py-src-variable">setUnjellyableForClass</span>(<span class="py-src-variable">MasterDuckPond</span>, <span class="py-src-variable">SlaveDuckPond</span>)
900 </pre><div class="caption">Source listing - <a href="listings/pb/cache_classes.py"><span class="filename">listings/pb/cache_classes.py</span></a></div></div>
901 <div class="py-listing"><pre><p class="py-linenumber"> 1
902  2
903  3
904  4
905  5
906  6
907  7
908  8
909  9
910 10
911 11
912 12
913 13
914 14
915 15
916 16
917 17
918 18
919 19
920 20
921 21
922 22
923 23
924 24
925 25
926 26
927 27
928 28
929 29
930 30
931 31
932 32
933 33
934 34
935 35
936 36
937 37
938 38
939 39
940 40
941 41
942 42
943 43
944 44
945 45
946 46
947 47
948 48
949 49
950 50
951 </p><span class="py-src-comment">#!/usr/bin/env python</span>
952
953 <span class="py-src-comment"># Copyright (c) Twisted Matrix Laboratories.</span>
954 <span class="py-src-comment"># See LICENSE for details.</span>
955
956 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>, <span class="py-src-variable">jelly</span>
957 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">log</span>
958 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
959 <span class="py-src-keyword">from</span> <span class="py-src-variable">cache_classes</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">MasterDuckPond</span>
960
961 <span class="py-src-keyword">class</span> <span class="py-src-identifier">Sender</span>:
962     <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">pond</span>):
963         <span class="py-src-variable">self</span>.<span class="py-src-variable">pond</span> = <span class="py-src-variable">pond</span>
964
965     <span class="py-src-keyword">def</span> <span class="py-src-identifier">phase1</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">remote</span>):
966         <span class="py-src-variable">self</span>.<span class="py-src-variable">remote</span> = <span class="py-src-variable">remote</span>
967         <span class="py-src-variable">d</span> = <span class="py-src-variable">remote</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;takePond&quot;</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">pond</span>)
968         <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">phase2</span>).<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">log</span>.<span class="py-src-variable">err</span>)
969     <span class="py-src-keyword">def</span> <span class="py-src-identifier">phase2</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">response</span>):
970         <span class="py-src-variable">self</span>.<span class="py-src-variable">pond</span>.<span class="py-src-variable">addDuck</span>(<span class="py-src-string">&quot;ugly duckling&quot;</span>)
971         <span class="py-src-variable">self</span>.<span class="py-src-variable">pond</span>.<span class="py-src-variable">count</span>()
972         <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-number">1</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">phase3</span>)
973     <span class="py-src-keyword">def</span> <span class="py-src-identifier">phase3</span>(<span class="py-src-parameter">self</span>):
974         <span class="py-src-variable">d</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">remote</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;checkDucks&quot;</span>)
975         <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">phase4</span>).<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">log</span>.<span class="py-src-variable">err</span>)
976     <span class="py-src-keyword">def</span> <span class="py-src-identifier">phase4</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">dummy</span>):
977         <span class="py-src-variable">self</span>.<span class="py-src-variable">pond</span>.<span class="py-src-variable">removeDuck</span>(<span class="py-src-string">&quot;one duck&quot;</span>)
978         <span class="py-src-variable">self</span>.<span class="py-src-variable">pond</span>.<span class="py-src-variable">count</span>()
979         <span class="py-src-variable">self</span>.<span class="py-src-variable">remote</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;checkDucks&quot;</span>)
980         <span class="py-src-variable">d</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">remote</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;ignorePond&quot;</span>)
981         <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">phase5</span>)
982     <span class="py-src-keyword">def</span> <span class="py-src-identifier">phase5</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">dummy</span>):
983         <span class="py-src-variable">d</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">remote</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;shutdown&quot;</span>)
984         <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">phase6</span>)
985     <span class="py-src-keyword">def</span> <span class="py-src-identifier">phase6</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">dummy</span>):
986         <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
987
988 <span class="py-src-keyword">def</span> <span class="py-src-identifier">main</span>():
989     <span class="py-src-variable">master</span> = <span class="py-src-variable">MasterDuckPond</span>([<span class="py-src-string">&quot;one duck&quot;</span>, <span class="py-src-string">&quot;two duck&quot;</span>])
990     <span class="py-src-variable">master</span>.<span class="py-src-variable">count</span>()
991
992     <span class="py-src-variable">sender</span> = <span class="py-src-variable">Sender</span>(<span class="py-src-variable">master</span>)
993     <span class="py-src-variable">factory</span> = <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBClientFactory</span>()
994     <span class="py-src-variable">reactor</span>.<span class="py-src-variable">connectTCP</span>(<span class="py-src-string">&quot;localhost&quot;</span>, <span class="py-src-number">8800</span>, <span class="py-src-variable">factory</span>)
995     <span class="py-src-variable">deferred</span> = <span class="py-src-variable">factory</span>.<span class="py-src-variable">getRootObject</span>()
996     <span class="py-src-variable">deferred</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">sender</span>.<span class="py-src-variable">phase1</span>)
997     <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
998
999 <span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
1000     <span class="py-src-variable">main</span>()
1001 </pre><div class="caption">Source listing - <a href="listings/pb/cache_sender.py"><span class="filename">listings/pb/cache_sender.py</span></a></div></div>
1002 <div class="py-listing"><pre><p class="py-linenumber"> 1
1003  2
1004  3
1005  4
1006  5
1007  6
1008  7
1009  8
1010  9
1011 10
1012 11
1013 12
1014 13
1015 14
1016 15
1017 16
1018 17
1019 18
1020 19
1021 20
1022 21
1023 22
1024 23
1025 24
1026 25
1027 26
1028 27
1029 28
1030 </p><span class="py-src-comment">#!/usr/bin/env python</span>
1031
1032 <span class="py-src-comment"># Copyright (c) Twisted Matrix Laboratories.</span>
1033 <span class="py-src-comment"># See LICENSE for details.</span>
1034
1035 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">service</span>, <span class="py-src-variable">internet</span>
1036 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
1037 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
1038 <span class="py-src-keyword">import</span> <span class="py-src-variable">cache_classes</span>
1039
1040 <span class="py-src-keyword">class</span> <span class="py-src-identifier">Receiver</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Root</span>):
1041     <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_takePond</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">pond</span>):
1042         <span class="py-src-variable">self</span>.<span class="py-src-variable">pond</span> = <span class="py-src-variable">pond</span>
1043         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;got pond:&quot;</span>, <span class="py-src-variable">pond</span> <span class="py-src-comment"># a DuckPondCache</span>
1044         <span class="py-src-variable">self</span>.<span class="py-src-variable">remote_checkDucks</span>()
1045     <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_checkDucks</span>(<span class="py-src-parameter">self</span>):
1046         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;[%d] ducks: &quot;</span> % <span class="py-src-variable">self</span>.<span class="py-src-variable">pond</span>.<span class="py-src-variable">count</span>(), <span class="py-src-variable">self</span>.<span class="py-src-variable">pond</span>.<span class="py-src-variable">getDucks</span>()
1047     <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_ignorePond</span>(<span class="py-src-parameter">self</span>):
1048         <span class="py-src-comment"># stop watching the pond</span>
1049         <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;dropping pond&quot;</span>
1050         <span class="py-src-comment"># gc causes __del__ causes 'decache' msg causes stoppedObserving</span>
1051         <span class="py-src-variable">self</span>.<span class="py-src-variable">pond</span> = <span class="py-src-variable">None</span>
1052     <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_shutdown</span>(<span class="py-src-parameter">self</span>):
1053         <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
1054
1055 <span class="py-src-variable">application</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">Application</span>(<span class="py-src-string">&quot;copy_receiver&quot;</span>)
1056 <span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-number">8800</span>, <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBServerFactory</span>(<span class="py-src-variable">Receiver</span>())).<span class="py-src-variable">setServiceParent</span>(
1057     <span class="py-src-variable">service</span>.<span class="py-src-variable">IServiceCollection</span>(<span class="py-src-variable">application</span>))
1058 </pre><div class="caption">Source listing - <a href="listings/pb/cache_receiver.py"><span class="filename">listings/pb/cache_receiver.py</span></a></div></div>
1059 <p>When run, this example emits the following:</p>
1060
1061 <pre class="shell" xml:space="preserve">
1062 $ twistd -n -y cache_receiver.py
1063 [-] twisted.spread.pb.PBServerFactory starting on 8800
1064 [-] Starting factory &lt;twisted.spread.pb.PBServerFactory instance at
1065 0x40615acc&gt;
1066 [Broker,0,127.0.0.1]  cache - sitting, er, setting ducks
1067 [Broker,0,127.0.0.1] got pond: &lt;cache_classes.SlaveDuckPond instance at
1068 0x406eb5ec&gt;
1069 [Broker,0,127.0.0.1] [2] ducks:  ['one duck', 'two duck']
1070 [Broker,0,127.0.0.1]  cache - addDuck
1071 [Broker,0,127.0.0.1] [3] ducks:  ['one duck', 'two duck', 'ugly duckling']
1072 [Broker,0,127.0.0.1]  cache - removeDuck
1073 [Broker,0,127.0.0.1] [2] ducks:  ['two duck', 'ugly duckling']
1074 [Broker,0,127.0.0.1] dropping pond
1075 </pre>
1076
1077 <pre class="shell" xml:space="preserve">
1078 $ ./cache_sender.py
1079 I have [2] ducks
1080 I have [3] ducks
1081 I have [2] ducks
1082 Main loop terminated.
1083 </pre>
1084
1085
1086 <p>Points to notice:</p>
1087
1088 <ul>
1089   <li>There is one <code>Observer</code> for each remote program that holds
1090   an active reference. Multiple references inside the same program don't
1091   matter: the serialization layer notices the duplicates and does the
1092   appropriate reference counting<a href="#footnote-5" title="This applies to multiple references through the same Broker. If you've managed to make multiple TCP connections to the same program, you deserve whatever you get."><super>5</super></a>.
1093   </li>
1094
1095   <li>Multiple Observers need to be kept in a list, and all of them need to
1096   be updated when something changes. By sending the initial state at the
1097   same time as you add the observer to the list, in a single atomic action
1098   that cannot be interrupted by a state change, you insure that you can send
1099   the same status update to all the observers.</li>
1100
1101   <li>The <code>observer.callRemote</code> calls can still fail. If the
1102   remote side has disconnected very recently and
1103   <code>stoppedObserving</code> has not yet been called, you may get a
1104   <code>DeadReferenceError</code>. It is a good idea to add an errback to
1105   those <code>callRemote</code>s to throw away such an error. This is a
1106   useful idiom:
1107
1108   <pre class="python"><p class="py-linenumber">1
1109 </p><span class="py-src-variable">observer</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">'foo'</span>, <span class="py-src-variable">arg</span>).<span class="py-src-variable">addErrback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">f</span>: <span class="py-src-variable">None</span>)
1110 </pre>
1111   </li>
1112
1113
1114   <li><code>getStateToCacheAndObserverFor</code> must return some object
1115   that represents the current state of the object. This may simply be the
1116   object's <code>__dict__</code> attribute. It is a good idea to remove the
1117   <code>pb.Cacheable</code>-specific members of it before sending it to the
1118   remote end. The list of Observers, in particular, should be left out, to
1119   avoid dizzying recursive Cacheable references. The mind boggles as to the
1120   potential consequences of leaving in such an item.</li>
1121
1122   <li>A <code>perspective</code> argument is available to
1123   <code>getStateToCacheAndObserveFor</code>, as well as
1124   <code>stoppedObserving</code>. I think the purpose of this is to allow
1125   viewer-specific changes to the way the cache is updated. If all remote
1126   viewers are supposed to see the same data, it can be ignored.</li>
1127
1128 </ul>
1129
1130
1131
1132
1133 <h3>More Information<a name="auto11"/></h3>
1134
1135 <ul>
1136   <li>The best source for information comes from the docstrings
1137   in <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.flavors.html" title="twisted.spread.flavors">twisted.spread.flavors</a></code>,
1138   where <code>pb.Cacheable</code> is implemented.</li>
1139
1140   <li><code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.manhole.explorer.html" title="twisted.manhole.explorer">twisted.manhole.explorer</a></code> uses
1141   <code>Cacheable</code>, and does some fairly interesting things with it.</li>
1142
1143   <li>The <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.publish.html" title="twisted.spread.publish">spread.publish</a></code> module also
1144   uses <code>Cacheable</code>, and might be a source of further
1145   information.</li>
1146 </ul>
1147
1148
1149
1150 <h2>Footnotes</h2><ol><li><a name="footnote-1"><span class="footnote">Note that, in this context, <q>unjelly</q> is
1151 a verb with the opposite meaning of <q>jelly</q>. The verb <q>to jelly</q>
1152 means to serialize an object or data structure into a sequence of bytes (or
1153 other primitive transmittable/storable representation), while <q>to
1154 unjelly</q> means to unserialize the bytestream into a live object in the
1155 receiver's memory space. <q>Unjellyable</q> is a noun, (<em>not</em> an
1156 adjective), referring to the the class that serves as a destination or
1157 recipient of the unjellying process. <q>A is unjellyable into B</q> means
1158 that a serialized representation A (of some remote object) can be
1159 unserialized into a local object of type B. It is these objects <q>B</q>
1160 that are the <q>Unjellyable</q> second argument of the 
1161 <code>setUnjellyableForClass</code> function.
1162 In particular, <q>unjellyable</q> does <em>not</em> mean <q>cannot be
1163 jellied</q>. <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.jelly.Unpersistable.html" title="twisted.spread.jelly.Unpersistable">Unpersistable</a></code> means <q>not
1164 persistable</q>, but <q>unjelly</q>, <q>unserialize</q>, and <q>unpickle</q>
1165 mean to reverse the operations of <q>jellying</q>, <q>serializing</q>, and
1166 <q>pickling</q>.</span></a></li><li><a name="footnote-2"><span class="footnote"><code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.RemoteCopy.html" title="twisted.spread.pb.RemoteCopy">pb.RemoteCopy</a></code> is actually defined
1167   in <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.flavors.html" title="twisted.spread.flavors">twisted.spread.flavors</a></code>, but
1168   <code>pb.RemoteCopy</code> is the preferred way to access it</span></a></li><li><a name="footnote-3"><span class="footnote">Of course you could be clever and
1169 add a hook to <code>__setattr__</code>, along with magical change-announcing
1170 subclasses of the usual builtin types, to detect changes that result from
1171 normal <q>=</q> set operations. The semi-magical <q>property attributes</q>
1172 that were introduced in Python 2.2 could be useful too. The result might be
1173 hard to maintain or extend, though.</span></a></li><li><a name="footnote-4"><span class="footnote">This is actually a <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.RemoteCacheObserver.html" title="twisted.spread.pb.RemoteCacheObserver">RemoteCacheObserver</a></code>, but it isn't very
1174 useful to subclass or modify, so simply treat it as a little demon that sits
1175 in your <code>pb.Cacheable</code> class and helps you distribute change
1176 notifications. The only useful thing to do with it is to run its 
1177 <code>callRemote</code> method, which acts just like a normal 
1178 <code>pb.Referenceable</code>'s method of the same name.</span></a></li><li><a name="footnote-5"><span class="footnote">This applies to
1179   multiple references through the same <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.spread.pb.Broker.html" title="twisted.spread.pb.Broker">Broker</a></code>. If you've managed to make multiple
1180   TCP connections to the same program, you deserve whatever you get.</span></a></li></ol></div>
1181
1182     <p><a href="index.html">Index</a></p>
1183     <span class="version">Version: 12.1.0</span>
1184   </body>
1185 </html>