/[debian]/libspin-java/branches/NM/docs/index.html
ViewVC logotype

Annotation of /libspin-java/branches/NM/docs/index.html

Parent Directory Parent Directory | Revision Log Revision Log


Revision 376 - (hide annotations)
Fri Sep 29 21:09:27 2006 UTC (14 years, 9 months ago) by gregoa
Original Path: libspin-java/branches/upstream/current/docs/index.html
File MIME type: text/html
File size: 24467 byte(s)
[svn-inject] Installing original source of libspin-java
1 gregoa 376 <!-- saved from url=(0022)http://internet.e-mail -->
2     <html>
3    
4     <head>
5     <title>Spin your Swing</title>
6     <meta name="description"
7     content="Spin transparent threading solution for Swing" />
8     <meta name="keywords"
9     content="Spin, Java, Swing, Thread,EventDispatcher, EventDispatchThread,
10     EventQueue,SwingWorker,SwingUtilities,invokeLater,
11     invokeAndWait" />
12     <style type="text/css">
13     <!--
14     *.EDT { color:#00dd00 }
15     *.notEDT { color:#dd0000 }
16     *.GUI { background-color:#ddffdd }
17     *.notGUI { background-color:#ffdddd }
18     td.SPIN { background-color:#ffffdd }
19     span.SPIN{ color:#bbbb00 }
20     -->
21     </style>
22     </head>
23    
24     <body>
25     <h1>
26     Spin your Swing
27     </h1>
28     <h2>
29     Abstract
30     </h2>
31     <p align="center">
32     <cite><em>Spin</em> is a transparent threading solution for non-freezing
33     Swing applications.</cite>
34     </p>
35     <p>
36     Swing is the standard component architecture for developing Java desktop
37     applications. Its exhaustive collection of widgets is the foundation for
38     easy development of rich graphical user interfaces (GUI).<br />
39     Alas every non trivial GUI sooner or later encounters the problem of
40     "freeze".
41     This annoying behaviour is experienced by users every time the application
42     performs extensive calculations or blocks for network or disk I/O.
43     </p>
44     <p>
45     In this document we will explain the reason for this problem and explore
46     different techniques to prevent Swing GUIs from "freezing".
47     We will present our project named <em>Spin</em> which offers a - to our
48     knowledge - revolutionary new approach.
49     It offers transparent thread handling with minimal impact on your application
50     code.
51     </p>
52     <p>
53     <em>Spin</em> is hosted at <a href="http://sourceforge.net/projects/spin/">
54     <img align="top" src="http://sourceforge.net/sflogo.php?group_id=3636&type=2"
55     width="125" height="37" border="0" alt="SourceForge.net Logo" />
56     </a>
57     </p>
58    
59     <h2>
60     Standard Swing
61     </h2>
62     <p>
63     In this section we take a look at a naive GUI implementation that shows how
64     Swing freezes in case the application programmer doesn't take any special
65     actions against it.
66     We also describe the problem of calls into Swing components triggered by any
67     other thread than the event dispatch thread.
68     <br/>
69     Swing is not designed for multi threading, so let us first recall the single
70     threading rule of every Swing GUI:
71     </p>
72     <p align="center">
73     <cite>Access to a (visible) Swing component has to occur in the event dispatch
74     thread.</cite>
75     </p>
76     <p>
77     The event dispatch thread (short EDT) is responsible to process all GUI related
78     events, e.g. notifying listeners of user input, repainting dirty regions or
79     updated areas.
80     All these events are enqueued and treated sequentially - if one of them takes
81     a long time to be processed, all further events will have to wait.
82     </p>
83     <p>
84     In the tables throughout this document the left column represents a Swing GUI
85     component, the right column represents a non visual multithreaded bean that
86     encapsulates extensive calculations.
87     Code run on the EDT is <span class="EDT">shown in green</span> and code
88     called by any other thread is <span class="notEDT">shown in red</span>.
89     </p>
90     <p>
91     As you can see in the upper half of the following table, the GUI calls the
92     method <code>getValue()</code> on the bean when an action is performed.
93     The event dispatch thread is routed from the GUI to the bean. While it is
94     performing its calculations no further swing events can be processed - the GUI
95     freezes.<br/>
96     One of these queued events is the repaint of the label triggered by
97     <code>label.setText("...")</code>. When <code>getValue()</code> returns, the
98     text of the label is changed again before the previous text was painted.
99     So in fact <code>"..."</code> is never seen:
100     </p>
101     <a name="standard" />
102     <table border="1" cellpadding="4" cellspacing="0" width="100%">
103     <tr valign="top">
104     <td width="50%" class="GUI">
105     GUI
106     </td>
107     <td width="50%" class="notGUI">
108     BeanImpl
109     </td>
110     </tr>
111     <tr valign="top">
112     <td>
113     <pre>
114     public void actionPerformed(ActionEvent e)
115     {<span class="EDT">
116     label.setText("...");
117     label.setText(bean.getValue());
118     </span>}
119    
120    
121    
122    
123     public void propertyChange(PropertyChangeEvent ev)
124     {<span class="notEDT">
125     label.setText((String)ev.getNewValue());
126     </span>}
127     </pre>
128     </td>
129     <td>
130     <pre>
131     public String getValue()
132     {<span class="EDT">
133     String value;
134    
135     // extensive calculation
136    
137     return value;
138     </span>}
139    
140     public void setValue(String value)
141     {<span class="notEDT">
142     this.value = value;
143     firePropertyChange(value);
144     </span>}
145     </pre>
146     </td>
147     </tr>
148     </table>
149     <p>
150     The lower half of the table shows what happens if <code>setValue()</code> is
151     invoked on the bean on another thread. The listeners are notified (GUI
152     implements <code>java.beans.PropertyChangeListener</code> and is registered as
153     a listener for changes of the bean), triggering a call to
154     <code>propertyChange()</code> on the GUI. The text of the label is altered
155     on the calling thread, violating the Swing threading rule.
156     </p>
157     <p>
158     The color distribution gives a hint where to search for problems of this
159     implementation:<br/>
160     <span class="EDT">Green</span> rows of code in the right column result in a
161     GUI freeze, <span class="notEDT">red</span> rows in left column show a
162     violation to the Swing threading rule.
163     </p>
164    
165     <h2>
166     Working Thread
167     </h2>
168     <p>
169     One obvious solution to the problems seen in the previous section is to shift
170     the invocation of <code>getValue()</code> from the EDT to a separate thread.
171     When this method returns we must not propagate the result to a Swing component
172     though. We have to return control to the EDT instead. This can be achieved via
173     <code>SwingUtilities.invokeLater()</code> which will use our Runnable to
174     correctly change the label's text on the EDT:
175     </p>
176    
177     <table border="1" cellpadding="4" cellspacing="0" width="100%">
178     <tr valign="top">
179     <td width="50%" class="GUI">
180     GUI
181     </td>
182     <td width="50%" class="notGUI">
183     BeanImpl
184     </td>
185     </tr>
186     <tr valign="top">
187     <td>
188     <pre>
189     public void actionPerformed(ActionEvent e)
190     {<span class="EDT">
191     label.setText("...");
192     new Thread(new Runnable()</span>
193     {
194     public void run()
195     {<span class="notEDT">
196     final String value = bean.getValue();
197     SwingUtilities.invokeLater(new Runnable()</span>
198     {
199     public void run()
200     {
201     <span class="EDT">label.setText(value);</span>
202     }
203     }<span class="notEDT">);</span>
204     }
205     }<span class="EDT">).start();</span>
206     }
207    
208     public void propertyChange(final PropertyChangeEvent ev)
209     {
210     <span class="notEDT">SwingUtilities.invokeAndWait(new Runnable()</span>
211     {
212     public void run()
213     {
214     <span class="EDT">label.setText((String)ev.getNewValue());</span>
215     }
216     }<span class="notEDT">);</span>
217     }
218     </pre>
219     </td>
220     <td>
221     <pre>
222     public String getValue()
223     {<span class="notEDT">
224     String value;
225    
226     // extensive calculation
227    
228     return value;
229     </span>}
230    
231    
232    
233    
234    
235    
236    
237    
238    
239    
240    
241     public void setValue(String value)
242     {<span class="notEDT">
243     this.value = value;
244     firePropertyChange(value);
245     </span>}
246     </pre>
247     </td>
248     </tr>
249     </table>
250     <p>
251     Now what happens if the bean informs the GUI about a value-change triggered
252     by another thread? In <code>propertyChange()</code> we pass a runnable to the
253     EDT via <code>SwingUtiltites.invokeAndWait()</code> that can safely alter the
254     label.
255     </p>
256     <p>
257     Let's take a look at the colors once again:
258     On the right there is only <span class="notEDT">red</span> - so we achieved a
259     non freezing GUI.
260     The left column is <span class="EDT">almost totally green</span>. Since we
261     restrict changes to Swing components to these <span class="EDT">green</span>
262     rows we are honouring the Swing threading rule too.<br/>
263     But the <span class="notEDT">red</span> rows on the left make things
264     difficult:
265     The programmer of the GUI always has to know which thread is stepping through
266     what part of the code - without any visual help of thread-coloring.
267     Any mistake reintroduces the problems mentioned above.
268     </p>
269    
270     <h2>
271     SwingWorker
272     </h2>
273     <p>
274     SwingWorker is a utility class that aims to ease the efforts to write a
275     non-freezing GUI. Although not included in the standard Java distribution it is
276     maintained by the Swing team and downloadable at
277     <a href="http://www.theswingconnection.com">The Swing Connection</a>.
278     </p>
279     <p>
280     As you can see in the following table a SwingWorker removes some of the visual
281     clutter seen in the previous section. To use it you have to subclass it,
282     placing extensive calculations into method <code>construct()</code>.
283     In <code>finished()</code> you can alter the label because this method is called
284     on the EDT. This is similar to our previous solution but this time the threading
285     is handled by the superclass:
286     </p>
287     <table border="1" cellpadding="4" cellspacing="0" width="100%">
288     <tr valign="top">
289     <td width="50%" class="GUI">
290     GUI
291     </td>
292     <td width="50%" class="notGUI">
293     BeanImpl
294     </td>
295     </tr>
296     <tr valign="top">
297     <td>
298     <pre>
299     public void actionPerformed(ActionEvent e)
300     {<span class="EDT">
301     label.setText("...");
302     new SwingWorker()</span>
303     {
304     public Object construct()
305     {
306     <span class="notEDT">return bean.getValue();</span>
307     }
308    
309     public void finished()
310     {
311     <span class="EDT">label.setText((String)getValue());</span>
312     }
313     }<span class="EDT">).start();</span>
314     }
315    
316    
317     public void propertyChange(final PropertyChangeEvent ev)
318     {
319     <span class="notEDT">SwingUtilities.invokeAndWait(new Runnable()</span>
320     {
321     public void run()
322     {
323     <span class="EDT">label.setText((String)ev.getNewValue());</span>
324     }
325     }<span class="notEDT">);</span>
326     }
327     </pre>
328     </td>
329     <td>
330     <pre>
331     public String getValue()
332     {<span class="notEDT">
333     String value;
334    
335     // extensive calculation
336    
337     return value;
338     </span>}
339    
340    
341    
342    
343    
344    
345    
346    
347    
348    
349     public void setValue(String value)
350     {<span class="notEDT">
351     this.value = value;
352     firePropertyChange(value);
353     </span>}
354     </pre>
355     </td>
356     </tr>
357     </table>
358     <p>
359     The SwingWorker offers no support for our notification problem so we stick to
360     our previous solution in <code>propertyChange()</code>.
361     </p>
362     <p>
363     What about the colors?<br/>
364     The situation hasn't really improved. The indentation of code was minimized but
365     the <span class="notEDT">red</span> and <span class="EDT">green</span> colors
366     in the GUI stay the same. So the problem above isn't resolved yet.
367     </p>
368    
369     <h2>
370     Spin
371     </h2>
372     <p>
373     Now let's take a look at the <em>Spin</em> solution. The following table shows
374     the code:
375     </p>
376     <table border="1" cellpadding="4" cellspacing="0" width="100%">
377     <tr valign="top">
378     <td width="50%" class="GUI">
379     GUI
380     </td>
381     <td rowspan="2" valign="middle" class="SPIN">
382     Spin
383     </td>
384     <td width="50%" class="notGUI">
385     BeanImpl
386     </td>
387     </tr>
388     <tr valign="top">
389     <td>
390     <pre>
391     public void actionPerformed(ActionEvent e)
392     {<span class="EDT">
393     label.setText("...");
394     label.setText(bean.getValue());
395     </span>}
396    
397    
398    
399    
400     public void propertyChange(PropertyChangeEvent ev)
401     {
402     <span class="EDT">label.setText((String)ev.getNewValue());</span>
403     }
404     </pre>
405     </td>
406     <td>
407     <pre>
408     public String getValue()
409     {<span class="notEDT">
410     String value;
411    
412     // extensive calculation
413    
414     return value;
415     </span>}
416    
417     public void setValue(String value)
418     {<span class="notEDT">
419     this.value = value;
420     firePropertyChange(value);
421     </span>}
422     </pre>
423     </td>
424     </tr>
425     </table>
426     <p>
427     Hey wait a minute!
428     It's the same code as shown in the <a href="#standard">first table</a>.
429     But the colors have changed - the GUI is completely
430     <span class="EDT">green</span> and the bean is <span class="red">red</span> -
431     how can this be?
432     </p>
433     <p>
434     <em>Spin</em> makes this solution possible - as you can see with no impact on
435     the old code. The <span class="SPIN">yellow</span> column in the middle handles
436     all threading issues transparently.<br/>
437     All we have to do is to <em>spin-off</em> the bean from the EDT. For this we
438     wrap the bean in an instance of type <code>Spin</code>.
439     The result can safely be casted to any interface the bean (or one of its
440     superclasses) implements. The best place to do this is before a reference to
441     this bean is passed to a GUI component (why bother the programmer of the GUI
442     with this little detail):
443     </p>
444     <pre>
445     bean = (Bean)Spin.off(bean);
446     </pre>
447     <p>
448     The only restriction here is that the Bean has to be broken into interface and
449     implementation. The GUI components will only use the interface!
450     The following picture shows how <em>Spin</em> connects the GUI and the bean.
451     Calls on the EDT from the GUI to the bean are brokered to other threads
452     invocating the beans functionality:
453     </p>
454     <p align="center">
455     <img src="spinoff.gif" alt="Spin off"/>
456     </p>
457     <p>
458     The need for an interface isn't really a restriction:
459     <ul>
460     <li>
461     It is generally recommended to separate an application in different layers
462     which communicate through well defined interfaces.
463     The GUI of an application is certainly part of another layer than extensive
464     calculations or I/O operations.
465     </li>
466     <li>
467     If you don't want to or are unable to use an interface you can
468     <a href="#cglib">utilize CGLib instead of JDK proxies</a>.
469     </li>
470     </ul>
471    
472     </p>
473     <p>
474     For the notification of changes to the bean we use an inverse technique.
475    
476     We must <em>spin-over</em> any invocation of a GUI callback-method on another
477     thread to the EDT. This time we wrap the GUI in a <code>Spin</code> instance
478     assuming that the bean allows for an <code>PropertyChangeListener</code> to
479     be added as a callback (this could be any interface like
480     foo.DataChangedListener):
481     </p>
482     <pre>
483     bean.addPropertyChangeListener((PropertyChangeListener)Spin.over(gui);
484     </pre>
485     <p align="center">
486     <img src="spinover.gif" alt="Spin over"/>
487     </p>
488     <p>
489     This is all you have to know to get <em>Spin</em> to work in your project.
490     If you're interested in the internals of <em>Spin</em> go on to the next
491     section.
492     </p>
493    
494     <h2>
495     Internals
496     </h2>
497     <p>
498     <em>Spin</em> is built on top of virtual proxies and a technique borrowed from
499     the java.awt.Dialog component.
500     While a modal dialog has to wait for user input, the EDT is rerouted to the
501     swing event processing to handle further events.
502     </p>
503     <p>
504     The following diagram shows how this is used in <em>Spin</em>.
505     Each invocation of a bean's method is intercepted and handled by a
506     <a href="./api/spin/off/SpinOffEvaluator.html">SpinOffEvaluator</a>:</br>
507     getValue() is evaluated asynchronously on another thread (customizable with
508     a <a href="./api/spin/off/Starter.html">Starter</a>) while Swing events are
509     dispatched through a <a href="./api/spin/off/Dispatcher.html">Dispatcher</a>.
510     Once the call to the bean returns the dispatching of events is stopped and the
511     EDT is free to return to the standard event processing:
512     </p>
513     <p align="center">
514     <img src="sequencespinoff.gif" alt="Spin off sequence"/>
515     </p>
516     <p>
517     For asynchronous notifications from the bean to the GUI we reuse the technique
518     introduced in the previous sections.
519     But this time the call to <code>invokeAndWait()</code> is encapsulated by
520     <em>Spin</em> with a <a href="./api/spin/over/SpinOverEvaluator.html">SpinOverEvaluator</a>:
521     </p>
522     <p align="center">
523     <img src="sequencespinover.gif" alt="Spin over sequence"/>
524     </p>
525     <p>
526     Please take a look at the full <a href="./api/index.html">API</a> for details
527     on how to customize <em>Spin</em>.
528     </p>
529    
530     <h2>
531     Utilizing CGLib
532     </h2>
533     <p>
534     <a name="cglib" />
535     Starting with release 1.4 Spin isn't any longer restricted on using JDK virtual
536     proxies. The creation of proxies is now encapsulated in the interface
537     <a href="./api/spin/ProxyFactory.html">ProxyFactory</a>.
538     </p>
539     <p>
540     <em>Spin</em> contains a <a href="http://cglib.sourceforge.net">CGLib</a> specific implementation
541     <a href="./api/spin/CGLibProxyFactory.html">CGLibProxyFactory</a> that offers the
542     following benefits:
543     <ul>
544     <li>
545     improved performance on interception of method invocations
546     </li>
547     <li>
548     no need to to use interfaces for your beans as required by JDK proxies
549     </li>
550     </ul>
551     For this you just have to change the default factory of proxies:
552     </p>
553     <pre>
554     Spin.setDefaultProxyFactory(new CGLibProxyFactory());
555     </pre>
556    
557     <h2>
558     Caveats
559     </h2>
560     <p>
561     Although <em>Spin</em> handles threading transparently there are caveats with
562     <em>spin-off</em> that you should be aware of:
563     </p>
564     <dl>
565     <dt>Security</dt>
566     <dd>
567     For dispatching <em>Spin</em> needs access to AWT internals that are not
568     available in applets or untrusted JavaWebStart applications due to
569     security restrictions. This will hopefully change once AWT offers an
570     official way to dispatch events.<br/>
571     Meanwhile <em>Spin</em> offers alternative solutions which are less
572     performant but also work in a secured environment. Please take a look at
573     <a href="./api/spin/off/DialogDispatcherFactory.html">
574     DialogDispatcherFactory</a> and
575     <a href="./api/spin/off/InternalOptionPaneDispatcherFactory.html">
576     InternalOptionPaneDispatcherFactory</a>.
577     </dd>
578     <dt>Reference backdoor</dt>
579     <dd>
580     If your GUI hands over references to parts of its swing models
581     (e.g. TreeModel, TableModel) in method calls to your bean, these could
582     possibly be altered on another thread than the EDT thus VIOLATING THE
583     SWING SINGLE THREADING RULE.
584     </dd>
585     <dt>Bean threadsafety</dt>
586     <dd>
587     If your GUI doesn't disable all further actions while an invocation on
588     your bean is being processed, the event dispatching may cause a second
589     concurrent call to the bean. In cases where this is desired the BEAN MUST
590     BE THREADSAFE.
591     </dd>
592     <dt>Asynchronous<a name="asynchronous"/></dt>
593     <dd>
594     Whenever your GUI calls a beans method through <em>Spin</em>, further
595     actions should be allowed only if they are related to the current
596     <em>Spin</em> invocation. This includes <code>Cancel</code> functionality
597     and the retrieval of the current state of invocation or intermediate
598     results (e.g. for updating a progress bar or incremental filling of a
599     table).<br/>
600     You're running into problems if you're using <em>Spin</em> for real
601     asynchronous executions. Let me give an example:<br/>
602     File tranfers of an Explorer-like application wich can be arbitrarily
603     started and stopped while others are independently continuing are NOT A
604     RECOMMENDED USAGE for <em>Spin</em>. Nevertheless <em>Spin</em> can be
605     used to <em>spin-over</em> events from the transfers (e.g. completion
606     notification) to the EDT.
607     </dd>
608     <dt>Incomplete Event Handling</dt>
609     <dd>
610     An event that triggers <em>Spin</em> will not be completely precessed until
611     the return of the <em>Spin</em> invocation.<br/>
612     This might lead to minor visual annoyances, e.g. a JComboBox that does not
613     close its popup or a JButton that stays depressed while <em>Spin</em> is
614     running. But this behaviour could also result in other unexpected behaviours
615     that you should be aware of.</br>
616     Because of this <em>Swing</em> developers have expressed their concern about
617     <em>Spin</em> and similar techniques, stating that '<em>Swing</em> is not
618     completely reentrant'.<br/>
619     While this may be true, the same objection could be brought forward against
620     any modal dialog or modal internal frame. If you're using these in your
621     application there is no reason to be afraid of <em>Spin</em>.
622     </dd>
623     </dl>
624    
625     <h2>
626     Conclusion
627     </h2>
628     <p>
629     <em>Spin</em> is a small library that concentrates on offering a powerful
630     solution to build non-freezing Swing applications. <em>Spin</em> enforces good
631     application design by separating the GUI and non-visual components through
632     interfaces. If it is used wisely in an application framework, the GUI
633     programmers will never have to think about threads again.
634     </p>
635     <p>
636     <em>Spin</em> comes with several demonstration classes that show how to solve
637     formerly challenging Swing programming problems with ease:
638     </p>
639     <ul>
640     <li>spin.demo.SpinOffGUI - shows how to execute extensive calculations
641     without "freeze"</li>
642     <li>spin.demo.SpinOverGUI - demonstrates asynchronous event notification
643     without pain</li>
644     <li>spin.demo.exception.ExceptionGUI - proves the transparent exception
645     handling offered by Spin</li>
646     <li>spin.demo.pogress.PullGUI - shows how to handle visual progress while
647     extensive calculations are executed</li>
648     <li>spin.demo.pogress.PushGUI - uses asynchronous event notification to update
649     a progressbar</li>
650     <li>spin.demo.prompt.CallGUI - explains how to prompt the user between
651     multiple extensive calculations</li>
652     <li>spin.demo.prompt.CallbackGUI - prompts the user for input which is
653     triggered by callbacks from an extensive
654     calculation</li>
655     <li>spin.demo.async.AsyncGUI - starts asynchronous calculations transparently
656     through Spin</li>
657     <li>spin.demo.dispatcher.DispatcherGUI - test different dispatchers</li>
658     </ul>
659     <p>
660     We have used <em>Spin</em> succesfullly in several projects to wrap all remote
661     communication (RMI) between rich-clients and the application server.
662     </p>
663    
664     <h2>
665     Acknowledgments
666     </h2>
667     <p>
668     The <em>Spin</em> project is influenced by the
669     <a href="http://foxtrot.sourceforge.net">Foxtrot</a> project. Foxtrot is the
670     inventor of the <b>Synchronous Model</b> (<em>Spin</em> has adopted this
671     technique) but uses an API that is similar to <code>SwingWorker</code>.
672     It offers a subset of <em>Spin</em>s features - it lacks transparent exception
673     handling and offers no solution for asynchronous callbacks:
674     </p>
675     <pre>
676     public void actionPerformed(ActionEvent e)
677     {<span class="EDT">
678     label.setText("...");
679     String text = (String)Worker.post(new Job()</span>
680     {
681     public Object run()
682     {
683     <span class="notEDT">return bean.getValue();</span>
684     }
685     }<span class="EDT">);
686     label.setText(text);</span>
687     }
688     </pre>
689     <p>
690     The following code shows how Foxtrot can be 'simulated' with <em>Spin</em>
691     (if you insist on restricting yourself to only one generic interface named
692     <code>Job</code> or what-ever-you-like):
693     </p>
694     <pre>
695     public void actionPerformed(ActionEvent e)
696     {<span class="EDT">
697     label.setText("...");
698     String text = ((Job)Spin.off(new Job()</span>
699     {
700     public String run()
701     {
702     <span class="notEDT">return bean.getValue();</span>
703     }
704     }<span class="EDT">)).run();
705     label.setText(text);</span>
706     }
707    
708     </pre>
709     </body>
710    
711     </html>

  ViewVC Help
Powered by ViewVC 1.1.26