The Incrementalist

8/21/2005

Building LuaJava on Mac OS X

Filed under: — Joe @ 1:48 pm

In my previous post about coroutines, I mentioned that I’d be looking into LuaJava (a bridge between Java and the Lua language) as a way to get coroutine behavior in a Java environment. Since I had some time this afternoon, I decided to get LuaJava up and running on my PowerBook. Here are some steps that you can follow to build LuaJava on Mac OS X 10.4.2 Tiger. (I’ve also successfully tested these instructions on Mac OS X 10.3.9 Panther.)

LuaJava requires Lua 5.0, so first we need to download the Lua 5.0 source and build it:

% tar xzvf lua-5.0.tar.gz
% cd lua-5.0
% make
% sudo make install

Next, we need to build LuaJava. Download LuaJava 1.0, then extract it and switch to its directory:

% tar xzvf luajava-1.0.tar.gz
% cd luajava-1.0

Since LuaJava’s config file comes set up for Linux by default, we need to edit it to Mac OS X-friendly settings. Comment the following lines:

#JDK= $(JAVA_HOME)
#LIB_EXT= .so
#LIB_OPTION= -shared
#DLLIB= -ldl

and uncomment the corresponding ones:

JDK=/Library/Java/Home
LIB_EXT= .jnilib
LIB_OPTION= -dynamiclib -all_load

We also need to change the LIB_LUA line to read:

LIB_LUA=/usr/local/lib/liblua.a /usr/local/lib/liblualib.a

With those changes in place, we can just type

% make

and apart from a few JavaDoc warnings, everything should go smoothly. To test it, we can fire up the LuaJava Console:

% java -cp "luajava-1.0.jar" org.keplerproject.luajava.Console
API Lua Java - console mode.
> print('Hello, world!')
Hello, world!
> exit

OK, that looks good. How about the included tests?

% cd test
% ./runawttest.sh
% ./runswingtest.sh

Again, working fine. There are a couple of other Lua test files in the test directory that we can run like so:

% java -cp "../luajava-1.0.jar" -Djava.library.path=.. 
    org.keplerproject.luajava.Console testMemory.lua

(replace testMemory.lua with the name of the file you want to run)

OK, let’s try creating a program of our own. There’s a decent Hello World on the LuaJava examples page, so (after switching back to the luajava-1.0 directory), create the Hello.java and hello.lua files depicted on the examples page. You’ll need to add an import line to the top of Hello.java so that Java knows where to find all the LuaJava objects:

import org.keplerproject.luajava.*;

Once you have the files, compile the Java class:

% javac -classpath luajava-1.0.jar Hello.java

Now run it:

% java -cp luajava-1.0.jar:. Hello

If everything is working correctly, you should see:

Hello World from Lua!
Hello World from Java!

Huzzah! Now we have all the pieces we need to start embedding Lua functionality in Java code.

8/18/2005

(Lack of) Coroutines in Java

Filed under: — Joe @ 10:43 am

My current work project involves lots of small bits of code talking to each other asynchronously and requesting data from a distributed network. This means that when my code goes to retrieve a piece of data, it may be returned quickly, slowly, or not at all. Because of this uncertainty, we wouldn’t want to hold up other parts of the code while waiting for data, and so we want to put the requesting code aside and just come back to it later if and when the data arrives.

The current state of the art looks a bit like this–effectively a callback-based state machine:

Snippet establishPreference = new Snippet() {
    // called when the result of requestData is available
    public void dataReceivedCallback(Data d) {
        if (d.getValue("likes_marmalade")) {
            serveToast.requestData("marmalade");
        } else {
            serveBagel.requestData("cream cheese");
        }            
    }
}

Snippet serveToast = new Snippet() {
    public void dataReceivedCallback(Data d) {
        spreadOnToast(d.getValue("spoonful_of_substance"));                  
    }
}

Snippet serveBagel = new Snippet() {
    public void dataReceivedCallback(Data d) {
        spreadOnBagel(d.getValue("spoonful_of_substance"));
    }
}

To kick off this process, you would call:

establishPreference.requestData("Joe Hughes");

And then depending on whether I liked marmalade or not, I would eventually get served either toast with marmalade or a bagel with cream cheese.

This works fine, but you can see how it could easily get convoluted once you do any kind of serious branching or looping. For the sake of easier creation and maintenance of these things, I’d really like to be able to express these operations more like this:

Data customer = requestData("Joe Hughes");
if (customer.getValue("likes_marmalade")) {
    Data topping = requestData("marmalade");
    spreadOnToast(topping.getValue("spoonful_of_substance"));
} else {
    Data topping = requestData("cream cheese");
    spreadOnBagel(topping.getValue("spoonful_of_substance"));
}

When you put it that way, it’s much easier to see what’s going on. The problem is that in order for this to work, you have to be able to pause this block of code whenever you go off to do a requestData() call, and then restart it with result when you receive it. It turns out that what I’m describing is a somewhat obscure programming language construct called a coroutine.

