Tuesday, August 12, 2008

A not so obvious answer to: Can Java interfaces have static initializers?

Static initializers are blocks of code that are automatically executed when a class is initialized. They are particularly handy when an expression is not enough to calculate an initial value or when the evaluation of an initializing expression may throw a (checked) exception. For instance, suppose we want to initialize a (final static) field me with the IP address of the local machine. We'd like to write:
import java.net.*;
class C {
  final static InetAddress me = InetAddress.getLocalHost();
}
but we can't because, as the compiler duly reminds us, "unreported exception java.net.UnknownHostException; must be caught or declared to be thrown". Ok, that's what static initializers are for:
import java.net.*;
class C {
  static final InetAddress me;
  static {
    
InetAddress addr = null;
    try {
      
addr = InetAddress.getLocalHost();
    } catch (UnknownHostException uhe) {
      uhe.printStackTrace();
      System.exit(-1);
    
}
    
me = addr;
  }
}
Now, the raison d'ĂȘtre of this post: what if C were an interface? Could we write the following? (fields are implicitly static and final in interfaces)
interface I {
  InetAddress me;
  static {
... as before ... }
}
Well, we could write that but it won't compile ;)
Is there any workaround? Yes, there is. However, before presenting it, allow me to make another point.
Tricky question: can interfaces have static initializers? After all, interfaces cannot contain code... can they?
Since I've said the question is tricky, you've probably guessed it right... yes, interfaces can indeed have static initializers, yet you (programmer) are not allowed to write static initializers inside interfaces. Uh... does the last sentence make any sense at all? Allow me to explain; please consider:
interface Universe {
  static final Integer theAnswer = new Integer(42);
}
That's it: Universe is an interface with a (well hidden?) static initializer! The expression new Integer(42) is not a compile-time constant, so the compiler emits the code for evaluating the expression inside a static initializer. Skeptical? Well, let's see what javap -c Universe has to say about it:
interface Universe{
public static final java.lang.Integer theAnswer;

static {};
  Code:
   0:   new     #1; //class java/lang/Integer
   3:   dup
   4:   bipush  42
   6:   invokespecial   #2; //Method java/lang/Integer." ":(I)V
   9:   putstatic       #3; //Field theAnswer:Ljava/lang/Integer;
   12:  return

}
if that isn't a static initializer, I don't really know what it is ;)
I think it's rather curious that programmers are not allowed to (explicitly) write static initializers in interfaces; I don't really see what problems could arise in allowing it.
However, there is a simple workaround: put the code inside static methods of a dummy nested class (this class should be private, but we can't make it private as all interface members are implicitly public). In our running example this idea translates to:
import java.net.*;
interface I {
  InetAddress me = Dummy.getAddress();
  class Dummy {
    private static InetAddress getAddress() {
      try {
        return InetAddress.getLocalHost();
      } catch (UnknownHostException uhe) {
        uhe.printStackTrace();
        System.exit(-1);
        return null; // not really, but makes the compiler happy
      }
    }
  }
}

Friday, August 8, 2008

Alice: a very cool way to teach programming

Alice is a freely available teaching tool designed to be a student's first exposure to object-oriented programming.

The idea reminds me of the Turtle Graphics of LOGO, that is, making the programming activity more "tangible" by leveraging a parallel with the real world, where (real) objects can interact. Anyway, about thirty years have passed since those seminal ideas were born and Alice is definitely up-to-date.

Alice is an innovative 3D programming environment that allows to learn fundamental programming concepts in the context of creating animated movies. In Alice, 3-D objects (people, animals and so on) populate a virtual world and students can create programs to animate these objects. I've particularly liked the way programs can be built: everything is very visual and you can do a lot of things by simply choosing actions and their objects. The environment is a sort of an extremely simplified IDE, which is great as the students can get accustomed to the environments they will use later. Also, it's easy to construct new actions by making sequences, loops and so on... that, is programming but without the hassle of pairing curly braces ;)

The current version of Alice (2.0) seems very promising but rather limited in what you can do after the basic skill has been acquired (which is quite a goal anyway!), however the next version promises to bring Java and the Sims-2 characters into play! I'm looking forward to that: if I have to teach basic programming skills, that's a tool I'd love to play with.
If you're a teacher, then I strongly suggest to check Alice out!
(it requires no installation and can run on Windows, Linux and Mac OS X)

