<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5496789096865583573</id><updated>2011-12-15T21:54:30.708+01:00</updated><category term='MVN'/><category term='Plugin'/><category term='Jasper'/><category term='RC'/><category term='hacking'/><category term='benchmark'/><category term='Puzzler'/><category term='NAS'/><category term='Synology'/><category term='NetBeans'/><category term='Java'/><category term='Programming'/><category term='Coffee'/><category term='C#'/><category term='iperf'/><category term='JDK7'/><category term='Firefox'/><category term='Maven'/><category term='Linux'/><category term='iGala'/><category term='JSF'/><category term='Ubuntu'/><category term='Rant'/><category term='Spring'/><category term='Optware'/><category term='Enum'/><category term='Android'/><category term='SVN'/><category term='Venting'/><category term='Books'/><title type='text'>BangBits</title><subtitle type='html'>- bits and pieces by Casper Bang</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.bangbits.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>39</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-6839518501768349443</id><published>2011-08-09T16:09:00.009+02:00</published><updated>2011-08-11T14:11:05.276+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='JDK7'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Java 7 on Ubuntu 11.04</title><content type='html'>So after 5+ years, we finally have a new version of Java. In spite of &lt;a href="http://drdobbs.com/java/231300060"&gt;mixed reviews&lt;/a&gt;, as a software engineer working a lot on the JVM, I still wanted to take it for a spin. However, being an Ubuntu user, this involves a tad bit of work since there are only RPM and binary packages available at this time.&lt;br /&gt;&lt;br /&gt;So until there are official or unofficial .deb packages available, we're going to have to sneak in the raw binaries outselves. The following is how I did this on my 64bit Ubuntu 11.04 system. I take no responsibility in breaking your existing Java installation yada yada, you do this at your own responsibility.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Procedure&lt;/B&gt;&lt;br /&gt;Start by downloading the binary.&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;casper@workstation:~$ wget http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-x64.tar.gz&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Then unpack it.&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;casper@workstation:~$ tar -xzf jdk-7-linux-x64.tar.gz&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Remove packed archive and move/rename the extracted folder into something a little more Ubuntu  appropiate.&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;casper@workstation:~$ sudo rm java-7-sun-1.7.0.tar.gz&lt;br /&gt;casper@workstation:~$ sudo mv jdk1.7.0 /usr/lib/jvm/java-7-sun-1.7.0&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Follow the Ubuntu tradition, by symlinking a generic major java version to a concrete minor version.&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;casper@workstation:~$ sudo ln -s /usr/lib/jvm/java-7-sun-1.7.0 /usr/lib/jvm/java-7-sun&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Override Ubuntu's standard alternatives mechanism, replacing links to Java 6 with links to Java 7. It would be better to use the update-alternatives tools available in Ubuntu, but I was unable to make this work. If you screw something up here, you may have to uninstall and reinstall your JDK/JRE stuff, in order to revert to a working Java installation.&lt;br /&gt;&lt;br /&gt;Delete any existing symlinks.&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;casper@workstation:~$ sudo rm /etc/alternatives/java&lt;br /&gt;casper@workstation:~$ sudo rm /etc/alternatives/javac&lt;br /&gt;casper@workstation:~$ sudo rm /etc/alternatives/javadoc&lt;br /&gt;casper@workstation:~$ sudo rm /etc/alternatives/javah&lt;br /&gt;casper@workstation:~$ sudo rm /etc/alternatives/javap&lt;br /&gt;casper@workstation:~$ sudo rm /etc/alternatives/javaws&lt;br /&gt;casper@workstation:~$ sudo rm /etc/alternatives/java_vm&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Create the new symlinks.&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;casper@workstation:~$ sudo ln -s /usr/lib/jvm/java-7-sun/jre/bin/java /etc/alternatives/java&lt;br /&gt;casper@workstation:~$ sudo ln -s /usr/lib/jvm/java-7-sun/bin/javac /etc/alternatives/javac&lt;br /&gt;casper@workstation:~$ sudo ln -s /usr/lib/jvm/java-7-sun/bin/javadoc /etc/alternatives/javadoc&lt;br /&gt;casper@workstation:~$ sudo ln -s /usr/lib/jvm/java-7-sun/bin/javah /etc/alternatives/javah&lt;br /&gt;casper@workstation:~$ sudo ln -s /usr/lib/jvm/java-7-sun/bin/javap /etc/alternatives/javap&lt;br /&gt;casper@workstation:~$ sudo ln -s /usr/lib/jvm/java-7-sun/bin/javaws /etc/alternatives/javaws&lt;br /&gt;casper@workstation:~$ sudo ln -s /usr/lib/jvm/java-7-sun/jre/bin/java_vm /etc/alternatives/java_vm&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Finally, we may aid various client software in locating where Java in installed, by adding a few environment variables. Do this by editing .bashrc in your home directory.&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;casper@workstation:~$ gksudo gedit $HOME/.bashrc&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Scroll down to the end of the file and add two new lines:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;export JDK_HOME=/usr/lib/jvm/java-7-sun&lt;br /&gt;export JAVA_HOME=$JDK_HOME&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Restart and that's pretty much it, this worked for me, hope it works for you too. Otherwise, throw me a comment below.&lt;br /&gt;&lt;br /&gt;Update: If you are unable to run applets wtihin your browsers, this may be caused by the existing Java Plug-in 1.6 clashing with the new incompatible JRE 1.7 you just installed. To remidy this, you can launch the Java Control Panel and disable the JRE 1.7, making 1.6 the only (and thus default) one.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-VU1BQisjfxw/TkPGQ6y034I/AAAAAAAAATc/Bs6L48pyPyE/s1600/JavaControlPanel.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="392" width="400" src="http://1.bp.blogspot.com/-VU1BQisjfxw/TkPGQ6y034I/AAAAAAAAATc/Bs6L48pyPyE/s400/JavaControlPanel.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;As you can see below, you still retain Java 1.7, but applets and webstart won't try to use any of this new stuff.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-mM8YYO52WSs/TkPGzxDw8wI/AAAAAAAAATk/cYgHc59hkxM/s1600/Screenshot-casper%2540workstation%253A%2B%257E.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="124" width="400" src="http://1.bp.blogspot.com/-mM8YYO52WSs/TkPGzxDw8wI/AAAAAAAAATk/cYgHc59hkxM/s400/Screenshot-casper%2540workstation%253A%2B%257E.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-6839518501768349443?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/6839518501768349443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=6839518501768349443' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/6839518501768349443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/6839518501768349443'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2011/08/java-7-on-ubuntu-1104.html' title='Java 7 on Ubuntu 11.04'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-VU1BQisjfxw/TkPGQ6y034I/AAAAAAAAATc/Bs6L48pyPyE/s72-c/JavaControlPanel.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-9140645110305848661</id><published>2011-05-20T20:01:00.023+02:00</published><updated>2011-06-01T23:08:11.962+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NAS'/><category scheme='http://www.blogger.com/atom/ns#' term='Synology'/><category scheme='http://www.blogger.com/atom/ns#' term='Optware'/><title type='text'>Optware/ipkg on Synology DS211+</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-WcD175MFVZg/Tda7Dij_8NI/AAAAAAAAAQo/XkBO4giFY4A/s1600/DS211%252B_resized.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="379" width="379" src="http://2.bp.blogspot.com/-WcD175MFVZg/Tda7Dij_8NI/AAAAAAAAAQo/XkBO4giFY4A/s400/DS211%252B_resized.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Modding&lt;/b&gt;&lt;br /&gt;&lt;i&gt;Note that the following covers the DS211+ device, which is characterized by being based on the Marvell Kirkwood mv6282 ARM core (1.6Ghz version of 1.2Ghz mv6281). AFAIK the content of this blog entry should be equally applicable to all DS211 variations, but you should consult the &lt;a href="http://forum.synology.com/wiki/index.php/What_kind_of_CPU_does_my_NAS_have"&gt;Synology wiki&lt;/a&gt; for your device to be certain.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;While quite feature rich out-of-the-box, developer types will likely want to make their NAS do even more, either out of a real need or just to tinker. For instance, I eventually plan to connect my USB weather station and generate live charts. Because of the modding desire, Synology has a faily &lt;a href="http://forum.synology.com/wiki/index.php/Overview_on_modifying_the_Synology_Server,_bootstrap,_ipkg_etc"&gt;comprehensive wiki&lt;/a&gt; about the subject. To make a long story short, ease of modding is greatly assisted by the possibility of installing Optware package manager.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Installing Optware&lt;/b&gt;&lt;br /&gt;Optware (ipkg) is an online package system a la what you may know from Debian/Ubuntu. This makes it easy to locate, install and uninstall compiled binaries (*.ipk) through the command-line.  &lt;br /&gt;&lt;br /&gt;Bootstrapper and Optware packages are maintained by the &lt;a href="http://www.nslu2-linux.org/"&gt;NSLU2-Linux community&lt;/a&gt; for use with various modifiable hardware devices incl. many Synology products. The installation procedure simply involves you downloading and installing the Optware-bootstrapper for your NAS. Here's what I wrote while logged in as root via SSH/telnet, to get it working.&lt;br /&gt;&lt;br /&gt;Download the Optware bootstrapper:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;NAS&gt; cd /volume1&lt;br /&gt;NAS&gt; wget http://wizjos.endofinternet.net/synology/archief/syno-mvkw-bootstrap_1&lt;br /&gt;.2-7_arm-ds111.xsh&lt;br /&gt;--22:58:07--  http://wizjos.endofinternet.net/synology/archief/syno-mvkw-bootstrap_1.2-7_arm-ds111.xsh&lt;br /&gt;           =&gt; `syno-mvkw-bootstrap_1.2-7_arm-ds111.xsh'&lt;br /&gt;Resolving wizjos.endofinternet.net... 94.212.228.25&lt;br /&gt;Connecting to wizjos.endofinternet.net|94.212.228.25|:80... connected.&lt;br /&gt;HTTP request sent, awaiting response... 200 OK&lt;br /&gt;Length: 251,866 (246K) [text/plain]&lt;br /&gt;&lt;br /&gt;100%[====================================&gt;] 251,866      435.14K/s             &lt;br /&gt;&lt;br /&gt;22:58:08 (434.50 KB/s) - `syno-mvkw-bootstrap_1.2-7_arm-ds111.xsh' saved [251866/251866]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Start the installation:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;NAS&gt; sh syno-mvkw-bootstrap_1.2-7_arm-ds111.xsh &lt;br /&gt;Optware Bootstrap for syno-mvkw.&lt;br /&gt;Extracting archive... please wait&lt;br /&gt;bootstrap/&lt;br /&gt;bootstrap/optware-bootstrap.ipk&lt;br /&gt;bootstrap/wget.ipk&lt;br /&gt;bootstrap/bootstrap.sh&lt;br /&gt;bootstrap/ipkg.sh&lt;br /&gt;1227+1 records in&lt;br /&gt;1227+1 records out&lt;br /&gt;bootstrap/ipkg-opt.ipk&lt;br /&gt;Creating temporary ipkg repository...&lt;br /&gt;Installing optware-bootstrap package...&lt;br /&gt;Unpacking optware-bootstrap.ipk...Done.&lt;br /&gt;Configuring optware-bootstrap.ipk...Modifying /etc/rc.local&lt;br /&gt;Done.&lt;br /&gt;Installing ipkg...&lt;br /&gt;Unpacking ipkg-opt.ipk...Done.&lt;br /&gt;Configuring ipkg-opt.ipk...WARNING: can't open config file: /usr/syno/ssl/openssl.cnf&lt;br /&gt;Done.&lt;br /&gt;Removing temporary ipkg repository...&lt;br /&gt;Installing wget...&lt;br /&gt;Installing wget (1.12-2) to root...&lt;br /&gt;Configuring wget&lt;br /&gt;Successfully terminated.&lt;br /&gt;Creating /opt/etc/ipkg/cross-feed.conf...&lt;br /&gt;Setup complete.&lt;br /&gt;&lt;br /&gt;BusyBox v1.16.1 (2011-04-08 10:13:55 CST) built-in shell (ash)&lt;br /&gt;Enter 'help' for a list of built-in commands.&lt;br /&gt;&lt;br /&gt;NAS&gt; &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;i&gt;Note, if you get the message "Error: CPU not Marvell Kirkwood, probably wrong bootstrap.xsh", this is likely due to a too agressive sanity check (mv6281 but not mv6282) in the install script. If the output of the command "cat /proc/cpuinfo" mentions a "Feroceon" CPU, then you may safely open up the file "/volume1/bootstrap/bootstrap.sh" and edit line 21, changing "Feroceon-KW" to just "Feroceon", and run the script manually with "sh /volume1/bootstrap/bootstrap.sh".&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;The above will install a boot hook and create the directories /volume1/bootstrap and  /volume1/@Optware where package manager and installed packages will reside. The content in /volume1/@Optware can also be found in /opt, due to an Optware bind mount requirement you can verify by invoking the mount command:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;NAS&gt; mount | grep @optware&lt;br /&gt;/volume1/@optware on /opt type bind (bind)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Now reboot the NAS:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;NAS&gt; reboot&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Managing packages&lt;/b&gt;&lt;br /&gt;After a reboot, you can update the list of packages with:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;NAS&gt; ipkg update&lt;br /&gt;Downloading http://ipkg.nslu2-linux.org/feeds/optware/cs08q1armel/cross/unstable/Packages.gz&lt;br /&gt;Inflating http://ipkg.nslu2-linux.org/feeds/optware/cs08q1armel/cross/unstable/Packages.gz&lt;br /&gt;Updated list of available packages in /opt/lib/ipkg/lists/cross&lt;br /&gt;Successfully terminated.&lt;br /&gt;NAS&gt; &lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;You can list all packages with "ipkg list" or search specific packages with "ipkg list [wildcard]". &lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;NAS&gt; ipkg list cpu* &lt;br /&gt;cpufrequtils - 006-2 - To make access to the Linux kernel cpufreq subsystem easier for users and cpufreq userspace tools, a cpufrequtils package was c&lt;br /&gt;Successfully terminated.&lt;br /&gt;NAS&gt; &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To install a package, simply type "ipkg install [name]". You may also browse the available packages by &lt;a href="http://ipkg.nslu2-linux.org/feeds/optware/cs08q1armel/cross/unstable/"&gt;accessing the repository directly&lt;/a&gt; from within a browser.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;NAS&gt; ipkg install iperf&lt;br /&gt;Installing iperf (2.0.4-1) to root...&lt;br /&gt;Downloading http://ipkg.nslu2-linux.org/feeds/optware/cs08q1armel/cross/unstable/iperf_2.0.4-1_arm.ipk&lt;br /&gt;Configuring iperf&lt;br /&gt;Successfully terminated.&lt;br /&gt;NAS&gt; &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Removing packages is just as easy as installing:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;NAS&gt; ipkg remove iperf &lt;br /&gt;Removing package iperf from root...&lt;br /&gt;Successfully terminated.&lt;br /&gt;NAS&gt; &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;To make sure all installed Optware packages are up to date:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;NAS&gt; ipkg upgrade     &lt;br /&gt;Upgrading grep on root from 2.7-1 to 2.8-1...&lt;br /&gt;Downloading http://ipkg.nslu2-linux.org/feeds/optware/cs08q1armel/cross/unstable/grep_2.8-1_arm.ipk&lt;br /&gt;Configuring grep&lt;br /&gt;update-alternatives: Linking //opt/bin/grep to /opt/bin/grep-grep&lt;br /&gt;update-alternatives: Linking //opt/bin/egrep to /opt/bin/grep-egrep&lt;br /&gt;update-alternatives: Linking //opt/bin/fgrep to /opt/bin/grep-fgrep&lt;br /&gt;Successfully terminated.&lt;br /&gt;NAS&gt; &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Uninstalling Optware&lt;/b&gt;&lt;br /&gt;To my knowledge, there isn't a one-liner for uninstalling the Optware system. It involves stopping the Optware service, unmounting the /opt bind mount, deleting the folder/files, editing the Linux service script and rebooting:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;NAS&gt; /etc/rc.optware stop&lt;br /&gt;NAS&gt; umount /opt&lt;br /&gt;NAS&gt; rm -rf /volume1/@optware&lt;br /&gt;NAS&gt; rm -f /etc/rc.optware&lt;br /&gt;NAS&gt; echo -e "#!/bin/sh\n" &gt; /etc/rc.local&lt;br /&gt;NAS&gt; reboot&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;i&gt;Note that the above wipes the rc.local script. If you have added custom stuff beyond just Optware, you should edit out the Optware stuff manually!&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Of course, there aren't as many packages available as one would like, but it's still impressive that you can install Mono, Java, Python, Perl, Lua etc. on a small NAS device just with a single command. Hope this entry helps others get to hacking on their Synology device.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-9140645110305848661?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/9140645110305848661/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=9140645110305848661' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/9140645110305848661'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/9140645110305848661'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2011/05/optwareipkg-on-synology-ds211.html' title='Optware/ipkg on Synology DS211+'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-WcD175MFVZg/Tda7Dij_8NI/AAAAAAAAAQo/XkBO4giFY4A/s72-c/DS211%252B_resized.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-4799857058265544529</id><published>2011-05-19T00:16:00.025+02:00</published><updated>2011-05-19T22:52:18.597+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NAS'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Synology'/><category scheme='http://www.blogger.com/atom/ns#' term='iperf'/><category scheme='http://www.blogger.com/atom/ns#' term='benchmark'/><title type='text'>Home network benchmarking with iperf</title><content type='html'>Having recently purchased a new &lt;a href="http://www.synology.com/enu/products/DS211+/photo.php"&gt;NAS device&lt;/a&gt;, as well as upgraded network cables in my house to cat6 (1Gbps), I started wondering about just how fast and healthy my network setup was. Are all cables in order? Are any of my switches a bottleneck? Any particular slow endpoints?&lt;br /&gt;performance challenged&lt;br /&gt;There are of course commercial software to assist in this, but after having compiled and loaded up a bunch of Linux software onto my small NAS, it was only natural to give "iperf" a try. It's a small open source client-server utility you start in listening mode on one device, and in transmission mode on another, and have it transfer a bunch of random data over TCP. You can obtain iperf from &lt;a href="http://sourceforge.net/projects/iperf/"&gt;sourceforge&lt;/a&gt;, from your Linux package manager or just Google for precompiled binaries if you are lazy.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Simple unidirectional test&lt;/b&gt;&lt;br /&gt;The process is simple, log onto the receiving device and run iperf in listening mode, in the following case it's my Synology NAS:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;NAS&gt; iperf -s -p 5555&lt;br /&gt;------------------------------------------------------------&lt;br /&gt;Server listening on TCP port 5555&lt;br /&gt;TCP window size: 85.3 kByte  (default)&lt;br /&gt;------------------------------------------------------------&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Then also run iperf, though this time in client mode targeting the server you just started:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span&gt;&lt;br /&gt;casper@laptop:~/$ iperf -c 192.168.0.100 -p 5555&lt;br /&gt;------------------------------------------------------------&lt;br /&gt;Client connecting to 192.168.0.100, TCP port 5555&lt;br /&gt;TCP window size: 19.0 kByte  (default)&lt;br /&gt;------------------------------------------------------------&lt;br /&gt;[  3] local 192.168.0.234 port 52742 connected with 192.168.0.100 port 5555&lt;br /&gt;[ ID] Interval       Transfer     Bandwidth&lt;br /&gt;[  3] 0.0-10.3 sec   26.2MBytes   21.4 Mbit/sec&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;i&gt;Note that the above result is quite slow, as a consequence of being on congested WiFi and benchmarking the slowest node in my household, the NAS.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;This gives you a bps metric for how fast the client could transfer data to the server. To benchmark both upstream and downstream, you must reverse the client-server pair and repeat the process.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Complex bidirectional test case&lt;br /&gt;&lt;/b&gt;By running tests between each and every possible node, it becomes possible to draw some interesting conclusions about the setup in general. The wired setup in my household looks roughly like this (without smartphones, TV, PS3, IP phone etc.):&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-7FUzmNTsE3I/TdV1M8BRFzI/AAAAAAAAAQQ/7rP7pKTmCE8/s1600/network-infra.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="153" width="400" src="http://4.bp.blogspot.com/-7FUzmNTsE3I/TdV1M8BRFzI/AAAAAAAAAQQ/7rP7pKTmCE8/s400/network-infra.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;With Gigabit connections between all major nodes, I expected to see throughput up around 90% of the theoretical maximum bandwidth. What I saw was hardly consistent however, as the following graph shows:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-zkTbAGs419I/TdV1bc09y2I/AAAAAAAAAQY/DTHHo_LI41U/s1600/network-bench.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="256" width="400" src="http://2.bp.blogspot.com/-zkTbAGs419I/TdV1bc09y2I/AAAAAAAAAQY/DTHHo_LI41U/s400/network-bench.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;i&gt;Note that solid edges signify physical cat6 cables, dashed edges logical connections. Edges are labeled with directional throughput in Mbps and nodes contains summerized throughput on the form in/downtream and out/uptream.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Lessons learned&lt;/b&gt;&lt;br /&gt;Infrastructure nodes like router and switch would appear to have performed optimal, and there is no hinting of faulty cabling. On several occasions, one can observe throughput beyond 940Mbps, or 94% of the theoretical maximum.&lt;br /&gt;I was a little surprised to see that the overall best performer, was actually my 3 year old sub-notebook. The network stack (hardware+software) is obviously very well implemented on the laptop. The PC's, particularly one of them, would probably benefit from a new dedicated Gigabit adapter rather than relying on the one built into the motherboard.&lt;br /&gt;However, the greatest surprise was to see how the NAS struggled, particularly when receiving data and when having to cross 2 switches. In all fairness, the slow CPU of the NAS (1.6GHz ARM) could very likely be key to the poor performance of iperf - loopback tests on all endpoints incl. the NAS suggests this to be the case.&lt;br /&gt;&lt;br /&gt;There are of course many other parameters one could care about; ping time, jitter, packet loss, UDP packets, jumbo frames etc. but I was mostly just concerned about TCP bandwidth throughput. I've learned that perhaps I should flash my DD-WRT router back with the original firmware, or perhaps try another open source image like Tomato, in order to see whether I can mitigate some of the observed bandwidth loss. It also seems abundantly clear, that the network system of my NAS device is more optimized for delivering data than receiving it.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;I'd like to do a plugin for Synology's management interface, having it run native iperf against a Java implementation hosted by the client as an applet. Currently looking into whether this is possible. I fear it's too low level for Java, as this was one of the reasons I changed to C# for dealing with raw sockets some years ago.&lt;/i&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-4799857058265544529?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/4799857058265544529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=4799857058265544529' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/4799857058265544529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/4799857058265544529'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2011/05/home-network-benchmarking-with-iperf.html' title='Home network benchmarking with iperf'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-7FUzmNTsE3I/TdV1M8BRFzI/AAAAAAAAAQQ/7rP7pKTmCE8/s72-c/network-infra.png' height='72' width='72'/><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-7956400584942013102</id><published>2011-03-24T00:10:00.022+01:00</published><updated>2011-03-24T13:05:46.299+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVN'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='SVN'/><title type='text'>SVN checkout without branches and tags</title><content type='html'>Subversion (SVN) is a decent step up from CVS, and Maven (MVN) likewise from Ant. However one thing continues to bug me about how the two work together. Since MVN requires a fixed directory layout of /trunk, /tags and /branches, it becomes more and more painful to checkout or update a complete corporate source tree from one of the lower roots.&lt;br /&gt;&lt;br /&gt;In the perfect world, every project may be checked in at the root of the tree, but we all know the world ain't perfect and it's not unusual to require checkout and build of up to a dozen SNAPSHOT dependencies spread around deeper in the hierarchy. There is no (to my knowledge) easy way around this, either you have to live with insanely long checkout times and the associated waste of disk space, or meticulously checkout each every project trunk individually.&lt;br /&gt;&lt;br /&gt;As unimpressed I am by the Java language itself, the hat must come off to the plethora of readily available libraries on this platform. One of these libraries is &lt;a href="http://svnkit.com/"&gt;SVNKit&lt;/a&gt;, a complete client API for accessing SVN servers. So I wondered just how hard it would be to put a client together, doing full tree checkouts, *without* /tags and /branches. Turns out it only took a few hours and under 100 lines of code. :)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:"Monospaced",monospace; color:#000000; white-space: pre;"&gt;&lt;br /&gt;&lt;span style="color:#969696;"&gt;/* Copyright (C) 2011 Casper Bang (casper.bang@gmail.com) */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;package&lt;/span&gt; com.blogspot.coffeecokeandcode;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;import&lt;/span&gt; java.io.File;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;import&lt;/span&gt; java.util.Collection;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;import&lt;/span&gt; org.tmatesoft.svn.core.*;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;import&lt;/span&gt; org.tmatesoft.svn.core.io.*;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;import&lt;/span&gt; org.tmatesoft.svn.core.wc.*;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;import&lt;/span&gt; org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;class&lt;/span&gt; svntrunks &lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;static&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; main(String... args) &lt;span style="color:#0000e6;"&gt;throws&lt;/span&gt; SVNException&lt;br /&gt;    {&lt;br /&gt;        String checkoutPath = &lt;span style="color:#0000e6;"&gt;null&lt;/span&gt;;&lt;br /&gt;        String username = &lt;span style="color:#0000e6;"&gt;null&lt;/span&gt;;&lt;br /&gt;        String password = &lt;span style="color:#0000e6;"&gt;null&lt;/span&gt;;&lt;br /&gt;        String checkoutRootPath = &lt;span style="color:#0000e6;"&gt;new&lt;/span&gt; File(&lt;span style="color:#ce7b00;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;).getAbsolutePath();&lt;br /&gt;        &lt;br /&gt;        &lt;span style="color:#0000e6;"&gt;if&lt;/span&gt;(args.length &amp;gt; &lt;span style="color:#000000;"&gt;2&lt;/span&gt;){&lt;br /&gt;            checkoutPath = args[&lt;span style="color:#000000;"&gt;0&lt;/span&gt;].trim();&lt;br /&gt;            username = args[&lt;span style="color:#000000;"&gt;1&lt;/span&gt;].trim();&lt;br /&gt;            password = args[&lt;span style="color:#000000;"&gt;2&lt;/span&gt;].trim();&lt;br /&gt;            &lt;br /&gt;            &lt;span style="color:#0000e6;"&gt;if&lt;/span&gt;(args.length == &lt;span style="color:#000000;"&gt;4&lt;/span&gt;)&lt;br /&gt;                checkoutRootPath = args[&lt;span style="color:#000000;"&gt;3&lt;/span&gt;].trim();&lt;br /&gt;        }&lt;br /&gt;        &lt;span style="color:#0000e6;"&gt;else&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;            System.out.println(&lt;span style="color:#ce7b00;"&gt;&amp;quot;Usage: java -jar svntrunks.jar URL USERNAME PASSWORD [PATH]\n&amp;quot;&lt;/span&gt;);&lt;br /&gt;            System.out.println(&lt;span style="color:#ce7b00;"&gt;&amp;quot;URL:        The mandatory path to the SVN reposatory&amp;quot;&lt;/span&gt;);&lt;br /&gt;            System.out.println(&lt;span style="color:#ce7b00;"&gt;&amp;quot;USERNAME:   The username to log in as&amp;quot;&lt;/span&gt;);&lt;br /&gt;            System.out.println(&lt;span style="color:#ce7b00;"&gt;&amp;quot;PASSWORD:   Password for the username&amp;quot;&lt;/span&gt;);&lt;br /&gt;            System.out.println(&lt;span style="color:#ce7b00;"&gt;&amp;quot;[PATH]      Optional destination folder (defaults to current)\n\n&amp;quot;&lt;/span&gt;);&lt;br /&gt;            System.out.println(&lt;span style="color:#ce7b00;"&gt;&amp;quot;Example:   java -jar svntrunks.jar https://svn.java.net/svn/jersey~svn david secret jersey-checkout&amp;quot;&lt;/span&gt;);&lt;br /&gt;            System.exit(&lt;span style="color:#000000;"&gt;1&lt;/span&gt;);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        DAVRepositoryFactory.setup();&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; SVNRepository repository = SVNRepositoryFactory.create( SVNURL.parseURIDecoded(checkoutPath) );&lt;br /&gt;        repository.setAuthenticationManager( SVNWCUtil.createDefaultAuthenticationManager( username , password ) );&lt;br /&gt;        &lt;br /&gt;        &lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; SVNClientManager clientManager = SVNClientManager.newInstance(&lt;span style="color:#0000e6;"&gt;null&lt;/span&gt;, repository.getAuthenticationManager());&lt;br /&gt;        &lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; SVNUpdateClient updateClient = clientManager.getUpdateClient();&lt;br /&gt;        updateClient.setIgnoreExternals(&lt;span style="color:#0000e6;"&gt;false&lt;/span&gt;);&lt;br /&gt;        &lt;br /&gt;        &lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; SVNNodeKind nodeKind = repository.checkPath( &lt;span style="color:#ce7b00;"&gt;&amp;quot;&amp;quot;&lt;/span&gt; ,  -&lt;span style="color:#000000;"&gt;1&lt;/span&gt; );&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#0000e6;"&gt;if&lt;/span&gt; ( nodeKind == SVNNodeKind.NONE ) {&lt;br /&gt;            System.err.println( &lt;span style="color:#ce7b00;"&gt;&amp;quot;There is no entry at '&amp;quot;&lt;/span&gt; + checkoutPath + &lt;span style="color:#ce7b00;"&gt;&amp;quot;'.&amp;quot;&lt;/span&gt; );&lt;br /&gt;            System.exit( &lt;span style="color:#000000;"&gt;1&lt;/span&gt; );&lt;br /&gt;        } &lt;span style="color:#0000e6;"&gt;else&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;if&lt;/span&gt; ( nodeKind == SVNNodeKind.FILE ) {&lt;br /&gt;            System.err.println( &lt;span style="color:#ce7b00;"&gt;&amp;quot;The entry at '&amp;quot;&lt;/span&gt; + checkoutPath + &lt;span style="color:#ce7b00;"&gt;&amp;quot;' is a file while a directory was expected.&amp;quot;&lt;/span&gt; );&lt;br /&gt;            System.exit( &lt;span style="color:#000000;"&gt;1&lt;/span&gt; );&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        System.out.println(&lt;span style="color:#ce7b00;"&gt;&amp;quot;Checkout source: &amp;quot;&lt;/span&gt;+ checkoutPath );&lt;br /&gt;        System.out.println(&lt;span style="color:#ce7b00;"&gt;&amp;quot;Checkout destination: &amp;quot;&lt;/span&gt;+ checkoutRootPath );&lt;br /&gt;        traverse(updateClient, repository , checkoutPath, checkoutRootPath, &lt;span style="color:#ce7b00;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;);&lt;br /&gt;        System.out.println( &lt;span style="color:#ce7b00;"&gt;&amp;quot;Repository latest revision: &amp;quot;&lt;/span&gt; + repository.getLatestRevision( ) );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;static&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; traverse(SVNUpdateClient updateClient, SVNRepository repository, String checkoutRootPath, String destRootPath, String repoPath ) &lt;span style="color:#0000e6;"&gt;throws&lt;/span&gt; SVNException {&lt;br /&gt;&lt;br /&gt;        System.out.println(repoPath);&lt;br /&gt;        &lt;br /&gt;        updateClient.doCheckout(&lt;br /&gt;                SVNURL.parseURIDecoded(checkoutRootPath + &lt;span style="color:#ce7b00;"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; + repoPath),  &lt;br /&gt;                &lt;span style="color:#0000e6;"&gt;new&lt;/span&gt; File(destRootPath + (!repoPath.isEmpty() ? &lt;span style="color:#ce7b00;"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;:&lt;span style="color:#ce7b00;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;) + repoPath), &lt;br /&gt;                SVNRevision.UNDEFINED, &lt;br /&gt;                SVNRevision.HEAD, &lt;br /&gt;                SVNDepth.FILES, &lt;span style="color:#0000e6;"&gt;false&lt;/span&gt;);&lt;br /&gt;    &lt;br /&gt;        &lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; Collection&amp;lt;SVNDirEntry&amp;gt; entries = repository.getDir( repoPath, -&lt;span style="color:#000000;"&gt;1&lt;/span&gt; , &lt;span style="color:#0000e6;"&gt;null&lt;/span&gt; , (Collection) &lt;span style="color:#0000e6;"&gt;null&lt;/span&gt; );&lt;br /&gt;        &lt;span style="color:#0000e6;"&gt;for&lt;/span&gt;(SVNDirEntry entry : entries){&lt;br /&gt;            &lt;span style="color:#0000e6;"&gt;if&lt;/span&gt;(!entry.getName().equalsIgnoreCase(&lt;span style="color:#ce7b00;"&gt;&amp;quot;branches&amp;quot;&lt;/span&gt;) &amp;amp;&amp;amp; !entry.getName().equalsIgnoreCase(&lt;span style="color:#ce7b00;"&gt;&amp;quot;tags&amp;quot;&lt;/span&gt;)){&lt;br /&gt;                &lt;span style="color:#0000e6;"&gt;if&lt;/span&gt; ( entry.getKind() == SVNNodeKind.DIR ) {&lt;br /&gt;                    traverse(&lt;br /&gt;                            updateClient, &lt;br /&gt;                            repository, &lt;br /&gt;                            checkoutRootPath, &lt;br /&gt;                            destRootPath, &lt;br /&gt;                            ( repoPath.equals( &lt;span style="color:#ce7b00;"&gt;&amp;quot;&amp;quot;&lt;/span&gt; ) ) ? entry.getName( ) : repoPath + &lt;span style="color:#ce7b00;"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; + entry.getName( ) );&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;em&gt;Note that I do not subscribe to the legacy policy of 80 columns per line! This is 2011, I have more monitors than I have shoes and none are below 22".&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;You may download &lt;a href="http://82.103.135.236/svntrunks-src.zip"&gt;the complete source&lt;/a&gt;, or just &lt;a href="http://82.103.135.236/svntrunks.jar"&gt;the compiled binary&lt;/a&gt; I have build. The source code is licenced under GPL.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;&lt;span&gt;&lt;br /&gt;casper@workstation:~/Development/Code/Java/$ java -jar svntrunks.jar&lt;br /&gt;Usage: java -jar svntrunks.jar URL USERNAME PASSWORD [PATH]&lt;br /&gt;&lt;br /&gt;URL:        The mandatory path to the SVN reposatory&lt;br /&gt;USERNAME:   The username to log in as&lt;br /&gt;PASSWORD:   Password for the username&lt;br /&gt;[PATH]      Optional destination folder (defaults to current)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Example:   java -jar svntrunks.jar https://svn.java.net/svn/jersey~svn david secret jersey-checkout&lt;br /&gt;casper@workstation:~/Development/Code/Java/$ &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Now it's considerably easier to do a new clean checkout of trees, in fact the tool cut down checkout time from the corporate tree I work in, with a factor of about 10! Your mileage may of course vary, depending on the amount of snapshots and branches in the tree.&lt;br /&gt;&lt;br /&gt;There are some obvious improvements I'd like to add, i.e. I never understood why the vanilla SVN client doesn't include commands to detach previously checked out source from its repository. Of course, the true solution to the above problems may simply be to switch to a distributed SCM/VCS like Mercurial or Git. :)&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-7956400584942013102?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/7956400584942013102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=7956400584942013102' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/7956400584942013102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/7956400584942013102'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2011/03/svn-checkout-without-branches-and-tags.html' title='SVN checkout without branches and tags'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-4641077375017274899</id><published>2010-09-04T19:56:00.039+02:00</published><updated>2011-02-15T09:10:03.668+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>My issues with Spring</title><content type='html'>One of the things I've had to come to turns with as a professional Java developer, is navigating the massive chaos of frameworks out there. It doesn't really matter which corner of the development stack we're talking, in Java we're sure there won't ever be just one official standard; if we're lucky, we can identify a state-of-the-art de-facto standard and if we're *truly* lucky, our choice will remain a good one for longer than a few years.&lt;br /&gt;&lt;br /&gt;One of those de-facto standards appears to be &lt;a href="http://www.springsource.org/"&gt;Spring&lt;/a&gt;. There is little doubt, that IoC (&lt;a href="http://en.wikipedia.org/wiki/Inversion_of_control"&gt;Inversion of Control&lt;/a&gt;), or more specifically DI (&lt;a href="http://en.wikipedia.org/wiki/Dependency_injection"&gt;Dependency Injection&lt;/a&gt;), can be a great tool to decouple concrete dependency layers. However, in my opinion Spring introduces just as many problems as it solves, and here's my take on why.&lt;br /&gt;&lt;br /&gt;&lt;B&gt;Everything and a Kitchen Sink&lt;/B&gt;&lt;br /&gt;While Spring does address IoC/DI, it also does a gazillion other things as well - as evident by &lt;a href="http://repo1.maven.org/maven2/org/springframework/"&gt;looking at the Spring maven repo&lt;/a&gt;. On one of the project I was on, my Maven POM ended up holding 15+ dependencies to Spring related technologies, leading me to categorize Spring as containing everything and a kitchen sink. Spring is so many things in one, that it's hard to fathom let alone explain the boundaries; there's Spring JDBC, Spring MVC, Spring Security, Spring Remoting, Spring AOP, Spring DI, Spring RESTfull and probably much more that. Each part may very well be useful in their own right, but one can not help but to be weary of this &lt;a href="http://en.wikipedia.org/wiki/Feature_creep"&gt;creeping featuritis&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;B&gt;Abstraction layer madness&lt;/B&gt;&lt;br /&gt;Most of the frameworks we use, take the shape of some sort of abstraction layer shielding us from hairy details further down. However, from navigating a Spring projects various configuration files and Stack traces (btw. confirmed by Nasa of being visible from space), I get reminded of a short conversation between two luminaries within our industry.&lt;br /&gt;&lt;br /&gt;Computer Scientist &lt;a href="http://en.wikipedia.org/wiki/Butler_Lampson"&gt;Butler Lampson&lt;/a&gt; is known to have said: &lt;blockquote&gt;"All problems in computer science can be solved by another level of indirection"&lt;/blockquote&gt;.&lt;br /&gt;&lt;br /&gt;Whereto &lt;a href="http://en.wikipedia.org/wiki/David_Wheeler_(computer_scientist)"&gt;David Wheeler&lt;/a&gt; supposedly responded wisely: &lt;blockquote&gt;"...except for the problem of too many layers of indirection."&lt;/blockquote&gt;.&lt;br /&gt;&lt;br /&gt;In other words, perhaps we should be careful not to get blinded by magic frameworks which, when everything gets added up, turns out to be as much a disadvantage as an advantage. In this day and age, arguably it's the frameworks rather than the programming languages, we spend the most time understanding - but where we &lt;span style="font-style:italic;"&gt;should&lt;/span&gt; spend our time, is in solving our clients problems.&lt;br /&gt;&lt;br /&gt;&lt;B&gt;Configuration madness&lt;/B&gt;&lt;br /&gt;The inventor of Java, James Gosling, is known to have said something along the line of &lt;blockquote&gt;"Every configuration file ends up becoming a programming language"&lt;/blockquote&gt;Now, if you've dived into Spring, you know this is very much true. Inevitably you'll find yourself looking up documentation trying to figure out what XML to write, where to write it and in which order. There's a trend towards depending on intelligent IDE's in order to conquer this type of complexity, but honestly that feels more like treating the symptom rather than fixing the actual problem. This goes for annotations too btw. which is often abused as a type-unsafe embedded DSL sneaked in by language designers who gave up on trying to innovate by adding first-class language constructs.&lt;br /&gt;&lt;br /&gt;&lt;B&gt;Conclusion&lt;/B&gt;&lt;br /&gt;No bashing of framework overuse can be complete, without a reference to the &lt;a href="http://discuss.joelonsoftware.com/default.asp?joel.3.219431"&gt;Hammer Story&lt;/a&gt;. While I understand that we do need frameworks and they can indeed help us solve many problems faster and better, Spring is one of those I just can't recommend. Perhaps it's just me and my interpretation of &lt;a href="http://en.wikipedia.org/wiki/KISS_principle"&gt;KISS&lt;/a&gt;, but since a picture says a thousands words let me end with one.&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/TIKRKUHiwfI/AAAAAAAAANI/tPbxV_AzS3w/s1600/spring-di.png"&gt;&lt;img style="display:block; margin:0px auto 1px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 209px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/TIKRKUHiwfI/AAAAAAAAANI/tPbxV_AzS3w/s400/spring-di.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5513128500239974898" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So if you're one of those who heard about Ioc and DI, but haven't quite made the jump yet, I urge you to try an alternative to Spring, one that does indeed reveal up front &lt;a href="http://www.urbandictionary.com/define.php?term=rabbit%20hole"&gt;how deep the rabbit hole goes&lt;/a&gt;. Google's &lt;a href="http://code.google.com/p/google-guice/"&gt;Guice&lt;/a&gt; is a good candidate, and it's a testament to its simplicity that it has been ported to other corners of Java i.e. &lt;a href="http://code.google.com/p/roboguice/"&gt;Android&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;B&gt;Update: &lt;/B&gt;It seems even &lt;a href="http://java.dzone.com/articles/maven-3-rides-town"&gt;Maven is now using Guice&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;B&gt;Update: &lt;/B&gt;I had no idea that jotting down my experiences and associated feelings about Spring would cause &lt;a href="http://www.dzone.com/links/my_issues_with_spring.html"&gt;such controversy&lt;/a&gt;. It's clear that Spring is working fine for many and/or is worth the extra complexity. For the record, I don't hate Spring but just find that perhaps we should question whether it's really needed before pulling in dependencies from left and right. &lt;br /&gt;&lt;br /&gt;So take this for what it is; a developer questioning whether we can't solve our problems in more elegant and lean ways than what the Spring stack has to offer. I think that often we can. Although at the concrete level I primarily address Spring IoC/DI above, the mere vastness of Spring makes it impossible to go into every aspect even if I had the knowledge to do so. "Pick and choose what you need" is a valid argument of course, but for now I remain unconvinced. Try to imagine the state of your applications dependencies a few years from now. Or try to imagine adding a new green developer to your team and how hard it will be for him to become productive. &lt;br /&gt;&lt;br /&gt;The one mantra that truly never failed me is to &lt;a href="http://en.wikipedia.org/wiki/KISS_principle"&gt;Keep It Simple Stupid&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-4641077375017274899?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/4641077375017274899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=4641077375017274899' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/4641077375017274899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/4641077375017274899'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2010/09/my-issues-with-spring.html' title='My issues with Spring'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_CauKCPUdin4/TIKRKUHiwfI/AAAAAAAAANI/tPbxV_AzS3w/s72-c/spring-di.png' height='72' width='72'/><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-4049819052796266969</id><published>2010-03-27T23:04:00.029+01:00</published><updated>2010-04-29T09:45:07.035+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><title type='text'>Android and task killers: Don't</title><content type='html'>There's an awful lot of misconceptions regarding Android and multitasking out there. When you read help forums and the issue of performance tweaking comes up, a very popular answer is to use a &lt;a href="http://www.knowyourmobile.com/smartphones/smartphoneapps/androidapplications/325122/advanced_task_killer_review.html"&gt;task killer&lt;/a&gt; to close unwanted apps. Even venerable tech people like &lt;a href="http://twit.tv/"&gt;TWiT's&lt;/a&gt; &lt;a href="http://twitter.com/LEOLAPORTE"&gt;Leo Laporte&lt;/a&gt; appears to have acquired this habit. I reckon that these people have no idea how Android actually works and/or are making erroneous assumptions pulled over from the world of traditional desktop computing. In the best case, nothing happens when you kill an application except you spend time manually doing something that would otherwise have been done for you automatically at a later time. Worst case, you crash an application or get up too late tomorrow because your alarm didn't go off.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How Android does things&lt;/b&gt;&lt;br /&gt;At an architectural level, applications running on Android are actually not supposed to halt its process in the traditional sense as we are used to from most desktop operating systems. When you switch to another application on Android, or use the back button, the previous application actually remains in memory but is just no longer active (though it's background services may be). It's up to the application and its author to play nicely in this environment. The vast majority of applications have no trouble doing so.&lt;br /&gt;&lt;br /&gt;Only very few applications are so performance demanding, that they introduce a distinct exit button. This can be seen i.e. in the GPS navigation software &lt;a href="http://www.alk.com/copilot/android/"&gt;CoPilot&lt;/a&gt; which engages many services and sensors on the phone, and is assuming that even if you require the use of another application (i.e. get a call), the navigation software should keep guiding you on your way. However, this exit button might as well be called "stop navigation services" but that would probably just confuse.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_CauKCPUdin4/S66gjS1tuvI/AAAAAAAAAL4/Z-St8IDnQk4/s1600/copilot_exit.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 150px; height: 225px;" src="http://3.bp.blogspot.com/_CauKCPUdin4/S66gjS1tuvI/AAAAAAAAAL4/Z-St8IDnQk4/s400/copilot_exit.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5453472727005248242" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Why Android does it this way&lt;/b&gt;&lt;br /&gt;At the usability level, I suspect Google liked being able to combine Cancel, Back and Exit into one physical button. To most people, the difference comes down to some fairly narrow semantics. Apple of course gets around this simply by not allowing multitasking altogether, probably driven by the desire to only have one button! At a more technical level, realize that &lt;a href="http://en.wikipedia.org/wiki/Dynamic_random_access_memory"&gt;DRAM memory cells&lt;/a&gt; in computers and smart-phones costs just as much in power/battery to keep alive, regardless of whether these cells are used or not. So in the world of Android, applications which you've used are considered likely candidates for use again later and hence, stays dormant in RAM. The Android operating system will manage these and in the case of low memory, will suspend and free up RAM for other purposes. Think of it this way, it's cheaper/faster to keep the application idle in fast RAM and just move a memory pointer to it when you want to use it again, than it is to load the whole application from scratch again from slow flash.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;So why do people use task killers?&lt;/b&gt;&lt;br /&gt;Apart from wrong assumptions that things works as on a PC, I suspect using too many applications (or rather, too many busy background services) and perhaps witnessing a small lag when Android is freeing memory, will get people to hunt for ways to shut down applications. A smart-phone does not have the same abundance of resources, so one must be careful when specifying settings for various synchronization services. So instead of killing an application, say i.e. the popular &lt;a href="http://www.bestandroidappsreview.com/2010/01/top-android-app-newsroom.html"&gt;News Room&lt;/a&gt; app, go into the preferences and disable or tweak the background update service instead.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;br /&gt;On a modern Android smart-phone, I have yet to see a real need for a task killer apart from shutting down Android Marked when changing carrier with Marked Enabler, but that's not performance related. And the few times I do need that, it's sufficient to do this using the stock Android option you can find by exploring Settings -&gt; Applications -&gt; Manage Applications, pick application and click "Force stop". &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/S66kNs2VYrI/AAAAAAAAAMA/n3uSWS6iCpE/s1600/nexus-one-force-stop.resized.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 164px; height: 148px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/S66kNs2VYrI/AAAAAAAAAMA/n3uSWS6iCpE/s400/nexus-one-force-stop.resized.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5453476754076558002" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;On my Nexus One here, after a day of using a bunch of applications I now have 26 running processes in 338MB of RAM, but still 48MB free. In essence, all the applications I use are loaded in RAM and ready for me to use - just as Google intended.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;UPDATE:&lt;/b&gt;&lt;br /&gt;Dianne Hackborn, a Google software engineer on the Android team &lt;a href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/ttPv5J4K1qo/multitasking-android-way.html"&gt;explains it in detail here&lt;/a&gt;.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-4049819052796266969?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/4049819052796266969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=4049819052796266969' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/4049819052796266969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/4049819052796266969'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2010/03/android-and-task-killers-dont.html' title='Android and task killers: Don&apos;t'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_CauKCPUdin4/S66gjS1tuvI/AAAAAAAAAL4/Z-St8IDnQk4/s72-c/copilot_exit.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-3776768506326214664</id><published>2010-01-04T05:06:00.006+01:00</published><updated>2010-01-04T05:20:42.252+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><title type='text'>Android cubicle figure</title><content type='html'>So my girlfriend, who is very artistic, has been doing some special clay modeling lately. Since I'm the kind of guy who likes to have lots of geek cubicle stuff (even if I do not work in a cubicle), what better to ask for than an Android figure. And lo and behold, this time I got what I asked for... hope this is a good indicator for the new year.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/S0Fqd9k7hgI/AAAAAAAAAJ8/OqK8-RxXA4A/s1600-h/IMG_2712.resized.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 318px; height: 400px;" src="http://2.bp.blogspot.com/_CauKCPUdin4/S0Fqd9k7hgI/AAAAAAAAAJ8/OqK8-RxXA4A/s400/IMG_2712.resized.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5422732489308997122" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Cute eh? &lt;br /&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-3776768506326214664?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/3776768506326214664/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=3776768506326214664' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/3776768506326214664'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/3776768506326214664'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2010/01/android-cubicle-figure.html' title='Android cubicle figure'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_CauKCPUdin4/S0Fqd9k7hgI/AAAAAAAAAJ8/OqK8-RxXA4A/s72-c/IMG_2712.resized.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-5517444834540488467</id><published>2009-12-30T01:56:00.032+01:00</published><updated>2011-07-12T10:58:00.722+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iGala'/><category scheme='http://www.blogger.com/atom/ns#' term='hacking'/><title type='text'>Fun with the iGala picture frame</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-m_047kq7cyI/TYucL5LJi0I/AAAAAAAAAOo/LWYhQ8pmtL4/s1600/iGala.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 319px;" src="http://2.bp.blogspot.com/-m_047kq7cyI/TYucL5LJi0I/AAAAAAAAAOo/LWYhQ8pmtL4/s400/iGala.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5587731490823310146" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;NOTE: This is an old article that I never got around to finishing. So it might or might not still be relevant. Turns out iGala is about to launch Android support for the frame, but until then, I suspect the following could still be of interest to some.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;One of the most geeky of shopping sites must be thinkgeek.com. They have many wonderful and useless items to appeal to the geek inside of you, hell even my wife had a blast reading their catalog. Anyway, one of the items they sell (exclusively apparently) is the iGala digital picture frame, from Aequitas Technologies. Now I've come across countless of these, but the iGala is one of the few ones running an easy-to-access embedded Linux. In the following I will show what I mean and provide some documentation that I have collected.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Probing the frame from outside&lt;/b&gt;&lt;br /&gt;It's an 8" LCD, capable of a 800x600 resolution and with a resistive touch membrane in front. Apart from that, not much info is given to the consumer - in spite of this frame being marked as "Linux inside". You can find the device on your local LAN, by doing an IP broadcast or using nmap. Here's how I found mine:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;casper@workstation:~$ nmap -sP 192.168.0.1-254&lt;br /&gt;Starting Nmap 5.00 ( http://nmap.org ) at 2009-12-30 02:06 CET&lt;br /&gt;Host 192.168.0.1 is up (0.0018s latency).&lt;br /&gt;Host 192.168.0.10 is up (0.086s latency).&lt;br /&gt;Host 192.168.0.101 is up (0.00015s latency).&lt;br /&gt;Host 192.168.0.105 is up (0.0025s latency).&lt;br /&gt;Nmap done: 254 IP addresses (4 hosts up) scanned in 12.88 seconds&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I happen to know that the 192.168.0.1 router, the 192.168.0.10 is a wifi web-cam, 192.168.0.101 is my own computer so that leaves only 192.168.0.105 as the frame. Once we located it on the LAN, let's probe it a bit with the nmap tool.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;casper@workstation:~$ nmap 192.168.0.105 -p1-65535&lt;br /&gt;Starting Nmap 5.00 ( http://nmap.org ) at 2009-12-30 02:11 CET&lt;br /&gt;Interesting ports on 192.168.0.105:&lt;br /&gt;Not shown: 65532 closed ports&lt;br /&gt;PORT      STATE SERVICE&lt;br /&gt;21/tcp    open  ftp&lt;br /&gt;514/tcp   open  shell&lt;br /&gt;65534/tcp open  unknown&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ok, it appears to be running an FTP server on port 21, an (unencrypted) telnet service at port 514 as well something unknown on port 65534. Let's check out the FTP server real quick.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;casper@workstation:~$ telnet 192.168.0.105 21&lt;br /&gt;Trying 192.168.0.105...&lt;br /&gt;Connected to 192.168.0.105.&lt;br /&gt;Escape character is '^]'.&lt;br /&gt;220 localhost.localdomain FTP server (GNU inetutils 1.4.1) ready.&lt;br /&gt;USER anonymous&lt;br /&gt;530 User anonymous unknown.&lt;br /&gt;USER igala&lt;br /&gt;530 p&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ok so no anonymous account. We'd have to use exhaustive trial and error to get in here so let's move on to the next.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;casper@workstation:~$ rsh -l igala 192.168.0.105 514&lt;br /&gt;Login incorrect.&lt;br /&gt;casper@workstation:~$ rsh -l root 192.168.0.105 514&lt;br /&gt;514: not found&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Not much better. Again, we'd have to start some brute-force attack against the device to get in. Off to the 3'rd one.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;casper@workstation:~$ telnet 192.168.0.105 65534&lt;br /&gt;Trying 192.168.0.105...&lt;br /&gt;Connected to 192.168.0.105.&lt;br /&gt;Escape character is '^]'.&lt;br /&gt;&lt;br /&gt;BusyBox v1.4.1 (2008-12-29 10:57:28 CST) Built-in shell (msh)&lt;br /&gt;Enter 'help' for a list of built-in commands.&lt;br /&gt;&lt;br /&gt;root:/&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Whoa, bingo! Someone left a BusyBox telnet service listening on one of the very last possible ports.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Probing the frame from inside&lt;/b&gt;&lt;br /&gt;Let's fire off some commands to see what we're dealing with here.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;root:/&gt; uname -a    &lt;br /&gt;Linux blackfin 2.6.22.16-ADI-2008R1-svn #2477 Wed Dec 31 13:02:59 CST 2008 blackfin unknown&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Interesting, Linux kernel 2.6.22.16 for the Blackfin processor.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;root:/&gt; cat /proc/cpuinfo&lt;br /&gt;processor : 0&lt;br /&gt;vendor_id : Analog Devices&lt;br /&gt;cpu family : 0x27a5000&lt;br /&gt;model name : ADSP-BF531 540(MHz CCLK) 108(MHz SCLK)&lt;br /&gt;stepping : 5&lt;br /&gt;cpu MHz  : 540.000/108.000&lt;br /&gt;bogomips : 1073.15&lt;br /&gt;Calibration : 536576000 loops&lt;br /&gt;cache size : 16 KB(L1 icache) 16 KB(L1 dcache-wt) 0 KB(L2 cache)&lt;br /&gt;dbank-A/B : cache/sram&lt;br /&gt;icache setup : 4 Sub-banks/4 Ways, 32 Lines/Way&lt;br /&gt;dcache setup : 1 Super-banks/4 Sub-banks/2 Ways, 64 Lines/Way&lt;br /&gt;No Ways are locked&lt;br /&gt;board name : ADDS-BF533-STAMP&lt;br /&gt;board memory : 65536 kB (0x00000000 -&gt; 0x04000000)&lt;br /&gt;kernel memory : 63476 kB (0x00002000 -&gt; 0x03dff000)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A fairly fast CPU - substantially faster than the 108MHz ARM inside my Samsung SPF-105V frame.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;root:/&gt; mount&lt;br /&gt;rootfs on / type rootfs (rw)&lt;br /&gt;proc on /proc type proc (rw)&lt;br /&gt;ramfs on /var type ramfs (rw)&lt;br /&gt;sysfs on /sys type sysfs (rw)&lt;br /&gt;devpts on /dev/pts type devpts (rw)&lt;br /&gt;usbfs on /proc/bus/usb type usbfs (rw)&lt;br /&gt;debugfs on /sys/kernel/debug type debugfs (rw)&lt;br /&gt;securityfs on /sys/kernel/security type securityfs (rw)&lt;br /&gt;/dev/mtdblock1 on /mnt/flash type yaffs (rw)&lt;br /&gt;/dev/mtdblock2 on /mnt/fdisk type yaffs (rw)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A good deal of various filesystems, of which /dev/mtdblock1 and /dev/mtdblock2 are probably the most interesting in regard to modding.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;root:/&gt; netstat&lt;br /&gt;Active Internet connections (w/o servers)&lt;br /&gt;Proto Recv-Q Send-Q Local Address           Foreign Address         State&lt;br /&gt;tcp        0      0 192.168.0.105:50350     www.flickr.vip.mud:http TIME_WAIT   &lt;br /&gt;tcp        0      0 192.168.0.105:50348     www.flickr.vip.mud:http TIME_WAIT   &lt;br /&gt;tcp        0      0 192.168.0.105:50351     www.flickr.vip.mud:http TIME_WAIT   &lt;br /&gt;tcp        0      0 192.168.0.105:50353     www.flickr.vip.mud:http TIME_WAIT   &lt;br /&gt;tcp        0      0 192.168.0.105:50352     www.flickr.vip.mud:http TIME_WAIT   &lt;br /&gt;tcp        0      0 192.168.0.105:50345     www.flickr.vip.mud:http TIME_WAIT   &lt;br /&gt;tcp        0      0 192.168.0.105:50347     www.flickr.vip.mud:http TIME_WAIT   &lt;br /&gt;tcp        0      0 192.168.0.105:50346     www.flickr.vip.mud:http TIME_WAIT   &lt;br /&gt;tcp        0    164 192.168.0.105:telnet    192.168.0.101:57949     ESTABLISHED &lt;br /&gt;tcp        0      0 192.168.0.105:50349     www.flickr.vip.mud:http TIME_WAIT   &lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A busy device indeed. For some reasons, the frame have multiple idle connections to flickr.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;root:/&gt; dmesg&lt;br /&gt;Hardware Trace:&lt;br /&gt;0 Target : &lt;0x000059f4&gt; { _trap_c + 0x0 }&lt;br /&gt;Source : &lt;0xffa0860c&gt; { _exception_to_level5 + 0xb4 }&lt;br /&gt;1 Target : &lt;0xffa08558&gt; { _exception_to_level5 + 0x0 }&lt;br /&gt;Source : &lt;0xffa084b0&gt; { _ex_trap_c + 0x5c }&lt;br /&gt;2 Target : &lt;0xffa08454&gt; { _ex_trap_c + 0x0 }&lt;br /&gt;Source : &lt;0xffa086ac&gt; { _trap + 0x28 }&lt;br /&gt;3 Target : &lt;0xffa08684&gt; { _trap + 0x0 }&lt;br /&gt;Source : &lt;0x0061ef62&gt; [ /lib/libuClibc-0.9.29.so + 0x1ef62 ]&lt;br /&gt;4 Target : &lt;0x0061ef46&gt; [ /lib/libuClibc-0.9.29.so + 0x1ef46 ]&lt;br /&gt;Source : &lt;0x0061ef3e&gt; [ /lib/libuClibc-0.9.29.so + 0x1ef3e ]&lt;br /&gt;5 Target : &lt;0x0061ef30&gt; [ /lib/libuClibc-0.9.29.so + 0x1ef30 ]&lt;br /&gt;Source : &lt;0x036257f8&gt; [ /mnt/flash/abies/lua + 0x257f8 ]&lt;br /&gt;6 Target : &lt;0x036257f0&gt; [ /mnt/flash/abies/lua + 0x257f0 ]&lt;br /&gt;Source : &lt;0x0362f49e&gt; [ /mnt/flash/abies/lua + 0x2f49e ]&lt;br /&gt;7 Target : &lt;0x0362f488&gt; [ /mnt/flash/abies/lua + 0x2f488 ]&lt;br /&gt;Source : &lt;0x0366a3a8&gt; [ /mnt/flash/abies/lua + 0x6a3a8 ]&lt;br /&gt;8 Target : &lt;0x0366a39c&gt; [ /mnt/flash/abies/lua + 0x6a39c ]&lt;br /&gt;Source : &lt;0x0362f484&gt; [ /mnt/flash/abies/lua + 0x2f484 ]&lt;br /&gt;9 Target : &lt;0x0362f45c&gt; [ /mnt/flash/abies/lua + 0x2f45c ]&lt;br /&gt;Source : &lt;0x0362f456&gt; [ /mnt/flash/abies/lua + 0x2f456 ]&lt;br /&gt;10 Target : &lt;0x0362f450&gt; [ /mnt/flash/abies/lua + 0x2f450 ]&lt;br /&gt;Source : &lt;0x0362f444&gt; [ /mnt/flash/abies/lua + 0x2f444 ]&lt;br /&gt;11 Target : &lt;0x0362f42e&gt; [ /mnt/flash/abies/lua + 0x2f42e ]&lt;br /&gt;Source : &lt;0x0362f420&gt; [ /mnt/flash/abies/lua + 0x2f420 ]&lt;br /&gt;12 Target : &lt;0x0362f3a4&gt; [ /mnt/flash/abies/lua + 0x2f3a4 ]&lt;br /&gt;Source : &lt;0x0362f39a&gt; [ /mnt/flash/abies/lua + 0x2f39a ]&lt;br /&gt;13 Target : &lt;0x0362f394&gt; [ /mnt/flash/abies/lua + 0x2f394 ]&lt;br /&gt;Source : &lt;0x0362f382&gt; [ /mnt/flash/abies/lua + 0x2f382 ]&lt;br /&gt;14 Target : &lt;0x0362f32e&gt; [ /mnt/flash/abies/lua + 0x2f32e ]&lt;br /&gt;Source : &lt;0x0362f2e4&gt; [ /mnt/flash/abies/lua + 0x2f2e4 ]&lt;br /&gt;15 Target : &lt;0x0362f2d4&gt; [ /mnt/flash/abies/lua + 0x2f2d4 ]&lt;br /&gt;Source : &lt;0x0366a3fa&gt; [ /mnt/flash/abies/lua + 0x6a3fa ]&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Looks like we have the omnipresent libC library servicing Lua code located in /mnt/flash/abies/&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;root:/&gt; top&lt;br /&gt;Print certain system information.  With no OPTION, same as -s.&lt;br /&gt;Mem: 45392K used, 15304K free, 0K shrd, 0K buff, 5600K cached&lt;br /&gt;Load average: 2.69 2.42 2.22&lt;br /&gt;PID USER     STATUS   VSZ  PPID %CPU %MEM COMMAND&lt;br /&gt;438 root     R      27536     1 71.7 45.0 lua&lt;br /&gt;21151 root     R        844 13454  7.2  1.3 top&lt;br /&gt;495 root     S      27536   460  3.2 45.0 lua&lt;br /&gt;343 root     S       2806     1  0.8  4.5 nano-X&lt;br /&gt;13453 root     S        508   276  0.8  0.8 telnetd&lt;br /&gt;349 root     SW         0     2  0.8  0.0 rt73&lt;br /&gt;460 root     S      27536   438  0.0 45.0 lua&lt;br /&gt;359 root     S        836     1  0.0  1.3 syslogd&lt;br /&gt;360 root     S        836     1  0.0  1.3 klogd&lt;br /&gt;194 root     S &lt;      800     1  0.0  1.3 udevd&lt;br /&gt;1 root     S        568     0  0.0  0.9 init&lt;br /&gt;547 root     S        516     1  0.0  0.8 dhcpcd&lt;br /&gt;277 root     S        484     1  0.0  0.7 udisk_mount&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;Some Lua processes, a nano-X server, a few telnet deamons, a DHCP client deamon and a udisk mount service.So anyway, since today is not the day for me to learn Lua, I will proceed playing with just shell scripting. Let's mod the frame to download some custom telemetry data or public weather satellite picture once a minute.&lt;pre style="background-color: #000000; color: #ffffff;"&gt;rm /mnt/flash/abies/default/*.*&lt;br /&gt;cp /mnt/flash/wait.png /mnt/flash/abies/default/chart.png&lt;br /&gt;sleep 30&lt;br /&gt;while [ 1 ]&lt;br /&gt;do&lt;br /&gt;rm /mnt/flash/abies/default/chart.png&lt;br /&gt;wget -O /mnt/flash/abies/default/chart.png http://www.ntua.gr/weather/sat.jpg&lt;br /&gt;sleep 60&lt;br /&gt;done&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;The above script takes advantage of the fact that the frame by default cycles between 4 preinstalled images located under /mnt/flash/abies/default/. So first it clears this picture index, then it copies a waiting image into the picture area, which makes the frame show a nice image while we wait for the actual live data. Then we loop indefinitely, and in this loop the old image is deleted, a new image is downloaded and then we sleep for 60 seconds.&lt;br&gt;&lt;br&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-DyLSCsjXibU/TYuhgdE895I/AAAAAAAAAOw/qvsIYhpnmUg/s1600/IMG_1691.resized.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/-DyLSCsjXibU/TYuhgdE895I/AAAAAAAAAOw/qvsIYhpnmUg/s400/IMG_1691.resized.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5587737341616519058" /&gt;&lt;/a&gt;The above image shows live telemetric data from my house, in the form of temperature, humidity etc. as 24h charts. In principle there's no limit to what you can render on the frame, as long as you are capable of producing 800x600 image representations.&lt;br&gt;&lt;br&gt;Turns out, it's even possible to use the official update mechanism and create an update package which does this modding on a frame just by inserting a USB stick with the software on - just be aware of updates being pulled down from iGala's website which may conflict (you can block this of course, but then you might as well simple write your own Lua hosting application).&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-5517444834540488467?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/5517444834540488467/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=5517444834540488467' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/5517444834540488467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/5517444834540488467'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2009/12/modding-igala-picture-frame.html' title='Fun with the iGala picture frame'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-m_047kq7cyI/TYucL5LJi0I/AAAAAAAAAOo/LWYhQ8pmtL4/s72-c/iGala.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-3665394494037791925</id><published>2009-12-23T02:42:00.023+01:00</published><updated>2010-01-15T20:21:49.401+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><title type='text'>Android debug bridge on ubuntu 9.10</title><content type='html'>It turns out the latest Ubuntu release makes it a bit more difficult to connect the multi purpose Android debug bridge to your Android device. The following is really just an update of &lt;a href="http://coffeecokeandcode.blogspot.com/2009/06/android-debug-bridge-on-ubuntu-904.html"&gt;my older entry&lt;/a&gt;, to remind myself of the changes in Ubuntu 9.10. This stuff is pieced together from various other sources online (mostly &lt;a href="http://groups.google.com/group/android-discuss"&gt;android-discuss&lt;/a&gt;) and thus not particularly original.&lt;br /&gt;&lt;br /&gt;Ok so first of all, there are quite a few more vendors and devices now (yay). In order to identify your device, make sure your device is not connected and then execute the Linux command lsusb.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;casper@workstation:~$ lsusb&lt;br /&gt;Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub&lt;br /&gt;Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub&lt;br /&gt;Bus 001 Device 004: ID 07cc:0501 Carry Computer Eng., Co., Ltd Mass Storage&lt;br /&gt;Bus 001 Device 002: ID 0409:005a NEC Corp. HighSpeed Hub&lt;br /&gt;Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub&lt;br /&gt;Bus 003 Device 002: ID 051d:0002 American Power Conversion Uninterruptible Power Supply&lt;br /&gt;Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub&lt;br /&gt;Bus 004 Device 002: ID 046d:c51a Logitech, Inc. MX Revolution/G7 Cordless Mouse&lt;br /&gt;Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now connect the device and make sure USB debugging is enabled, and run the command again. You should have one more line:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;casper@workstation:~$ lsusb&lt;br /&gt;Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub&lt;br /&gt;Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub&lt;br /&gt;&lt;b&gt;Bus 001 Device 016: ID 0bb4:0c02 High Tech Computer Corp.&lt;/b&gt;&lt;br /&gt;Bus 001 Device 004: ID 07cc:0501 Carry Computer Eng., Co., Ltd Mass Storage&lt;br /&gt;Bus 001 Device 002: ID 0409:005a NEC Corp. HighSpeed Hub&lt;br /&gt;Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub&lt;br /&gt;Bus 003 Device 002: ID 051d:0002 American Power Conversion Uninterruptible Power Supply&lt;br /&gt;Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub&lt;br /&gt;Bus 004 Device 002: ID 046d:c51a Logitech, Inc. MX Revolution/G7 Cordless Mouse&lt;br /&gt;Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So now we learned that HTC stands for High Tech Computer. :) We then need to install the rule for the device, by creating a file under /etc/udev/&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;gksudo gedit /etc/udev/rules.d/51.android.rules&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Enter the following, but adjust vendor id and product ID according to what you just found out in the previous step. The device entry below will likely only work if you also happen to have an HTC Magic/Saphire A6161/Nordic (32a).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="0bb4", ATTRS{idProduct}=="0c01", MODE="0666"&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Make sure everyone can access and execute it:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;sudo chmod a+rx /etc/udev/rules.d/51.android.rules&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now reload the udev service:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;sudo service udev reload&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now you are ready to start the adb service. Note that due to a change/bug in the security policies of Ubuntu 9.10, you won't have access to the device unless you execute adb (or rather, the adb service) as a super user. This is mildly annoying:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;casper@workstation:~/development/android-sdk-linux/tools$ adb devices&lt;br /&gt;* daemon not running. starting it now *&lt;br /&gt;* daemon started successfully *&lt;br /&gt;List of devices attached &lt;br /&gt;???????????? no permissions&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Instead what you will have to do is start the server manually in super user mode (make sure to kill any existing server first, with sudo adb kill-server):&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;casper@workstation:~/development/android-sdk-linux/tools$ sudo ./adb start-server&lt;br /&gt;* daemon not running. starting it now *&lt;br /&gt;* daemon started successfully *&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And now you may use adb as per usual:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;casper@workstation:~/development/android-sdk-linux/tools$ adb devices &lt;br /&gt;List of devices attached &lt;br /&gt;HT95PKF00221 device&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Not really groundbreaking stuff, but I thought it might be useful and save time for others running Ubuntu 9.10 and wanting to get ADB up and running.&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;b&gt;Update&lt;/b&gt;&lt;br /&gt;The Nexus One, Google's latest Android beast, appears to be identified as 18d1:4e11 but without any vendor string. Interesting since the Nexus One is also hardware produced by HTC. However using adb, it will list with serialid: HT9CRP805273 so HTC is not entirely hidden. It appears that internally the phone is referenced as the Passion and/or Mahimahi.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-3665394494037791925?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/3665394494037791925/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=3665394494037791925' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/3665394494037791925'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/3665394494037791925'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2009/12/android-debug-bridge-on-ubuntu-910.html' title='Android debug bridge on ubuntu 9.10'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-4264722296964252542</id><published>2009-08-20T04:32:00.070+02:00</published><updated>2009-08-25T15:41:32.235+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Tweaking javac leniency</title><content type='html'>While a great fan of type-safety and static checking, I also like a certain amount of leniency from compilers. Sun's Java compiler is a good example of one that goes overboard in some anal, misunderstood attempt at servicing the developer. &lt;br /&gt;In the following I will explain why I think so and how to fix it by modifying the publicly available source code for the compiler. Note that although I have &lt;a href="http://docs.google.com/Doc?id=dfkvb9sc_0pcr8szdd"&gt;done something similar&lt;/a&gt; before, I am no compiler expert and never will be. The modifications shown in this post are mere tweaks and I will stay far away from anything below semantic analysis.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;"Exception is never thrown"&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Have you ever had a good coding session, with design, implementation and refactoring happening at an immense speed as you try to perfect the internals of a piece of code? All of a sudden you are distracted because a try block no longer contains any methods that declares a checked exception. So now, in order to satisfy the compiler, you'll have to focus on removing these alternate, albeit dead and harmless paths. Indeed, you will have to carefully uncomment everything but the body of the try block.&lt;br /&gt;&lt;br /&gt;As a concrete but contrived example, imagine something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace; color:#000000; white-space: pre;"&gt;&lt;br /&gt;    Settings settings = &lt;span style="color:#0000e6;"&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000e6;"&gt;try&lt;/span&gt; {&lt;br /&gt;        settings = Settings.loadFile(&lt;span style="color:#ce7b00;"&gt;&amp;quot;settings.conf&amp;quot;&lt;/span&gt;);&lt;span style="font-family:"Monospaced",monospace; color:#000000; white-space: pre;"&gt;&lt;br /&gt;        settingsObservers.fireChangeEvent();&lt;/span&gt;&lt;br /&gt;    } &lt;span style="color:#0000e6;"&gt;catch&lt;/span&gt; (IOException ex) {&lt;br /&gt;        &lt;span style="color:#969696;"&gt;// Logging...&lt;br /&gt;&lt;/span&gt;    }&lt;br /&gt;    &lt;span style="color:#0000e6;"&gt;finally&lt;/span&gt;{&lt;br /&gt;        &lt;span style="color:#969696;"&gt;// Cleanup...&lt;br /&gt;&lt;/span&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now then imagine you need to test something real quick, and thus prefers to just new up the Settings() object or something similar, so you comment out the line where it loads from a file:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace; color:#000000; white-space: pre;"&gt;&lt;br /&gt;    Settings settings = &lt;span style="color:#0000e6;"&gt;new&lt;/span&gt; Settings();&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000e6;"&gt;try&lt;/span&gt; {&lt;br /&gt;        &lt;span style="color:#969696;"&gt;// settings = Settings.loadFile(&amp;quot;settings.conf&amp;quot;);&lt;/span&gt;&lt;span style="font-family:"Monospaced",monospace; color:#000000; white-space: pre;"&gt;&lt;br /&gt;        settingsObservers.fireChangeEvent();&lt;/span&gt;&lt;br /&gt;    } &lt;span style="color:#0000e6;"&gt;catch&lt;/span&gt; (IOException ex) {&lt;br /&gt;        &lt;span style="color:#969696;"&gt;// Logging...&lt;br /&gt;&lt;/span&gt;    }&lt;br /&gt;    &lt;span style="color:#0000e6;"&gt;finally&lt;/span&gt;{&lt;br /&gt;        &lt;span style="color:#969696;"&gt;// Cleanup...&lt;br /&gt;&lt;/span&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That won't work of course, because of the paranoid rules surrounding checked exceptions. Instead, we'll see the compiler complain:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: rgb(0, 0, 0); color: rgb(255, 255, 255);"&gt;&lt;br /&gt;casper@workstation:~$ javac ExceptionNeverThrown.java &lt;br /&gt;ExceptionNeverThrown.java:13: exception java.io.IOException is never thrown in body of corresponding try statement&lt;br /&gt;    } catch (IOException ex) {&lt;br /&gt;1 error&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So in order to have it run, you meticulously comment out everything related to the try-catch-finally block:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace; color:#000000; white-space: pre;"&gt;&lt;br /&gt;    Settings settings = &lt;span style="color:#0000e6;"&gt;new&lt;/span&gt; Settings();&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#969696;"&gt;//try {&lt;br /&gt;&lt;/span&gt;        &lt;span style="color:#969696;"&gt;// settings = Settings.loadFile(&amp;quot;settings.conf&amp;quot;);&lt;br /&gt;&lt;/span&gt;        settingsObservers.fireChangeEvent();&lt;br /&gt;    &lt;span style="color:#969696;"&gt;//} catch (IOException ex) {&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:#969696;"&gt;//    // Logging...&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:#969696;"&gt;//}&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:#969696;"&gt;//finally{&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:#969696;"&gt;//    // Cleanup...&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:#969696;"&gt;//}&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's just stupid and gets even worse if you have any kind of propagating hierarchy in place! Static checking should be an assistance rather than an annoyance, this is clearly a case of the static dial being placed a tad too high.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Catching checked exceptions without a throw&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;We can fix this by getting our hands on the OpenJDK source, in my case I opted for the easy-to-use &lt;a href="https://kijaro.dev.java.net/"&gt;Kijaro sandbox&lt;/a&gt;, which &lt;a href="http://www.jroller.com/scolebourne/"&gt;Stephen Colebourne&lt;/a&gt; set up to encurrage this kind of hacking. Kijaro includes instructions on how to build javac for both Windows and Linux. If you want to try this kind of hacking yourself, you are going to need a checkout of this sandbox or a similar OpenJDK branch. Alternatively, if all you want to do is play with the tweaks I'll demonstrate here, you may just get a copy of &lt;a href="http://82.103.135.236/tweakedjavac.jar"&gt;my modified javac&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The semantic analysis parts of OpenJDK is largely contained in the package com.sun.tools.javac.comp, for our purpose we're going to need Flow.java hosting a bunch of  data-flow analysis methods that's responsible for raising error conditions surrounding the use of checked exceptions. The compiler walks the AST of the source code through a double-dispatch mechanism (visitor pattern) that calls methods in Flow.java with the current AST node as argument. This means all we have to do is locate the proper callback and modify it according to our need. Down around line 951 you should see the following:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace; color:#000000; white-space: pre;"&gt;&lt;br /&gt;    &lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; visitTry(JCTry tree) {&lt;br /&gt;            &lt;span style="color:#969696;"&gt;...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#0000e6;"&gt;if&lt;/span&gt; (chk.subset(exc, caughtInTry)) {&lt;br /&gt;                log.error(l.head.pos(),&lt;br /&gt;                          &lt;span style="color:#ce7b00;"&gt;&amp;quot;except.already.caught&amp;quot;&lt;/span&gt;, exc);&lt;br /&gt;            } &lt;span style="color:#0000e6;"&gt;else&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;if&lt;/span&gt; (!chk.isUnchecked(l.head.pos(), exc) &amp;amp;&amp;amp;&lt;br /&gt;                       exc.tsym != syms.throwableType.tsym &amp;amp;&amp;amp;&lt;br /&gt;                       exc.tsym != syms.exceptionType.tsym &amp;amp;&amp;amp;&lt;br /&gt;                       !chk.intersects(exc, thrownInTry)) {&lt;br /&gt;                log.error(l.head.pos(),&lt;br /&gt;                          &lt;span style="color:#ce7b00;"&gt;&amp;quot;except.never.thrown.in.try&amp;quot;&lt;/span&gt;, exc);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#969696;"&gt;...&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Evidently, here's some logic that looks like it's logging an error if a checked exception is not being thrown (catch-list does not intersect with thrown-in-try-list). Let's change the line from logging an error, to logging a warning:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace; color:#000000; white-space: pre;"&gt;&lt;br /&gt;&lt;br /&gt;    log.warning(l.head.pos(), &lt;span style="color:#ce7b00;"&gt;&amp;quot;except.never.thrown.in.try&amp;quot;&lt;/span&gt;, exc);&lt;br /&gt;            &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's actually all that's needed in the compiler itself. However, note the obvious reference to a resource key "except.never.thrown.in.try". This is part of a reference to an entry in the file com.sun.tools.javac.resources.compiler.properties. If you open this you'll notice the following line:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace; color:#000000; white-space: pre;"&gt;&lt;br /&gt;compiler.err.except.never.thrown.in.try=\&lt;br /&gt;    exception {0} is never thrown in body of corresponding try statement&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The key does not match the one from the log statement completely, as it is prepended with "compiler.err.". Since we changed the logging from an error to being a warning, javac will search in vain for an entry with the key "compiler.warn.except.never.thrown.in.try". As we can not simply fix this by changing the key reference in Flow.java, we are going to modify the existing, or add a new entry to compiler.properties:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace; color:#000000; white-space: pre;"&gt;&lt;br /&gt;compiler.warn.except.never.thrown.in.try=\&lt;br /&gt;    exception {0} is never thrown in body of corresponding try statement&lt;br /&gt;            &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now compile Kijaro/OpenJDK and watch what happens when you use your new javac build to compile our previous Settings sample:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: rgb(0, 0, 0); color: rgb(255, 255, 255);"&gt;&lt;br /&gt;casper@workstation:~$ tweakedjavac ExceptionNeverThrown.java &lt;br /&gt;casper@workstation:~$&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We have successfully modified the compiler to make our life a little easier. There are a bunch of similar tweaks one could make, all in the same easy fashion as explained above. For instance, I have converted checked exceptions from being an error to being a warning (hint: errorUncaught on line 298), which means they don't get in the way of rapid development while at the same time not really losing any of the benefits - production code should compile without warnings anyway. &lt;br /&gt;Likewise, I have made it so that the unreachable statement error is now also just a warning (hint: scanStat on line 493), thus allowing me to short-circuit a method or similar with a return statement without having me temporarily comment out the remaining code. To demonstrate all of this in one go, take a look at the following sample code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:"Monospaced",monospace; color:#000000; white-space: pre;"&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;import&lt;/span&gt; java.io.IOException;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;class&lt;/span&gt; TweakedJavaCTest{&lt;br /&gt;    &lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;static&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; main(String... args){&lt;br /&gt;        &lt;span style="color:#969696;"&gt;// Test of &amp;quot;checked exception not caught&amp;quot; (throws InterruptedException)&lt;br /&gt;&lt;/span&gt;        Thread.sleep(&lt;span style="color:#000000;"&gt;100&lt;/span&gt;);&lt;br /&gt;        System.out.println(&lt;span style="color:#ce7b00;"&gt;&amp;quot;After sleep...&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#969696;"&gt;// Test of &amp;quot;checked exception not thrown&amp;quot;&lt;br /&gt;&lt;/span&gt;        &lt;span style="color:#0000e6;"&gt;try&lt;/span&gt;{&lt;br /&gt;            System.out.println(&lt;span style="color:#ce7b00;"&gt;&amp;quot;Inside try...&amp;quot;&lt;/span&gt;);&lt;br /&gt;        }&lt;span style="color:#0000e6;"&gt;catch&lt;/span&gt;(IOException e){&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#969696;"&gt;// Test of &amp;quot;unreachable statement&amp;quot;&lt;br /&gt;&lt;/span&gt;        &lt;span style="color:#0000e6;"&gt;return&lt;/span&gt;;&lt;br /&gt;        System.out.println(&lt;span style="color:#ce7b00;"&gt;&amp;quot;This will never be executed!&amp;quot;&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With a stock javac, you won't get very far:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: rgb(0, 0, 0); color: rgb(255, 255, 255);"&gt;&lt;br /&gt;casper@workstation:~$ javac TweakedJavaCTest.java &lt;br /&gt;TweakedJavaCTest.java:12: exception java.io.IOException is never thrown in body of corresponding try statement&lt;br /&gt;        }catch(IOException e){&lt;br /&gt;         ^&lt;br /&gt;TweakedJavaCTest.java:17: unreachable statement&lt;br /&gt;        System.out.println("This will never be executed!");&lt;br /&gt;        ^&lt;br /&gt;TweakedJavaCTest.java:6: unreported exception java.lang.InterruptedException; must be caught or declared to be thrown&lt;br /&gt;        Thread.sleep(100);&lt;br /&gt;                    ^&lt;br /&gt;3 errors&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In fact, we have no artifact to run. With the tweaked compiler it's an entirely different matter however:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: rgb(0, 0, 0); color: rgb(255, 255, 255);"&gt;&lt;br /&gt;casper@workstation:~$ tweakedjavac TweakedJavaCTest.java&lt;br /&gt;TweakedJavaCTest.java:12: warning: exception java.io.IOException is never thrown in body of corresponding try statement&lt;br /&gt;        }catch(IOException e){&lt;br /&gt;         ^&lt;br /&gt;TweakedJavaCTest.java:17: warning: unreachable statement&lt;br /&gt;        System.out.println("This will never be executed!");&lt;br /&gt;        ^&lt;br /&gt;TweakedJavaCTest.java:6: warning: unreported exception java.lang.InterruptedException; must be caught or declared to be thrown&lt;br /&gt;        Thread.sleep(100);&lt;br /&gt;                    ^&lt;br /&gt;3 warnings&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Since we've reduced the previous errors to now being just warnings, we'll get an actual build which we can run:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: rgb(0, 0, 0); color: rgb(255, 255, 255);"&gt;&lt;br /&gt;casper@workstation:~$ java TweakedJavaCTest&lt;br /&gt;After sleep...&lt;br /&gt;Inside try...&lt;br /&gt;casper@workstation:~$&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Voila, pretty easy eh? If you want to play with this javac build you can &lt;a href="http://82.103.135.236/tweakedjavac.jar"&gt;grab it here&lt;/a&gt;. To compile a Java source file with this javac build, you need to use it this way:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: rgb(0, 0, 0); color: rgb(255, 255, 255);"&gt;&lt;br /&gt;casper@workstation:~$ java -Xbootclasspath/p:tweakedjavac.jar -ea:com.sun.tools -jar tweakedjavac.jar TweakedJavaCTest.java&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;In conclusion&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I'm actually surprised at how easy it was to make these small tweaks. While some people clap their hand at checked exceptions, I think this more lenient version is how the Java compiler should have behaved from day one. The obvious drawback is that you are required to build and distribute your own javac which won't sit very well in many organizations, even if you could still use it as a less-hassle development tool for yourself. The other issue is that of IDE support, although it should be relatively easy* to plug this javac into NetBeans, other IDE's rely entirely on their own parser.&lt;br /&gt;&lt;br /&gt;It would be nice if tweaks like these would be considered for the official JDK7, since it doesn't actually break backwards compatibility. However, Sun is an extremely conservative company and has not shown interest in fixing or evolving the compiler over the last couple of years. &lt;br /&gt;Perhaps the way forward is an alternative approach, which does much the same, but without requiring a modified compiler. Reinier Zwitserloot from the &lt;a href="http://projectlombok.org/"&gt;Lombok project&lt;/a&gt; is dabbling on such an approach which you might want to &lt;a href="http://projectlombok.org/disableCheckedExceptions.html"&gt;check out&lt;/a&gt;.&lt;br /&gt;&lt;br&gt;&lt;br /&gt;* &lt;em&gt;I did give it a quick try, packing up a tools.jar and placed in the JAVA_HOME/lib folder and making sure NetBeans were using this platform for my project. However it did not work as expected. While I was able to build inside NetBeans, the syntax highlighting did not pick up on my modifications.&lt;/em&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;b&gt;Update&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I have since added this to Kijaro under the branch &lt;a href="https://kijaro.dev.java.net/svn/kijaro/branches/leniency/"&gt;leniency&lt;/a&gt; (you'll need a java.net login).&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-4264722296964252542?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/4264722296964252542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=4264722296964252542' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/4264722296964252542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/4264722296964252542'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2009/08/tweaking-javac-leniency.html' title='Tweaking javac leniency'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-5645734852007748077</id><published>2009-08-06T06:24:00.048+02:00</published><updated>2009-08-14T20:53:41.749+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Books'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><title type='text'>Android book roundup</title><content type='html'>While it may no longer be so much for reference purposes as in the past, I still really like to have good books at my disposal as a software developer. The DPI of a book still beats that of any screen and I can bring a book to the restroom without raising eyebrows from my girlfriend. In the following I will come with a brief but hopefully useful review of the 3 Android books I have in my library.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://oreilly.com/catalog/9780596521479/"&gt;O'Reilly's Android Application Development&lt;/a&gt;&lt;/h4&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_CauKCPUdin4/SnsOBRiUxhI/AAAAAAAAAJk/bFG4WCXB7XQ/s1600-h/androidappdev.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 153px; height: 200px;" src="http://3.bp.blogspot.com/_CauKCPUdin4/SnsOBRiUxhI/AAAAAAAAAJk/bFG4WCXB7XQ/s200/androidappdev.gif" alt="" id="BLOGGER_PHOTO_ID_5366898795992106514" border="0" /&gt;&lt;/a&gt;The book covers Android 1.1 stuff and is thus already a little dated. The content and organization is a odd and lackluster I find, for instance there's a chapter on signing and publishing your application which comes before chapters on basic views and widgets. It also doesn't come with an ebook/PDF so there's really not a whole lot going for this book, you are probably better of looking elsewhere.&lt;br /&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://www.manning.com/ableson/"&gt;Manning's Unlocking Android&lt;/a&gt;&lt;/h4&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/SnsOmlhGr5I/AAAAAAAAAJs/zmYM_Ki8_kY/s1600-h/ableson_cover150.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 150px; height: 188px;" src="http://2.bp.blogspot.com/_CauKCPUdin4/SnsOmlhGr5I/AAAAAAAAAJs/zmYM_Ki8_kY/s200/ableson_cover150.jpg" alt="" id="BLOGGER_PHOTO_ID_5366899437010857874" border="0" /&gt;&lt;/a&gt;Also covers 1.1 stuff, but better content and definitely better organized than the O'Reilly book. It comes with ebook/PDF as well as source code. It does make certain assumptions regarding the skills of the reader (for instance how the Eclipse IDE works, as examples are Ant based and needs to be imported) but I reckon that most readers would be quite satisfied with this book. It has foreword by none other than Java Posse's chief editor Dick Wall.&lt;br /&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://commonsware.com/Android/"&gt;Commonware's The Busy Coder's Guide to Android Development&lt;/a&gt;&lt;/h4&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/SnsOwegZ-2I/AAAAAAAAAJ0/UUP0-PQ4hFc/s1600-h/busy-coders-guide.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 162px; height: 200px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/SnsOwegZ-2I/AAAAAAAAAJ0/UUP0-PQ4hFc/s200/busy-coders-guide.gif" alt="" id="BLOGGER_PHOTO_ID_5366899606927571810" border="0" /&gt;&lt;/a&gt;This is the most recent published book in this mini roundup. I only have the ebook/PDF version so I am not 100% sure whether the dead tree version covers 1.5/Cupcake as well. You actually get 3 books, incl. one on advanced topics such as reading sensory and camera data. It works by 1 year subscription basis and without DRM, so you are likely to also get 1.6 and 2.0 coverage by simply downloading the books at a later point in time when they have been revised. The material itself feels very to-the-point, yet it's actually the only book I have come across that provides a thorough introduction to lists - an essential part of any Android application.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;In conclusion&lt;/h4&gt;It's my humble opinion that all the above books favors XML layout a bit too much, as it makes examples harder to read/type - and lets face it, it's limited how complex a layout will be on such a small screen anyway. This appears to be more or less dictated by the architecture of Android so not much to do about that. If you have developed in JSF vs. Wicket/GWT then you know what I'm talking about. :)&lt;br&gt;&lt;br /&gt;If you only want one book on the subject, "The busy coders guide to Android Development" would be the one to go for. The content, organization and presentation is just unmatched by any of the others, though "Unlocking Android" was by no means a bad book. However, "Android Application Development" was a disappointment.&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;b&gt;Update&lt;/b&gt;&lt;br /&gt;Since writing this initial entry, Romain Guy from the Android team have informed me on &lt;a href="http://groups.google.com/group/android-beginners/browse_thread/thread/a103d29460e3d51f/e2df83392a434266?lnk=gst&amp;q=XML#e2df83392a434266"&gt;this thread&lt;/a&gt;, that XML is favored in order to have multiple resources  set up declaratively such that Android can automatically select the best match depending on hardware and environment. That makes a lot of sense of course, even if I still think this is an aspect better introduced to the reader after having tried some basic UI building with Java in order to even out the initial learning curve. After all, Java provides beginners with familiarity, type-safety and code completion. Although I've talked to other developers who share this opinion (&lt;a href="http://www.version2.dk/grupper/android/filarkiv/download/Android-stinker"&gt;slides from a Danish JUG meeting&lt;/a&gt;), yours may of course vary.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-5645734852007748077?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/5645734852007748077/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=5645734852007748077' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/5645734852007748077'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/5645734852007748077'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2009/08/android-books-review.html' title='Android book roundup'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_CauKCPUdin4/SnsOBRiUxhI/AAAAAAAAAJk/bFG4WCXB7XQ/s72-c/androidappdev.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-3444956554883454819</id><published>2009-07-10T20:05:00.007+02:00</published><updated>2009-07-10T22:00:21.345+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><title type='text'>DDMS on Ubuntu 64bit</title><content type='html'>The Android SDK comes with a pretty nice suite of tools, one of these is the &lt;a href="http://developer.android.com/guide/developing/tools/ddms.html"&gt;Dalvik Debug Monitor Service&lt;/a&gt; (DDMS). However, it seems like the Android SDK is distributed with some 32bit SWT libraries so if you are on a 64bit Linux, running a 64bit Java default, you might run into this little message:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: rgb(0, 0, 0); color: rgb(255, 255, 255);"&gt;&lt;br /&gt;casper@workstation:/$ dbms&lt;br /&gt;43:27 E/ddms: shutting down due to uncaught exception&lt;br /&gt;43:27 E/ddms: java.lang.UnsatisfiedLinkError: /android-sdk-linux_x86-1.5_r2/tools/lib/libswt-pi-gtk-3236.so: /android-sdk-linux_x86-1.5_r2/tools/lib/libswt-pi-gtk-3236.so: wrong ELF class: ELFCLASS32 (Possible cause: architecture word width mismatch)&lt;br /&gt;at java.lang.ClassLoader$NativeLibrary.load(Native Method)&lt;br /&gt;at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1778)&lt;br /&gt;at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1687)&lt;br /&gt;at java.lang.Runtime.loadLibrary0(Runtime.java:823)&lt;br /&gt;at java.lang.System.loadLibrary(System.java:1030)&lt;br /&gt;at org.eclipse.swt.internal.Library.loadLibrary(Library.java:123)&lt;br /&gt;      ...&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This is fairly easy to fix, by first installing the 32bit version of the JRE:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: rgb(0, 0, 0); color: rgb(255, 255, 255);"&gt;&lt;br /&gt;casper@workstation:/$ sudo apt-get install ia32-sun-java6-bin&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And then making sure DDMS is using this particular one. There are countless ways to do this (add new environment variables etc.) but I chose to simply modify DDMS itself, which seems like the least invasive way for this purpose. If you go to line 71, it should currently read:&lt;pre&gt;&lt;span style="color: rgb(0, 0, 0);font-family:Monospaced,monospace;" &gt;&lt;br /&gt;java_cmd="java"&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;It's obviously relying on the /usr/bin/java symlink which we have in path, which leads to /etc/alternatives/java which again leads to our default 64bit version of the JRE. So change the line to this instead:&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(0, 0, 0);font-family:Monospaced,monospace;" &gt;&lt;br /&gt;java_cmd="/usr/lib/jvm/ia32-java-6-sun/jre/bin/java"&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Now DDMS should run so you can monitor, debug and take screenshots of your virtual or physical device.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/SleG-0A1-jI/AAAAAAAAAJc/YVjUCDPROLc/s1600-h/ddms.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 293px;" src="http://2.bp.blogspot.com/_CauKCPUdin4/SleG-0A1-jI/AAAAAAAAAJc/YVjUCDPROLc/s400/ddms.png" alt="" id="BLOGGER_PHOTO_ID_5356898695452686898" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-3444956554883454819?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/3444956554883454819/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=3444956554883454819' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/3444956554883454819'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/3444956554883454819'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2009/07/ddms-on-ubuntu-64bit.html' title='DDMS on Ubuntu 64bit'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_CauKCPUdin4/SleG-0A1-jI/AAAAAAAAAJc/YVjUCDPROLc/s72-c/ddms.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-490286159340270000</id><published>2009-06-30T22:43:00.000+02:00</published><updated>2009-07-10T00:40:13.790+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='Firefox'/><title type='text'>Firefox 3.5 on Ubuntu 9.04</title><content type='html'>Well today the much anticipated speedy Firefox 3.5 arrived. Ubuntu probably won't push this one out as an update and I am not sure when Firefox's own auto-update would provide this upgrade, so if you're impatient as I, this is how to install it manually. Do read the whole thing through before deciding whether to do this, as there are some potential plugin issues involved!&lt;br /&gt;&lt;br /&gt;&lt;B&gt;Installation procedure&lt;/B&gt;&lt;br /&gt;First you need to download and extract in an appropriate place. I'm extracting to /opt/firefox-3.5 such as to avoid collisions later when an official Ubuntu version is available:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;casper@workstation/$ cd /opt/&lt;br /&gt;casper@workstation/opt/$ sudo wget http://releases.mozilla.org/pub/mozilla.org/firefox/releases/3.5/linux-i686/en-US/firefox-3.5.tar.bz2&lt;br /&gt;casper@workstation/opt/$ sudo tar -xjf firefox-3.5.tar.bz2&lt;br /&gt;casper@workstation/opt/$ sudo mv firefox firefox-3.5&lt;br /&gt;casper@workstation/opt/$ sudo rm firefox-3.5.tar.bz2 -f&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Perhaps you notice that the download is a i686/32bit Linux release, this is because Mozilla do not presently build amd64/64bit versions. For this, we will have to wait for a version from our distribution. Now, lets check Ubuntu's browser settings:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;casper@workstation:/opt$ sudo update-alternatives --display x-www-browser &lt;br /&gt;x-www-browser - status is auto.&lt;br /&gt; link currently points to /usr/bin/firefox-3.0&lt;br /&gt;/usr/bin/firefox-3.0 - priority 40&lt;br /&gt;Current `best' version is /usr/bin/firefox-3.0.&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As you can see on my machine, only Firefox 3.0 is installed. We can add the newly downloaded version as an alternative and give it precedence on the system by issuing:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;casper@workstation/opt/$ sudo update-alternatives --install /usr/bin/firefox-3.5 x-www-browser /opt/firefox-3.5/firefox 50&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Also, we can make it default:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;casper@workstation/opt/$ sudo update-alternatives --set x-www-browser /opt/firefox-3.5/firefox&lt;br /&gt;Using '/opt/firefox-3.5/firefox' to provide 'x-www-browser'.&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;However, it's still not default on the path. To make it so, Ubuntu needs to update its symlink from /usr/bin/firefox to /opt/firefox-3.5/firefox:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;casper@workstation/opt/$ sudo rm /usr/bin/firefox&lt;br /&gt;casper@workstation/opt/$ sudo ln -s /opt/firefox-3.5/firefox /usr/bin/firefox&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Voila. Issuing "firefox" on the command-line should now start Firefox 3.5 just as Ubuntu's shortcuts should now also point to the new version. On initial launch, Firefox 3.5 will check your extensions and plugins, as well as use your existing bookmarks etc. from your users home as usual on Linux.&lt;br /&gt;&lt;br /&gt;&lt;B&gt;Caveats&lt;/B&gt;&lt;br /&gt;Note that if you previously had the amd64/64bit version of Firefox and plugins, your plugins will no longer work! It is of course very easy to just use 32bit plugins instead. In my case, I just lifted the two plugins I am interested in (libflashplayer.so and libjavaplugin.so) from another 32bit installation, but you can simply use Synaptic package manager to install 32bit plugins if you do not have these already.&lt;br /&gt;&lt;br /&gt;If you don't wish to have multiple versions and perhaps have already uninstalled the old 64bit 3.0 version, then you may simply place the files in ~/.mozilla/plugins/. However, if you wish to have both versions on your system, you should keep the 64bit stuff around and instead add the 32bit plugins locally to your 32bit Firefox 3.5 installation in /opt/firefox-3.5/plugins/.&lt;br /&gt;&lt;br /&gt;It's annoying to be back to 32bit for the time being but I do love the speed of this new version, and I'm sure you will too.&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Update: Turns out there's an easier way, explained in this blog entry: http://talkingincircles.net/2009/07/01/firefox-3-5-in-ubuntu-9-04-64-bit/&lt;br /&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-490286159340270000?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/490286159340270000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=490286159340270000' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/490286159340270000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/490286159340270000'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2009/06/firefox-35-on-ubuntu-904.html' title='Firefox 3.5 on Ubuntu 9.04'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-599432808484868192</id><published>2009-06-30T02:51:00.000+02:00</published><updated>2009-07-01T02:17:26.067+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><title type='text'>Android Debug Bridge on Ubuntu 9.04</title><content type='html'>To perform general debugging and install alternative ROM's on the HTC Magic in Ubuntu 9.04, you will need a little more footwork than the documentation mentions.&lt;br /&gt;&lt;br /&gt;First, I assume you have installed the SDK and added it to path so that you can perform ADB commands from everywhere. Then, you need to have USB debugging enabled on the phone, do this by going under Settings &gt; Applications &gt; Development and check the "USB Debugging" item.&lt;br /&gt;&lt;br /&gt;Now, add a udev rule for your device:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;gksudo gedit /etc/udev/rules.d/51.android.rules&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Add the following to the file and save it:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;SUBSYSTEM=="usb", ATTRS{idVendor}=="0bb4", MODE="0666"&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Reload USB devices by issuing the command:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;sudo /etc/init.d/udev reload&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Unplug and plug the device. Check if you can see the device:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;casper@workstation:~$ adb devices&lt;br /&gt;* daemon not running. starting it now *&lt;br /&gt;* daemon started successfully *&lt;br /&gt;List of devices attached &lt;br /&gt;HT95PKF00221 device&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There, now you can browse your phone with the adb shell command and start diving into the rather interesting world of rooting and alternative ROM's found over on &lt;a href="http://forum.xda-developers.com/forumdisplay.php?f=480"&gt;XDA-developers&lt;/a&gt;. My next move is to try the &lt;a href="http://forum.xda-developers.com/showthread.php?t=531617"&gt;HTC Hero ROM&lt;/a&gt; on my Magic, which will give the phone the new multitouch Rosie/Sense interface.&lt;br /&gt;&lt;br /&gt;Another cool thing is that if you start your Eclipse SDK and try to run an application, it will now deploy to the physical device rather than the emulator - pretty neat!&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-599432808484868192?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/599432808484868192/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=599432808484868192' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/599432808484868192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/599432808484868192'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2009/06/android-debug-bridge-on-ubuntu-904.html' title='Android Debug Bridge on Ubuntu 9.04'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-1140783955439135410</id><published>2009-06-20T05:39:00.000+02:00</published><updated>2009-07-01T05:17:39.012+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><title type='text'>HTC Magic Android emulator skin</title><content type='html'>So I started playing with Android development, just received "Unlocking Android" and "Android Application Development" from Amazon. However before getting to do any real development, I got sidetracked in trying to create a skin for the Android Emulator that matches my new fancy HTC Magic. There actually &lt;a href="http://teavuihuang.com/android/"&gt;exists one&lt;/a&gt;, but it's branded Vodafone, looks silvery and has the buttons all wrong so I decided this would be a good way to brush up on some Gimp skills. And here it is, I am no graphics artist so I am moderately pleased.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/SkOJnf0f1oI/AAAAAAAAAJQ/E65vY5y2I1Y/s1600-h/HTCMagicEmulatorSkin.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 201px; height: 400px;" src="http://2.bp.blogspot.com/_CauKCPUdin4/SkOJnf0f1oI/AAAAAAAAAJQ/E65vY5y2I1Y/s400/HTCMagicEmulatorSkin.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5351272093895874178" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You may use images and skin as you please, under the creative commons license. You can download the skin by &lt;a href="http://82.103.135.236/HTCMagic.zip"&gt;clicking here&lt;/a&gt;. To install, simply extract the files to {android_install_dir}/platforms/android-1.5/skins/HTCMagic/.&lt;br /&gt;&lt;br /&gt;If you can not select the skin in Eclipse, you may have to edit the config.ini file of your virtual android device setting manually (under ~/.android/avd/), simply set the skin.path property to point to HTCMagic. You can also run the emulator manually by executing {android_install_dir}/tools/emulator and pass along the command line argument "-skin HTCMagic".&lt;br /&gt;&lt;br /&gt;NOTE: I am aware that pressing the search button in the emulator has no effect. This appears to be because it is not implemented for the emulator at this time, since no other skin appears to have a working search button. I even read through the C and Python source code to see if I could find the proper key name, but with no success. Also note, the screen shown within the emulator in the above image, is not of the generic Android 1.5 (Cupcake) but rather a static image of &lt;a href="http://phandroid.com/2009/06/03/htc-rosie-screenshots/"&gt;HTC's Rosie/Sense UI&lt;/a&gt; which I find more sexy (can phone software look sexy?).&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-1140783955439135410?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/1140783955439135410/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=1140783955439135410' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/1140783955439135410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/1140783955439135410'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2009/06/htc-magic-skin-for-android-emulator.html' title='HTC Magic Android emulator skin'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_CauKCPUdin4/SkOJnf0f1oI/AAAAAAAAAJQ/E65vY5y2I1Y/s72-c/HTCMagicEmulatorSkin.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-1215941305794883645</id><published>2009-06-10T00:11:00.000+02:00</published><updated>2009-06-23T16:26:06.964+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><title type='text'>Android awesomeness</title><content type='html'>So I finally got an Android device, in the form of the second generation hardware from HTC known as the Magic, G2, Ion and Saphire. Since the original HTC Dream (G1) this phone received a major visual overhaul and now boosts a soft keyboard rather than a physical one making it a loss less clunky. And let me admit right away, I fell in love at once and have hardly put it down since. It is not my intention here to write any kind of throughough or balanced review, but merely to showcase Android and the applications to others contemplating getting one of these phones as well.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Initial impression&lt;/b&gt;&lt;br /&gt;The phone looks and feels sturdy and quality, thankfully not branded like appears to be the case in the US. The 3.2" touch screen is glass just like the iPhone and the body is thick scratch-proof plastic. It has what amounts to 11 buttons (incl. a joypad) below the screen such as well as volume buttons on the side.&lt;br /&gt;Having played with an iPhone a few times, my impression is that the Magic is very reminiscent of this groundbreaking device. I never actually invested in an iPhone as I don't care very much for the handcuffs Apple like to put on its customers - it's a somewhat different story with this phone. Also, to me the Magic feels better in the hand than an iPhone and definately slips easier down into a pocket. The battery is a 1340mAh Litium-Ion, bigger than the one in the G1 and enough to keep the phone powered for the day. It's important to note that it takes a few days for the battery to start charging correctly (to know its state) and it also takes a few days to learn how to use it such as not to drain the battery immediately but this is true of any smartphone.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/SjcHLvkSqKI/AAAAAAAAAIo/puRlurSjw5Y/s1600-h/23032.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 312px;" src="http://2.bp.blogspot.com/_CauKCPUdin4/SjcHLvkSqKI/AAAAAAAAAIo/puRlurSjw5Y/s400/23032.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5347750980854392994" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Android&lt;/b&gt;&lt;br /&gt;While the hardware is nice, the real kicker is Google's Android operating system. The HTC Magic comes with version 1.5 (Cupcake) as well as some extra software installed into the ROM by my phone carrier that enables Microsoft Exchange integration etc.&lt;br /&gt;Android can have applications installed from either the Android marked or by directly downloading the .apk file. There's already around 5.000 applications available, and with so many phones coming out and a rapidly growing community I see no reason why Android would stay shy of iPhone's 50.000 applications.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_CauKCPUdin4/SjbyRazJ_QI/AAAAAAAAADw/DhI3e88wag4/s1600-h/1-unlock.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://3.bp.blogspot.com/_CauKCPUdin4/SjbyRazJ_QI/AAAAAAAAADw/DhI3e88wag4/s400/1-unlock.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347727988614626562" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;You can opt to lock the device by a custom gesture. This is a very handy feature that beats the traditional approach of having to enter a code.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CauKCPUdin4/SjbyRQNnIPI/AAAAAAAAAD4/GHuUXVmhjCQ/s1600-h/2-home-center.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://1.bp.blogspot.com/_CauKCPUdin4/SjbyRQNnIPI/AAAAAAAAAD4/GHuUXVmhjCQ/s400/2-home-center.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347727985772798194" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;The home screen with widgets and shortcuts on the desktop, live picture of the Eiffel tower as wallpaper.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/SjbyRoNNJ8I/AAAAAAAAAEA/3PHckB82vaA/s1600-h/3-home-left.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/SjbyRoNNJ8I/AAAAAAAAAEA/3PHckB82vaA/s400/3-home-left.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347727992213546946" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;On the left home screen I have primarily system tools.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/SjbyR3uQ79I/AAAAAAAAAEI/3mKTB7XirTQ/s1600-h/4-home-right.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/SjbyR3uQ79I/AAAAAAAAAEI/3mKTB7XirTQ/s400/4-home-right.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347727996378738642" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;On the right home screen I have frequently used applications.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/SjbySBTxQxI/AAAAAAAAAEQ/e2sz8wEKb_w/s1600-h/5-applications.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://2.bp.blogspot.com/_CauKCPUdin4/SjbySBTxQxI/AAAAAAAAAEQ/e2sz8wEKb_w/s400/5-applications.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347727998951965458" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;The applications menu pops up when you drag the slider up. The screenshot does not convey this information, but I have around 75 application installed.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CauKCPUdin4/Sjby1bjvhVI/AAAAAAAAAEY/Zn3YAElrIrQ/s1600-h/6-multitask.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://1.bp.blogspot.com/_CauKCPUdin4/Sjby1bjvhVI/AAAAAAAAAEY/Zn3YAElrIrQ/s400/6-multitask.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347728607293703506" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;Long-pressing the home button reveals other recently run applications, unlike the iPhone this device has no trouble multitasking.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CauKCPUdin4/SjbzEHOITKI/AAAAAAAAAEg/EFHo3JGi-Po/s1600-h/7-status.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://1.bp.blogspot.com/_CauKCPUdin4/SjbzEHOITKI/AAAAAAAAAEg/EFHo3JGi-Po/s400/7-status.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347728859532381346" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;At the top of the screen, the status panel can be expanded as well. It's here notifications of any kind goes (email, SMS, instant message) and it works remarkable well.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/SjbzeDi7t5I/AAAAAAAAAE4/FZ2OqUkJL-s/s1600-h/8-keyb-horizontal.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 267px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/SjbzeDi7t5I/AAAAAAAAAE4/FZ2OqUkJL-s/s400/8-keyb-horizontal.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347729305222494098" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;In horizontal mode, the soft keyboard is a joy to use thanks to the dictionary suggestions.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/SjbzEmdVaJI/AAAAAAAAAEw/2rjujx7Za1Y/s1600-h/9-keyb-vertical.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/SjbzEmdVaJI/AAAAAAAAAEw/2rjujx7Za1Y/s400/9-keyb-vertical.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347728867917654162" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;In vertical mode, you really need to be precise and having small fingers is definitely a plus.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Google applications&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb0EYyCcCI/AAAAAAAAAFA/YV6BPTYk7Vs/s1600-h/10-browser.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 267px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb0EYyCcCI/AAAAAAAAAFA/YV6BPTYk7Vs/s400/10-browser.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347729963758022690" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;The build in browser, based on KHTML like Safari and Crome. It does its job to perfection, best mobile browser experience I have tried.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb0EocSVII/AAAAAAAAAFI/hsQdROYjhdQ/s1600-h/11-gmail.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 267px;" src="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb0EocSVII/AAAAAAAAAFI/hsQdROYjhdQ/s400/11-gmail.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347729967961756802" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;The gmail integration is equally impressive. Simple and functional.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/Sjb0E0tSbrI/AAAAAAAAAFQ/mQA9bcex5Mk/s1600-h/12-gmap-map.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://2.bp.blogspot.com/_CauKCPUdin4/Sjb0E0tSbrI/AAAAAAAAAFQ/mQA9bcex5Mk/s400/12-gmap-map.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347729971254292146" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;Of course, Google maps is there as well and works with the GPS.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb0FG_QmjI/AAAAAAAAAFY/OY6rkJ7ahwM/s1600-h/13-gmap-sat.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb0FG_QmjI/AAAAAAAAAFY/OY6rkJ7ahwM/s400/13-gmap-sat.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347729976161507890" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;It feels special to be out and about, with satellite pictures looking down at your position.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_CauKCPUdin4/Sjb0FqrgqLI/AAAAAAAAAFg/jApHcrs9fB4/s1600-h/14-gmap-street.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://3.bp.blogspot.com/_CauKCPUdin4/Sjb0FqrgqLI/AAAAAAAAAFg/jApHcrs9fB4/s400/14-gmap-street.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347729985742350514" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;Even street view is integrated.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb0qDQP_KI/AAAAAAAAAFo/wFFBlkn18oc/s1600-h/15-skymap.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb0qDQP_KI/AAAAAAAAAFo/wFFBlkn18oc/s400/15-skymap.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347730610814188706" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;Skymap uses all the sensors of the phone to render an accurate representation of the sky complete with stars, planets etc. depending at where you point the phone.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb0qWWXV7I/AAAAAAAAAFw/3XlNSOG1kK8/s1600-h/16-video.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 267px;" src="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb0qWWXV7I/AAAAAAAAAFw/3XlNSOG1kK8/s400/16-video.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347730615940110258" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;It plays mp4 in very decent quality, here Romain Guy from the Android team.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/Sjb0qQw4iBI/AAAAAAAAAF4/y_yrai5MRb4/s1600-h/17-youtube.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 267px;" src="http://2.bp.blogspot.com/_CauKCPUdin4/Sjb0qQw4iBI/AAAAAAAAAF4/y_yrai5MRb4/s400/17-youtube.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347730614440724498" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;YouTube is available via an integrated application that simply works.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb0qtI55BI/AAAAAAAAAGA/wOj5IrZnvpk/s1600-h/18-barcode1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 267px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb0qtI55BI/AAAAAAAAAGA/wOj5IrZnvpk/s400/18-barcode1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347730622057669650" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;The camera used as a barcode scanner, here a book is scanned.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb0qzOswWI/AAAAAAAAAGI/TWeGBeT2Yjc/s1600-h/19-barcode2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 267px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb0qzOswWI/AAAAAAAAAGI/TWeGBeT2Yjc/s400/19-barcode2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347730623692587362" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;Voila, we have looked up a book and can read reviews and find cheapest stores.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb2HGab4WI/AAAAAAAAAGQ/r078xIbENfI/s1600-h/20-marked.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb2HGab4WI/AAAAAAAAAGQ/r078xIbENfI/s400/20-marked.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347732209390051682" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;The Android marked is full of stuff, approximately 5.000 apps. but growing daily.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/Sjb2HStspUI/AAAAAAAAAGY/JhdzY4F_ghQ/s1600-h/21-aTrackDog.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://2.bp.blogspot.com/_CauKCPUdin4/Sjb2HStspUI/AAAAAAAAAGY/JhdzY4F_ghQ/s400/21-aTrackDog.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347732212692067650" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;aTrackDog can track all installed applications and tell you when there are new versions and provide an easy way to update.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb2HcKiv5I/AAAAAAAAAGg/OmuxHK5jlSM/s1600-h/22-gpsstats.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb2HcKiv5I/AAAAAAAAAGg/OmuxHK5jlSM/s400/22-gpsstats.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347732215228972946" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;GPSstats is good to determine GPS coverage.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb2HofpA3I/AAAAAAAAAGo/B-pxDwx4lKE/s1600-h/23-cell-tower.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb2HofpA3I/AAAAAAAAAGo/B-pxDwx4lKE/s400/23-cell-tower.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347732218538689394" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;CellTower can be used to triangulate and display cell towers around your neighbourhood. Not really useful, but fun to see in action.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb2H9cR8_I/AAAAAAAAAGw/nBGTyNktIQ0/s1600-h/24-flightstats.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb2H9cR8_I/AAAAAAAAAGw/nBGTyNktIQ0/s400/24-flightstats.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347732224161739762" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;FlightStats was great on a recent trip, always providing me with up-to-date info about delays.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_CauKCPUdin4/Sjb2vBe65AI/AAAAAAAAAG4/ok_hU8i6Uj4/s1600-h/25-game.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://3.bp.blogspot.com/_CauKCPUdin4/Sjb2vBe65AI/AAAAAAAAAG4/ok_hU8i6Uj4/s400/25-game.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347732895261451266" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;There are of course countless games, though they are less interesting to me personally.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/Sjb2viurcQI/AAAAAAAAAHA/ScHRe3LuTLk/s1600-h/26-im.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://2.bp.blogspot.com/_CauKCPUdin4/Sjb2viurcQI/AAAAAAAAAHA/ScHRe3LuTLk/s400/26-im.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347732904185917698" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;No matter the IM protocol you rely on, you are sure to be connected.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb2vqaS8OI/AAAAAAAAAHI/TPWZoDa5TjA/s1600-h/27-metaldetect.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb2vqaS8OI/AAAAAAAAAHI/TPWZoDa5TjA/s400/27-metaldetect.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347732906247909602" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;Yes believe it or not, there's even a metal detector.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb2v9PNXLI/AAAAAAAAAHQ/-KCSQxgE8pA/s1600-h/28-netcounter.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb2v9PNXLI/AAAAAAAAAHQ/-KCSQxgE8pA/s400/28-netcounter.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347732911301680306" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;NetCounter is invaluable in monitoring data traffic. It may save you from receiving a nasty bill.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/Sjb2wN9JC2I/AAAAAAAAAHY/5WZe50U4HiU/s1600-h/29-SpareParts.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://2.bp.blogspot.com/_CauKCPUdin4/Sjb2wN9JC2I/AAAAAAAAAHY/5WZe50U4HiU/s400/29-SpareParts.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347732915789302626" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;SpareParts provides great system info as well as tweaks.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb3SJMkMFI/AAAAAAAAAHg/2HEB0BDjcnE/s1600-h/30-speedtest.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb3SJMkMFI/AAAAAAAAAHg/2HEB0BDjcnE/s400/30-speedtest.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347733498627371090" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;Speedtest is good to debug and determine connection speeds.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb3SQXa7aI/AAAAAAAAAHo/WBcEo04BY9M/s1600-h/31-taskmanager.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/Sjb3SQXa7aI/AAAAAAAAAHo/WBcEo04BY9M/s400/31-taskmanager.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347733500551949730" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;TaskManager lets you monitor and kill applications.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/Sjb3ShkXWmI/AAAAAAAAAHw/wkZF7ivrUfw/s1600-h/32-mytracks-workwalk1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://2.bp.blogspot.com/_CauKCPUdin4/Sjb3ShkXWmI/AAAAAAAAAHw/wkZF7ivrUfw/s400/32-mytracks-workwalk1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347733505169644130" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;MyTracks tracks you as you move around. Here is my walking route from the office to the local subway.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb3S4lRaUI/AAAAAAAAAH4/_JUVfmBsc9c/s1600-h/33-mytracks-workwalk2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb3S4lRaUI/AAAAAAAAAH4/_JUVfmBsc9c/s400/33-mytracks-workwalk2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347733511347464514" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;Some metrics from the walk.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb3TJmkbCI/AAAAAAAAAIA/yj5q3Mij-KA/s1600-h/34-lawn.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb3TJmkbCI/AAAAAAAAAIA/yj5q3Mij-KA/s400/34-lawn.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347733515916307490" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;Not quite detailed enough to show me mowing the lawn. lol&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_CauKCPUdin4/Sjb36r94KbI/AAAAAAAAAII/f3Jfe1DP80c/s1600-h/35-mono.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://3.bp.blogspot.com/_CauKCPUdin4/Sjb36r94KbI/AAAAAAAAAII/f3Jfe1DP80c/s400/35-mono.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347734195155773874" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;The beauty of an open platform. You can run Mono/C# stuff on it.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb365e5l8I/AAAAAAAAAIQ/eJFsPaE9DZs/s1600-h/36-scripting.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://1.bp.blogspot.com/_CauKCPUdin4/Sjb365e5l8I/AAAAAAAAAIQ/eJFsPaE9DZs/s400/36-scripting.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347734198783940546" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;...as well as Python, BeanShell and Lua.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_CauKCPUdin4/Sjb37I3WfhI/AAAAAAAAAIY/P7oN2_RuS8Y/s1600-h/37-term.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://3.bp.blogspot.com/_CauKCPUdin4/Sjb37I3WfhI/AAAAAAAAAIY/P7oN2_RuS8Y/s400/37-term.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5347734202913029650" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;em&gt;&lt;small&gt;...and execute shell commands since it's a real Linux underneath.&lt;/small&gt;&lt;/em&gt;&lt;/center&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;br /&gt;There are only a few thorns on this white rose. It would be nice if HTC would use a standard 2.5mm mini jack instead of the propriatary mini-USB plug although this is easily fixed with a small adaptor. Also, the speakers are not the loudest I've heard from a phone so I would've preferred if they faced the same direction as the screen such as to improve the video experience.&lt;br /&gt;&lt;br /&gt;As for Android and the software it's even harder to find flaws. The menu where you see each and every application is perhaps a bit overwhelming, although you quickly get used to it (sorted alphabetically). To remedy this, people sometimes install home application extensions such as to allow more than 3 screens. This is something Google can easily adjust through the Android updates coming.&lt;br /&gt;&lt;br /&gt;The real beauty of this device is how open it is. For instance, Android itself has not been ported to other languages than english yet, but that has not stopped people from developing localized soft keyboards that matches a particular locale (in my case Danish). Even if the phone is 200-300$ cheaper than an iPhone, it has more potential and longevity that I think only Apple fanboys will miss the slightly better polish put on by Apple. I'm already looking forward to the next upgrade to Donut in a few months, as well as Eclair by the end of the year and I'm eager to start developing on it myself.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-1215941305794883645?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/1215941305794883645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=1215941305794883645' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/1215941305794883645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/1215941305794883645'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2009/06/android-awesomeness.html' title='Android awesomeness'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_CauKCPUdin4/SjcHLvkSqKI/AAAAAAAAAIo/puRlurSjw5Y/s72-c/23032.jpg' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-4293685498845358233</id><published>2009-05-25T19:49:00.000+02:00</published><updated>2009-06-05T21:30:18.926+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><title type='text'>Maven: Compile to a RAM-drive</title><content type='html'>While preparing to do a backup recently, I realized that I had over 2GB in 110.000 files which was the result of either an Ant build or Maven target. It occured to me that with Maven especially, this is nothing more than garbage to keep around, since Maven will copy the artefacts to its /.m2 folder anyway!&lt;br /&gt;&lt;br /&gt;In a &lt;a href="http://coffeecokeandcode.blogspot.com/2008/08/netbeans-on-speed.html"&gt;previous blog entry&lt;/a&gt;, I explained how to mount a RAM-drive on Ubuntu and use it as a development folder for much higher performance in the compile-test-run cycle. I have to admit, I don't use this for each and every project since it's a little complex and fragile.&lt;br /&gt;&lt;br /&gt;But there's an interesting compromise to be had here. It turns out it is possible to instruct Maven to build artefacts to a RAM-drive. That way you not only gain some performance but also some automatic "garbage collection" in that by the next boot, you will have no traces of these build steps laying around. It would also be a very healthy thing to do if you're running from of an SSD drive, which are susceptible to wear-and-tear. The following will explain how to set this up with Maven.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Prerequisites&lt;/b&gt;&lt;br /&gt;You are going to need a RAM-drive for this purpose. It is extremely easy to set one up on Ubuntu. In the following I set the permissions of the mount to that of the Ubuntu user "plugdev" which is the one being used for auto-mounting USB-drives etc. That way all users should have permission to use it:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;sudo mkdir /media/ramdrive&lt;br /&gt;sudo chgrp plugdev /media/ramdrive&lt;br /&gt;sudo chmod g+w /media/ramdrive&lt;br /&gt;sudo chmod +t /media/ramdrive&lt;br /&gt;sudo mount tmpfs /media/ramdrive -t tmpfs&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You can have your system automatically create and mount a TMPFS partition for you, by modifying your /etc/fstab file. Simply add the following to it:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;none /media/ramdrive tmpfs defaults,user,size=1G,mode=0777 0 0&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;An alternative approach could be to have the RAM-drive mounted at compile time. This is perfectly possible by calling out to an Ant target in Maven, and have it execute a Bash script. The problem is though, in order to mount filsystems on Linux you need to be a super user. So for this approach to work, you would need to hardwire your SUDO password in the script and that would be pretty dumb. It is entirely possible there is a way to do it, but if there is I am unaware of it.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The POM modification&lt;/b&gt;&lt;br /&gt;Basically all we need to do is instruct Maven where out build directory is, our output directory and our test directory. This can be done by simply specifying it within the build tag:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;&amp;lt;project&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;build&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;directory&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;/media/ramdrive/maven-targets/${project.name}&lt;span style="color:#0000e6;"&gt;&amp;lt;/directory&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;outputDirectory&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;/media/ramdrive/maven-targets/${project.name}/classes&lt;span style="color:#0000e6;"&gt;&amp;lt;/outputDirectory&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;testOutputDirectory&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;/media/ramdrive/maven-targets/${project.name}/test-classes&lt;span style="color:#0000e6;"&gt;&amp;lt;/testOutputDirectory&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;/build&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br/&gt;&lt;span style="color:#0000e6;"&gt;&amp;lt;/project&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You'll notice I place everything under the sub-folder "maven-targets", this is so that none of my targets conflicts with other stuff on my RAM-drive. Also, the actual sub-folder for each individual project will be named the same as the project.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;As Maven profile&lt;/b&gt;&lt;br /&gt;While the above certainly works, it's arguably some heavy bending of Maven's conventions and we run the risk that other people not as fortunate as us (i.e. Windows users) won't have a RAM-drive nor the possibility to create one. To remedy this, we can encapsulate this custom behaviour in a Maven profile.&lt;br /&gt;&lt;br /&gt;Sadly in a profile, we are not allowed to specify build paths like we just saw above. We can however cheat a bit, by going through some properties. Start by defining some global properties somewhere in a properties tag under the project tag:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;&amp;lt;project&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;properties&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;build.dir&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;target&lt;span style="color:#0000e6;"&gt;&amp;lt;/build.dir&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;build.outputDir&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;target/classes&lt;span style="color:#0000e6;"&gt;&amp;lt;/build.outputDir&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;build.testOutputDir&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;target/test-classes&lt;span style="color:#0000e6;"&gt;&amp;lt;/build.testOutputDir&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;/properties&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br/&gt;&lt;span style="color:#0000e6;"&gt;&amp;lt;/project&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This complies with the standard Maven conventions. Then in the non-profile build tag, do like before but rather than hardwire the paths, use the properties we just defined. Like so:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;&amp;lt;project&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;build&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;directory&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;${build.dir}&lt;span style="color:#0000e6;"&gt;&amp;lt;/directory&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;outputDirectory&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;${build.outputDir}&lt;span style="color:#0000e6;"&gt;&amp;lt;/outputDirectory&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;testOutputDirectory&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;${build.testOutputDir}&lt;span style="color:#0000e6;"&gt;&amp;lt;/testOutputDirectory&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;/build&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br/&gt;&lt;span style="color:#0000e6;"&gt;&amp;lt;/project&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The behaviour thus far should not differ in any way from the default Maven build cycle. The last thing we need to do now is to add a profile for emitting to the RAM-drive:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;&amp;lt;project&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;profile&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;id&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;RAM-drive&lt;span style="color:#0000e6;"&gt;&amp;lt;/id&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;build&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;plugins&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;plugin&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;artifactId&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;maven-compiler-plugin&lt;span style="color:#0000e6;"&gt;&amp;lt;/artifactId&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;inherited&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;true&lt;span style="color:#0000e6;"&gt;&amp;lt;/inherited&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;configuration&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;source&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;1.6&lt;span style="color:#0000e6;"&gt;&amp;lt;/source&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;target&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;1.6&lt;span style="color:#0000e6;"&gt;&amp;lt;/target&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;/configuration&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;/plugin&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;/plugins&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;/build&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;properties&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;build.dir&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;/media/ramdrive/maven-targets/${project.name}&lt;span style="color:#0000e6;"&gt;&amp;lt;/build.dir&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;build.outputDir&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;/media/ramdrive/maven-targets/${project.name}/classes&lt;span style="color:#0000e6;"&gt;&amp;lt;/build.outputDir&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;build.testOutputDir&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;/media/ramdrive/maven-targets/${project.name}/test-classes&lt;span style="color:#0000e6;"&gt;&amp;lt;/build.testOutputDir&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;/properties&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#0000e6;"&gt;&amp;lt;/profile&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;br/&gt;&lt;span style="color:#0000e6;"&gt;&amp;lt;/project&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That's it. Now you just select the profile "RAM-drive" in your IDE when you build, without it having negative consequences for your less fortunate collegues. Of course a similar setup can be made with Ant and most other build environments.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-4293685498845358233?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/4293685498845358233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=4293685498845358233' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/4293685498845358233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/4293685498845358233'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2009/05/compile-to-ram-drive.html' title='Maven: Compile to a RAM-drive'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-7042565384371930693</id><published>2009-05-16T12:46:00.000+02:00</published><updated>2009-05-30T10:39:40.656+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='JSF'/><title type='text'>The pain of request scoped JSF</title><content type='html'>While I like the idea of a component based web framework, JSF never really felt right to me. There are too many pitfalls and the whole programming model (even with the use of Facelets) feels cumbersome and more complex than necessary. I could probably write up a detailed list of reasons for why I think JSF is the least productive and fun web frameworks of those I know, but that is not the purpose of this blog post. Suffice to say this appears to be a &lt;a href="http://www.dzone.com/links/jsf_sucks_compendium_of_jsf_rantsreviews.html"&gt;shared sentiment&lt;/a&gt;. This post addresses only JSF's focus on server state and the associated overloaded POST aspect.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The problem of state&lt;/b&gt;&lt;br /&gt;All programs that does anything remotely interesting, needs to keep some kind of state. In web applications, there are really only two places to put state and that is either on the server or on the client. Because HTTP itself is stateless, most frameworks stores state on the server in a session that is allocated the very first time a unique user visits. This is done either through an associated cookie or a sessionId that's passed along at all times. It's a simple approach that works reasonable well, but it also has some problems.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;em&gt;Scalability&lt;/em&gt; - When you do state, inevitably you start to consume memory that accumulates over time only to be cleared when your session times out. While memory and swap space by itself is relatively cheap, you can only throw hardware at it while your user count remains relatively low. Another problem comes to play when you decide to add more machines to assist in carrying the workload, since then you need to propagate out to a globally shared state between all the machines.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;em&gt;Complexity&lt;/em&gt; - The moment you do state, you have to think about concurrency and visibilty. Everything is essentially shared so opening several windows in the browser or using asyncronious (Ajax) calls can potentially wreck havoc in the state space for your session. Only with a debugger and non-trivial testing can you gain an overview of this aspect. It does not help that in JSF, there's (to my knowledge) no way to detect a new page load in a session scoped backing bean so you can't use that to do a partial "reset".&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;em&gt;Unpredictable&lt;/em&gt; - Have you ever been working on something online, then picked up a phone call or gone to lunch only to return and receive an error message that says &lt;a href="http://www.codinghorror.com/blog/archives/001100.html"&gt;your session has timed out&lt;/a&gt;?. In JSF you often receive the more cryptic message "Could not restore view!". This happens because of the stateless nature of HTTP, there's no way for the server to know if a user is still sitting there in the other end, so it relies on a timeout for the session. There's a reverse proportional relationship between the size of this session timeout and the amount of memory consumed by the server, which is why the timeout is often kept down around 30 min.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;I'm not totally against state on the server when it's used as a application level caching mechanism or for lightweight session info like language setting etc. Unfortunately it is all too common to see a heavyweight hierarchy from another layer (JPA entities comes to mind) creep into the user session and then it's bye bye to scalability.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;JSF favors statefullness&lt;/b&gt;&lt;br /&gt;Everything about the JSF programming model is clearly made with session scoped backing beans in mind. For instance, if you try to use various components in request scope, you will find it to be a major problem how events dispatch BEFORE your bean have had its properties filled out from the POST request. So, since JSF does not provide sufficient context, what people often do is to go behind JSF's back and grab the required context from the request parameters.&lt;br /&gt;&lt;br /&gt;Example, say that you have a JSF page that displays some info about a customer entity. You would like an easy way to test and interface with legacy apps, so you allow a request parameter called customerId to be passed along as initial context. From within this page, you may perform various CRUD operations on the customer, which means you pass along this context in various ways, typically by including something like this in your POST-back form:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&amp;lt;html:form id="someform"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;html:commandButton value="Show customer" action="showCustomer"/&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;html:inputHidden id="customerId" value="#{customerBB.customerId}" binding="#{customerBB.customerIdHidden}"/&amp;gt;&lt;br /&gt;&amp;lt;/html:form&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;What people do then in the backing bean, is to use lazy detection code to first try to fetch a property directly (if they know the form name) or from bound components. The latter approach would look something like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;static&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; String CUSTOMER_ID_PARAM = &lt;span style="color:#ce7b00;"&gt;&amp;quot;customerId&amp;quot;&lt;/span&gt;;&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt; Long customerId;&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt; HtmlInputHidden customerIdHidden;&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; HtmlInputHidden getCustomerIdHidden() {&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;return&lt;/span&gt; customerIdHidden;&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; setCustomerIdHidden(HtmlInputHidden customerIdHidden) {&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;this&lt;/span&gt;.customerIdHidden = customerIdHidden;&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; Long getCustomerId(){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;if&lt;/span&gt;(customerId == &lt;span style="color:#0000e6;"&gt;null&lt;/span&gt;){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;String customerIdString = getRequestParameter(CUSTOMER_ID_PARAM, &lt;span style="color:#0000e6;"&gt;false&lt;/span&gt;);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;if&lt;/span&gt;(customerIdString != &lt;span style="color:#0000e6;"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; !customerIdString.isEmpty())&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;customerId= Long.parseLong(customerIdString);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;else&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;if&lt;/span&gt;(getCustomerIdHidden() != &lt;span style="color:#0000e6;"&gt;null&lt;/span&gt;){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;customerIdString = getRequestParameter(getCustomerIdHidden().getClientId(getFacesContext()), &lt;span style="color:#0000e6;"&gt;false&lt;/span&gt;);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;if&lt;/span&gt;(customerIdString != &lt;span style="color:#0000e6;"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; !customerIdString.isEmpty())&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;customerId = Long.parseLong(customerIdString);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;return&lt;/span&gt; customerId;&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;/span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Very verbose and fragile. And while JSF proponents will probably claim this is not the sanctioned way to use JSF, that's the kind of hacks I've seen on numerous occasions. In the following sections I'll describe an approach which is essentially a return to an action based framework where the idea is to separate functionality out into distinct pages and backing beans, with a controlled context flowing between these.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Managed properties&lt;/b&gt;&lt;br /&gt;It turns out, you can instruct JSF to automatically initialize a backing bean property from both POST and GET requests. You do this via the managed-property tag in faces-config.xml, like so:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&amp;lt;managed-property&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;property-name&amp;gt;customerId&amp;lt;/property-name&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;value&amp;gt;#{param['customerId']}&amp;lt;/value&amp;gt;&lt;br /&gt;&amp;lt;/managed-property&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That still leaves us with the problem that in JSF, input variables are identified on the form [formname]:[inputname], so a &amp;lt;h:inputHidden&amp;gt; would not be injected into the beans customerId field. There's a way around this though. In your form, simply escape back to basic HTML by using the &amp;lt;core:verbatim&amp;gt; tag. This prevents JSF from modifying the tag name and id:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&amp;lt;core:verbatim&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;input type="hidden" id="customerId" name="custumerId" value="#{customerBB.customerId}"&amp;gt;&amp;lt;/input&amp;gt;&lt;br /&gt;&amp;lt;/core:verbatim&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Overloaded POST's with GET redirects&lt;/b&gt;&lt;br /&gt;A strongly associated aspect of the state on the server, is how everything in JSF is done through POST's. That presents a particular problem to JSF authors who wish to write in request scope, since an URL no longer expresses any of the necessary minimum state needed for the website to "live in the know". Hitting refresh in the browser won't work. What I do is to peek over at the &lt;a href="http://en.wikipedia.org/wiki/REST"&gt;RESTfull architectures&lt;/a&gt;, and only use POST for actions that causes state to mutate (updating or creation), and GET for the remaining idempotent actions.&lt;br /&gt;&lt;br /&gt;For instance, rather than using a &amp;lt;html:commandLink&amp;gt; and navigation rules to go to an edit page for an item in a list, I'll use &amp;lt;html:outputLink&amp;gt; that points to the JSF page itsef along with the necessary context:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&amp;lt;html:outputLink value="customer-edit.jsf"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;html:outputText value="Edit"&amp;gt;&amp;lt;/html:outputText&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;core:param name="customerId" value="#{customerBB.customerId}"/&amp;gt;&lt;br /&gt;&amp;lt;/html:outputLink&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Note that this actually has nothing to do with the form, it simply expands to a hyperlink which is why in this case we won't need the &amp;lt;core:verbatim&amp;gt; tag. &lt;br /&gt;The second part to this is to ensure we always emit the new context from the logic in the backingbean, that means for mutating POST operations to forward to a GET. This can be done by manually navigating to a result URL rather than returning a navigation rule. The following could be an example of what to do after a save operation was invoked on the consumer-edit.jsf page.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;FacesContext.getCurrentInstance().getExternalContext()&lt;br /&gt;.redirect("customer-view.jsf?customerId=" + getCustomerId());&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;In conclusion&lt;/b&gt;&lt;br /&gt;JSF makes it very hard to avoid state on the server, but I hope this entry will have proven that it is possible to compose simple CRUD pages with this objective in mind. It's arguably bending JSF beyond its intentions, but if you have had your share of problems with JSF as I have, perhaps this classic way of thinking in request parameters will let you utilize some of JSF's nice looking components in a simple way without walking down the dreaded statefull alley. As a side effect, it becomes trivial to document the state space and assert preconditions of your pages.&lt;br /&gt;&lt;br /&gt;The approach probably does not scale beyond relatively simple pages although I could claim adherence to the &lt;a href="http://en.wikipedia.org/wiki/Separation_of_concerns"&gt;Separation of concerns&lt;/a&gt;  principle. So if you command your own toolchain, I would urge you to have a look at &lt;a href="http://wicket.apache.org/"&gt;Wicket&lt;/a&gt; (for classic broad-spectred web apps) or &lt;a href="http://code.google.com/webtoolkit/"&gt;GWT&lt;/a&gt; (for data-intensive intranet apps) instead.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-7042565384371930693?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/7042565384371930693/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=7042565384371930693' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/7042565384371930693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/7042565384371930693'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2009/05/pain-of-request-scoped-jsf.html' title='The pain of request scoped JSF'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-3993877799698353789</id><published>2009-01-11T16:18:00.000+01:00</published><updated>2009-04-27T16:46:38.050+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RC'/><title type='text'>Confessions of an RC heli noob</title><content type='html'>Ever since I was a boy, I've been impressed with two kinds of machines: Ferrari's and helicopters. I guess the two don't share much apart from the price tag and being primarily a male thing. Never the less, since treating myself a ride this summer in a Robinson R-44 over a Canadian national park, I've been moving slowly but surely into the realm of remote controlled helicopters.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_CauKCPUdin4/SWpMnS8RP7I/AAAAAAAAADY/oejn8IE0qOU/s1600-h/n1146362123_30145028_5877.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_CauKCPUdin4/SWpMnS8RP7I/AAAAAAAAADY/oejn8IE0qOU/s320/n1146362123_30145028_5877.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5290124950283304882" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Off to a wrong start&lt;/span&gt;&lt;br /&gt;I always knew helicopters were among the most difficult things to control, yet I still wasn't prepared for exactly HOW difficult. Of course, I did not exactly make it easy for myself by starting out with a 400 series 6-channel 3D capable outdoor helicopter, like this Hughes 300:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/SWoRShD50MI/AAAAAAAAADI/O3LpBRSoKYk/s1600-h/hughes300.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_CauKCPUdin4/SWoRShD50MI/AAAAAAAAADI/O3LpBRSoKYk/s320/hughes300.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5290059722110128322" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Since then, I had some fun with other models. For instance, just as a toy for my nephew I got the Silverlit TandemZ mini helicopter, a tiny 3-channel indoor model that actually flies pretty decently albeit terrible susceptible to drafts. This really is just a toy though, do not expect to be able to practice for the big ones with these:&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/yCKNJMzk26I&amp;hl=en&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/yCKNJMzk26I&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;The last model I got is somewhere in between, the &lt;a href="http://www.esky-heli.com/esky-4ch-rc-helicopter-lama-v4-silver-color-p-774.html?ref=1&amp;gclid=CJb60vGih5gCFUog3godBlntCw"&gt;Lama V4&lt;/a&gt;, a very popular 4-channel co-axial indoor model. At half the size of the Hughes 300, it still takes a bit of space and will break if you're too tough, but it's a great learner since the controls are so similar to a full size one.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_CauKCPUdin4/SWodrNCuMoI/AAAAAAAAADQ/e3dvl6qRmSI/s1600-h/LamaV4.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_CauKCPUdin4/SWodrNCuMoI/AAAAAAAAADQ/e3dvl6qRmSI/s320/LamaV4.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5290073340372726402" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Tips and advice&lt;/span&gt;&lt;br /&gt;You must walk before you can run, and crawl before you can walk. It's the same with helicopter flying. With that in mind, here are a few pointers to other newbies considering going into this fun but potentially very expensive hobby.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;A 4-channel indoor is realistic enough to provide you with a lot of cheap flying time and practice reflexes. Do not get ambitious and go for a 6 or 7 channel chopper. Trust me, learning to control yaw, pitch and roll with the aileron stick and the trottle/rudder stick is challenging enough.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Start to fly indoor. You won't have to fight any wind which can have profound implications to the flight characteristics of the helicopter, so that's one variable you should factor out when initially learning.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The smaller the helicopter, the more durable it will be when crashing and the cheaper the parts usually are. If you already are going for an indoor practice helicopter, you have already excluded wind as a factor and then size matters less. The larger the helicopter, the more stable it flies. There's a balance here, i.e. while you can fly the medium sized &lt;a href="http://www.esky-heli.com/esky-4ch-rc-helicopter-lama-v4-silver-color-p-774.html?ref=1&amp;gclid=CJb60vGih5gCFUog3godBlntCw"&gt;Lama V4&lt;/a&gt; outside in no wind, the same is not true for the &lt;a href="http://www.e-fliterc.com/Products/Default.aspx?ProdID=EFLH2200"&gt;Blade mCX&lt;/a&gt; as its simply too small.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Consider going with a co-axial model where left and right torque cancels itself out such as to not need a tail rotor. There are a few advantages to this. The tail rotor is delicate by itself, not having it is one less thing that can break. It also makes it possible to grab the heli by the tail if something goes wrong which I've done several times. There's one drawback to it though. Turning a co-axial helicopter basically means relaxing the speed a bit on one of the axles and that means you'll loose lift and start to drop. It's not too hard to learn to compensate for this by giving it a bit more thrust as you turn, but it's a habit you don't want to carry with you over to uni-axial helicopters.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Needless to say, you are also going to need a training gear. The intuitive reflex we all have when something is about to go wrong, is to cut the gas - biiiig mistake with a helicopter. Even if you've learned never to do this, maintaining perfect pitch, roll and yaw takes a long time to master and it takes only one wrong turn on the aileron stick to slam the blades into the ground. &lt;br /&gt;The training gear can be purchased or you can &lt;a href="http://3.bp.blogspot.com/_CauKCPUdin4/SWodrNCuMoI/AAAAAAAAADQ/e3dvl6qRmSI/s1600-h/LamaV4.JPG"&gt;do as I, and construct it yourself&lt;/a&gt; using some bamboo (flexing is your friend), a glue gun and some ping-pong or Styrofoam balls. That way you can drop the heli from about a meters height and it won't suffer any damage. &lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Consider getting some better blades when you master the basics. The plastic blades that often come with the smaller/cheaper models are inexpensive to replace, but they also flex more, require higher RPM's and is generally less stable in the air while breaking extremely easy. You can purchase carbon fiber or fiberglass blade upgrades for many small helicopters and in my experiences its well worth it for the 40-50% higher price.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Get a 2.4GHz spread spectrum version rather than a fixed frequency x-tal. The problem with a x-tal system is that it's inherently susceptible to crosstalk from other devices and require a long antenna on both helicopter and radio controller. This is the reason why, if you go to an RC club, you will see people holding a dedicated frequency token such as to prevent two from using the same frequency. With 2.4GHz technology, you can pair up (bind) the receiver and the transmitter just like you may know from blue-tooth technology. It's just more future proof to get 2.4GHz stuff which is why I payed slightly extra to have this for my Lama V4. Potentially you also save money in the long run, by being able to own only one controller for your fleet of helicopters.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Last but not least, you should get a simulator. I'm no big fan of simulators myself, but they can help you build up more of the required "feel" while keeping crashing a cost-free exercise. There are some fine commercial ones out there I am told, but I just practice with the free one you often get with the helicopter. &lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Wrapping up&lt;/span&gt;&lt;br /&gt;Keep in mind, I am just a beginner and my advice needs to be taken with a grain of salt. Those are my own real experiences however. Start in the small, keep things simple and minimize variables before to drive a $300-400 piece of electronics into the ground and loose your interest. Happy flying. :)&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-3993877799698353789?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/3993877799698353789/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=3993877799698353789' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/3993877799698353789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/3993877799698353789'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2009/01/confessions-of-rc-heli-noob.html' title='Confessions of an RC heli noob'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_CauKCPUdin4/SWpMnS8RP7I/AAAAAAAAADY/oejn8IE0qOU/s72-c/n1146362123_30145028_5877.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-4259069049615104956</id><published>2008-12-06T22:18:00.000+01:00</published><updated>2008-12-10T17:53:27.418+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Enum'/><title type='text'>Java Enum relational modelling</title><content type='html'>As I have blogged about before, the &lt;a href="http://coffeecokeandcode.blogspot.com/search?updated-max=2008-08-14T18%3A28%3A00-07%3A00&amp;max-results=3"&gt;Java Enum is almost perfect&lt;/a&gt;. I say  almost because of the annoying restriction that its constructor cannot include a relation to itself, due to forward reference limitations when using the Sun compiler. The issue came up again recently when I wanted to model authority roles in &lt;a href="http://wicket.apache.org/"&gt;Wicket&lt;/a&gt;, so I spent a bit more time with the issue and the following is what I've learned. First though, a recap of the original problem. Consider the following attempt at modeling states of a CD player:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #ffffff;"&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000;font-size: 90%;"&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;class&lt;/span&gt; IlligalForwardReference {&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;enum&lt;/span&gt; Player{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;PLAYING(Player.PAUSED, Player.STOPPED),&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;PAUSED(Player.PLAYING, Player.STOPPED),&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;STOPPED(Player.PLAYING);&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt;&lt;span style="color:#000000;"&gt; &amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; EnumSet&amp;lt;Player&amp;gt; transitionStates;&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;Player(&lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; Player... states){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;this&lt;/span&gt;.transitionStates = EnumSet.copyOf( Arrays.asList(states));&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; EnumSet&amp;lt;Player&amp;gt; getTransitionStates(){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;return&lt;/span&gt; transitionStates;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;static&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; main(String... args){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;System.out.println(Player.PLAYING);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;/span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The compiler will complain with:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span style="font-size: 90%;"&gt;&lt;br /&gt;IlligalForwardReference.java:18: illegal forward reference&lt;br /&gt;        PLAYING(Player.PAUSED, Player.STOPPED),&lt;br /&gt;IlligalForwardReference.java:18: illegal forward reference&lt;br /&gt;        PLAYING(Player.PAUSED, Player.STOPPED),&lt;br /&gt;IlligalForwardReference.java:19: illegal forward reference&lt;br /&gt;        PAUSED(Player.PLAYING, Player.STOPPED),&lt;br /&gt;3 errors&lt;br /&gt;BUILD FAILED (total time: 0 seconds)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;This problem comes up as soon as you need to reference an Enum value which has not yet been initialized. Often you can avoid this if no circular relationship exists, by declaring the ones with no relations first and then adding related ones below. That is not an option however in the above example.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Passing ordinals instead&lt;/span&gt;&lt;br /&gt;One could imagine then passing in the ordinal value or String representation instead, as a workaround to this limitation. It's less type safe and somewhat reminiscent of what an Enum is supposed to solve in the first place. The following is an attempt at this, using ordinal values:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000;font-size: 90%;"&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;class&lt;/span&gt; ExceptionInInitializerError {&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;enum&lt;/span&gt; Player{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;PLAYING(&lt;span style="color:#000000;"&gt;1&lt;/span&gt;, &lt;span style="color:#000000;"&gt;2&lt;/span&gt;),&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;PAUSED(&lt;span style="color:#000000;"&gt;0&lt;/span&gt;, &lt;span style="color:#000000;"&gt;2&lt;/span&gt;),&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;STOPPED(&lt;span style="color:#000000;"&gt;0&lt;/span&gt;);&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; EnumSet&amp;lt;Player&amp;gt; transitionStates;&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;Player(&lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;int&lt;/span&gt;... ordinals){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;Collection&amp;lt;Player&amp;gt; states = &lt;span style="color:#0000e6;"&gt;new&lt;/span&gt; ArrayList&amp;lt;Player&amp;gt;();&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;for&lt;/span&gt;(&lt;span style="color:#0000e6;"&gt;int&lt;/span&gt; ordinal : ordinals)&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;states.add( Player.values()[ordinal]);&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;transitionStates = EnumSet.copyOf(states);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; EnumSet&amp;lt;Player&amp;gt; getTransitionStates(){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;return&lt;/span&gt; transitionStates;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;@Override&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; String toString(){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;return&lt;/span&gt; name() + &lt;span style="color:#ce7b00;"&gt;&amp;quot; -&amp;gt; &amp;quot;&lt;/span&gt; + transitionStates;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;static&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; main(String... args){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;System.out.println(Player.PLAYING);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But unfortunately not. Although the code now compiles, we have effectively just traded the compile time error with a runtime InitializerError:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span style="font-size: 90%;"&gt;&lt;br /&gt;Exception in thread "main" java.lang.ExceptionInInitializerError&lt;br /&gt;        at ExceptionInInitializerError.main(ExceptionInInitializerError.java:42)&lt;br /&gt;Caused by: java.lang.NullPointerException&lt;br /&gt;        at ExceptionInInitializerError$Player.values(ExceptionInInitializerError.java:15)&lt;br /&gt;        at ExceptionInInitializerError$Player.&lt;init&gt;(ExceptionInInitializerError.java:26)&lt;br /&gt;        at ExceptionInInitializerError$Player.&lt;clinit&gt;(ExceptionInInitializerError.java:16)&lt;br /&gt;        ... 1 more&lt;br /&gt;Java Result: 1&lt;br /&gt;BUILD SUCCESSFUL (total time: 0 seconds)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;That's because we cannot access the ordinals before the Player Enum has been initialized. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Deferred initialization&lt;/span&gt;&lt;br /&gt;Hmm ok, but we can defer this step until we actually start querying for transition states. The following is an attempt at this, using String representations this time around:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000;font-size: 90%;"&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;class&lt;/span&gt; DeferredStringBased {&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;enum&lt;/span&gt; Player{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;PLAYING(&lt;span style="color:#ce7b00;"&gt;&amp;quot;PAUSED&amp;quot;&lt;/span&gt;, &lt;span style="color:#ce7b00;"&gt;&amp;quot;STOPPED&amp;quot;&lt;/span&gt;),&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;PAUSED(&lt;span style="color:#ce7b00;"&gt;&amp;quot;STOPPED&amp;quot;&lt;/span&gt;, &lt;span style="color:#ce7b00;"&gt;&amp;quot;PLAYING&amp;quot;&lt;/span&gt;),&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;STOPPED(&lt;span style="color:#ce7b00;"&gt;&amp;quot;PLAYING&amp;quot;&lt;/span&gt;);&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; String[] transitionStateStrings;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;volatile&lt;/span&gt; EnumSet&amp;lt;Player&amp;gt; transitionStates;&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;Player(&lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; String... transitionStateStrings){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;this&lt;/span&gt;.transitionStateStrings = transitionStateStrings;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; EnumSet&amp;lt;Player&amp;gt; getTransitionStates(){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;if&lt;/span&gt;(transitionStates == &lt;span style="color:#0000e6;"&gt;null&lt;/span&gt;){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;synchronized&lt;/span&gt;(&lt;span style="color:#0000e6;"&gt;this&lt;/span&gt;) {&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;if&lt;/span&gt;(transitionStates == &lt;span style="color:#0000e6;"&gt;null&lt;/span&gt;){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;transitionStates = EnumSet.noneOf(Player.&lt;span style="color:#0000e6;"&gt;class&lt;/span&gt;);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;for&lt;/span&gt;(String transitionStateString : transitionStateStrings){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;transitionStates.add( Player.valueOf(transitionStateString));&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;return&lt;/span&gt; transitionStates;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; String toStringWithTransitions(){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;return&lt;/span&gt; toString() + &lt;span style="color:#ce7b00;"&gt;&amp;quot; -&amp;gt; &amp;quot;&lt;/span&gt; + getTransitionStates();&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;static&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; main(String... args){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;System.out.println(Player.PLAYING.toStringWithTransitions());&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;System.out.println(Player.PAUSED.toStringWithTransitions());&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;System.out.println(Player.STOPPED.toStringWithTransitions());&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;/span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Halleluja, it's working, we get:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span style="font-size: 90%;"&gt;&lt;br /&gt;PLAYING -&gt; [PAUSED, STOPPED]&lt;br /&gt;PAUSED -&gt; [PLAYING, STOPPED]&lt;br /&gt;STOPPED -&gt; [PLAYING]&lt;br /&gt;BUILD SUCCESSFUL (total time: 0 seconds)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Note that if you are modelling something where it makes sence to have transitivity (say authority roles where an administrator automatically assumes the role of user, as long as administrator declares a transition to superuser, and superuser declares a transition to user) then in the inner loop of the getTransitionStates() method, add the line:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000";font-size: 90%;&gt;&lt;br /&gt;transitionStates.addAll( Player.valueOf(transitionStateString).getTransitionStates() );&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Modelling transitions instead&lt;/span&gt;&lt;br /&gt;It was suggested to me in my last entry about the subject, that I could model the transitions instead of the states, as Josh Bloch recommends in Effective Java SE, item 33. This is true, if you do not need symmetric relations (if playing can go to stopped, then stopped must also go to playing) and is fine with adding another layer consisting of the transition states too. By focusing on modelling transitions rather than states (which makes sence in Bloch's phase change example), you arrive at something like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000;font-size: 90%;"&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;class&lt;/span&gt; Bloch{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;enum&lt;/span&gt; Player {&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;STOPPED, PLAYING, PAUSED;&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;enum&lt;/span&gt; PlayerTransition {&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;STOPFROMPLAYING(PLAYING, STOPPED), PLAYFROMSTOPPED(STOPPED, PLAYING),&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;PAUSEFROMPLAYING(PLAYING, PAUSED), PLAYFROMPAUSED(PAUSED, PLAYING),&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;STOPFROMPAUSED(PAUSED, STOPPED);&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; Player src;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; Player dst;&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;PlayerTransition(Player src, Player dst) {&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;this&lt;/span&gt;.src = src;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;this&lt;/span&gt;.dst = dst;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;static&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; Map&amp;lt;Player, Map&amp;lt;Player, PlayerTransition&amp;gt;&amp;gt; m =&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;new&lt;/span&gt; EnumMap&amp;lt;Player, Map&amp;lt;Player, PlayerTransition&amp;gt;&amp;gt;(Player.&lt;span style="color:#0000e6;"&gt;class&lt;/span&gt;);&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;static&lt;/span&gt; {&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;for&lt;/span&gt; (Player p : Player.values()) {&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;m.put(p, &lt;span style="color:#0000e6;"&gt;new&lt;/span&gt; EnumMap&amp;lt;Player, PlayerTransition&amp;gt;(Player.&lt;span style="color:#0000e6;"&gt;class&lt;/span&gt;));&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;for&lt;/span&gt; (PlayerTransition trans : PlayerTransition.values()) {&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;m.get(trans.src).put(trans.dst, trans);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;static&lt;/span&gt; PlayerTransition from(Player src, Player dst) {&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;return&lt;/span&gt; m.get(src).get(dst);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;static&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; main(String... args)&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;System.out.println( Player.PlayerTransition.from(Player.STOPPED, Player.PLAYING) );&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;System.out.println( Player.PlayerTransition.from(Player.PLAYING, Player.PAUSED) );&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;System.out.println( Player.PlayerTransition.from(Player.PAUSED, Player.STOPPED) );&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;/span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Which yields the output:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span style="font-size: 90%;"&gt;&lt;br /&gt;PLAYFROMSTOPPED&lt;br /&gt;PAUSEFROMPLAYING&lt;br /&gt;STOPFROMPAUSED&lt;br /&gt;BUILD SUCCESSFUL (total time: 0 seconds)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;While I'm sure there are things you can model with this approach, I would much rather be modelling the states rather than the transitions. There are however an idea that comes to mind from seeing this. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Getting rid of the circular dependency&lt;/span&gt;&lt;br /&gt;If the whole problem stems from the fact that we cannot have circular relations, then perhaps we can split it in two such that only one relation is modelled statically, while the other is modelled dynamically - but setup statically. It's hard to explain, but take a look at this code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000;font-size: 90%;"&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;class&lt;/span&gt; MirrorEnum {&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;enum&lt;/span&gt; TransitionTo{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;PLAYING, PAUSED, STOPPED;&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;Player state;&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; setState(Player state){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;this&lt;/span&gt;.state = state;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt; Player getState(){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;return&lt;/span&gt; state;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;enum&lt;/span&gt; Player{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;PLAYING(TransitionTo.STOPPED, TransitionTo.PAUSED),&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;PAUSED(TransitionTo.PLAYING, TransitionTo.STOPPED),&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;STOPPED(TransitionTo.PLAYING);&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; EnumSet&amp;lt;TransitionTo&amp;gt; transitionToSet;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;volatile&lt;/span&gt; EnumSet&amp;lt;Player&amp;gt; transitionStates;&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;Player(&lt;span style="color:#0000e6;"&gt;final&lt;/span&gt; TransitionTo... transitionToArray){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;this&lt;/span&gt;.transitionToSet = EnumSet.copyOf( Arrays.asList( transitionToArray ) );&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; EnumSet&amp;lt;Player&amp;gt; getTransitionStates(){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;if&lt;/span&gt;(transitionStates == &lt;span style="color:#0000e6;"&gt;null&lt;/span&gt;){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;synchronized&lt;/span&gt;(&lt;span style="color:#0000e6;"&gt;this&lt;/span&gt;){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;if&lt;/span&gt;(transitionStates == &lt;span style="color:#0000e6;"&gt;null&lt;/span&gt;){&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#969696;"&gt;// Make sure each Transition state is in sync with each PlayerState&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;for&lt;/span&gt;(TransitionTo transition : TransitionTo.values()){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;transition.setState( Player.values()[transition.ordinal()]);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#969696;"&gt;// Construct TransitionState's by mapping from Transition to PlayerState&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;transitionStates = EnumSet.noneOf(Player.&lt;span style="color:#0000e6;"&gt;class&lt;/span&gt;);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;for&lt;/span&gt;(TransitionTo transition : &lt;span style="color:#0000e6;"&gt;this&lt;/span&gt;.transitionToSet){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;transitionStates.add( transition.getState() );&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;return&lt;/span&gt; transitionStates;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; String toStringWithTransitions(){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;return&lt;/span&gt; toString() + &lt;span style="color:#ce7b00;"&gt;&amp;quot; -&amp;gt; &amp;quot;&lt;/span&gt; + getTransitionStates();&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;static&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; main(String... args){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;System.out.println(TransitionTo.Player.PLAYING.toStringWithTransitions());&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;System.out.println(TransitionTo.Player.PAUSED.toStringWithTransitions());&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;System.out.println(TransitionTo.Player.STOPPED.toStringWithTransitions());&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;/span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;When run, the above results in:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;span style="font-size: 90%;"&gt;&lt;br /&gt;PLAYING -&gt; [PAUSED, STOPPED]&lt;br /&gt;PAUSED -&gt; [PLAYING, STOPPED]&lt;br /&gt;STOPPED -&gt; [PLAYING]&lt;br /&gt;BUILD SUCCESSFUL (total time: 0 seconds)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;The whole idea is to have two Enum's which mirror eachother yet are distinct to the Java compiler - not unlike when aliasing a column in SQL. You have to deal with two Enum's (Player and TransitionTo) at compile time, but at runtime only Player comes into play. It's not a solution I will actually use however, for that it is too complex and not DRY enough.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;In practice I'll go for the ordinal approach when modeling relations. While there is no code completion to be had and only limited type-safety, it stands out as the cleanest and most elegant solution. It's also relatively easy to add some assertions and unit testing to improve on this a bit.&lt;br /&gt;&lt;br /&gt;The best would obviously be for Sun to simply fix this in the compiler. The Eclipse compiler have already shown it is possible to do this and make it more lenient. Until then, if you have a more elegant solution to the stated problem, I'd love to hear about it.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-4259069049615104956?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/4259069049615104956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=4259069049615104956' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/4259069049615104956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/4259069049615104956'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/12/java-enum-relational-modelling.html' title='Java Enum relational modelling'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-6294078022117368652</id><published>2008-11-08T03:14:00.000+01:00</published><updated>2008-12-10T19:51:04.174+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Jasper'/><title type='text'>Jasper Reports and legacy formats</title><content type='html'>I'm not sure when exactly or between which versions, but at some point Jasper Report designs moved from being based on legacy DTD to the more modern XSD schema. It turns out that most tools today, i.e. the iReport plugin for NetBeans, are now overwriting the DTD information of legacy designs in favor of XSD information. &lt;br /&gt;This can cause problems if and when you are not able to change the Jasper engine itself that fills out the template designs. It also did not seem possible to simply plug-in another XML parser and I found it rather hard in general to find information about this and support forums to turn to. So I sought another solution.&lt;br /&gt;&lt;br /&gt;If you try to run an XSD based design against the Jasper engine that can only deal with DTD, you will get an error along the line of this:&lt;br /&gt;&lt;pre style="font-size: 90%;"&gt;&lt;br /&gt;net.sf.jasperreports.engine.JRException: org.xml.sax.SAXParseException: Document root element "jasperReport", must match DOCTYPE root "null".&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;By using a legacy designer which favors DTD's (iReport 3.0 standalone) and the recent NetBeans plugin which favors XSD's, it becomes apparent what the exact differences are. Obviously the DTD version has a doctype clause:&lt;br /&gt;&lt;pre style="font-size: 90%;"&gt;&lt;br /&gt;&amp;lt;!DOCTYPE jasperReport PUBLIC "//JasperReports//DTD Report Design//EN" "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Furthermore, the jasperReport root element has the extra attributtes:&lt;br /&gt;&lt;pre style="font-size: 90%;"&gt;&lt;br /&gt;xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" &lt;br /&gt;xsi:schemaLocation=http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;One could just edit the files manually, but seriously, what fun is that. Instead, we can create a decorator to perform this job on-the-fly as we send the design off to the Jasper engine to be compiled. We would need to do the following:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Read the InputStream into a DOM tree&lt;/li&gt;&lt;li&gt;Add the missing DTD doctype&lt;/li&gt;&lt;li&gt;Remove the undesired attributtes&lt;/li&gt;&lt;li&gt;Write the dom back out to an InputStream&lt;/li&gt;&lt;/ol&gt;The result of doing the above I've placed in &lt;a href="http://82.103.135.236/LegacyJasperInputStream.java"&gt;LegacyJasperInputStream.java&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;An example on how to use it:&lt;br /&gt;&lt;pre style="font-size: 90%;"&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;JasperDesign design = JRXmlLoader.load(&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;new&lt;/span&gt; LegacyJasperInputStream(&lt;span style="color:#0000e6;"&gt;new&lt;/span&gt; FileInputStream(&lt;span style="color:#ce7b00;"&gt;&amp;quot;MyXsdBasedDesign.jrxml&amp;quot;&lt;/span&gt;))&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;);&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Probably I am not the only one facing this issue, which is why I chose to write a small entry about it and hopefully helping others. Be advised, you're going to need the slf4j logging facility, or modify the source slightly to make use of the standard java.util.Logger.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-6294078022117368652?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/6294078022117368652/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=6294078022117368652' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/6294078022117368652'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/6294078022117368652'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/11/jasper-reports-and-legacy-formats.html' title='Jasper Reports and legacy formats'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-464231626198172153</id><published>2008-11-07T01:55:00.000+01:00</published><updated>2008-11-07T13:01:17.959+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Venting'/><title type='text'>Congratulations America!</title><content type='html'>I think it's only in order to congratulate the USA for what has happened. While oddly 47% of Americans still haven't noticed, the last 8 years of an illiterate republican doctrine "if you're not with us, you're against us" has hurt their country incredibly much. As evident right from the beginning to most of us, Bush will go over in history as the worst president of all time - only elected for his second term I suppose due to that fuzzy term called "American patriotism".&lt;br /&gt;&lt;br /&gt;The only sad part will be missing someone to laugh at when watching Letterman, The Colbert Report or The Daily Show. Ah for a while at least, we'll always have Gucci Palin. ;)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://cache.boston.com/universal/site_graphics/blogs/bigpicture/obama_11_05/obama01_16773717.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 330px; height: 224px;" src="http://cache.boston.com/universal/site_graphics/blogs/bigpicture/obama_11_05/obama01_16773717.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Best of luck Obama, you sure have your work cut out for you! The future just got a lot brighter  in the prospect of regaining an America so many of us used to admire once! With a new dawn near and a fresh breeze blowing from the west, let the healing begin.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-464231626198172153?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/464231626198172153/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=464231626198172153' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/464231626198172153'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/464231626198172153'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/11/congratulations-america.html' title='Congratulations America!'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-1165647280907324186</id><published>2008-09-27T16:48:00.000+02:00</published><updated>2008-09-27T17:04:48.257+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Groupwise 7 on Ubuntu 8.04</title><content type='html'>While web applications in browsers are continuing to improve, they still can't quite compete with desktop applications. One of the examples of this is the Novell Groupwise client. Running 64bit Ubuntu poses a bit of a challenge, since Novell only offer prepackaged rpm bundles for 32bit Red Hat and Suse systems. Note, some of this stuff is inspired by &lt;a href="http://scottf.wordpress.com/2008/02/08/getting-groupwise-to-work-on-64-bit-ubuntu/"&gt;Scott's blog entry&lt;/a&gt; earlier this year, however I could never get his howto to work for me.&lt;br /&gt;&lt;br /&gt;Start by downloading the Groupwise client RPM onto a 32bit version of Ubuntu (I use a 32bit image in VirtualBox). I'm not sure from where I found mine, but it's out there if you search a little. You should end up having a file called something like novell-groupwise-gwclient-7.0.3-20080310.i386.rpm&lt;br /&gt;&lt;br /&gt;To convert this into a debian package, you are going to need alien. Get this by typing:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sudo apt-get install alien&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;With alien, you can convert the RPM into DEB by typing:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sudo alien -c novell-groupwise-gwclient-7.0.3-20080310.i386.rpm&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now you're done with the 32bit stuff. Move your novell-groupwise-gwclient_7.0.3-20080310.deb to your target 64 bit box. Before installing the DEB, make sure you have the nessesary dependencies. On my system I needed lib std. C++ 5 (you might need others as well) so I had to do:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sudo apt-get install libstdc++5&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Install the Groupwise client itself by issuing:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sudo aptitude install novell-groupwise-gwclient_7.0.3-20080310_i386.deb&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You should now have Groupwise installed in the /opt/novell/groupwise folder and shortcuts created on your desktop and in the Ubuntu Internet application menu. Groupwise is actually written (mostly) in Java, which it bundles (in my case the Sun JRE 1.5.0_06-B05). This works fine &lt;a href="http://coffeecokeandcode.blogspot.com/2008/09/installing-java-6-update-10-on-ubuntu.html"&gt;except if you are using Compiz&lt;/a&gt;, but I am so I needed to replace the 32bit slightly old bundles JRE with a newer one. Download a .bin from &lt;a href="http://java.sun.com/javase/downloads/ea/6u10/6u10rcDownload.jsp#6u10JREs"&gt;SUN's site&lt;/a&gt;, be sure to only download a JRE (not a JDK) and a 32bit (i586, not a amd64) one. Once downloaded, you can extract it to a folder by running:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sh jre-6u10-rc2-bin-b32-linux-i586-12_sep_2008.bin&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Finally, we need to replace the JRE Groupwise is bundled with, with this new one you just extracted into the folder /jre1.6.0_10. So delete the folder /opt/novell/groupwise/client/jre/:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sudo rm -R -f /opt/novell/groupwise/client/jre&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then copy the new JRE in folder jre1.6.0_10/ to /opt/novell/groupwise/client/jre/:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sudo cp jre1.6.0_10 /opt/novell/groupwise/client/jre -R&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There you go. That should give you Groupwise 7.03 running on the latest Ubuntu 8.04.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-1165647280907324186?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/1165647280907324186/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=1165647280907324186' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/1165647280907324186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/1165647280907324186'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/09/groupwise-7-on-ubuntu-804.html' title='Groupwise 7 on Ubuntu 8.04'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-6509353900360144295</id><published>2008-09-26T21:01:00.000+02:00</published><updated>2008-10-14T15:35:56.326+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Java 6 update 10 on Ubuntu 8.04</title><content type='html'>The official Ubuntu 8.04 repositories comes with a slightly outdated version of Java, namely 1.6.0 update 6. If you issue a java -version you can assert this is the case:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/SN09UhJsKZI/AAAAAAAAACg/HSvDB-s2ZiQ/s1600-h/ubuntu-old-java.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_CauKCPUdin4/SN09UhJsKZI/AAAAAAAAACg/HSvDB-s2ZiQ/s320/ubuntu-old-java.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5250420163289557394" /&gt;&lt;/a&gt;&lt;br /&gt;Unfortunately, if you are running Compiz, you are likely to then suffer the notorious gray rectangle syndrome as described in &lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6429775"&gt;6429775&lt;/a&gt;, &lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=a00ce585bdd7cffffffffd05bd9619f0aa45?bug_id=6434227"&gt;6434227&lt;/a&gt; and &lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6632124"&gt;6632124&lt;/a&gt; among others. The good news, the problem appears to be fixed in update 10.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Installing the latest JDK&lt;/span&gt;&lt;br /&gt;Start by &lt;a href="http://java.sun.com/javase/downloads/ea/6u10/6u10rcDownload.jsp#6u10JDKs"&gt;downloading the JDK&lt;/a&gt; for your architecture from SUN. Take the .bin file, extract it by running it as a shell script:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sh jdk-6u10-rc2-bin-b32-linux-amd64-12_sep_2008.bin&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This will create a new folder called /jdk1.6.0_10. Rename this to java-6-sun-1.6.0.10 (just to remain consistent with how Debian/Ubuntu refers to JDK's) and move this folder to /usr/lib/jvm:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sudo mv jdk1.6.0_10 java-6-sun-1.6.0.10&lt;br /&gt;sudo mv jdk1.6.0_10/ /usr/lib/jvm&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Officially you are suppose to use the update-java-alternatives command when using a Debian distro, but frankly I find it easier to do this manually. We need to update the /usr/lib/jvm/.java-6-sun.jinfo, so type:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;gksu gedit .java-6-sun.jinfo&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This will open up a hidden configuration file. The first line likely shows:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;name=java-6-sun-1.6.0.06&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Simply change this to point to the new version: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;name=java-6-sun-1.6.0.10&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Also, update the java 6 symlink to point to the one we just installed:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sudo rm /usr/lib/jvm/java-6-sun&lt;br /&gt;sudo ln -s /usr/lib/jvm/java-6-sun-1.6.0.10/ /usr/lib/jvm/java-6-sun&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This should actually work for most applications, but to be sure I always like to add a few common environment variables. Do this by typing:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;gksu gedit $HOME/.bashrc&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Scroll down to the end of the file and add two new lines:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;export JDK_HOME=/usr/lib/jvm/java-6-sun&lt;br /&gt;export JAVA_HOME=$JDK_HOME&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That should do it. Issuing a java -version command now yields the latest version:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/SN09xB5q9-I/AAAAAAAAACo/tFcRt8S7dAA/s1600-h/ubuntu-latest-java.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_CauKCPUdin4/SN09xB5q9-I/AAAAAAAAACo/tFcRt8S7dAA/s320/ubuntu-latest-java.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5250420653117077474" /&gt;&lt;/a&gt;&lt;br /&gt;Remember the above isn't necessarily the official sanctioned way to do it, but it worked for me. Good luck to you!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt;&lt;br /&gt;It has come to my attention that Ubuntu 8.04 updates to the JVM overrides/reverts the modifications above. Keep an eye on this, I noticed it when starting seeing Compiz grey-box frames again in NetBeans.&lt;br /&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-6509353900360144295?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/6509353900360144295/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=6509353900360144295' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/6509353900360144295'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/6509353900360144295'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/09/installing-java-6-update-10-on-ubuntu.html' title='Java 6 update 10 on Ubuntu 8.04'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_CauKCPUdin4/SN09UhJsKZI/AAAAAAAAACg/HSvDB-s2ZiQ/s72-c/ubuntu-old-java.png' height='72' width='72'/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-6668466188783798151</id><published>2008-09-03T01:53:00.000+02:00</published><updated>2008-09-27T17:54:12.166+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Plugin'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>@SuppressWarnings completion</title><content type='html'>&lt;b&gt;Why it was made&lt;/b&gt;&lt;br /&gt;Although NetBeans is capable of suggesting and auto-inserting @SuppressWarnings, it doesn't actually provide code completion or documentation for these values. Indeed, as &lt;a href="http://coffeecokeandcode.blogspot.com/2008/05/suppresswarnings-annotations.html"&gt;I've blogged about before&lt;/a&gt;, it is tricky to track down the exact enumeration and semantics of these magic values. This is due to the fact that they are entirely dependent on the compiler and IDE. This plugin adds support for the values currently supported by NetBeans 6.1, namely "cast", "deprecation", "divzero", "empty-statement", "empty", "fallthrough", "finally", "serial" and "unchecked". It also tries to explain how and when to use them.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/SL7clOkzyqI/AAAAAAAAACY/wMGkSkowfms/s1600-h/dump65.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_CauKCPUdin4/SL7clOkzyqI/AAAAAAAAACY/wMGkSkowfms/s320/dump65.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5241869548431592098" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;How it was made&lt;/span&gt;&lt;br /&gt;Creating plugins for NetBeans is relatively easy if you start by grabbing existing code and have invested in the RCP book. Especially blogs like &lt;a href="http://blogs.sun.com/geertjan/"&gt;Geertjan'&lt;/a&gt;s and &lt;a href="http://blogs.sun.com/scblog/"&gt;Sandip's&lt;/a&gt; are virtual goldmines. So for this one, I used the Geertjan's blog entry entitled &lt;a href="http://blogs.sun.com/geertjan/entry/how_to_create_a_caret"&gt;Caret Aware Code Completion&lt;/a&gt;. I had some trouble hooking into the Java parser as the tutorial shows, whenever invoking completion, there would be a lag between obtaining the caret position and resolving the current element. I did not figure out why this is, other than for some reason, the mapping from caret position to the underlying AST went out of sync. So instead I ended up relying only on the build-in Java lexer, which did not exhibit the same lag. This means there were a little bit of manual parsing to do, to assert if indeed the context invites for @SuppressWarnings values. The following scenarios had to be accounted for:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    @SuppressWarnings(STRING_LITERAL&lt;br /&gt;    @SuppressWarnings({STRING_LITERAL&lt;br /&gt;    @SuppressWarnings({STRING_LITERAL, STRING_LITERAL&lt;br /&gt;    @SuppressWarnings(value=STRING_LITERAL&lt;br /&gt;    @SuppressWarnings(value={STRING_LITERAL, STRING_LITERAL&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In other words, we have to consume the Java token stream in reverse, from any open of closed STRING_LITERAL, and pass the following finite-state machine:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_CauKCPUdin4/SL7cLWAASCI/AAAAAAAAACQ/HgYr0tfdVxg/s1600-h/test.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;border: dashed;" src="http://2.bp.blogspot.com/_CauKCPUdin4/SL7cLWAASCI/AAAAAAAAACQ/HgYr0tfdVxg/s320/test.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5241869103748106274" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is implemented by a simple recursive descent parser, which &lt;a href="http://82.103.135.236/SuppressWarningsCompletionProvider.java.html"&gt;looks like this&lt;/a&gt;. Should you care to use it for your own parsing of a DSL inside Java String tokens, you can download the complete source code &lt;a href="http://82.103.135.236/SuppressWarningsCompletionSrc.zip"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Where to get it&lt;/span&gt;&lt;br /&gt;There might still be some bugs and perhaps I a missing something, but if you want to give it a spin, you can download the plugin from &lt;a href="http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=13065"&gt;NetBeans plugin central&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The hardest thing was to gather information regarding the valid values, since it differs from compiler to compiler and the various IDE's. If you do happen to find a bug or something incorrect, please let me know so I can correct it.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-6668466188783798151?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/6668466188783798151/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=6668466188783798151' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/6668466188783798151'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/6668466188783798151'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/09/netbeans-plugin-suppresswarnings.html' title='@SuppressWarnings completion'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_CauKCPUdin4/SL7clOkzyqI/AAAAAAAAACY/wMGkSkowfms/s72-c/dump65.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-345765510205152768</id><published>2008-08-29T14:51:00.000+02:00</published><updated>2008-12-10T17:56:03.450+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Myth: Java widely used in the browser</title><content type='html'>Yes I aspire to be a MythBuster, don't we all? For a while now there has been some concern over Apple's apparent lack of love for Java. Lately the debate has shifted over to the iPhone and the Java blogosphere is &lt;a href="http://weblogs.java.net/blog/terrencebarr/archive/2008/08/get_real_apple.html"&gt;doing its best&lt;/a&gt; to send a message to Apple. While I am far from a supporter of the policies and practices of Apple, I do think they are right in determining Java as legacy or an anomaly on the web of 2008.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;A sniffing bot&lt;/span&gt;&lt;br /&gt;It turns out it's hard to find concrete evidence of how widespread the use of Java client technology is on the internet. What we can do however, is simulate a web user, randomly browsing around and taking note of how often we bump into Java.&lt;br /&gt;The first issue is, how can we come up with truly random URL's? Three different approaches comes to mind:&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Use some existing randomizer service&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Methodically run through IP ranges&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Screen scrape Google results&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;I actually implemented all 3. Of those both item 2 and 3 potentially raises some ethical questions, consistent scanning of remote systems can be considered a hostile activity as can &lt;a href="http://www.perlmonks.org/?node_id=477825"&gt;web scraping&lt;/a&gt;. Thus the one presented here uses the 1'st approach only and is quite slow due to the fact that the random function of &lt;a href="http://random.yahoo.com/bin/ryl"&gt;the site I am using&lt;/a&gt;  seems to be bound by timestamp data (probably works by hashing the hh:mm:ss and looking up an index in a table). For that reason, and out of politeness, I've inserted a 1 sec delay between each attempt.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The scent of Java&lt;/span&gt;&lt;br /&gt;Due to Java's age, there are quite a few ways it can be embedded onto a page depending on both HTML standards and individual browsers. There the APPLET tag, there's the OBJECT tag and then there's the EMBED tag. This should also include the recent iteration of Java client technology, namely JavaFX, since they appear to be reusing the APPLET tag for this - odd actually, considering W3C/HTML4.x &lt;a href="http://www.w3.org/TR/REC-html40/struct/objects.html"&gt;deprecated this tag&lt;/a&gt; 9 years ago now.&lt;br /&gt;&lt;br /&gt;Apart from these tags, JavaScript and frames can further hide the fact that Java technology is being used. This is not very common from what I've experienced though, much more common with Flex and especially Silverlight. Also we need to take into consideration Java Web Start, we do this by capturing links which points at *.jnlp files.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Implementation&lt;/span&gt;&lt;br /&gt;Was pretty trivial, thanks to Java Swing's old but readily at hand  &lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/text/html/HTMLEditorKit.html"&gt;HTMLEditorKit&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;. The hardest part was coming up with a simple yet functional query language as I did not want to hardwire these rules nor depend on any 3'rd part library. The essence of the markup matching is modeled by an enum (I love Java enum's) and it looks like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&lt;span style="color:#0000e6;"&gt;enum&lt;/span&gt; TagMatch{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;JAVA(&lt;span style="color:#969696;"&gt;// Most Java applets exist inside an APPLET tag&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;Tag.create(HTML.Tag.APPLET, Attr.create(HTML.Attribute.CODE)),&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#969696;"&gt;// Java Web Start will be anchors ending in .jnlp&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;Tag.create(HTML.Tag.A, Attr.create(HTML.Attribute.HREF, &lt;span style="color:#ce7b00;"&gt;&amp;quot;.*\\.jnlp$&amp;quot;&lt;/span&gt;)),&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#969696;"&gt;// OBJECT and EMBED tags pass in class or jar file&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;Tag.create(HTML.Tag.PARAM, Attr.create(HTML.Attribute.VALUE, &lt;span style="color:#ce7b00;"&gt;&amp;quot;.*\\.(class|jar)$&amp;quot;&lt;/span&gt;))&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;private&lt;/span&gt; List&amp;lt;Tag&amp;gt; tagMatches = &lt;span style="color:#0000e6;"&gt;new&lt;/span&gt; ArrayList&amp;lt;Tag&amp;gt;();&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;TagMatch(Tag... tagVararg){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;tagMatches = Arrays.asList(tagVararg);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; List&amp;lt;Tag&amp;gt; getTagMatches(){&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;return&lt;/span&gt; tagMatches;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt;&lt;/span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you want to take a look at the whole source file, it's available &lt;a href="http://82.103.135.236/TagMatchRobot.java.html"&gt;righ here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Enough with the talk&lt;/span&gt;&lt;br /&gt;The following is the result of scanning 1.000 random sites:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;Found 7 sites matching JAVA&lt;br /&gt;+--[&lt;a href="http://www.gailzavala.com/"&gt;www.gailzavala.com/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.nationalhealthcouncil.org/"&gt;www.nationalhealthcouncil.org/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://web2c.com/"&gt;web2c.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://armadaweb.com/Anime/Sailor/"&gt;armadaweb.com/Anime/Sailor/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.gloverpainting.com/"&gt;www.gloverpainting.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.theschrodts.com/"&gt;www.theschrodts.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://members.shaw.ca/micheil/burns/burns.htm"&gt;members.shaw.ca/micheil/burns/burns.htm&lt;/a&gt;]&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Well well, 7 sites out of 1000 were identified as using Java on the client tier. I have of course run it a number of times, each resulting in roughly the same numbers somewhere between 5 and 10. This leaves me to conclude that the amount of sites using Java is less than 1%. And how about those that do? If you take a look at some of the links, at least half of them are webcam viewers, scrollers and counters reminiscent of the 90's.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;Can't say I was surprised by the result. I am aware of a few things that relies on Java (home banking comes to mind) but then again, I also know of minority sites that use ActiveX. So I still think we can not slam Apple for this one. Certainly iPhone users would be missing Flash much more than Java. Of course, let's hope the new &lt;a href="http://www.sun.com/software/javafx/index.jsp"&gt;JavaFX&lt;/a&gt; stuff and the forthcoming &lt;a href="http://java.sun.com/javase/downloads/ea/6u10/6u10RC.jsp"&gt;update 10&lt;/a&gt; will pan the way for a renascence.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt;&lt;br /&gt;People don't seem to like this entry very much. I'm not sure whether its because I am speaking negative about Java in the browser or if I simply didn't convey the message good enough. So to rephrase, this is a simple test to show that Java applets and web start applications are in such low use on websites that to most people (and by inference browser vendors) not having support for these doesn't matter much. Contrast this to the results I get when running another test, this time searching 1000 random sites for for Flash/Flex usage (tags with a SRC attribute containing ".swf"). Such a query results in the following matches:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;Found 179 sites matching FLASH&lt;br /&gt;+--[&lt;a href="http://www.countrybumpkin.com.au/"&gt;www.countrybumpkin.com.au/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.chrissmithphoto.com/"&gt;www.chrissmithphoto.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.bostonbw.com/"&gt;www.bostonbw.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.lipseylipsey.com/"&gt;www.lipseylipsey.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.zewa.com"&gt;www.zewa.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.webguide.com/attractions.html"&gt;www.webguide.com/attractions.html&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.socaldelivery.com"&gt;www.socaldelivery.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.lincolnspeedway.com"&gt;www.lincolnspeedway.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.redcliffslodge.com/"&gt;www.redcliffslodge.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.baldwin-school.org/"&gt;www.baldwin-school.org/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.bdainc.com/"&gt;www.bdainc.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.hydraulicpumps.co.uk/"&gt;www.hydraulicpumps.co.uk/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.mainstreetcottonshop.com"&gt;www.mainstreetcottonshop.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.yellowstonevacations.com/"&gt;www.yellowstonevacations.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.acmotorcars.com"&gt;www.acmotorcars.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.deadwooddicks.com/"&gt;www.deadwooddicks.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.judycarter.com"&gt;www.judycarter.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://biz.yahoo.com/n/l/s/sun.html"&gt;biz.yahoo.com/n/l/s/sun.html&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.siasat.com/"&gt;www.siasat.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.jackand.co.jp/"&gt;www.jackand.co.jp/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.meritax.com/"&gt;www.meritax.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.westpasco.com/"&gt;www.westpasco.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.calpers-governance.org/"&gt;www.calpers-governance.org/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.paradiseranch.com/"&gt;www.paradiseranch.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.tamilnaduwomen.org/"&gt;www.tamilnaduwomen.org/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.dynamitedetail.com"&gt;www.dynamitedetail.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://sportsillustrated.cnn.com/basketball/ncaa/men/teams/oregon/"&gt;sportsillustrated.cnn.com/basketball/ncaa/men/teams/oregon/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.glenfir.com"&gt;www.glenfir.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.marquette.org/"&gt;www.marquette.org/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.uwwsports.com/index.asp?path=football"&gt;www.uwwsports.com/index.asp?path=football&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.sfballoonguy.com/"&gt;www.sfballoonguy.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.alliedmodular.com/"&gt;www.alliedmodular.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.helenelliott.com/"&gt;www.helenelliott.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.nationwidemortgage.com.au/"&gt;www.nationwidemortgage.com.au/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.admissions.umich.edu/"&gt;www.admissions.umich.edu/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.globalcredit.com"&gt;www.globalcredit.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.godinos.com/"&gt;www.godinos.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.leonidas-chocolate.com/"&gt;www.leonidas-chocolate.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.01-flash-web-templates.com/"&gt;www.01-flash-web-templates.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.gwmcnamara.com/"&gt;www.gwmcnamara.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.HiDoctor.com/"&gt;www.HiDoctor.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.metromayors.org/"&gt;www.metromayors.org/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.vigorita.com/"&gt;www.vigorita.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.goforth.org/"&gt;www.goforth.org/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.reitdesign.com/"&gt;www.reitdesign.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.brentlmiller.com"&gt;www.brentlmiller.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.abingdon.com/"&gt;www.abingdon.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.ravenwoodgolf.com/"&gt;www.ravenwoodgolf.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.goldner.com/"&gt;www.goldner.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.sarasota.k12.fl.us/brookside/"&gt;www.sarasota.k12.fl.us/brookside/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.craigsmithrv.com/"&gt;www.craigsmithrv.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.labelexpress.com.au/"&gt;www.labelexpress.com.au/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.bagsoflove.co.uk/"&gt;www.bagsoflove.co.uk/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.var-provence.com/web_anglais/"&gt;www.var-provence.com/web_anglais/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.santafe.cc.fl.us/"&gt;www.santafe.cc.fl.us/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.terrybryant.com/"&gt;www.terrybryant.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.philanthropy.iupui.edu"&gt;www.philanthropy.iupui.edu&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.kkla.com/"&gt;www.kkla.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.iconicimaging.co.uk/"&gt;www.iconicimaging.co.uk/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.christielodge.com/"&gt;www.christielodge.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.waynegoodwin.org/"&gt;www.waynegoodwin.org/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.livingdesert.org/"&gt;www.livingdesert.org/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.scblues.com/"&gt;www.scblues.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.skippinggirl.com/"&gt;www.skippinggirl.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.thebusinessgarden.co.uk/"&gt;www.thebusinessgarden.co.uk/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.armbrusterrealty.com"&gt;www.armbrusterrealty.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.butterfly-kisses.com/"&gt;www.butterfly-kisses.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.acceptancefinancial.com"&gt;www.acceptancefinancial.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.nvhomes.com/"&gt;www.nvhomes.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.gerlinglaw.com/"&gt;www.gerlinglaw.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.aweuk.com/"&gt;www.aweuk.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.uintagolf.com"&gt;www.uintagolf.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.lawinc.com"&gt;www.lawinc.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.neteffects.com"&gt;www.neteffects.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.coe.ufl.edu/"&gt;www.coe.ufl.edu/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.key2holidays.co.uk/"&gt;www.key2holidays.co.uk/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.sachem.k12.ny.us/"&gt;www.sachem.k12.ny.us/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://asia.weather.yahoo.com/asia/China/"&gt;asia.weather.yahoo.com/asia/China/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.ecofurn.com.au/"&gt;www.ecofurn.com.au/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.breckenridgeskishop.com/"&gt;www.breckenridgeskishop.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.camroadproperties.com/"&gt;www.camroadproperties.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.saassociates.com/"&gt;www.saassociates.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.cabrillo-inn.com/"&gt;www.cabrillo-inn.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.wwf.org.nz/"&gt;www.wwf.org.nz/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.kenilworthinn.com/"&gt;www.kenilworthinn.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.marinedivers.com/"&gt;www.marinedivers.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://wagner.rivals.com/"&gt;wagner.rivals.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.kanales.gr/"&gt;www.kanales.gr/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.tourinfo.ru"&gt;www.tourinfo.ru&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.krischs.com"&gt;www.krischs.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.visitlaportecounty.com/"&gt;www.visitlaportecounty.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.roninyachtcharters.com/"&gt;www.roninyachtcharters.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.utp.ac.pa/"&gt;www.utp.ac.pa/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.colmet.com"&gt;www.colmet.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.rolltidebama.com/"&gt;www.rolltidebama.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.automotivecad.co.uk/"&gt;www.automotivecad.co.uk/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.titancomics.com"&gt;www.titancomics.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.breakfastclub80.com/"&gt;www.breakfastclub80.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.arowanaclub.com/"&gt;www.arowanaclub.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.parachuteschool.com/"&gt;www.parachuteschool.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.kraft.com.au/"&gt;www.kraft.com.au/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.insuranceoffice.com/"&gt;www.insuranceoffice.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.sbpolo.com/"&gt;www.sbpolo.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.jlg.com/jlg/products/product-center.html"&gt;www.jlg.com/jlg/products/product-center.html&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.whmis.net/"&gt;www.whmis.net/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.theharleystreetclinic.com/"&gt;www.theharleystreetclinic.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.rimatravel.co.uk/"&gt;www.rimatravel.co.uk/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.uppercaperealty.com/"&gt;www.uppercaperealty.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.cranecare.ltd.uk/"&gt;www.cranecare.ltd.uk/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.hostingpartners.co.uk/"&gt;www.hostingpartners.co.uk/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.jawfixer.com/"&gt;www.jawfixer.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.telemoneyworld.com/"&gt;www.telemoneyworld.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.minaret.vic.edu.au"&gt;www.minaret.vic.edu.au&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.houstontexaslaw.com/"&gt;www.houstontexaslaw.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.noisepop.com/2003/"&gt;www.noisepop.com/2003/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.crosswind.ms/"&gt;www.crosswind.ms/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.sweethomestexas.com/"&gt;www.sweethomestexas.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.kahaku.go.jp/"&gt;www.kahaku.go.jp/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.keyualcohol.com/"&gt;www.keyualcohol.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.sdb.com"&gt;www.sdb.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.fgcswim.org/"&gt;www.fgcswim.org/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.quesnelcurlingclub.com/"&gt;www.quesnelcurlingclub.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.eggsolutions.ca/"&gt;www.eggsolutions.ca/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.msmedia.com.au"&gt;www.msmedia.com.au&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.revesbypress.com.au/"&gt;www.revesbypress.com.au/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.strategicevents.com/"&gt;www.strategicevents.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.anabenitez.com/"&gt;www.anabenitez.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.ldai.com"&gt;www.ldai.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.c21capital.ca/"&gt;www.c21capital.ca/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.olympic.si/"&gt;www.olympic.si/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.mma.org.my/"&gt;www.mma.org.my/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.markspencer.com/"&gt;www.markspencer.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.tdfund.com/"&gt;www.tdfund.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.residence-hotel.com/"&gt;www.residence-hotel.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.loanguy.com/"&gt;www.loanguy.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.middletonmann.freeserve.co.uk/"&gt;www.middletonmann.freeserve.co.uk/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.dallashomesales.com/"&gt;www.dallashomesales.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.firstcolorado.com"&gt;www.firstcolorado.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.predatorsoftheheart.com/"&gt;www.predatorsoftheheart.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.adtechintl.com/"&gt;www.adtechintl.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.bleibtreu.com/"&gt;www.bleibtreu.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.kurt-darla.com/"&gt;www.kurt-darla.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.dreamkitchens.com"&gt;www.dreamkitchens.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.artsaloft.com"&gt;www.artsaloft.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.Theoakridgeschool.org/"&gt;www.Theoakridgeschool.org/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.maharashtratourism.gov.in/"&gt;www.maharashtratourism.gov.in/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.lampson.com/"&gt;www.lampson.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.token.com.tw/"&gt;www.token.com.tw/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.panoptic-online.com/"&gt;www.panoptic-online.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.cbpacific.com/"&gt;www.cbpacific.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.stricklandchevrolet.com"&gt;www.stricklandchevrolet.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.jamesnewhouselaw.com/"&gt;www.jamesnewhouselaw.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.vlada.hr/"&gt;www.vlada.hr/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.calc.com/"&gt;www.calc.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.mustakbil.com/"&gt;www.mustakbil.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://southwestutahfilm.com/"&gt;southwestutahfilm.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.sackville.com"&gt;www.sackville.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.bonbonniere.nl/"&gt;www.bonbonniere.nl/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.lizzydesign.com/"&gt;www.lizzydesign.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.ambientjobs.com/"&gt;www.ambientjobs.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.nola.com/lsu/"&gt;www.nola.com/lsu/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.greenbergchiropractic.com"&gt;www.greenbergchiropractic.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.donsphoto.com"&gt;www.donsphoto.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://sports.espn.go.com/ncf/clubhouse?teamId=324"&gt;sports.espn.go.com/ncf/clubhouse?teamId=324&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.dangleterrehotel.com/"&gt;www.dangleterrehotel.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.mcsellshomes.com/"&gt;www.mcsellshomes.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.driversity.com/"&gt;www.driversity.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.gbm.net/"&gt;www.gbm.net/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.ingraham.net"&gt;www.ingraham.net&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.bib-aveiro.rcts.pt"&gt;www.bib-aveiro.rcts.pt&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.carlos-restaurant.com/"&gt;www.carlos-restaurant.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://sanbruno.ca.gov/"&gt;sanbruno.ca.gov/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.tufts.edu/as/astronomy/"&gt;www.tufts.edu/as/astronomy/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.ci.superior.wi.us/"&gt;www.ci.superior.wi.us/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.mitchellrepublic.com/"&gt;www.mitchellrepublic.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.utcc.ac.th/amsar/about/document24.htm"&gt;www.utcc.ac.th/amsar/about/document24.htm&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.nonchalance.org/"&gt;www.nonchalance.org/&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.pelicancruiser.com/"&gt;www.pelicancruiser.com&lt;/a&gt;]&lt;br /&gt;+--[&lt;a href="http://www.rayhana.com/"&gt;www.rayhana.com&lt;/a&gt;]&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With 179 vs. 7 hits, obviously one must conclude that, at present time at least, having Flash support in the browser matters a great deal more to an average user than having Java support does.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-345765510205152768?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/345765510205152768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=345765510205152768' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/345765510205152768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/345765510205152768'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/08/myth-java-widely-used-on-web.html' title='Myth: Java widely used in the browser'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-5752355534852370097</id><published>2008-08-23T01:47:00.001+02:00</published><updated>2010-05-15T17:20:40.821+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>NetBeans on speed</title><content type='html'>In &lt;a href="http://coffeecokeandcode.blogspot.com/2008/08/netbeans-pretty-much-unusable.html"&gt;the post from yesterday&lt;/a&gt; I was a little harsh regarding the performance of recent NetBeans versions, which seems to have taken a toll for the worse. One of the most annoying things is how much scanning and processing is going on all the time which harms responsiveness and the overall user experience. The NetBeans mailing list yielded responses like "more features requires more work" which is fair enough. However, I decided I wanted to have my cake (speed) and eat it too (features).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Memory mapping to the rescue&lt;/span&gt;&lt;br /&gt;It's not exactly new. So called "RAM drives" have been used for ages to speed things up, some Linux distro's even mount the temporary files location into RAM to improve performance. We can do the same to our source checkouts to gain massive increase in throughput as well as access time. There are two easy ways to archive this out of the (Linux) box, mount a dedicated &lt;a href="http://en.wikipedia.org/wiki/Sysfs"&gt;RAM drive&lt;/a&gt; or use the &lt;a href="http://en.wikipedia.org/wiki/TMPFS"&gt;TMPFS filesystem&lt;/a&gt;. Sorry, Windows users will have to &lt;a href="http://www.ramdisk.tk/"&gt;look elsewhere&lt;/a&gt; for info about how to set up a RAM drive.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;RAM drive&lt;/span&gt;&lt;br /&gt;In this approach, you allocate a part of the memory and map it to a mount point. The following will create a 64MB RAM disk and let you access it under /media/ramdisk/:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;dd if=/dev/zero of=/dev/ram1 bs=4096 count=16k&lt;br /&gt;mke2fs /dev/ram1&lt;br /&gt;mkdir /media/ramdisk&lt;br /&gt;mount /dev/ram1 /media/ramdisk&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It turns out that the kernel decides how much memory you can mount like this, on Ubuntu 8.04 the limit is 64MB. You can however change this to your liking by adding a kernel option before it loads:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ramdisk_size=&lt;size in="" kb=""&gt; XX&lt;br /&gt;&lt;br /&gt;&lt;/size&gt;&lt;/pre&gt;&lt;br /&gt;Note however that while you can unmount these again, the physical memory it occupied will not be released to the system. Another limitation of this approach is that whether you need it or not, the RAM disk will permanently occupy whatever you allocated to it - no more and no less. So you should probably only use this approach if you need a small RAM drive or you are just testing the technique out. The only benefit of this approach I can think of, is that your mounted partition will be listed and can be monitored from the system monitor.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Temporary filesystem&lt;/span&gt;&lt;br /&gt;TMPFS is rather different than the traditional block oriented RAM disk. It turns out it's actually even easier to deal with, just try this:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;mkdir /media/ramdisk&lt;br /&gt;mount tmpfs /media/ramdisk -t tmpfs&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Not only is it easier, it's much more flexible. As you no doubt noticed, we did not actually specify any capacity. TMPFS will use half of your RAM as default. Although you can also specify it directly, there's really no need to since TMPFS is not only able to dynamically decrease but also increase its capacity on demand. This means that if you do not use the partition, you won't pay any memory penalty. Apparently TMPFS is even able to use swap file so that IF you should go overboard in space consumption, you won't suffer loss of data or the like.&lt;br /&gt;&lt;br /&gt;You can have your system automatically create and mount a TMPFS partition for you, by modifying your /etc/fstab file. Simply add the following to it:&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;none /media/ramdisk tmpfs defaults,user,size=1G,mode=0777 0 0&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now I don't actually want to run into scenarios where my system has to start using virtual memory, so I limited the size of the temporary partition to 1GB, that leaves me with at least 3GB for the OS and applications.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Applied to a NetBeans project&lt;/span&gt;&lt;br /&gt;It's rather hard to measure and express something as subjective as responsiveness and general feeling of an IDE with and without a RAM drive. Suffices to say it feels like it's running at a blazing speed! Nodes expand at once, tabs activate immediately and it's just an overall impressive experience - it feels like you're back to writing C code rather than Java. Let me try and prove this to you the best I can with just static images. The below screen shots both show the result of running the same simple Ant build target on a small NetBeans module project, first on a normal disk drive and then from of a RAM drive.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_CauKCPUdin4/SLIQaAizx7I/AAAAAAAAABw/xX2EpOsB-Go/s1600-h/Screenshot-SuppressWarningsCompletionLexer+-+NetBeans+IDE+6.5+Beta-1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_CauKCPUdin4/SLIQaAizx7I/AAAAAAAAABw/xX2EpOsB-Go/s400/Screenshot-SuppressWarningsCompletionLexer+-+NetBeans+IDE+6.5+Beta-1.png" alt="" id="BLOGGER_PHOTO_ID_5238267355593951154" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;It took 10 sec to build on my &lt;a href="http://www.westerndigital.com/en/products/products.asp?driveid=459"&gt;10.000rpm VelociRaptor&lt;/a&gt; disc, the fastest desktop drive available today. An average disc would require around 12-13 sec I suspect.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CauKCPUdin4/SLIQmL0gI9I/AAAAAAAAAB4/JFeJhwHMcpI/s1600-h/Screenshot-SuppressWarningsCompletionLexer+-+NetBeans+IDE+6.5+Beta.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_CauKCPUdin4/SLIQmL0gI9I/AAAAAAAAAB4/JFeJhwHMcpI/s400/Screenshot-SuppressWarningsCompletionLexer+-+NetBeans+IDE+6.5+Beta.png" alt="" id="BLOGGER_PHOTO_ID_5238267564779381714" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Running from of the RAM drive it took just 1 sec, an amazing 10x faster. It's the kind of thing you have to see in order to believe.&lt;br /&gt;&lt;br /&gt;I also tried placing NetBeans itself as well as its user directory directly on the RAM drive, but without noticeable difference at run time. It did start up 40-50% faster and became responsive right away, but this is probably not an optimization worth going for.&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Applied in practice&lt;/span&gt;&lt;br /&gt;So there you have it. No magic involved, all you need is enough RAM which is dirt cheap* and some consistent working habits. You do have to manually copy your project onto the RAM drive as well as remember to move it to a non-volatile partition before you shut your computer down. However given the fact that we usually always work out of CVS/SVN/HG this should not be much of an issue, in fact you could claim it encourages &lt;a href="http://www.codinghorror.com/blog/archives/001134.html"&gt;healthier check-in habits&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;As a cautionary measure though, I have invested in a cheap UPS in case of power loss and when I shut down my system, a script will automatically copy the content of the RAM drive to a persistent backup partition. For convenience, when I start up, another script will automatically copy the most recent backup back onto to the RAM drive. Thus, rather than having to do a full checkout/clone in the morning, I only have to issue an update. If you really wanted to minimize risks, you could also have a timed cron job or a low-priority synchronization deamon running.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;In conclusion&lt;/span&gt;&lt;br /&gt;Of course, this technique really doesn't have anything to do with NetBeans per se, so any IDE would benefit from it as well as freeform/Ant/Maven projects. If you feel uneasy about working entirely in volatile memory, I suppose it would be possible to simply modify your build scripts such that only the build artifacts are emitted this way, leaving the actual source code intact on a fully journaled non-volatile file system.&lt;br /&gt;&lt;br /&gt;I had fun setting this up, though I am somewhat surprised of how I/O-bound NetBeans appears to be. In a related exercise with Visual Studio and C# a few years back I did not experience anywhere near this speed-up, possibly because the compiler and tool chain is multi-threaded unlike javac and Ant.&lt;br /&gt;So go ahead and give it a try, you might like it too. I obviously take no responsibility for whatever data loss you may experience yada yada. You have been warned!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update:&lt;/span&gt;&lt;br /&gt;Someone asked me how to put the automatic copy mechanism I mentioned above into effect. We are going to need 2 scripts as well as installing these at the appropriate life cycle hooks of Linux. In the following I assume you have created a directory at /ramdisk_archives with root access permissions only and that you are using a Debian derived distro.&lt;br /&gt;&lt;br /&gt;Put the below script in a file called ramdisk_to_archive.sh, give it execute rights (chmod +x ramdisk_to_archive.sh) and save it under the /etc/init.d/ directory which is usually where service scripts are put.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;#/etc/init.d/ramdisk_to_archive.sh&lt;br /&gt;a=$(date +%T-%d-%m-%Y)&lt;br /&gt;&lt;br /&gt;mkdir /ramdisk_archives/$a&lt;br /&gt;cp -i -p -R /media/ramdisk/* /ramdisk_archives/$a&lt;br /&gt;rm /ramdisk_archives/latest&lt;br /&gt;ln -s /ramdisk_archives/$a /ramdisk_archives/latest&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This script will create a new subdirectory under /ramdisk_archives based on the current timestamp  and copy all content of the RAM disk (with file permissions intact), to this newly created folder. Then it will delete any eventual existing link called latest and finally, it will create this new link again and point to the directory we just created. Finally, you need to install it so it runs at system halt (runlevel 0) as well as reboot (runlevel 6) which you can do by typing this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;ln -s /etc/init.d/ramdisk_to_archive.sh /etc/rc0.d/ramdisk_to_archive.sh&lt;br /&gt;ln -s /etc/init.d/ramdisk_to_archive.sh /etc/rc6.d/ramdisk_to_archive.sh&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next time you reboot or shut down your system, the script above will be run, thus saving the content of the RAM disk onto /ramdisk_archives/ somewhere. Now, to have your RAM disk restored again at boot time, write another script:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;#/etc/init.d/ramdisk_to_archive.sh&lt;br /&gt;cp -i -p -R /ramdisk_archives/latest/* /media/ramdisk/&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Again, remember to give it execute permission and copy it to the services directory like the prior script. This time we're going to hook into all the other remaining runlevels 2-5. To do this, issue the following command:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #000000; color: #ffffff;"&gt;&lt;br /&gt;update-rc.d /etc/init.d/ramdisk_to_archive.sh defaults&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's it. Remember to clean up the /ramdisk_archive folder from time to time as there's no purge or rotation scheme in place. You are of course free to add this yourself, if you do, drop me a line. :)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;*You can have 4GB DDR2 for less than US$ 100. Even older consumer motherboards supports 4GB, newer ones 16-32GB.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-5752355534852370097?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/5752355534852370097/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=5752355534852370097' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/5752355534852370097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/5752355534852370097'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/08/netbeans-on-speed.html' title='NetBeans on speed'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_CauKCPUdin4/SLIQaAizx7I/AAAAAAAAABw/xX2EpOsB-Go/s72-c/Screenshot-SuppressWarningsCompletionLexer+-+NetBeans+IDE+6.5+Beta-1.png' height='72' width='72'/><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-7738029576761982448</id><published>2008-08-20T04:23:00.000+02:00</published><updated>2008-08-27T21:27:55.624+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Venting'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>NetBeans: Pretty Much Unusable</title><content type='html'>&lt;span style="font-weight: bold;"&gt;NetBeans Pretty Much Unusable&lt;br /&gt;&lt;/span&gt;If you care about NetBeans and its performance, an interesting development occurred over the last 24h on the nbusers mailinglist. It seems the upcoming 6.5 release sparked a debate claiming that it's &lt;a href="http://markmail.org/search/?q=Pretty+Much+Unusable&amp;amp;q=list%3Aorg.netbeans.nbusers"&gt;pretty much unusable&lt;/a&gt;. While I wouldn't go that far, there is actually some truth to the matter as experienced by my colleagues and I.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;A little bit of history&lt;/span&gt;&lt;br /&gt;I've been back and forth between various IDE's over the years, coming from Visual Studio (VB/C/C#) I've been rather spoiled in regard to syntax highlighting, code completion and debugging. In fact I remember back in 2001 how I was convinced into doing a college project in Java, primarily because of the assistance offered by Visual Studio J++. At that time, no tool provided these kind of features (although Forte and JBuilder tried). &lt;br /&gt;In this day and age, things looks quite different of course. SUN finally realized that it's worth having great tools (some would argue they have to solve the problems at the tooling level, since &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=221903"&gt;the language has effectively gone stale&lt;/a&gt;). In any event, todays Java developers can rely on pretty much the same features as Visual Studio. However, for this there still is a price to pay.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The paradox of choice&lt;/span&gt;&lt;br /&gt;Having choices is generally a positive thing. But when it comes to software, having too many choices quickly becomes a burden - &lt;a href="http://video.google.com/videoplay?docid=6127548813950043200&amp;amp;hl=en"&gt;less is sometimes more&lt;/a&gt;. The problem with having multiple IDE's is that, apart from handling of java source files, they aren't really compatible. They all use each their own build system, supports different layout managers etc. so in reality you can't just switch from one IDE to the other. Given the love for committees in the Java space, I do not understand why a project standard was never established through a JSR. In light of this, it becomes rather important you and your project team settle on one IDE that hopefully satisfies everyone.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;We chose NetBeans&lt;/span&gt;&lt;br /&gt;After initially having used Oracle's JDeveloper for a number of years, we got fed up with the complex stack that Oracle pushed, as well as the semi-yearly releases. We had to live with bugs for a very long time and newer versions of the IDE could never really cope with migrating from the existing code base.&lt;br /&gt;We chose NetBeans 5.5 after having had some success with Swing UI work (Matisse) as well as noticing how SUN were pushing for standards as well as de-facto standards such as Ant etc. Swing now also seemed to be better able to deliver a UI experience where you did not curse constantly at the lack of responsiveness or mismatched L&amp;amp;F. The best part of NetBeans is probably how we constantly get new versions (release, beta, milestone or daily) as well as the plugin community around it. However, not everything is rosy.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Why we might not stay&lt;/span&gt;&lt;br /&gt;Since SUN decided to focus their attention on a polyglot of languages, performance seems to be hurting. Java and Swing always felt slow and overly complex to me... but that's subject for another blog post. In NetBeans 6.0 it really did get worse though. Often you would experience lag as you were typing, clicking tab or invoking a menu. It may very well only be 200-300ms but it is enough to be perceived as annoying. I believe it was in 6.1 where they introduced massive Action lazy-loading, with the end result that after NetBeans had started, the whole UI was effectively still &lt;a href="http://www.netbeans.org/issues/show_bug.cgi?id=144426"&gt;unusable for 3-5 seconds&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Having tried 6.5 beta, I can't say I've experienced the gain in speed the new &lt;a href="http://wiki.netbeans.org/CompileOnSave"&gt;compile-on-save&lt;/a&gt; feature promised. Instead, NetBeans feels* even more busy and hence, less responsive to what I am actually trying having it do. I hope this will be sorted out because otherwise I might be compelled to try and move on to Eclipse or IntelliJ. The former always did run fast and smooth but I never really committed to it fully. The latter I have absolutely no idea about, except I keep hearing it's the best.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Is there a point to this?&lt;/span&gt;&lt;br /&gt;No not really, apart from documenting the dilemma of choice and warn about the negative developing performance trend of NetBeans. I love NetBeans and the potential I've seen over the last year but productivity comes first. For SUN's sake I hope it will all be resolved, seeing as NetBeans 6.5 is now in beta 2, I doubt it will happen in the 6.5 time frame though.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;*I should probably note that I by no means rely on slow hardware (Core II 2.66GHz/4GB Ram/10.000rpm HD) nor outdated software (Ubuntu 8.04 64bit with Sun's Java6u10rc JDK).&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-7738029576761982448?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/7738029576761982448/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=7738029576761982448' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/7738029576761982448'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/7738029576761982448'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/08/netbeans-pretty-much-unusable.html' title='NetBeans: Pretty Much Unusable'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-7451562114422449401</id><published>2008-08-15T03:28:00.000+02:00</published><updated>2008-09-04T18:38:41.094+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='JSF'/><title type='text'>JSF and binary content</title><content type='html'>So I have been learning JSF and JPA at work recently. While I can't say those are the most exciting technologies to me, at least they appear to be (or become) de-facto standards and that means more leverage over the long term (something not always the case when dealing with Java technologies). Using JSF with Facelets can be a little challenging, the tools are only so-so and frankly it bugs me to have to type so much type-unsafe stuff in XML, EL and annotations. Anyway, what this blog entry is about is how you can bridge the gab between JSF page rendering and binary content delivery.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;JSF and PDF&lt;/span&gt;&lt;br /&gt;Corporate applications often need to deliver a lot of PDF content, and it is no different where I work. Static PDF documents as well as dynamic ones. Even if frames and iframes are generally frowned upon these days, I find then to be the best way to embed PDF documents inside the browser. However, with JSF you can't just make an xhtml page and expect to be able to stream binary content from it, since the HTTP protocol only allows you to send the header once. Indeed, JSF contains assertions to try and catch this and will complain:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:Monospaced,monospace;" &gt;&lt;br /&gt;java.lang.IllegalStateException: getWriter() has already been called for this response&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You can always use an ActionListener or even an accessor on the backing bean if you just want a link to download a PDF, but embedding one inside a frame or iframe is an entirely different matter. I tried many things, most of them felt like fragile hacks. I will now present the best solution in my opinion, it's generic, it's KISS and it solves the problem.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;Back to basics: HttpServlet&lt;/span&gt;&lt;br /&gt;It turns out that it is possible, inside a processRequest method of a vanilla HttpServlet, to access session scoped backing beans. This means we just need some way of telling the Servlet about where it can uptain the binary data from and various other meta-data. So I came up with the following simple "API" using HTTP GET parameters:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:Monospaced,monospace;" &gt;&lt;br /&gt;ServletName?BackingBeanName.MethodName[;ContentType][;FileName]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The Servlet then has to do the following:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Parse and validate parameters&lt;/li&gt;&lt;li&gt;Locate the specified backing bean and call the method to uptain the binary content&lt;/li&gt;&lt;li&gt;Stream the result back to the browser using the specified parameters&lt;/li&gt;&lt;/ol&gt;The complete source code for the Java Servlet that perform this job, you can &lt;a href="http://82.103.135.236/BinaryJSFServlet.java.html"&gt;get here&lt;/a&gt;. To use it, you would add it to your web.xml configuration and then simply call it from your JSF or Facelet files like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:Monospaced,monospace;" &gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;&amp;lt;iframe&lt;/span&gt; &lt;span style="color: rgb(0, 153, 0);"&gt;name&lt;/span&gt; ="frame" &lt;span style="color: rgb(0, 153, 0);"&gt;scrolling&lt;/span&gt;="auto" &lt;span style="color: rgb(0, 153, 0);"&gt;align&lt;/span&gt;="center"&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;src&lt;/span&gt;="BinaryJSFServlet?myBackingBean.createPDF;application/pdf" &lt;span style="color: rgb(0, 153, 0);"&gt;width&lt;/span&gt;="100%" &lt;span style="color: rgb(0, 153, 0);"&gt;height&lt;/span&gt;="700" &lt;span style="color: rgb(0, 0, 230);"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;&amp;lt;/iframe&lt;/span&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This way, you can still keep your state and logic in the backing beans without having to mess around with JavaScript, ActionListeners or PhaseListeners. Just generate your URL in the *.jsp or *.xhtml file such that it specifies a backing bean, a method name to invoke as well as optional MIME type and file name.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update:&lt;/span&gt;&lt;br /&gt;Tim Boudreau &lt;a href="http://weblogs.java.net/blog/timboudreau/archive/2008/08/objects_not_str.html"&gt;mentions a cool technique&lt;/a&gt; the code above could make good use of, by relying on a general key/value parser based on dynamic proxies.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-7451562114422449401?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/7451562114422449401/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=7451562114422449401' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/7451562114422449401'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/7451562114422449401'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/08/jsf-and-binary-content.html' title='JSF and binary content'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-6435194489633962780</id><published>2008-07-01T21:55:00.000+02:00</published><updated>2008-08-25T14:28:28.754+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Venting'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>The Enum is perfect... well almost.</title><content type='html'>Ok so its time to admit to something. I'm deeply in love with Java's Enum! In my opinion it was the best part of Java 5 and I still wonder why it took Sun 10 years to add this powerful static modeling construct.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;The power of the Enum&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;Although there certainly are known limitations of the Enum, i.e. how &lt;a href="http://freddy33.blogspot.com/2007/05/why-java-enum-cannot-extends.html"&gt;you can't extend it&lt;/a&gt;, I have never run into a practical limitation myself. Until now that is. The issue I want to raise is that of Enum forward referencing&lt;span style="font-weight: bold;"&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;The great &lt;a href="http://www.codinghorror.com/blog/archives/001143.html"&gt;Alan Turing&lt;/a&gt; taught us that at the end of the day, everything can be modeled by a Turing Machine and finite automata. We may not often consciously operate at this level, but many things still makes sense to model this way being it a regular expression matcher, navigation rules or similar. The Java Enum appears to be a perfectly simple, fast and type-safe way of modeling this... or does it?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;State machine with an Enum&lt;/span&gt;&lt;br /&gt;Since the Java Enum effectively is just a group of static class instances, it allows us to attach methods and state to each static instance. We should be able to use this fact to express a transitive relationship with outself. To model a CD player, we'd write something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:Monospaced,monospace;" &gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0, 0, 230);"&gt;enum&lt;/span&gt; PlayerState {&lt;br /&gt;   STOPPED(PlayerState.PLAYING),&lt;br /&gt;   PLAYING(PlayerState.STOPPED, PlayerState.PAUSED),&lt;br /&gt;   PAUSED(PlayerState.PLAYING, PlayerState.STOPPED);&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;    private&lt;/span&gt; &lt;span style="color: rgb(0, 0, 230);"&gt;final&lt;/span&gt; EnumSet&amp;lt;PlayerState&gt; transitions;&lt;br /&gt;&lt;br /&gt;   PlayerState(&lt;span style="color: rgb(0, 0, 230);"&gt;final&lt;/span&gt; PlayerState... transitions){&lt;br /&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;        this&lt;/span&gt;.transitions = EnumSet.copyOf( Arrays.asList(transitions));&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(150, 150, 150);"&gt;    // State transition and query logic below...&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Except that won't compile! The compiler complains with an "illegal forward reference" error. I can understand why it's the easiest to simply not allow this circular use case, but considering everything else in Java allows forward referencing (i.e. we don't need header files as in C++) it would've been nice if that was the case with Enum's too. &lt;/span&gt;&lt;span style="font-size:100%;"&gt;The &lt;a href="http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9"&gt;JLS&lt;/a&gt; simply states: &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-size:100%;"&gt;"&lt;/span&gt;It is a compile-time error for the constructors, instance initializer blocks, or instance variable initializer expressions of an enum constant &lt;i&gt;e&lt;/i&gt; to refer to itself or to an enum constant of the same type that is declared to the right of &lt;i&gt;e"&lt;/i&gt;&lt;/blockquote&gt;&lt;span style="font-size:100%;"&gt;Granted, it has been some years since my last compiler course but I can't see any reason not to allow forward referencing in this particular case where everything is known. &lt;/span&gt;&lt;span style="font-size:100%;"&gt;I suspect the culprit simply being that Enum, as with so many other things, was added later using only existing features such as not to change existing initialization rules of the JVM.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-6435194489633962780?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/6435194489633962780/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=6435194489633962780' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/6435194489633962780'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/6435194489633962780'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/07/enum-is-perfect-well-almost.html' title='The Enum is perfect... well almost.'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-2909150261026977980</id><published>2008-05-14T19:57:00.000+02:00</published><updated>2008-08-20T22:54:28.816+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Plugin'/><category scheme='http://www.blogger.com/atom/ns#' term='NetBeans'/><title type='text'>NetBeans plugin: Special copy/paste</title><content type='html'>The very little I've had to paste code into this fairly new blog, was enough to give me the idea of creating an extension to NetBeans which would help to remedy this formatting nightmare. Now, in my world, there's approximately a 100:1 ratio between idea and actual realization, so I'd have to salute the awesome OpenIDE API's for making this possible spending just a few late nights and taking just 200 lines of code. Without further ado, I present, &lt;a href="http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=9275"&gt;my first NetBeans plugin&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Special copy/paste&lt;/span&gt;&lt;br /&gt;The plugin will add a couple of new actions to the context-sensitive popup-menu of the source editor, which will allow you to copy the selected text as preformatted HTML, as well as a CSS version which will preserve the formatting used in NetBeans.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_CauKCPUdin4/SCsziZa77hI/AAAAAAAAAA4/DkFr2AMvQDc/s1600-h/special-copy-paste-436x408.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_CauKCPUdin4/SCsziZa77hI/AAAAAAAAAA4/DkFr2AMvQDc/s400/special-copy-paste-436x408.png" alt="" id="BLOGGER_PHOTO_ID_5200306860761804306" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Using the "Copy as HTML and CSS" menu as in the above screen dump will result in you being able to paste it directly into a website/wiki/blog and have it display like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(0, 0, 0);font-family:Monospaced,monospace;" &gt;&lt;br /&gt;&lt;span style="color: rgb(150, 150, 150);"&gt;    /**&lt;br /&gt;    * @param args the command line arguments&lt;br /&gt;    */&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;    public&lt;/span&gt; &lt;span style="color: rgb(0, 0, 230);"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0, 0, 230);"&gt;void&lt;/span&gt; main(String[] args) {&lt;br /&gt;&lt;span style="color: rgb(150, 150, 150);"&gt;      // TODO code application logic here&lt;br /&gt;&lt;/span&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For a larger example of what the output of the plugin looks like, take a look at the plugin's &lt;a href="http://docs.google.com/Doc?id=dfkvb9sc_1cqps4hdb"&gt;own source code&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It's supposed to be language agnostic, in that it should work with all types of sources NetBeans is able to tokenize. The plugin will try to mimic the formatting of the tokens in regard to font family, keyword and literal colors. It will however *not* be able to show member-wide variables in green as NetBeans does nor show method and class decelerations in bold. This is a limitation caused by the fact that I am only using the NetBeans lexer API rather than doing any kind of semantic analysis or parsing.&lt;br /&gt;&lt;br /&gt;If you want to give the plugin a try, download it from &lt;a href="http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=9275"&gt;NetBean's Plugin Portal&lt;/a&gt;. Source code is available &lt;a href="http://82.103.135.236/NBSpecialCopyPaste.zip"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Update:&lt;/span&gt;&lt;br /&gt;It has been made clear to me through the comments, that NetBeans already contains functionality to extract source code as HTML. You can find the feature in the "File" menu under the ill named item "Print to HTML". Since it would appear other people than just me did not associate "print" with that of exporting HTML content, I have &lt;a href="http://www.netbeans.org/issues/show_bug.cgi?id=144501"&gt;filed an issue&lt;/a&gt; for the relocation and/or renaming of this.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-2909150261026977980?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/2909150261026977980/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=2909150261026977980' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/2909150261026977980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/2909150261026977980'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/05/special-copypaste.html' title='NetBeans plugin: Special copy/paste'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_CauKCPUdin4/SCsziZa77hI/AAAAAAAAAA4/DkFr2AMvQDc/s72-c/special-copy-paste-436x408.png' height='72' width='72'/><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-2833738183615302208</id><published>2008-05-09T20:44:00.000+02:00</published><updated>2009-05-17T18:06:04.167+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Coffee'/><title type='text'>Keurig Platinum B70</title><content type='html'>Time to try to live more up to the name of this blog. As most developers, I have a passion for coffee and coke and consume it in quantities which are probably not on the healthy side. Anyway, when I saw the &lt;a href="http://www.keurig.com/b70.asp"&gt;Keurig Platinum B70&lt;/a&gt; coffee maker in action, I absolutely had to own one. Why? Take a look below.&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="350"&gt; &lt;param name="movie" value="http://www.youtube.com/v/P-Q0XsdU1kw"&gt; &lt;/param&gt; &lt;embed src="http://www.youtube.com/v/P-Q0XsdU1kw" type="application/x-shockwave-flash" width="425" height="350"&gt; &lt;/embed&gt; &lt;/object&gt;&lt;br /&gt;&lt;br /&gt;Yup, it takes 45 sec. for it to brew a large cup (4 sizes to choose from) of fresh programmer oil, has a very gadgety blue light and is ready to serve its master 24/7. It probably isn't the most economical way to get your caffeine dose, but it does allow for a small filter so that you can use normal coffee beans rather than the convenient K-cups. Also, it came with samples of Van Houtte's Kenyan &lt;a href="http://www.amazon.com/Keurig-Houtte-Kenya-Kilimanjaro-K-Cups/dp/B000QGKDT6"&gt;Kilimandjaro roast&lt;/a&gt;, so now I know why &lt;a href="http://www.jroller.com/scolebourne/"&gt;Stephen Colebourne&lt;/a&gt; named his OpenJDK sandbox &lt;a href="https://kijaro.dev.java.net/"&gt;Kijaro&lt;/a&gt;. ;)&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-2833738183615302208?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/2833738183615302208/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=2833738183615302208' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/2833738183615302208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/2833738183615302208'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/05/keurig-b70-platinum.html' title='Keurig Platinum B70'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-8624578533676704314</id><published>2008-05-07T21:30:00.000+02:00</published><updated>2008-11-07T03:45:18.814+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Type registry strategy pattern</title><content type='html'>One pattern that I have often seen applied in Java, is the one where you plug-in and register a handler for a given type of object to thereby supply a specific behavior for it. For instance, this is often used in order to render, edit and validate elements of various visual components in Swing, such as the JTable. I am unaware of any official name for this mechanism, but it appears to be a combination of Martin Fowlers &lt;a href="http://martinfowler.com/eaaCatalog/registry.html"&gt;Registry Pattern&lt;/a&gt; and the GoF &lt;a href="http://en.wikipedia.org/wiki/Strategy_pattern"&gt;Strategy pattern&lt;/a&gt; so I like to think of it as the Type registry strategy pattern.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Legacy example&lt;/span&gt;&lt;br /&gt;Conditional behavior is encapsulated by some common interface, which provides the mechanism for dispatching to elsewhere, responsible for applying a concrete strategy. An example is this format handler, which allows an object to be formatted as a String:&lt;br /&gt;&lt;span style="font-size:85%;font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;1  interface Handler&lt;br /&gt;2  {&lt;br /&gt;3      String format(Object object);&lt;br /&gt;4  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;And an API, capable of associating handlers for various Object types registered and dispatching to these:&lt;br /&gt;&lt;span style="font-size:85%;font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;5  class SomeAPI&lt;br /&gt;6  {&lt;br /&gt;7      Map handlers = new HashMap();&lt;br /&gt;8&lt;br /&gt;9      public void installHandler(Class clazz, Handler handler)&lt;br /&gt;10     {&lt;br /&gt;11         handlers.put(clazz, handler);&lt;br /&gt;12     }&lt;br /&gt;13&lt;br /&gt;14     public String format(Object obj)&lt;br /&gt;15     {&lt;br /&gt;16         Handler handler = (Handler)handlers.get( obj.getClass() ); &lt;br /&gt;17         if(handler != null)&lt;br /&gt;18             return handlers.format( obj );&lt;br /&gt;19         else&lt;br /&gt;20             return obj.toString();&lt;br /&gt;19     }&lt;br /&gt;20 }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;This way, we can supply an API with an implementation (in the following example, an anonymous inner class) of formatting behavior for a given Object type, i.e. a Date:&lt;br /&gt;&lt;span style="font-size:85%;font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;21 someApiInstance.installHandler(Date.class, new Handler(){&lt;br /&gt;22     public String format(Object obj)&lt;br /&gt;23     {&lt;br /&gt;24         Date date = (Date)obj;&lt;br /&gt;25         return SimpleDateFormat.getInstance().format(date);&lt;br /&gt;26     }&lt;br /&gt;27 });&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;This works fine, but it's a little verbose and not particular type-safe. I wondered if I could device a generified version which improved on this. After all, we KNOW that the object passed is an instance of Date, we just need to convince Java of this as well.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Generified type strategy&lt;/span&gt;&lt;br /&gt;Like many others in the Java space, I am not super comfortable nor experienced with generifying methods and dealing with use-site covariance. So in order to work out the following, I got some much appreciated help from the usenet group comp.lang.java.help.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Take one&lt;/span&gt;&lt;br /&gt;First things first, the required changes to the callback interface is pretty obvious. We now simply declare our Handler to be of the type T, for which it has a format method accepting an instance of this type:&lt;br /&gt;&lt;span style="font-size:85%;font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;28 interface Handler&amp;lt;T&amp;gt;&lt;br /&gt;29 {&lt;br /&gt;30     String format(T object);&lt;br /&gt;31 }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Now comes the tricky part. We need to have the compiler able to infer the type we provide, that is, apply some wildcard capturing magic. Our map now maps unknown Class types to an unknown Handler type. The installHandler method makes use of this, and associates an unknown Class type with a Handler of type T. We capture the type of the Handler in the format method, by casting to any type that is a super type of T:&lt;br /&gt;&lt;span style="font-size:85%;font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;32 class SomeAPI&lt;br /&gt;33 {&lt;br /&gt;34     Map&amp;lt;Class&amp;lt;?&amp;gt;, Handler&amp;lt;?&amp;gt;&amp;gt; handlers = new HashMap&amp;lt;Class&amp;lt;?&amp;gt;, Handler&amp;lt;?&amp;gt;&amp;gt;(); &lt;br /&gt;35&lt;br /&gt;36     public &amp;lt;T&amp;gt; void installHandler(Class clazz&amp;lt;?&amp;gt;, Handler&amp;lt;T&amp;gt; handler&gt;)&lt;br /&gt;37     {&lt;br /&gt;38         handlers.put(clazz, handler);&lt;br /&gt;39     }&lt;br /&gt;40&lt;br /&gt;41     public &amp;lt;T&amp;gt; String format(T obj)&lt;br /&gt;42     {&lt;br /&gt;43         Handler handler&amp;lt;? super T&amp;gt; = getHandler(obj); &lt;br /&gt;44         if(handler != null)&lt;br /&gt;45             return handler.format( obj );&lt;br /&gt;46         else&lt;br /&gt;47             return obj.toString();&lt;br /&gt;48     }&lt;br /&gt;49&lt;br /&gt;50     @SuppressWarnings("unchecked")&lt;br /&gt;51     private &amp;lt;t&amp;gt; Handler&amp;lt;? super T&amp;gt; getHandler(T obj)&lt;br /&gt;52     {&lt;br /&gt;53         return (Handler&amp;lt;? super T&amp;gt;) handlers.get(obj.getClass());&lt;br /&gt;54     }&lt;br /&gt;55 }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;This allows the type to flow all the way out through the callback, such that we may implement it as follows:&lt;br /&gt;&lt;span style="font-size:85%;font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;56  someApiInstance.installHandler(Date.class, new Handler&amp;lt;Date&amp;gt;(){&lt;br /&gt;57         public String format(Date obj){&lt;br /&gt;58             return SimpleDateFormat.getInstance().format(obj);&lt;br /&gt;59         }&lt;br /&gt;60 }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Voila, no more casting needed. :)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Take two&lt;/span&gt;&lt;br /&gt;Now, the observant reader will notice that while we got rid of the casts, we still need to supply the type twice, once as class literal (the key of the internal map) and secondly as the type of the Handler (the value of the map). I was not sure if this could be done, given Java's generics by erasure. But it turns out that the type information actually is saved as meta-data, in order for reflection to still be possible:&lt;br /&gt;&lt;span style="font-size:85%;font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;61     public &amp;lt;T&amp;gt; void installHandler(Handler&amp;lt;T&amp;gt; handler) &lt;br /&gt;62     {&lt;br /&gt;63         callbacks.put(extractGenericType(handler), handler);&lt;br /&gt;64     }&lt;br /&gt;65&lt;br /&gt;66     private &amp;lt;T&amp;gt; Class&amp;lt;T&amp;gt; extractGenericType(Handler&amp;lt;T&amp;gt; handler)&lt;br /&gt;67     {&lt;br /&gt;68         Type[] interfaces = handler.getClass().getGenericInterfaces();&lt;br /&gt;69&lt;br /&gt;70         for(Type type:interfaces)&lt;br /&gt;71             if(type instanceof ParameterizedType)&lt;br /&gt;72                 return (Class&amp;lt;T&amp;gt;)&lt;br /&gt;                           ((ParameterizedType)type).getActualTypeArguments()[0];&lt;br /&gt;73&lt;br /&gt;74         throw new IllegalArgumentException ("You must supply a generified Handler&lt;br /&gt;                    with a single parameterized type");&lt;br /&gt;77     }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;It's not pretty and generally makes everything a bit more fragile, but it sure makes for a nice public API for your consumers:&lt;br /&gt;&lt;span style="font-size:85%;font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;78  someApiInstance.installHandler(new Handler&amp;lt;Date&amp;gt;(){&lt;br /&gt;79         public String format(Date obj){&lt;br /&gt;80             return SimpleDateFormat.getInstance().format(obj);&lt;br /&gt;81         }&lt;br /&gt;82 }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;The issue of erasure&lt;/span&gt;&lt;br /&gt;While the parameterized type of the Handler can be uptained through reflection, as shown in the previous example, it isn't actually available at the core of the type system. For a demonstration of this, imagine your consumer of SomeAPI tries to implement several formatters:&lt;br /&gt;&lt;span style="font-size:85%;font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;83 public class Formatter implements Handler&amp;lt;Date&amp;gt;, Handler&amp;lt;Calendar&amp;gt;&lt;br /&gt;84 {&lt;br /&gt;85     public String format(Date obj){&lt;br /&gt;86              return SimpleDateFormat.getInstance().format(obj); &lt;br /&gt;87     }&lt;br /&gt;88&lt;br /&gt;89     public String format(Calendar obj){&lt;br /&gt;90              return SimpleDateFormat.getInstance().format(obj.getTime()); &lt;br /&gt;91     }&lt;br /&gt;92 ...&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;This code won't compile, for the simple reason that during compilation, the parameterized types with Date and Calendar are lost and both resolve to the same Handler interface, and you are of course not allowed to implement the same interface twice (one of the reasons for why delegates exists in C#, but that's another story).&lt;br /&gt;&lt;br /&gt;I'll try to make more use of this type-safe way of applying composition to factor away centralized conditional complexity. And it should be interesting having it work together with the &lt;a href="http://java.sun.com/j2se/1.4.2/docs/guide/jar/jar.html#Service%20Provider"&gt;service provider pattern&lt;/a&gt;.&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;b&gt;Update&lt;/b&gt;&lt;br /&gt;It turns out there's a trick to get rid of the unchecked cast in the SomeAPI class. The trick is to use a dynamic cast to make up for a limitation in the Java type system and is mentioned in Joshua Bloch's Effective Java Second Edition, item 29.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-8624578533676704314?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/8624578533676704314/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=8624578533676704314' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/8624578533676704314'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/8624578533676704314'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/05/type-strategy-pattern.html' title='Type registry strategy pattern'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-8466966215354321925</id><published>2008-05-02T14:32:00.001+02:00</published><updated>2008-09-03T15:58:58.373+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>@SuppressWarnings values</title><content type='html'>Meta-data and how to associate it has always been a bit of a confusing topic in Java. For instance, the transient modifier is really a kind of marker annotation, as is the @deprecated javadoc tag compilers are also required to process, as is the marker interface Serializable. Then in JDK 1.5, a dedicated annotation facility was added, probably in light of the success of C#'s attributes. One of the first practical uses of annotations appears to be as a way to suppress compiler warnings.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;@SuppressWarnings&lt;/span&gt;&lt;br /&gt;This build-in annotation allows the developer to signal a respecting compiler that it should forgo a particular warning. It can be applied in front of a type, a field, a method, a parameter, a constructor as well as a local variable. It is up to the compiler to make sense of whatever you put inside the String, the only value mandated by the JLS is the "unchecked". Compilers as well as IDE's will typically implement each their own set of warning types, the Eclipse IDE defines far more of these than NetBeans does for instance.&lt;br /&gt;Here I will only cover the ones supported by the SUN compiler. To see the supported types, issue a "javac -X" command. On my JDK1.6.0_03 system I get:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-Xlint:{all,cast,deprecation,divzero,empty,unchecked,&lt;br /&gt;fallthrough,path,serial,finally,overrides}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Of those ones, "all", "empty", "path" and "overrides" doesn't seem to have any effect when using the SUN compiler or when used inside NetBeans. The following lists the remaining ones and how to use them.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;@SuppressWarnings("deprecation")&lt;/span&gt;&lt;br /&gt;Use this when you are deliberately using a deprecated method, realizing full well that your code might one day break, but you do not wish to be notified of this. In the following example, we use getYear of java.util.Date which has been deprecated:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;@SuppressWarnings(&lt;span style="color:#ce7b00;"&gt;&amp;quot;deprecation&amp;quot;&lt;/span&gt;)&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; suppressWarningsTest()&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;Date date = &lt;span style="color:#0000e6;"&gt;new&lt;/span&gt; Date();&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;int&lt;/span&gt; year = date.getYear();&lt;span style="color:#000000;"&gt;&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Without suppressing the warning, the compiler (if invoked with -Xlint:deprecation) would've complained:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;warning: [deprecation] getYear() in java.util.Date has been deprecated&lt;br /&gt;       int year = date.getYear();&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;@SuppressWarnings("unchecked")&lt;/span&gt;&lt;br /&gt;Java 1.5 brought a crippled, but mostly working generics facility into play. This of course vastly improves type-safety. However, you often need to mix non-generic and generic types and this usually provoked the compiler into complaining. Take the following example:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;@SuppressWarnings(&lt;span style="color:#ce7b00;"&gt;&amp;quot;unchecked&amp;quot;&lt;/span&gt;)&lt;span style="color:#000000;"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; uncheckedTest()&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;List nonGenericStringList = &lt;span style="color:#0000e6;"&gt;new&lt;/span&gt; ArrayList();&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;nonGenericStringList.add(&lt;span style="color:#ce7b00;"&gt;&amp;quot;Some string&amp;quot;&lt;/span&gt;);&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;List&amp;lt;String&amp;gt; genericStringList = (List&amp;lt;String&amp;gt;)nonGenericStringList;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Without suppresssing the warning, the compiler (if invoked with -Xlint:unchecked) will complain with something like:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.List&lt;br /&gt;nonGenericStringList.add("Some string");&lt;br /&gt;warning: [unchecked] unchecked cast&lt;br /&gt;    found : java.util.List&lt;br /&gt;    required: java.util.List&lt;br /&gt;List genericStringList = (List)nonGenericStringList;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;@SuppressWarnings("fallthrough")&lt;/span&gt;&lt;br /&gt;Java has always followed the C-style of switch statements, where you need to explicititly break out of a switch unless you wish to simply fall through and execute the code in the case below. This can be dangerous of cousee and errors of this kind can be very hard to track down. In the following example, case 1 lacks a break:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;@SuppressWarnings(&lt;span style="color:#ce7b00;"&gt;&amp;quot;fallthrough&amp;quot;&lt;/span&gt;)&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; fallthroughTest(&lt;span style="color:#0000e6;"&gt;int&lt;/span&gt; i)&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;switch&lt;/span&gt; (i)&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;case&lt;/span&gt; &lt;span style="color:#000000;"&gt;1&lt;/span&gt;:&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#969696;"&gt;// Execute both 1 and 2&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;case&lt;/span&gt; &lt;span style="color:#000000;"&gt;2&lt;/span&gt;:&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#969696;"&gt;// Execute only 1&lt;br/&gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Without suppresssing the warning, the compiler (if invoked with -Xlint:fallthrough) will complain with something like:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;warning: [fallthrough] possible fall-through into case&lt;br /&gt;         case 2:&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;@SuppressWarnings("serial")&lt;/span&gt;&lt;br /&gt;To ensure a serialized class is consistent with how the Java runtime perceives this object (based on its class definition), it is important that serialVersionUID be present. In practice, most people rely on the compiler to insert an appropriate UID:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;@SuppressWarnings(&lt;span style="color:#ce7b00;"&gt;&amp;quot;serial&amp;quot;&lt;/span&gt;)&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;class&lt;/span&gt; Serialest &lt;span style="color:#0000e6;"&gt;implements&lt;/span&gt; Serializable&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Without suppressing this warning, the compiler (if invoked with -Xlint:serial) will complain with something along the following lines:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;warning: [serial] serializable class SerTest has no definition of serialVersionUID&lt;br /&gt;    class SerTest implements Serializable&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;@SuppressWarnings("finally")&lt;/span&gt;&lt;br /&gt;Since try-finally blocks are really glorified goto instructions, the compiler can be instructed to complain if it sees a violation of "good practice" when it comes to execution flow. In the following example we issue a return from within a finally. The compiler allows this, since the JLS specifies a finally clause will always get executed, but realize that any exception thrown in the try may be completely disregarded:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;@SuppressWarnings(&lt;span style="color:#ce7b00;"&gt;&amp;quot;finally&amp;quot;&lt;/span&gt;)&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; String finallyTest(String str)&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;try&lt;/span&gt;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;str+=&lt;span style="color:#ce7b00;"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;finally&lt;/span&gt;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;return&lt;/span&gt; str.toUpperCase();&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;span style="color:#000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Without suppressing this warning, the compiler (if invoked with -Xlint:finally) will complain with something along the following lines:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;warning: [finally] finally clause cannot complete normally&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;@SuppressWarnings("divzero")&lt;/span&gt;&lt;br /&gt;This can be used to catch explicit integer division by 0. It should be default in my opinion, since the compiler KNOWS that executing the code will always result in a a java.langArithmeticException. The annotation has no effect on double's or float's, since these can represent infinity:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:Monospaced,monospace;color:#000000"&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;@SuppressWarnings(&lt;span style="color:#ce7b00;"&gt;&amp;quot;divzero&amp;quot;&lt;/span&gt;)&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;public&lt;/span&gt; &lt;span style="color:#0000e6;"&gt;void&lt;/span&gt; divzeroTest()&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;{&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:#0000e6;"&gt;long&lt;/span&gt; l = &lt;span style="color:#000000;"&gt;12l&lt;/span&gt;/&lt;span style="color:#000000;"&gt;0&lt;/span&gt;;&lt;span style="color:#000000;"&gt;&lt;br/&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Without suppressing this warning, the compiler (if invoked with -Xlint:divzero) will complain with:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;warning: [divzero] division by zero&lt;br /&gt;       long l = 12l/0;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;IDE's&lt;/span&gt;&lt;br /&gt;I reckon most people do not mess with the compiler and supply -Xlint flags, but use the facilities of their IDE. NetBeans allows you to see all (+more) warnings as hints in the gutter section of the editor. You can tweak this to your liking, by going in the options.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_CauKCPUdin4/SBs00pW1E2I/AAAAAAAAAAw/FbRltTnR6wA/s1600-h/NB61hints.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_CauKCPUdin4/SBs00pW1E2I/AAAAAAAAAAw/FbRltTnR6wA/s320/NB61hints.png" alt="" id="BLOGGER_PHOTO_ID_5195804674161447778" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;NetBeans supports a few more values, namely "empty-statement" and "cast". But that's nothing compared to Eclipse, which supports "unused", "empty", "UnusedAssignment", "UnusedDeclaration", WeakerAccess", "autoboxing" and &lt;a href="http://help.eclipse.org/help33/index.jsp?topic=/org.eclipse.jdt.doc.isv/guide/jdt_api_compile.htm"&gt;many more&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update&lt;/b&gt;&lt;br /&gt;Should you be using NetBeans 6.1 or later, I have created a small plugin to assist in the code completion and documentation of these values. You can read more about that &lt;a href="http://coffeecokeandcode.blogspot.com/2008/09/netbeans-plugin-suppresswarnings.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-8466966215354321925?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/8466966215354321925/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=8466966215354321925' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/8466966215354321925'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/8466966215354321925'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/05/suppresswarnings-annotations.html' title='@SuppressWarnings values'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_CauKCPUdin4/SBs00pW1E2I/AAAAAAAAAAw/FbRltTnR6wA/s72-c/NB61hints.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-7891369218104559367</id><published>2008-04-14T20:12:00.000+02:00</published><updated>2008-07-03T12:29:42.786+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Venting'/><title type='text'>Worst travel experience ever</title><content type='html'>&lt;span style="font-size:100%;"&gt;Friday I was suppose to go to Montreal, the usual route over London Heathrow. Slightly concerned with the &lt;a href="http://www.iht.com/articles/2008/03/31/europe/heathrow.php"&gt;recent mishaps&lt;/a&gt; of the new Terminal 5, I actually managed to get to the good old Terminal 4 without much trouble. Little did I know, my trouble were just about to start.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:130%;"&gt;Canceled flight&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;Yup, just 1 min. after entering Terminal 4 I learned that BA95 to Montreal was canceled. Inquiring at the help desk I experienced the deja-vu of being told that I had to go fetch my luggage, contact the ticket office and expect a layover. I had experienced another layover about 2 years ago so I pretty much knew what has coming... or so I though anyway.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:130%;"&gt;Heathrow, JFK or Newark&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;My luggage was nowhere to be found, so I proceeded to the ticket counter and when it was my time to be served I was presented with the option og taking the same flight tomorrow, go to JFK in New York and a very short layover involving an early flight or go to Newark in New York and a longer layover involving a later flight. I thought the Heathrow option would take too long (tried that before btw.), that the JFK option would be too hectic so I opted for going to Newark. With a couple of new tickets in my hand, I rushed to check in and to my gate and soon was on the way across the Atlantic - towards Newark.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:130%;"&gt;The American greeting&lt;/span&gt;&lt;br /&gt;After setting the right check marks documenting that I am not a terrorist, have never been deported from the US and a bunch of equally ridiculous questions I landed around 22:30 and was provided a few notes by ground personnel. One note said my luggage had not made it there and another provided me with a hotel voucher for "Newark Airport Hotel". This was expected, so I began to make my way out of the airport. The initial customs check went fine, they just wanted the usual prints and photo. However, prior to exiting the secure area there was another individual collecting customs cards. The guy took a quick look at mine and asked where my luggage was. I replied that I was in transit so the backpack was all I had. As if he didn't hear me, he asked the same a second time only more aggravated. I then tried explaining that my original flight had been canceled so my luggage was somewhere between London and Montreal. That seems to have made him even more mad, and now raised his voice considerably and said that he had been working there for 13 years and bla... blah. I did not know quite how to react, but realized that I was now in the country where I could be &lt;a href="http://www.alternet.org/blogs/peek/71319/"&gt;held back&lt;/a&gt;, &lt;a href="http://taseroftheday.blogspot.com/search/label/us"&gt;tasered &lt;/a&gt;etc. without that being particularly unusual. So I tried once again to explain myself. He must have gotten tired of me, because he then waved me off and I could walk in to the land of the free with a sigh of relief.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:130%;"&gt;A ghost airport&lt;/span&gt;&lt;br /&gt;I now just wanted to find my hotel so I could grab as much sleep as possible before the next morning. But that proved to be quite difficult. It was apparently too late in the evening for any information people to be working, so all I could find were the occasional passenger like myself, janitor/cleaning personnel and suspicious looking people.&lt;br /&gt;Newark airport is a bit like a maze. Rather than having a large open space where you can get an overview from a far and navigate your way like London or Amsterdam, Newark consists 5-6 split-levels which reminded me of a mall more than of an airport. It took me 30 min of walking around to realize that I was not going to find anyone who knew about "Newark Airport Hotel" or signs to help me. Eventually, I was able to find the British Airways check in counter located at the lower level (basement) but it was as abandoned as everything else. Not far from the counter however, a woman was located behind a counter so I decided to ask her. She kept asking "which one?" when I mentioned "Newark Airport Hotel". So I tried showing her my voucher which didn't really say anything else, but she either refused or just couldn't see it. I asked what I was to do, as a passenger in an airport which for all practical purposes was sleeping. She then got very defensive and said she couldn't help me if I was going to be like that. I might have sound frustrated, but I don't know what else could be expected of me... in any event, I apologized and asked her again, this time putting extra effort into not sounding tired or irritated.&lt;br /&gt;She advised me to contact British Airways. I told her I had failed at locating anyone else than her, let alone British Airways staff. She pointed to a woman behind the BA counter and said "There's one right there". I told her that was a cleaning lady, which made her stand up and yell "Are you cleaning?" to which a mute "Yes" was returned. She then told me she saw BA personnel enter the door in the back so advised me to go knock. Knocking and a brief conversation earned me a photocopy of a poster for "Newark Airport Hotel" with a picture and address, but most importantly of all, the tip that all hotel shuttle buses leave from parking area P4.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;Newark Airport Hotels&lt;/span&gt;&lt;br /&gt;A quick train ride later I arrived at P4 and started investigating which shuttle bus I needed. There were a bunch of buses arriving and leaving constantly, and a list of about 20 hotels in the vicinity. It quickly became clear to me, that the vast majority of the hotels referred to themselves as Newark Airport Hotel. When a shuttle bus arrived 15 min later, saying Newark Airport Hotel in capital and Sheraton after, I thought that might be it. I showed the driver the picture of the hotel I had and asked if this was the hotel he was going to, but there was no answer. So instead I asked, is this the Sheraton hotel? He answered yes so I quickly got in. As soon as we were on our way, I realized he COULD have misunderstood me as asking if he goes to the Sheraton hotel. It later became clear that indeed it was not the Newark Airport Hotel I was looking for. I asked if they recognized the hotel in the picture, and they thought it looked like the Renaissance. So I went out in front again and started waiting in front of the two mini-buses parked with the engines running. After about 15 min. a guy came and asked if I was waiting for the bus. He agreed to take me back to P4. I was back at P4 around 00:30 and started investigating hotels again, this time I noticed a picture of the Renaissance and made a call for a shuttle. It arrived about 10 min. later and I finally thought a comfortable bed was within reach. When I arrived and was told by the lady at the front desk that everything was sold out, I did not know whether to laugh or cry.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;Classic yellow cab&lt;/span&gt;&lt;br /&gt;The lady informed me that no hotel in the vicinity had any available rooms, but that she could call their sister hotel in Springfield about 20 min. away, only, I had to pay cash because they did not accept my voucher. I was drop dead tired, with no intention to spend the night in the insecure part of the ghostly Newark Airport so I accepted her proposal and thought I would simply have to try and get British Airways to give me a refund later. The lady was nice, clearly felt bad for me because she gave me an apple and a soft drink while I waited for the cab.&lt;br /&gt;The cab arrived and I got in on the backseat as I've seen is the custom in the US. And sure enough, a thick Plexiglas window separated me and the driver. It started pouring down and we slowly made out way... somewhere unknown. I could hear the cab radio, in typical big city jargon, talking about whether the police had arrived yet. After about 20 min. I started getting worried, I really did not want to get too far from the airport, also knowing there would be a bill to pay. But we soon arrived so I fetched my Visa card and gave it to the driver through the little door in the protective glass. But his card sweeper didn't work, after many attempts on both my Visa and MasterCard he gave up and called his boss. They were annoyed at each other, obviously not agreeing on whether it was the card or the machine that didn't work. Eventually he handed the cellphone to me and I provided his boss with my Visa detail and that was the end of that - 55$ but no receit.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Springfield Holiday Inn&lt;/span&gt;&lt;br /&gt;Not exactly the Hilton, but after paying 144$ I was just glad to have a bed within reach. I slept about 4 hours that night and got up around 6 such as to try and make my way back to the airport and resolve the various issues that had piled up. I got the hotel to call me a cab and not long after a large black car pulled up. Apparently that was the taxi, I couldn't help wonder whether it was a limo service or perhaps a pirate-cab but I went along. Unlike the night before, this chap was very chatty. The driver was originally from Egypt and as soon as he learned I was from Denmark he wanted to discuss the &lt;a href="http://en.wikipedia.org/wiki/Jyllands-Posten_Muhammad_cartoons_controversy"&gt;Muhammad drawings&lt;/a&gt;. Not knowing where exactly he was taking me, and wanting to remain on friendly terms, I adopted an unusually confrontationless style of argumentation trying to convince him that Danes do not intentionally want to mock or make fun but that religion isn't really particular important to us and that Denmark is a little isolated/ignorant up there in the north. I certainly was not going to say that by all accounts, Muhammad would qualify as being called a pedophile and that the current problems comes from the more moderate Muslims not taking a stand against the primitive head-chopping &lt;/span&gt;&lt;span style="font-size:100%;"&gt;Shari Muslims.&lt;br /&gt;On the way I noticed the guy had no taximeter and when he said he couldn't take credit cards I got convinced he was a pirate-taxi. I proposed that we go find an ATM right inside the airport but he refused, claiming he could not park there. So we went to the Hilton hotel which was close by, he asked how much I had payed the night before. I quickly realized he was going to use that as a benchmark to charge me, so instead of 55$ I said 45$. And sure enough, he required 60$. Had I said 55 he would probably have said 70$.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:130%;"&gt;Bye bye US&lt;/span&gt;&lt;br /&gt;I went to the British Airways check in counter from last night and get a hold of someone, explaining my situation and that I would like to have a refund. They were very understanding, almost puttied me, but were confused as to how to resolve the matter. So we agreed it would probably be best if I pursued it at my end destination Montreal. I quickly made my way to Terminal A and within long was on the way to Montreal. When I arrived in Montreal, my luggage was not there (really, I was not expecting that after all that happened) so I tried to find British Airways missing luggage personnel... with no success. I went to the Air Canada counter instead, since my last flight was actually operated by Air Canada. And sure enough, the guy there informed me that my luggage had just left London on the way to Montreal. I've had delayed suitcases many times before so that didn't really concern me much, I filled out a report and hurried out. Then I tried locating British Airways personnel at a ticket office or checking counter, to try and make my case of getting a refund. The time now was around 13:00 and at the counter all I saw was a sign with the opening hours saying they open at 16:30. Not wanting to wait 3½ hour just to complain, I left and planned on making my case another way. I received my luggage the day after.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:130%;"&gt;The moral of the story&lt;/span&gt;&lt;br /&gt;I am sure this will be yet another laughable experience eventually, but for now it is still a little too close for comfort. I have definitely had enough of American "hospitality" as well as London's Heathrow airport. I am now more sure than ever that it's worth it paying more for a ticket going with KLM (my preferred airline).&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-7891369218104559367?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/7891369218104559367/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=7891369218104559367' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/7891369218104559367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/7891369218104559367'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/04/worst-travel-experience-ever.html' title='Worst travel experience ever'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-289768784675070953</id><published>2008-04-07T23:53:00.000+02:00</published><updated>2008-05-16T20:30:40.683+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Know thy acronyms</title><content type='html'>Maybe it's caused by the passing of time, maybe it's because of its open nature or maybe it's simply because people like to make them up. In any event, few technologies in computing are as littered with acronyms as Java is.&lt;br /&gt;&lt;br /&gt;Just for fun, while eating lunch (yeah I know it's bad habit) I compiled a list off the top of my head of what an average developer might be subjected to, when tracking technologies in the Java space.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;AWT - Abstract Window Toolkit (UI)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;BGGA - Gilad Bracha, Neal Gafter, James Gosling, and Peter von der Ahe (Closures)&lt;/li&gt;&lt;li&gt;CICE - Concise Instance Creation Expressions (Closures)&lt;/li&gt;&lt;li&gt;EAR - Enterprise ARchive (Packaging)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;EDT - Event Dispatching Thread (Lingo)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;EJB - Enterprice Java Beans (Packaging/technology)&lt;/li&gt;&lt;li&gt;FCM - First Class Methods (Closures)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;JAR - Java ARchive (Packaging)&lt;/li&gt;&lt;li&gt;JAX-RPC - Java API for Xml-based Remote Procedure Call&lt;/li&gt;&lt;li&gt;JAX-RS - The Java API for RESTful Web Services&lt;/li&gt;&lt;li&gt;JAX-WS - Java API for Xml-based Web Services&lt;/li&gt;&lt;li&gt;JAXB - Java Archtecture for Xml Binding&lt;/li&gt;&lt;li&gt;JAXP - Java API for Xml Processing&lt;/li&gt;&lt;li&gt;JCK - Java Compatibility Kit&lt;/li&gt;&lt;li&gt;JCP - Java Community Process&lt;/li&gt;&lt;li&gt;JDBC - Java DataBase Connector&lt;/li&gt;&lt;li&gt;JDK - Java Development Kit&lt;/li&gt;&lt;li&gt;JDO - Java Data Objects&lt;/li&gt;&lt;li&gt;JDOM - Java Document Object Model&lt;/li&gt;&lt;li&gt;JEE - Java Enterprise Edition&lt;/li&gt;&lt;li&gt;JLS - Java Language Specification&lt;/li&gt;&lt;li&gt;JME - Java Micro Edition&lt;/li&gt;&lt;li&gt;JMM - Java Memory Model&lt;/li&gt;&lt;li&gt;JMS - Java Messenging Service&lt;/li&gt;&lt;li&gt;JMX - Java Management Specification&lt;/li&gt;&lt;li&gt;JNDI - Java Naming and Directory Interface&lt;/li&gt;&lt;li&gt;JNI -  Java Native Interfacing&lt;/li&gt;&lt;li&gt;JNLP - Java Network Launch Protocol&lt;/li&gt;&lt;li&gt;JPA - Java Persistency API&lt;/li&gt;&lt;li&gt;JPQL - Java Persistency Query Language&lt;br /&gt;&lt;/li&gt;&lt;li&gt;JRE - Java Runtime Environment&lt;/li&gt;&lt;li&gt;JRO - Java Runtime Object&lt;/li&gt;&lt;li&gt;JSE - Java Standard Edition&lt;/li&gt;&lt;li&gt;JSF - Java Server Faces&lt;/li&gt;&lt;li&gt;JSP - Java Server Pages&lt;/li&gt;&lt;li&gt;JSR - Java Specification Request&lt;/li&gt;&lt;li&gt;JSTL - JavaServer Pages Standard Tag Library&lt;/li&gt;&lt;li&gt;JTA - Java Transaction API&lt;br /&gt;&lt;/li&gt;&lt;li&gt;JTS - Java Transaction Service&lt;/li&gt;&lt;li&gt;JVM - Java Virtual Machine&lt;/li&gt;&lt;li&gt;JWS - Java Web Start (Deployment)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;JXTA -Juxtapose (Peer-2-Peer)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;NIO - New Input/Output API&lt;/li&gt;&lt;li&gt;NPE - NullPointerException (Lingo)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;POJO - Pure Old Java Object (Lingo)&lt;/li&gt;&lt;li&gt;RT - Runtime (rt.jar, the JRE)&lt;/li&gt;&lt;li&gt;SAF - Swing Application Framework (JSR-296)&lt;/li&gt;&lt;li&gt;SOP - System.out.print (Lingo)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;SWT - Standard Widget Toolkit (UI)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;StAX - Pull-parsing XML&lt;/li&gt;&lt;li&gt;WAR - Web ARchive (Packaging)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;I have only included direct Java acronyms, not framework (Swing, Spring, Struts...), libraries (iText, JodaTime, log4j...), tools (Maven, JUnit, JMeter...) or general purpose technologies (SVN, HG, CVS...).&lt;br /&gt;&lt;br /&gt;The amount of acronym soup is staggering. No wonder people are sometimes overwhelmed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-289768784675070953?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/289768784675070953/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=289768784675070953' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/289768784675070953'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/289768784675070953'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/04/know-thy-acronyms.html' title='Know thy acronyms'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-8405540528067789565</id><published>2008-03-31T00:16:00.000+02:00</published><updated>2008-05-15T00:47:59.165+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>C# type inference</title><content type='html'>While I work mainly in a Java shop, I continue to be impressed by what Anders Hejlsberg, chief architect of C#, brings to the table to a language which in my mind has always represented Java done right. I do wonder however, how come they did not take the concept of type inference just a little bit further.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Local variable type inference&lt;/span&gt;&lt;br /&gt;This feature of C# 3.0 basically allows you to omit the declaration which, especially when generics is involved, causes a lot of repetition and long lines of code:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Dictionary&amp;lt;int, IEnumerable&amp;lt;decimal&amp;gt;&amp;gt; myCollection =&lt;br /&gt;        new Dictionary&amp;lt;int, IEnumerable&amp;lt;decimal&amp;gt;&amp;gt;();&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Which can be reduced to this:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;var myCollection = new Dictionary&amp;lt;int, IEnumerable&amp;lt;decimal&amp;gt;&amp;gt;();&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;No late binding is taking place, the compiler simply infers the actual type and substitutes var with it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;No method return type inference?&lt;/span&gt;&lt;br /&gt;Some languages operates with the concept of tuples, a way of returning multiple values without having to wrap them in an array and use casting or a predefined data transfer object. Wouldn't it be nice, if we could use type inference here instead to be able to return multiple values from one invocation - and still be type-safe about the whole thing:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;var getInferredType()&lt;br /&gt;{&lt;br /&gt;    return new {X = 22, Y = -3};&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;var coordinate = getInferredType();&lt;br /&gt;Console.WriteLine(coordinate.X);&lt;br /&gt;Console.WriteLine(coordinate.Y);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Perhaps this isn't doable for reasons of method signature lookup or polymorphism rules, I don't know. But it strikes me as something that would be very usefull and further reduce the need of temporary housekeeping objects.&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-8405540528067789565?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/8405540528067789565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=8405540528067789565' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/8405540528067789565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/8405540528067789565'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/03/c-type-inference.html' title='C# type inference'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-2691928285766682139</id><published>2008-03-10T23:26:00.000+01:00</published><updated>2008-05-13T19:42:50.619+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Puzzler'/><title type='text'>Java Puzzler: How low can you go?</title><content type='html'>Any seasoned Java developer would know of the seminal books &lt;a href="http://www.amazon.com/Effective-Java-Programming-Language-Guide/dp/0201310058"&gt;Effective Java&lt;/a&gt; and &lt;a href="http://www.amazon.com/Effective-Java-Programming-Language-Guide/dp/0201310058"&gt;Java Puzzlers&lt;/a&gt; by Joshua Bloch. The latter covering pitfalls and corner cases of the Java language, listing some 95 different examples of traps to watch out for in your daily work.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Java puzzlers&lt;/span&gt;&lt;br /&gt;While a great read for toilet visits, unlike Effective Java, I don't consider Java Puzzlers particularly essential material to know as a developer. Not because there isn't anything to learn, but because there are many other pitfalls of the language not mentioned which you are just as likely to encounter before many of the exotic ones mentioned in the book. I recently ran into another one of this kind, which I will now describe.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;How low can you go?&lt;/span&gt;&lt;br /&gt;Take a look at the following snippet, which is a more flexible version of &lt;span style="font-family:courier new;"&gt;Math.max()&lt;/span&gt; which tries to find the largest &lt;span style="font-family:courier new;"&gt;Double &lt;/span&gt;in an array:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;System.out.println( max(0.0, -1.0, -2.0) );&lt;br /&gt;&lt;br /&gt;public static &lt;span class="keyword"&gt;double&lt;/span&gt; max(double... candidates)&lt;br /&gt;{&lt;br /&gt;   assert(candidates.length &gt; 0);&lt;br /&gt;   double knownMaxValue = Double.MIN_VALUE;&lt;br /&gt;   for(double candidate : candidates)&lt;br /&gt;       if(candidate &gt; knownMaxValue)&lt;br /&gt;           knownMaxValue = candidate;&lt;br /&gt;   return knownMaxValue;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What do you think will be printed to &lt;span style="font-family:courier new;"&gt;System.out&lt;/span&gt;? Hint: No, it doesn't have anything to do with autoboxing this time around. Scroll down to read on...&lt;br /&gt;&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;&lt;br /&gt;Well, I would expect 0.0 to be printed, but instead 4.9E-324 is. That's because &lt;span style="font-family:courier new;"&gt;Double.MIN_VALUE&lt;/span&gt; yields 4.9E-324, the smallest *positive* number. So when we initially assign it to knownMaxValue,  thinking it represents the smallest possible value, the net effect is that candidate values less than 0 are not considered at all.&lt;br /&gt;To get the expected behavior, you instead have to initialize with &lt;span style="font-family:courier new;"&gt;-Double.MAX_VALUE&lt;/span&gt; to get the actual smallest number including negative numbers which yields -1.7976931348623157E308.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Justification&lt;/span&gt;&lt;br /&gt;You may argue that this is fully specified in the JLS and documented in the JavaDocs, which is true. The JavaDoc for Double states "A constant holding the smallest positive nonzero value of type double". However, I'd consider this to be an extremely easy trap to fall into as it completely defies logic and common sense. Javascript not surprisingly follows the Java definition of &lt;span style="font-family:courier new;"&gt;Double.MIN_VALUE&lt;/span&gt; while more modern languages such as C# defines it the way most people would expect, including negative numbers.&lt;br /&gt;&lt;br /&gt;The above puzzler could also have dealt with problems associated with the abnormal signed definition of a &lt;span style="font-family:courier new;"&gt;java.lang.Byte&lt;/span&gt;, or the treacherous scale semantics of a &lt;span style="font-family:courier new;"&gt;java.math.BigDecimal.equals()&lt;/span&gt;or... well you get the idea when I say there are a fair share of puzzlers out there not officially declared so.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-2691928285766682139?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/2691928285766682139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=2691928285766682139' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/2691928285766682139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/2691928285766682139'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/03/java-puzzler-how-low-can-you-go.html' title='Java Puzzler: How low can you go?'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5496789096865583573.post-1347925774033810024</id><published>2008-03-04T18:56:00.000+01:00</published><updated>2008-05-03T04:20:07.317+02:00</updated><title type='text'>Gee... Another one?</title><content type='html'>Hey everyone and no one! Like so many others, I've decided to start my own blog.&lt;br /&gt;&lt;br /&gt;Up until now I've just been an avid participant in various forums, blogs and communities with all the problems associated with that. It's my desire with this blog to be able to write my opinions without having to conform to established or expected perspectives which sometimes gets me into trouble.&lt;br /&gt;&lt;br /&gt;I will also use the blog as a personal wiki, an institutional memory and a communication medium, which may or may not be of interest to others. The content will probably revolve mostly around software engineering and associated technical issues, but I reserve the right to use it as a venting space for whatever comes to mind.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5496789096865583573-1347925774033810024?l=blog.bangbits.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bangbits.com/feeds/1347925774033810024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5496789096865583573&amp;postID=1347925774033810024' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/1347925774033810024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5496789096865583573/posts/default/1347925774033810024'/><link rel='alternate' type='text/html' href='http://blog.bangbits.com/2008/03/gee-another-one.html' title='Gee... Another one?'/><author><name>Casper Bang</name><uri>http://www.blogger.com/profile/09493174484116672294</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp0.blogger.com/_CauKCPUdin4/R82eRB-5k-I/AAAAAAAAAAk/ReXHrS3PQSs/S220/casper.jpg'/></author><thr:total>0</thr:total></entry></feed>
