Monday, December 12, 2011

JKstat at Play!

The Play framework seems to be quite popular around Cambridge.

For those not familiar with it, it's a java application framework built for REST. And, like Ruby on Rails, it emphasizes convention over configuration.

Rather than creating yet another boring blogging example I decided to use JKstat as an example, and see how involved building a RESTful JKstat server was using the Play framework.

Creating a project is easy:

play new jkstat

The one thing I'm not keen on is the way it manages dependencies for you to get you jar files. You can either mess about with yaml files, or drop the jar file into the lib directory of the project. Full details of the complex way are in the play directory of the JKstat source.

The next step is to decide how to route requests. The JKstat client only has a few requests, in a fairly fixed form. So I can write the routes file explicitly by hand:

# JKstat queries get sent to JKplay
GET /jkstat/getkcid    JKplay.getkcid
GET /jkstat/list    JKplay.list
GET /jkstat/get/{module}/{instance}/{name} JKplay.get

All this means is that if a client requests /jkstat/list, then the list() method in the JKplay class gets called.

Slightly more complex, something of the form /jkstat/get/module/instance/name will invoke a call to get(module, instance, name).

Putting this in a routes file in the application's conf directory is all that's needed to set up the routing. The other thing you need to do is write the JKplay class and put the java source in the application's app/controllers directory. The class just contains public static void methods with the correct signatures. For example:

    public static void list() {
 KstatSet kss = new KstatSet(jkstat);
 renderJSON(kss.toJSON());
    }

JKstat knows how to generate JSON output, and the renderJSON()call tells Play that this is JSON data (which just means it won't do anything with it, like format a template, which is the normal mode of operation).

And that's basically it. All I then had to do was run the project (with LD_LIBRARY_PATH set to find my jni library) and it was all set. The JKstat client was able to communicate with it just fine.

Sunday, December 11, 2011

Editing cells in a JTable

For the recently released update to Jangle I wanted to do a couple of things for the cousin and sibling tabs.

First, I wanted to have the list of OIDs and associated data to be slightly better formatted and to update along with the charts. This wasn't too difficult - the chart knows what the data is, so I got it to extend AbstractTableModel and could then simply use JTable to display it, just calling fireTableDataChanged at the end of the loop that updates the data.

(As an aside, I'm irritated that the API doesn't include fireTableColumnsChanged. You can do the whole table, or a cell, or by row, but not by column.)

The second thing I wanted to do was to allow the user to select the list of items to be shown in the chart. The picture above shows the table with the data, and how I wanted it to look. (And is exactly how I managed to implement it.)

Now, the table is already showing the list of available data, so I just added a third column to handle whether it's displayed in the chart or not. I simply implemented getColumnClass and returned Boolean.class for the third column, and the JTable automatically shows it as a checkbox. (With the value of the checkbox simply toggled from the underlying model.)

The next step was to be able to edit that field - tick or untick the checkbox - and get it to update the chart. The first step is easy enough - just get isCellEditable to return true for the third column.

I then actually got stuck, because the documentation simply isn't clear as to how to connect that all back up. I was looking for all sorts of listeners or event handlers, and couldn't find anything. Searching found a number of threads where someone else clearly didn't understand this either, with responses that were rude, patronising, or unhelpful - from people who regarded the answer as obvious.

Anyway, the important thing is that it really is easy and obvious once you've worked it out. Making the cell editable automatically creates a cell editor, and all the plumbing is created for you. All you have to do is implement setValueAt which gets called when you do your edit. So my implementation simply adds or removes the relevant field from the chart. (And because that's what's supplying the model, the value displayed in the checkbox automatically tracks it.)

That's the sort of basic thing that ought to be covered in documentation but isn't; this blog entry is there for the next time I forget how to do it.

Saturday, December 03, 2011

Building current gcc on Solaris 10

While Solaris 10 comes with gcc, it's quite an old version. For some modern code, you need to use a newer version - this is the case in my Node.js for Solaris builds, for example.

Actually building a current gcc on Solaris 10 turns out to be reasonably straightforward but, as in most things, there's a twist. So the follwoing is the procedure I've used successfully to get 4.6.X built.

You first need to download the release tarball from http://gcc.gnu.org/, and unpack it:

bzcat /path/to/gcc-4.6.2.tar.bz2 | gtar xf -

There are 3 prerequisites: gmp (4.3.2), mpfr (2.4.2), and mpc (0.8.1). However, you should use the specific version mentioned, which may not be the current versions. Conveniently, there's a copy of the right versions on ftp://gcc.gnu.org/pub/gcc/infrastructure/. Go into the gcc source, unpack them, and rename them to remove the version numbers.

cd gcc-4.6.2
bzcat /path/to/gmp-4.3.2.tar.bz2 | gtar xf -
mv gmp-4.3.2 gmp
zcat /path/to/mpfr-2.4.2.tar.bz2 | gtar xf -
mv mpfr-2.4.2 mpfr
gzcat /path/to/mpc-0.8.1.tar.gz | gtar xf -
mv mpc-0.8.1 mpc
cd ..

You have to build from outside the tree. If you followed the above, you'll be in the parent to gcc-4.6.2. Create a build directory and change into it:

mkdir build
cd build

Then you're ready to configure and build:

env PATH=/usr/bin:$PATH ../gcc-4.6.2/configure \
--prefix=/usr/local/versions/gcc-4.6.2 \
--enable-languages=c,c++,fortran
env PATH=/usr/bin:$PATH gmake -j 4
env PATH=/usr/bin:$PATH gmake install

There are three things to note here.

First is that I'm installing it into a location that is specific to this particular version of gcc. You don't have to, but I maintain large numbers of different versions of all sorts of applications, so they always live in their own space. You can put symlinks into a common location if necessary.

The second is one of the key tricks: I just build c, c++, and fortran. They're the only languages I actually need, and the build dies spectacularly with other languages enabled.

The third is that I force /usr/bin to the front of the PATH. Not ucb, and not xpg4 either.

You'll have to wait a while (and then some), but hopefully when that's all finished you'll have a modern compiler installed that will make building modern software such as Node.js much easier.