Tuesday, August 5, 2008

Installing fully encrypted Windows and Ubuntu on the EEE 900

In the last few days I've played a lot with my latest toy, an ASUS EEE 900, that I really love. The only thing I have a hard time with is its keyboard: it's very small, which is both cute and uncomfortable (anyway, an external rollable keyboard could easily solve this matter).

I've managed to get Windows XP and Ubuntu working, sharing a data partition on a fully encrypted disk (well, actually "fully" means "all partitions except for the Linux /boot").
Also, I've installed both operating systems using a pendrive, without resorting to an external CD/DVD reader (that I don't have). While all the information on how to do this are already around, in a form or another, I hope that this mini-tutorial (but long post), containing pointers to the tutorials and tools I've used, will be useful anyway.

Before going on, let me state a thing very clearly: this mini-tutorial is targeted to sysadmins: you can easily lose your data or make your computer stop working when "playing" with partitions, MBRs and so on. I'm just telling what worked for me once. There are no guarantees that what I'm describing here will work for you too. So, please read everything once and don't even start if there is anything unclear.

My EEE PC has 20 GB, split into two drives of 4 and 16 giga. I've decided to install Windows on the first drive (4 giga), use 8 giga for a shared data partition and leave the remaining 8 giga for Ubuntu. The shared partition will be encrypted using true crypt, and formatted with NTFS for obvious reasons; that is, I have no idea how to mount ext3 partitions on XP and FAT... well... sucks ;-)

First of all, how can we install an operating system without a CD reader? We can create a bootable Windows Installation Pendrive, using an installation CD (or, of course, a mounted ISO) and USB Multiboot. It's a very easy to use program and the pendrive created with USB Multiboot has worked like a charm. Roughly the same idea works for Ubuntu, but we'll talk about it in the following.

So, let's start booting from the Pendrive containing the Windows Installation. In order to boot from the pendrive, you have to change the boot order in the EEE BIOS; to enter the BIOS press F2 while booting.

Now, take a deep breath and erase all partitions. I know: it's scary and the feeling of having just done something really bad will haunt you until you'll see the Windows logon screen ;-)
Then, proceed with the installation of XP on the first drive (that is, create a single NTFS partition as large as possible).

Note: rest assured that in the end both operating systems will be on encrypted partitions, but we'll reach that goal in a few steps. First we'll install Windows on a plain partition and create the shared data partition, then we'll install Ubuntu on a (newly created) encrypted partition, and finally we'll encrypt the Windows system partition and format the shared (encrypted) data partition.

If everything has gone as it should, you can now boot Windows. Inside Windows, create the 8 giga data partition (using the Disk Management function of XP) but don't format it yet, we'll format it using truecrypt later. You'll probably want to install Windows drivers now; just download them from the ASUS site and follows the instructions. Hopefully, there are no surprises there. Let's think about Ubuntu now.

While there are Ubuntu distributions for the EEE (for instance, Ubuntu Eee), I think their installation don't allow to encrypt the drive, so we're going to use the official Alternate Install CD and then we'll apply some patches to make all the feature of the EEE work.

