4th International Conference on Principles and Practices ... - MADOC
4th International Conference on Principles and Practices ... - MADOC
4th International Conference on Principles and Practices ... - MADOC
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
01 public void sendFile(ResourceNode parent,<br />
02 File f) {<br />
03 try {<br />
04 ManagedSocket s = new //...<br />
05 FileInputStream in =<br />
06 new ManagedFileInputStream(f,g);<br />
07 ManagedOutputStream out =<br />
08 s.getOutputStream();<br />
09 byte[] buf = new byte[4096];<br />
10 int len;<br />
11 while ((len = in.read(buf)) >= 0) {<br />
12 out.write(buf, 0, len);<br />
13 }<br />
14 } catch (IOExcepti<strong>on</strong> exc) {}<br />
15 parent.release();<br />
16 }<br />
Figure 2-12. A “leaky” method<br />
2.5 Automatic Resource Cleanup<br />
When properly used, Furm opens up new possibilities for resource<br />
auditing. Furm provides a WatchDog class for m<strong>on</strong>itoring threads<br />
for proper resource cleanup. A WatchDog is given a thread to<br />
guard, <strong>and</strong> a reference to the root of the resource tree (or subtree)<br />
being used by that thread. Whenever that thread dies, the<br />
WatchDog can take some acti<strong>on</strong> <strong>on</strong> any resources ab<strong>and</strong><strong>on</strong>ed by<br />
that thread. This can be used as a safeguard to prevent resource<br />
leaks at runtime. The WatchDog can also be used as a resource<br />
profiler. If resource leaks are suspected or known to exist, every<br />
thread in a program can be assigned a WatchDog for tracing<br />
purposes. As threads die, any resources they leave open can be<br />
inspected. Informati<strong>on</strong> about those resources can aid in tracking<br />
down the leak.<br />
There are two ways to c<strong>on</strong>trol what acti<strong>on</strong> will take place when a<br />
thread dies. The first is to provide a ThreadListener. When a<br />
WatchDog observes that its thread has died, it will call the<br />
threadDied() method <strong>on</strong> the ThreadListener, much the way a<br />
ResourceNode calls excepti<strong>on</strong>Thrown() <strong>on</strong> an Excepti<strong>on</strong>Listener.<br />
To specify a ThreadListener, simply pass it to the WatchDog<br />
c<strong>on</strong>structor. The sec<strong>on</strong>d way to c<strong>on</strong>trol what acti<strong>on</strong> the<br />
WatchDog should take is to extend the WatchDog class <strong>and</strong><br />
override its threadDied() method. The WatchDog class itself<br />
implements the ThreadListener interface, <strong>and</strong> so has the<br />
threadDied() method. 5<br />
WatchDog has two WatchLevels. The WatchLevel determines<br />
what forms of thread terminati<strong>on</strong> will be m<strong>on</strong>itored. The two<br />
WatchLevels are excepti<strong>on</strong>al (declared as EXCEPTIONAL_END)<br />
<strong>and</strong> general (declared as ANY_END). If the WatchLevel is<br />
excepti<strong>on</strong>al, then the threadDied() method will <strong>on</strong>ly be called if<br />
the thread dies by throwing an uncaught excepti<strong>on</strong>. If the<br />
WatchLevel is general, then the threadDied() method will be<br />
called regardless of the circumstances of thread terminati<strong>on</strong>.<br />
As an example of how to use the WatchDog class, we present a<br />
small, “leaky” method which uses Furm. This method simply<br />
creates a socket c<strong>on</strong>necti<strong>on</strong> <strong>and</strong> sends a file to the output stream<br />
of the socket. Figure 2-12 c<strong>on</strong>tains its full implementati<strong>on</strong>.<br />
5 This model follows that of the Thread class, which has a<br />
c<strong>on</strong>structor that accepts a Runnable object, but also implements<br />
the Runnable interface.<br />
01 class Examiner implements ThreadListener {<br />
02 private void printRes(ResourceNode res) {<br />
03 Class c = res.getResource().getClass()<br />
04 System.out.println(c.getCan<strong>on</strong>icalName());<br />
05 for (ResourceNode rn : res) {<br />
06 printResource(rn);<br />
07 }<br />
08 }<br />
09 public void threadDied(Thread t,<br />
10 ResourceNode node,<br />
11 Throwable e) {<br />
12 synchr<strong>on</strong>ized(node.getM<strong>on</strong>itor()) {<br />
13 if (!node.isReleased()) {<br />
14 printRes(node);<br />
15 node.release();<br />
16 }<br />
17 }<br />
18 }<br />
19 }<br />
20 // ...<br />
21 new WatchDog(Thread.currentThread(),group,<br />
22 new Examiner(),WatchLevel.ANY_END);<br />
Figure 2-13. Utilizing WatchDog<br />
Notice that the file transfer code is wrapped in a try-catch block<br />
which catches IOExcepti<strong>on</strong> (lines 3-14). The release() call is<br />
made <strong>on</strong> line 15. While this code will work in cases when no<br />
errors occur or when an IOExcepti<strong>on</strong> is thrown, if the File<br />
reference passed into the method is null, a NullPointerExcepti<strong>on</strong><br />
will occur <strong>on</strong> line 6, <strong>and</strong> the release() call will never be made.<br />
The Socket <strong>and</strong> socket output stream will be leaked. The correct<br />
soluti<strong>on</strong> is to add a finally h<strong>and</strong>ler, but here this has not been<br />
d<strong>on</strong>e. If the code were part of a very large project, it may be<br />
reas<strong>on</strong>able to assume that no <strong>on</strong>e has discovered the bug.<br />
Let us assume that the WatchDog class is being used to hunt for a<br />
suspected bug, or that the WatchDog is simply being used as an<br />
additi<strong>on</strong>al safeguard in development code. To this end, the<br />
Examiner class (Figure 2-13) is added. Lines 21 <strong>and</strong> 22 create a<br />
WatchDog to m<strong>on</strong>itor the thread. A WatchDog can be created to<br />
watch any thread. In this case, it is created to m<strong>on</strong>itor the current<br />
thread. The Examiner class used here implements ThreadListener<br />
<strong>and</strong> performs two tasks in the threadDied() callback. First, it<br />
traverses the tree to discover any unreleased resources <strong>and</strong> prints<br />
that informati<strong>on</strong>. Sec<strong>on</strong>d, it releases the tree.<br />
An Examiner object is passed to the WatchDog c<strong>on</strong>structor, <strong>and</strong><br />
the general WatchLevel is specified. When the current thread<br />
dies, whether normally or as the result of an uncaught excepti<strong>on</strong>,<br />
the Examiner object will inspect the thread’s resource tree. This<br />
simple auditing may reveal the problem with the sendFile()<br />
method. The WatchDog class is not a replacement for correct<br />
resource management, but it can make it simpler to track down<br />
cases of incorrect behavior.<br />
One major benefit of the WatchDog class is that its use does not<br />
require watched threads to be aware of its presence. In fact, it is<br />
entirely possible for multiple WatchDogs to watch the same<br />
thread, each oblivious to the others, <strong>and</strong> the thread itself blind to<br />
them all. The main restricti<strong>on</strong> <strong>on</strong> the use of the WatchDog class<br />
is that it requires that any thread m<strong>on</strong>itored by a WatchDog place<br />
its resources in a resource tree. The WatchDog class cannot<br />
m<strong>on</strong>itor resources which are not in a resource tree. Watched<br />
threads can ignore the WatchDogs, but must utilize Furm resource<br />
trees.<br />
121