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.
ManagedInputStream<br />
ResourceGroup<br />
ManagedSocket<br />
ManagedOutputStream<br />
Figure 2-6. A potential resource tree associated<br />
with a Socket<br />
zero indicates that no excepti<strong>on</strong>s occurred.<br />
Am<strong>on</strong>g the most obvious differences is the reducti<strong>on</strong> in cleanup<br />
code. The release <strong>and</strong> excepti<strong>on</strong>-h<strong>and</strong>ling code has been reduced<br />
by almost half. The nested try-catch blocks are no l<strong>on</strong>ger needed<br />
because that functi<strong>on</strong>ality is now encapsulated in the release()<br />
call. Additi<strong>on</strong>ally, excepti<strong>on</strong>s are no l<strong>on</strong>ger discarded silently.<br />
Instead they are passed to an Excepti<strong>on</strong>Listener. The overall<br />
method is shorter as well, even with the overhead of creating the<br />
ResourceGroup. Compared to the original, use of Furm reduced<br />
the amount of code, eliminated the resource cleanup error, <strong>and</strong><br />
minimized the loss of informati<strong>on</strong> related to excepti<strong>on</strong>s.<br />
2.2 Creating Managed Resources<br />
Adding new resources to Furm is straightforward. The most<br />
difficult issue with using Furm is that each type of resource to be<br />
added to the tree must be wrapped in a new class to produce the<br />
equivalent managed resource. For example, to add an<br />
01 private boolean copy(File src, File dest) {<br />
02 FileInputStream is = null;<br />
03 FileOutputStream os = null;<br />
04 try {<br />
05 is = new FileInputStream(src);<br />
06 os = new FileOutputStream(dest);<br />
07 byte[] buf = new byte[4096];<br />
08 while (true) {<br />
09 int len = is.read(buf);<br />
10 if (len < 0) break;<br />
11 os.write(buf, 0, len);<br />
12 }<br />
13 is.close();<br />
14 os.close();<br />
15 } catch (IOExcepti<strong>on</strong> e) {<br />
16 return false;<br />
17 } finally {<br />
18 try {<br />
19 if (is != null) is.close();<br />
20 } catch (Excepti<strong>on</strong> e) {/*Ignore*/}<br />
21 try {<br />
22 if (os != null) os.close();<br />
23 } catch (Excepti<strong>on</strong> e) {/*Ignore*/}<br />
24 }<br />
25 return true;<br />
26 }<br />
Figure 2-7. The copy() method from Tomcat’s Java engine<br />
InputStream to the tree, a new wrapper class,<br />
ManagedInputStream, must be defined. Additi<strong>on</strong>ally, each<br />
managed resource must define its own subclass of ResourceNode,<br />
described in Secti<strong>on</strong> 2.3, to override the cleanup() method. In<br />
practice, these requirements pose little problem.<br />
Figure 2-9 shows <strong>on</strong>e possible implementati<strong>on</strong> of the<br />
ManagedInputStream class. This class extends FilterInputStream<br />
to wrap an underlying InputStream. ManagedInputStream uses<br />
an an<strong>on</strong>ymous inner class [8] to subclass ResourceNode <strong>and</strong><br />
override its cleanup() method. Use of an an<strong>on</strong>ymous inner class<br />
is not necessary. A named class would be sufficient, but less<br />
succinct. The close() method is also overridden to call the<br />
release() method of ResourceNode. This will automatically<br />
release any child resources <strong>and</strong> call the cleanup() method of the<br />
ResourceNode subclass, which in turn will call<br />
ManagedInputStream’s superclass close() method.<br />
ManagedInputStream exposes its ResourceNode instance variable<br />
publicly to expose the ResourceNode functi<strong>on</strong>ality. This is the<br />
recommended practice. Because forwarding all relevant calls to<br />
the underlying ResourceNode would be a tedious task, the choice<br />
was made to simply expose the ResourceNode directly, rather<br />
than hide it. In practice, this means little except that to release the<br />
resource, the correct call is stream.node.release() rather than<br />
stream.release(). For the sake of c<strong>on</strong>sistency, the name node is<br />
recommended, but not m<strong>and</strong>ated by Furm. The node variable<br />
should be declared final to protect it from modificati<strong>on</strong>.<br />
It is recommended that managed resource classes extend (or<br />
implement) the class they are intended to replace. In this<br />
example, ManagedInputStream extends FilterInputStream (so that<br />
it indirectly implements InputStream). This allows<br />
ManagedInputStream to be passed to methods <strong>and</strong> c<strong>on</strong>structors<br />
which expect an InputStream. ManagedInputStream thus<br />
becomes a drop-in replacement.<br />
In cases where the original resource is a class, the c<strong>on</strong>structors of<br />
the original resource class will need to be duplicated in the<br />
managed subclass. In cases where a resource has a large number<br />
of c<strong>on</strong>structors, this could be tedious. However, a tool could<br />
automate this task. In cases where the original resource is an<br />
01 private boolean copy(File src, File dest) {<br />
02 ResourceGroup root = new ResourceGroup(…);<br />
03 boolean success = false;<br />
04 try {<br />
05 InputStream is =<br />
06 new ManagedFileInputStream(src,root);<br />
07 OutputStream os =<br />
08 new ManagedFileOutputStream(dest,root);<br />
09 byte[] buf = new byte[4096];<br />
10 int len;<br />
11 while ((len = is.read(buf)) >= 0) {<br />
12 os.write(buf, 0, len);<br />
13 }<br />
14 success = true;<br />
15 } catch (IOExcepti<strong>on</strong> exc) {<br />
16 root.getListener().<br />
17 excepti<strong>on</strong>Thrown(null, exc);<br />
18 } finally {<br />
19 if (root.release() != 0) success = false;<br />
20 }<br />
21 return success;<br />
22 }<br />
Figure 2-8. A versi<strong>on</strong> of the copy() method using Furm<br />
118