While there is a "standard" way to install Ubuntu from a pendrive, it didn't work for me. After a couple of failed attempts, I've luckily found a blog post with detailed instructions that worked :-)
Bear in mind that those instructions are for Gutsy, so you have to change a few URLs (http://archive.ubuntu.com/ubuntu/dists/hardy/main/installer-i386/current/images/hd-media/...) to install the current version of Ubuntu.

Now you should be able to install Ubuntu booting from the pendrive, as we did with Windows. As I said before, we're going to install Ubuntu on an already encrypted partition, so in the installer choose to manually partition the drives and be careful; a very useful tutorial can be found in this blog post. Basically, along the (unformatted) 8 giga data partition, create a small boot partition (the only partition that will remain unencrypted) and a “physical volume for encryption” in the remaining space. Inside this volume, create a “physical volume for LVM”, containing a swap partition and the root partition with the remaining space.
Install Ubuntu and, for the time being, allow the installer to write GRUB on the MBR.

Now you should be able to boot both the unencrypted Windows and the encrypted Ubuntu. I've stressed you should because, well, I couldn't :-(
GRUB was correctly installed on the MBR, but from GRUB I could only boot Ubuntu. Windows boot failed saying that the file hal.dll was missing or corrupted.
So, I booted Ubuntu (not that I had much choice) and mounted the NTFS Windows system partition under Linux. I looked inside the folder system32 and there it was: hal.dll. So it was certainly not missing, maybe corrupted? Maybe. Maybe not. Indeed, it was not.
I solved the problem editing the file c:\boot.ini, which is a sort of GRUB menu.lst, replacing a 1 into a 0 because... it felt right... I know it's stupid, yet it worked. Windows booted, although showing a strange error on a command console that popped up from nowhere. Unfortunately I haven't written the error down and it vanished without ever reappearing.
My point is: I've fixed the problem, but I don't know why and, moreover, I don't understand what went wrong. I mean: before installing Ubuntu, Windows worked fine with the given boot.ini and Ubuntu installer should have not touched the first drive at all, so the old boot.ini should have worked fine. There it is: an unsolved mystery. I'm writing this down for a reason though: if the same thing happens to you, don't panic and don't trust Windows error messages ;-)

Now it's time configure Ubuntu for the EEE. Fortunately, there are pre-made scripts that do all the dirty work :-)
I've used this script, which is a slight modification of this one (see the site) to make it work for the EEE 900.
Of course, check the script before running it (you're reading a tutorial about installing everything on an encrypted drive, please don't tell me that you'd blindly run any script linked from a blog post!).
Alas, the code of the wireless drivers has changed, so after having run the script, check the README inside madwifi-ng-r3366+ar5007 and follow those instructions. For more tweakings, check this site.

Back to our installation story: when you can boot both (unencrypted) Windows and (encrypted) Ubuntu it's time to encrypt Windows. Before doing that, you need to install GRUB to a partition because the MBR will be overwritten by the Truecrypt loader. The truecrypt loader can do two thing: the former is starting up Windows from an encrypted partition (duh!), and the latter is passing the control to another bootloader, which can be installed in any partition (even on the second drive). In my case, the Linux boot partition was /dev/sdb3 so I've installed GRUB there issuing sudo grub-install /dev/sdb3

Now, boot Windows, download and install truecrypt (reboot if necessary), and encrypt the system partition (from truecrypt menu: System -> Encrypt System Partition/Drive...). Truecrypt will create an ISO of its rescue-disk (specific for your system) and will not continue until you've successfully burnt the ISO on a CD. Uhm... ok, it's a sensible choice and it's probably idiot-proof... yet, I didn't have (and want to connect) an external CD burner. So I copied the ISO to a pendrive (because making a copy is sensible) and cheated ;-) mounting the just-copied ISO with an old version of Daemon Tools. That did the trick :-)
Note: old version of Daemon Tools were free, with no strings attached. As far as I understand, now there exists a lite version that can be freely used for private use but I'm not sure. Anyway, any tool that allows you to mount an ISO file as a drive should work as well.

After a reboot, your Windows system partition will be encrypted, so it remains to encrypt the last partition: the shared one. Now, it's a piece of cake: just use truecrypt to create an NTFS volume (Volumes -> Create New Volume... -> Create a volume within a non-system partition/device).

At this point, on power up the EEE will start showing the truecrypt loader screen. From there you can either: enter the passphrase and boot Windows, or press ESC and use GRUB to boot Linux (the passphrase will be asked shortly thereafter).

In Linux, after you've installed the package truecrypt, you can mount the shared partition with:
truecrypt --filesystem=ntfs --mount /dev/sdb1 mountpoint
or by using the Truecrypt GUI (of course, assuming /dev/sdb1 is the shared partition)

Phew! This was indeed a long post, my longest post ever (among all the three I've written so far :-) )

Monday, August 4, 2008

Audiotapes, a trip down memory lane

Once upon a time there were homecomputers, that used analogue audio tapes to store programs. Those who've played with computers in the eighties will surely recognize some of these tapes from tapedeck.org

Saturday, August 2, 2008

Achieving your childhood dreams

Randy Pausch was an American professor of computer science, who died from cancer when he was 47.

Randy has achieved worldwide fame for his "The Last Lecture", a speech entitled Achieving your childhood dreams, that manages to be touching, fun and extremely inspiring.