Monday, December 27, 2010

Java GUI Toolkits Revisited

At the very beginning of the design of Fractus, Jarrett (the other committer) and I decided to use java-gnome as our GUI framework.  We both like the look of GTK2, and as can be seen on Pidgin, it still looks Windowsy on Windows (though GTK1 did not).  This decision is also largely the result of my failure to research when support for this toolkit ended.  After version 2, a company called Operational Dynamics took over its development.  Because they only have a need for Linux code, they ended support for Windows.  I probably should have looked into this more.  After Jarrett had completed a lot of GUI work, we had to start this part over.

The next decision was made with more research.  We knew that we didn't want to use Swing because Swing applications that we had seen before are ugly.  At the time, I didn't know that you can change the LAF from Metal to something somewhat native.

So, we went with SWT -- the other large and well-supported framework.  SWT itself is a pretty hefty dependency -- not to mention deployment means making separate packages for each of the platform-specific SWT jars.  Later I discovered that SWT is not even close to being MVC.  In fact, you typically can't even subclass things.  I found a bunch of things awkward to do before I discovered JFace (a very large but helpful dependency indeed).  Unfortunately, I didn't discover this until I started playing with...

Swing!  I found Matisse, the Netbeans GUI builder, amazing.  It's just too easy and too flexible.  It's probably my second favorite GUI builder next to Qt's (see below).  I got about 50% done with the GUI design with Swing before I realized that, while I think I got rid of a lot of platform-specific oddities (i.e. the menus looked awful -- sometimes unusably so), I could never make an interface that people would be impressed with.  Though I must say, it was very easy and elegant to make something that is relatively usable while keeping the code very well separated and organized by MVC.  It made it even sweeter that Swing is included with Java SE so there are no external dependencies, but I wasn't satisfied with the very "Swing" look that it has, even when using the platform's pseudo-native rendering.  It gave me a bad taste, like AWT, but far less bad.


Currently, I am torn between
  • Going back to SWT (with JFace this time): the dependency isn't that big, considering disk space and bandwidth are cheap.  This may produce the most functional and pretty interface.  I have used the visual editor and I don't like it nearly as much as the one in NetBeans.
  • Going with Qt Jambi: While Nokia's support for this Java binding has recently ended, development on Qt is extremely active.  It has one of the best GUI designers imaginable that will put out ".ui" files which generate code in almost any modern language (and even Ada!)  Its development has been taken over by an open source community.  Qt4 looks aesthetically amazing.  Skype for Linux uses it -- and I will admit that one thing Skype is very good at is looking pretty!  VLC uses it.  Google Earth uses it.  The list of sexy applications continues and can be found at qt.nokia.com
I hope my quest to find a decent Java GUI toolkit will save you some time.

Friday, December 10, 2010

Web Interface

A web interface has been designed and implemented for managing Fractus.

It handles:
  • User Registration
  • Password Resets
  • Download JAR link (not functional)
  • Java Web Start (not functional)
 It is written in Perl and uses jQuery to provide neat Ajax features and fancy fading.

Tuesday, November 16, 2010

How I used Protocol Buffers in Fractus

Rarely in the development of software is there a single technique which both boosts the productivity of the programmer and the efficiency of his implementation.  One very generic issue which is applicable to any non-trivial program is serialization -- how to represent an arbitrarily complex data structure as a series of bits, which can then be written to disk, socket or other I/O system, then be reconstructed later.  This is made complicated by the common requirement of differing source and sink points for the serialized data, especially in network programming.  Various endianess and language choice present tricky challenges.