Unfortunately, not many modern programming languages natively support coroutines. Python does, somewhat (through Stackless and the new Generator construct). Ruby seems to. Io and Lua do. Java, however, doesn’t.

I’ve certainly been able to use threads to make things that look like coroutines:

public abstract class PseudoCoroutine 
    implements DataListener, Runnable {

    private Data response = null;

    /**
     * This method starts a thread to run the specified task.
     *
     * @param task the PseudoCoroutine subclass to be run.
     */

    public static void doTask(PseudoCoroutine task) {
        t = new Thread(task, task.getClass().getName());
        t.start();
    }

    /**
     * This is a callback method from the DataListener interface
     * provided to the DataService to call when it has retrieved the requested data.
     *
     * @param d the data received
     */

    synchronized public void dataReceived(Data d) {
        this.response = d;
        notifyAll();
    }

    /**
     * Provides a delayed-synchronous way to perform a data request.
     * This method call will block until the response
     * is received from the server. 
     *
     * @param dataID the ID of the data to be requested.
     * @return A Data object corresponding to the requested dataID.
     * @throws InterruptedException
     */

    protected Data requestData(String dataID) throws InterruptedException {
        // second parameter is used to pass this.dataReceived() as a callback
        DataService.getInstance().requestData(dataID, this);

        synchronized (this) {
            while (this.response == null) {
                wait();
            }
        }

        return this.response;
    }

    // to make this a Runnable that can be passed to a thread
    public void run() {
        taskBody();
    }

    /**
     * This is where the PseudoCoroutine subclass should perform its task.
     */

    public abstract void taskBody();
}

This class lets me just use the code I had written above:

private class ServeBreakfastBread extends PseudoCoroutine {
    private String customerID;

    public ServeBreakfastBread(String customerID) {
        this.customerID = customerID;
    }

    public void taskBody() {
        Data customer = requestData(customerID);
        if (customer.getValue("likes_marmalade")) {
            Data topping = requestData("marmalade");
            spreadOnToast(topping.getValue("spoonful_of_substance"));
        } else {
            Data topping = requestData("cream cheese");
            spreadOnBagel(topping.getValue("spoonful_of_substance"));
        }
    }    
}

...

PseudoCoroutine.doTask(new ServeBreakfastBread("Joe Hughes"));

This works fine, except that each of these things now requires an OS thread, with their attendant limitations (good luck getting more than a few thousand on a desktop VM). I’d also like to have the ability for several of these coroutines to be able to operate on common state information without lots of synchronization hassle, which I can’t do if each coroutine lives in its own thread.

So, where to now? Maybe I can embed another language interpreter within my Java system and express the coroutines in that. Unfortunately, Jython doesn’t support Generators yet. I’ll have to look into LuaJava and JRuby to see if they have anything to offer.

8/16/2005

Teleport

Filed under: — Joe @ 9:05 am

The typical setup in my office is that I have my G5 powering two monitors front and center, and the powerbook beside them, on a (modified) iCurve for ergonomic viewing. While this is great for the displays, it leaves the problem of controlling the laptop. At one point I had a KVM switch set up, but the hassle of plugging in a USB cable and flipping the switch led me to just type un-ergonomically on the laptop’s keyboard.

Then I came across Synergy. It’s a cross-platform tool that lets you send your keyboard and mouse commands to other machines on your network–sort of like VNC without the screen-sharing (since the other screen is right in front of you). The Synergy team’s most brilliant innovation, though, is the interface for switching machines. Basically, you can configure your machines so that when you roll your mouse pointer off the edge of one machine’s screen, it magically appears on the corresponding edge of a different machine’s screen. You can roll your mouse from your Linux box across your Windows box over to your Mac in one smooth motion. It’s like the way that multi-monitor setups work, except that under the hood it’s seamlessly switching to sending your input to another machine over the network.

I’ve been using Synergy for a few months now, but it’s not without its rough edges. Last time I did it, configuration was a text-editing affair, though the SynergyKM preference pane add-on for Mac OS X makes things much more automatic. I also tended to experience general glitchiness on OS X. A vestigial mouse pointer would often remain on my main monitor, twitching distractingly, as I controlled the laptop. It also didn’t handle modifier and function keys, meaning I still had to press the function keys on the laptop directly to trigger Exposé.

Enter Teleport. While (or perhaps because) it’s Mac-only, it solves most of the problems I had with Synergy. The configuration is a breeze (using Rendezvous AKA Bonjour), and input forwarding is smooth and comprehensive. It also seems to automatically sync clipboards well, something that I was using Erik Lagercrantz’s ClipboardSharing utility for until he failed to update it for Tiger.

So far, I only have a few minor critiques. First, it doesn’t appear to allow you to put two remote screens side-by-side–the remote screens must be adjacent to the main computer’s screens. Also, it seems to hit the disk every time I roll over the boundary between two machines, which is audibly distracting and causes an annoying delay in which mouse motion isn’t counted on the new screen. Even so, I think it will be a part of my desktop setup from now on. Thanks Julien!