15.01.2015 Views

4th International Conference on Principles and Practices ... - MADOC

4th International Conference on Principles and Practices ... - MADOC

4th International Conference on Principles and Practices ... - MADOC

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!