XML achieves the former goal -- boosting the productivity of the programmer -- through its myriad libraries available for nearly any popular language which provide methods for manipulating documents as an object model (DOM - "Document Object Model") or simply as a stream of its elements (SAX - "Simple API for XML").  Each "record" -- an intentionally vague term -- is intuitively serialized as an element and its children, allowing for representation of data as a tree (i.e., 1:N), or as a row (i.e., 1:1).  As a simple example, however, consider an instance of a model for some CD (less the songs' musical data):
<cd artist="Elliott Smith" title="Figure 8">
<track title="Son of Sam" index="1" bitrate="160" duration="3:04" />

<!-- the other tracks go here -->
</cd>



Before such an extensible (no pun intended) and widely relevant standard existed for serializing data, especially before extremely powerful commodity computers existed at low cost, programmers resorted to binary protocols that they designed themselves, on a case-by-case basis.  Using XML, a programmer would end up generating the text 'index="..."' for each record.  Because a CD wouldn't contain more than 256 tracks, this could easily just be represented as a single byte at a predetermined offset from the start of the record.  Yet in a unicode encoded XML file, 'index="255"' would require 11*2 = 22 bytes.  Not very efficient.

XML has other drawbacks.  Who is to say that a certain piece of data which has a 1:1 relationship with its parent element should be an attribute and not a separate child element?  Both would produce logically valid solutions.  The attribute, or child element as the case may be, is a logical part of its parent.  Having a separate child element would, later on, allow for the child element to have its own child elements if this were necessary.  But just using a single attribute would be more efficient.  Then, if a programmer changed the definition, would other programmers be happy with writing separate parsers for different versions of a similar document?  If a Document Type Definition is not made for a given XML subset (as my experience has shown is often the case), how does a programmer know what elements and attributes can be added to generate a valid document?

These issues with XML are usually trivial, depending on how the XML is used.  Representing an image as
<image name="hello.jpg"><row number="0"><pixel red="0"... would, of course, be ridiculous.  However, even representing a very large CD collection may be practical with XML, because disk space is cheap and programmers' time is not.  JSON offers a (potentially) much more efficient solution to nearly the same kinds of problems.  But what about serializing data which is already binary?  The typical solution is to use Base64 encoding, or similar, which isn't terribly efficient compared to writing raw bytes in an agreed-upon endianness.

Protocol Buffers, a very innovative and extremely useful solution developed by Google for their internal serialization needs offers a great alternative to text-based serialization without significantly compromising efficiency.

Protocol Buffers have also dramatically improved my productivity with implementing the Fractus protocol.  I will jump right in with an example of the definition of a simple message.  This is how I represented a public key to be sent over a socket:


message PublicKey {
    required string encoding = 1;
    required bytes public_key = 2;
}


A detailed explanation of the Protocol Buffer definition language can be found on Google's Protocol Buffer website.  It's very straightforward to follow.

This way, the public key itself can be in any format, though X.509 is the representation used now.  The encoding is simply "X.509" in Unicode.  Very efficient and yet still extensible. 

Using this definition is extremely simple.  "protoc" is the Protocol Buffer compiler provided by Google.  It's even obtainable through Aptitude if you're on Ubuntu - `sudo apt-get install protobuf-compiler` will provide you with the utility needed to turn this into Java, C++ and Python with (if you wish) a single command.  Of course, this utility can also be downloaded directly from Google at the link provided above.

Each generated message comes with its own "Builder," which includes components for requisite parts of the message, such as enumerations (which naturally differ by each languages' native representation).  Then it's as simple as using the builder to construct a message, then serializing it, eventually to an array of bytes, which can then be deserialized by the receiver in any language without much hassle.

Here's how I made a public key message:


ProtocolBuffer.PublicKey pk =
ProtocolBuffer.PublicKey.newBuilder()
.setEncoding(em.getEncodingFormat())
.setPublicKey(ByteString.copyFrom(em.getPublicKey()))
.build();

ByteArrayOutputStream os = new ByteArrayOutputStream();
pk.writeTo(os);


The "em" object is the "encryption manager" which, among other things, keeps track of the user's public key data. "os," the ByteArrayOutputStream, now contains a cross-platform, serialized version of our public key. There's still one problem.

Protocol buffers natively only supports an RPC interface -- not implementation. So if you are using the messages as part of a network application, as I am, you have to do that part yourself. I chose to simply write my own because the RPC interface was very limited. It's a wrapper of the serialized protocol buffers which includes its own message type descriptor, which Google does not include. It's simply two bytes, prepended to the message, which is later used on the receiving end. For details, see the FractusMessage class in my Github repository. The client receiving the messages first reads these two bytes, and based on the current state of the connection (such as whether it's authenticated, and to whom it is), the message is sent to a strategy object which determines what to do with it, like change the icon in the buddy list, or display an instant message.

Protocol buffers can dramatically increase your productivity as a programmer and decrease the amount of resources your applications use -- in networking, memory and CPU. Benchmarks are widely available and usually place protocol buffers well ahead of any competition. They were a clear choice for Fractus, which transfers text data and will transfer audio and video in the near future as well. Using a uniform system for serializing all such kinds of data is important for writing clean, maintainable and high-performing code.

Monday, November 1, 2010

Netbeans GUI Builder Bug in Sun JVM

'Today, while working on the GUI for various parts of the application, I ran into this bug:



http://netbeans.org/bugzilla/show_bug.cgi?id=187697



It turns out that by switching to the OpenJDK''s JRE, this bug didn''t exist.  "java -version" gives:



java version "1.6.0_18"

OpenJDK Runtime Environment (IcedTea6 1.8.1) (6b18-1.8.1-0ubuntu1)

OpenJDK 64-Bit Server VM (build 16.0-b13, mixed mode)

'

Protocol Buffers

'Implementation continues of the binary protocol, based on Google''s Protocol Buffer technology .  This will allow for a much more elegant and efficient transfer of data both between peers, as well as between the client and server.



The basic unit of the Fractus protocol is the "Fractus Packet," which consists of:

  • The length of the data following as a four byte NBO integer
  • A FractusMessage, encrypted unless it''s a public key message (for ECDH purposes)

The Fractus Message consists of:

  • A two byte NBO short descriptor, which indicates its type (like "Instant Message" or "Add Friend Request")
  • A serialized Protocol Buffer Message (created by Google''s protoc-generated Java code.)
'

Fractus Development Blog is now live!

'At last, the Fractus development blog has been created to keep you updated on progress of the instant messenger''s design and implementation.  Stay tuned (via RSS) to find out more!'