2008-11-15
Password Composer Mini
From time to time, I have had the need for it on computers where I can't readily install it (e.g. some friend's machine), and sometimes on computers (e.g. hotel lobby PCs) that I distrust enough that I don't even want to enter my master password on the static form version available on the Password Composer website. For those occasions, I've writtena little J2ME thingie I call Password Composer Mini that does the same.
It's one of the first J2ME apps I've completed, and the code is entirely uninteresting, apart from the MD5 implementation that I pilfered from the J2ME version of Fast MD5. The interesting parts were writing a Makefile for building J2ME code and learning enough of Bazaar to do release management with it. This will serve useful for more interesting things to come later...
2008-08-19
Packet Decoding and the Limits of (mainstream) Static Typing
Naturally, when dealing with these things, I want to have a class for each packet type. Since the mapping between what's in the data field for a packet type and what the correspoding class contains is fixed, it seems natural to me to place the code for decoding and encoding is the class itself: a constructor for building an instance from the data field and a method for encoding a packet into a data byte array.
So given this, I want to write a little decoding loop that reads the type and then creates a new packet of the correct type using the length and data fields. This is where the problems start. Ideally, I would just have a map from type to class, index with the type I just read and then call the constructor of the class, but in the statically typed languages I usually dabble in there is no way of specifying a contract that talks about constructors. This means that there is no way of describing the type of the map. Factory methods are also out of the question, since static methods can't be part of the contract either. Apart from talking about the instances of the types and the relations between types, there is not much more the type systems alow you to say (well, except in spec-abusing C++ and languages with dependent types).
That seems to leave me with one option left: using instances as spring-boards for creating classes. Something like the following would work:
Then the type of the map would be
abstract class Builder
{
public abstract Packet Build(byte[] data);
}
class FooBuilder : Builder
{
public override Packet Build(byte[] data)
{
return new FooPacket(data);
}
}
Dictionary<int,Builder>
, and then all that is necessary is to create a builder class per packet type and then register the builders.
First, let's look at registering the builders. Since the builders don't contain any fields (and thus aren't really objects IMNSHO), the can be singletons, and classes could register themselves with the map in a static constructor. Except that static constructors only are run when the class is loaded, and since no code is supposed to refer to them directly (which is kind of the point of having the map to begin with), they will never be loaded, and thus never register. So again, we have to abandon doing things statically and have someone (e.g. the class holding the map) fill the map with items, one by one. So much for isolating the instantiation.
So, now we're left with something like
abstract class Builder {/*...*/}
class FooBuilder {/*...*/}
class PacketFactory
{
private Dictionary<int,Builder> builders=new Dictionary<int,Builder>();
public PacketFactory()
{
builders.Add(FooPacket.Id, new FooBuilder());
}
public Packet Build(int type, data[] data)
{
return builders[type].Build(data);
}
}
which is (sort-of) fine, except for all the extra code that was necessary for just calling
new
. Well, lambda/delegate/closure/anonymous-inner-class/whatever to the rescue. In current Java, you could do it something like
interface Builder
{
Packet build(byte[] data);
}
//...
buiders.add(FooPacket.Id, new Builder(){public Packet build(byte[] data) {return new FooPacket(data);}});
which is still a bit too much noise for my taste, or in C#
delegate Packet Builder(byte[]);
//...
builders.Add(FooPacket.Id, delegate(byte[]) {return new FooPacket(r);});
which is better. Still, being able to say that a
Packet
class is required to have a static member that holds the ID that the described packets have and has a constructor that takes a byte array would have removed the need for the builder interface, a (possibly anonymous) class for just delegating the call, and all the resulting code noise.So some questions then: Why is it we cannot say that a FooPacket
is a Packet
with 42
as its type Id or that all Packet
subtypes can be constructed from byte arrays? Also, why do type parameters only get to say things about the types the parametric type refers to, and not the names it uses when doing so? The Pair<A,B>
kind of types would be so much more usefull if it would let the subclass decide what the accessors are called. Answers on a postcard.
2008-08-17
bzr commit -m "zoom"
My non-blogging friend, which I've managed to meet for a friendly game of drunken zombies has hinted that he will start blogging. Looking forward to it :-)
2008-07-23
Netbeans, Eclipse, Ubuntu
This is all expected to be troublesome, Linux does not have drivers for stuff, I know that. Most things have a work-around but not all. But I find it rather sad that the real time patches that has been floating around for years still is not in the kernel or that Ubuntu officially uses the realtime kernel in the desktop version. Be that as it may, for java development I do not need a realtime kernel.
What really surprised me was that Eclipse does not run. It crashes the JVM (JDK1.6u10). Apparently this is a known defect in Java on AMD64. Java on 64 bit, by the way, still does not have a browser plugin. I seriously hope that OpenJDK will make this happen.
But no worries, this was a great opportunity to use NetBeans. It has been a long time ago since I actually used it. Usually I only poke at it before going back to Eclipse since they are usually ahead in features I use.
So Netbeans in anger, on an AMD64 linux, what could possibly go wrong :-) Well, not much actually but one thing that really bugs me is that it does not discover compilation errors. Sometimes not at all until I quit NB and start it again, then it happily marks the errors in the task list, in the editor and in the project tree. Sometimes I have to open the offending file and the editor usually marks it, but not the task list and the project tree. Yes, I know about the refresh function and no, it has absolutely no effect. I have come to rely on my IDE to find compilation errors when I save files in the same way that I couldn't really live without syntax colouring and the very handy "mark occurances" I first found in eclipse.
So I can't really say that Hardy Heron, Java or Netbeans zoom but they are actually quite nice anyway.
One thing that definately does not zoom is that my friend still has not started blogging about software design.
2008-06-06
Nothing has zoomed
Went to JavaOne and found out that this years JavaOne was a recap of the previous one. I like Java and I think Sun does a reasonable job with it but this year was basically 'things go according to plan and stuff will be released in fall or next year'.
Found out that OpenID is supported on sourceforge, that is nice. Went to www.myopenid.com and registered a persona to try an alternative to this site. I hope it zooms.
ExtJS went GPL which I personally don't like but it sure is a nice library to use, go JavaScript!