Compiling HAProxy on OS X

Posted in Uncategorized on June 26th, 2009 by Joel – Be the first to comment

If you want to use PCRE when building HAProxy on your mac (recommended by the docs) and you’ve installed PCRE using MacPorts (sudo port install pcre), you may need to tweak Makefile.osx to help it find the headers, otherwise you’ll see a whole slew of errors starting with this:

In file included from include/types/proxy.h:34,
                 from include/common/cfgparse.h:29In file included from include/types/proxy.h:34,
                 from include/common/cfgparse.h:29,
                 from src/haproxy.c:63:
include/common/regex.h:28:18:,
                 from src/haproxy.c:63:
include/common/regex.h:28:18: error:  error: pcre.h: No such file or directory
include/common/regex.h:29:23: error: pcreposix.h: No such file or directory

To fix that, open up Makefile.osx and find the two lines that define PCREDIR:

PCREDIR!= pcre-config --prefix 2>/dev/null || :
#PCREDIR=/usr/local

I commented out the first line, uncommented the second line and modified it to point at /opt/local instead of /usr/local:

PCREDIR=/opt/local

After that the compile worked. While I was at it I also set ARCH=x86_64 and TARGET=darwin, though I’m not sure if it actually accomplished anything.

Java 1.6 on OS X (Safari/Webkit crashes on start)

Posted in Uncategorized on June 26th, 2009 by Joel – Be the first to comment

… or maybe it’s Java 6 on OS X? – I can’t remember how they’re versioning the JDK these days.

After installing the recent Apple update for Java I started getting the “invalid target release: 1.6″ error when attempting to build a maven project. After some digging I found that the CurrentJDK symlink was pointing at 1.5 again, instead of 1.6, so I corrected that:

letdown:~ joel$ cd /System/Library/Frameworks/JavaVM.framework/
letdown:Versions joel$ sudo ln -s -f -n 1.6 CurrentJDK

This fixed maven (and, incidentally, I was also able to compile Cassandra without having to specify JAVA_HOME explicitly) and I thought all was well again.

A day later Safari crashed and attempts to relaunch it repeatedly failed. After a few attempts I clicked on the “Send Report to Apple” button and scrolled down to see what was being sent over. I noticed a line near the top said something about the JDK, which reminded me of the change I’d made above. Sure enough, switching CurrentJDK back to 1.5 allowed Safari to start without any problems. With Safari started again I went to Preferences and unchecked “Enable Java” in the Security tab. After that, I was able to point CurrentJDK at 1.6 as well as start Safari.

Hopefully this will save someone a little time if they encounter the same problem.

Thrift: Bidirectional Async RPC

Posted in Uncategorized, programming, thrift on April 3rd, 2009 by Joel – Be the first to comment

Source: BidiMessages.tgz
Jars: BidiMessagesJars.tgz

A reader posted to the thrift-user mailing list wondering if it was possible for a Thrift RPC server to send messages to the client. The responses indicated that this could be accomplished by polling the server for updates or hosting another Thrift server in the client that could receive RPCs from the server (requires opening another port on the client and handling firewall issues). I responded with a technique I’d used for accomplishing something similar and the responses made me think maybe this would be worth writing up and posting some example code.

Here’s my email to the mailing list that describes what I’m doing:

I think I’ve done something similar to what you’re trying to do, and as long as you can commit to using only async messages it’s possible to pull it off without having to start a server on the client to accept RPCs from the server.

When your RPC is marked as async the server doesn’t send a response and the client doesn’t try to read one. So, if all your RPC calls from the client to the server are async you have effectively freed up the inbound half of the socket connection. That means that you can use it for receiving async messages from the server – the only catch is that you have to start a new thread to read and dispatch the incoming async RPC calls.

In a typical Thrift RPC system you’d create a MyService.Processor on your server and a MyService.Client on your client. To do bidirectional async message sending you’ll need to go a step further and create a MyService.Client on your server for each client that connects (this can be accomplished by providing your own TProcessorFactory) and then on each client you create a MyService.Processor. (This assumes that you’ve gone with a generic MyService definition like you described above that has a bunch of optional messages, another option would be to define separate service definitions for the client and server.) With two clients connected the objects in existence would look something like this:

Server:
MyService.Processor mainProcessor – handles incoming async RPCs
MyService.Client clientA – used to send outgoing async RPCs to ClientA
MyService.Client clientB – used to send outgoing async RPCs to ClientB

ClientA:
MyService.Client – used to send messages to Server
MyService.Processor clientProcessor – used (by a separate thread) to process incoming async RPCs

ClientB:
MyService.Client – used to send messages to Server
MyService.Processor clientProcessor – used (by a separate thread) to process incoming async RPCs

Hopefully that explains the concept. If you need example code I can try and pull something together (it will be in Java). The nice thing about this method is that you don’t have to establish two connections, so you can get around the firewall issues others have mentioned. I’ve been using this method on a service in production and haven’t had any problems. When you have a separate thread in your client running a Processor you’re basically blocking on a read, waiting for a message from the server. The benefit of this is that you’re notified immediately when the server shuts down instead of having to wait until you send a message and then finding out that the TCP connection was reset.

Cheers,
Joel

Here’s an example app that sends messages between clients connected to a server. It’s similar to a chat app.

Thrift Definition

First, define your Thrift objects and the service. Our object and service are extremely simple:

#!/usr/local/bin/thrift --gen java:beans:hashcode -O ../
 
namespace java com.joelpm.bidiMessages.generated
 
struct Message {
  1: string clientName,
  2: string message
}
 
service MessageService {
  oneway void sendMessage(Message msg),
}

In this case the service is generic enough that both the client and server will use the same service definition. We could also create a ClientMessageService and a ServerMesageService if we needed different functionality.

Server

On the server side, when a client connection is accepted we want to create a MessageService.Client object that we’ll use to send messages back to the client. We can accomplish this by creating our own TProcessorFactory and using the getProcessor method as an opportunity to get access to the transport being used between the client and server:

    final MessageDistributor messageDistributor = new MessageDistributor();
 
    new Thread(messageDistributor).start();
 
    TProcessorFactory processorFactory = new TProcessorFactory(null) {
      @Override
      public TProcessor getProcessor(TTransport trans) {
        messageDistributor.addClient(new MessageServiceClient(trans));
        return new MessageService.Processor(messageDistributor);
      }
    };
 
    TServerTransport serverTransport = new TServerSocket(port);
    TServer server = new TThreadPoolServer(processorFactory, serverTransport);
    LOGGER.info("Server started");
    server.serve();

As you can see above, we’re using the same MessageDistributor for each new processor that we create. Before we create and return the processor we create a new client and add it to the list of clients that the MessageDistributor is aware of. The server is pretty simple and you can take a look at the code to see how the MessageDistributor uses the clients to send messages back.

Client

On the client side things are a little more complex because we have to create a separate thread to read incoming messages (this is handled by the TThreadPoolServer on the server side). Here’s the class that reads incoming messages:

public class MessageReceiver extends ConnectionRequiredRunnable {
  private final MessageService.Processor processor;
  private final TProtocol protocol;
 
  public MessageReceiver(
      TProtocol protocol,
      MessageService.Iface messageService,
      ConnectionStatusMonitor connectionMonitor) {
    super(connectionMonitor, "Message Receiver");
    this.protocol = protocol;
    this.processor = new MessageService.Processor(messageService);
  }
 
  @Override
  public void run() {
    connectWait();
    while (true) {
      try {
        while (processor.process(protocol, protocol) == true) { }
      } catch (TException e) {
        disconnected();
      }
    }
  }
}

It extends a utility class called ConnectionRequiredRunnable that provides utility methods for handling server disconnects and reconnects, but on the whole it’s pretty simple because we pass in a separate class that actually handles the incoming messages. We also create a MessageService.Client, but we wrap it in a separate thread and use a blocking queue so that other components in the system wanting to send a message can do so very quickly – or at least, have the message handed off for delivery extremely quickly.

Here’s the class that handles our message sending:

public class MessageSender extends ConnectionRequiredRunnable {
  private final MessageService.Client client;
  private final BlockingQueue<Message> msgSendQueue;
 
  public MessageSender(
      TProtocol protocol,
      ConnectionStatusMonitor connectionMonitor) {
    super(connectionMonitor, "Message Sender");
    this.client = new MessageService.Client(protocol);
    this.msgSendQueue = new LinkedBlockingQueue<Message>();
  }
 
  public void send(Message msg) {
    msgSendQueue.add(msg);
  }
 
  @Override
  public void run() {
    connectWait();
    while (true) {
      try {
        Message msg = msgSendQueue.take();
        try {
          client.sendMessage(msg);
        } catch (TException e) {
          // The message isn't lost, but it could end up being sent out of
          // order - not ideal.
          msgSendQueue.add(msg);
          disconnected();
        }
      } catch (InterruptedException e) {
        // Thread will be interrupted if connection is lost, we should wait
        // for reconnection if that happens.
        connectWait();
      }
    }
  }
}

This class also extends ConnectionRequiredRunnable since it can’t send messages without a connection. Here’s the main method of the Client that establishes the connection to the server:

    this.transport = new TSocket(server, port);
    this.protocol = new TBinaryProtocol(transport);
 
    this.connectionMonitor = new ConnectionStatusMonitor(transport);
 
    this.sender = new MessageSender(protocol, connectionMonitor);
    this.receiver = new MessageReceiver(protocol, messageHandler, connectionMonitor);
 
    new Thread(sender).start();
    new Thread(receiver).start();
 
    this.connectionMonitor.tryOpen();

It actually looks pretty simple since all the different pieces are organized in separate classes. The ConnectionStatusMonitor class is responsible for opening the actual connection and notifying the MessageSender and MessageReceiver when the connection has been established, at which point they’ll start sending and receiving messages. If the server dies both of those processes will stop and wait until a connection has been re-established (a task the ConnectionStatusMonitor is responsible for). Here’s sample output from the server:

2009-04-03 16:28:44,029  INFO main com.joelpm.bidiMessages.server.Server:43 - Server started
2009-04-03 16:28:45,814  INFO pool-1-thread-1 com.joelpm.bidiMessages.server.MessageDistributor:36 - Added client at 127.0.0.1
2009-04-03 16:28:45,822  INFO pool-1-thread-1 com.joelpm.bidiMessages.server.MessageDistributor:66 - Adding message to queue:
Message(clientName:client1, message:Hello there!)
2009-04-03 16:28:45,823  INFO pool-1-thread-1 com.joelpm.bidiMessages.server.MessageDistributor:66 - Adding message to queue:
Message(clientName:client1, message:Message 0)
2009-04-03 16:28:46,807  INFO pool-1-thread-1 com.joelpm.bidiMessages.server.MessageDistributor:66 - Adding message to queue:
Message(clientName:client1, message:Message 1)
2009-04-03 16:28:46,864  INFO pool-1-thread-2 com.joelpm.bidiMessages.server.MessageDistributor:36 - Added client at 127.0.0.1
2009-04-03 16:28:46,895  INFO pool-1-thread-2 com.joelpm.bidiMessages.server.MessageDistributor:66 - Adding message to queue:
Message(clientName:client2, message:Hello there!)
2009-04-03 16:28:46,897  INFO pool-1-thread-2 com.joelpm.bidiMessages.server.MessageDistributor:66 - Adding message to queue:
Message(clientName:client2, message:Message 0)
2009-04-03 16:28:47,805  INFO pool-1-thread-1 com.joelpm.bidiMessages.server.MessageDistributor:66 - Adding message to queue:
Message(clientName:client1, message:Message 2)
2009-04-03 16:28:47,885  INFO pool-1-thread-2 com.joelpm.bidiMessages.server.MessageDistributor:66 - Adding message to queue:
Message(clientName:client2, message:Message 1)
2009-04-03 16:28:48,806  INFO pool-1-thread-1 com.joelpm.bidiMessages.server.MessageDistributor:66 - Adding message to queue:
Message(clientName:client1, message:Message 3)
2009-04-03 16:28:48,885  INFO pool-1-thread-2 com.joelpm.bidiMessages.server.MessageDistributor:66 - Adding message to queue:
Message(clientName:client2, message:Message 2)
2009-04-03 16:28:49,806  INFO pool-1-thread-1 com.joelpm.bidiMessages.server.MessageDistributor:66 - Adding message to queue:
Message(clientName:client1, message:Message 4)
2009-04-03 16:28:49,885  INFO pool-1-thread-2 com.joelpm.bidiMessages.server.MessageDistributor:66 - Adding message to queue:
Message(clientName:client2, message:Message 3)
^C2009-04-03 16:28:50,807  INFO pool-1-thread-1 com.joelpm.bidiMessages.server.MessageDistributor:66 - Adding message to queue:
Message(clientName:client1, message:Message 5)

And here’s output from client1:

$ java -jar Client/target/BidiMessages.Client-0.9-jar-with-dependencies.jar client1 localhost 10101
2009-04-03 16:28:45,792  INFO Thread-3 com.joelpm.bidiMessages.client.ConnectionRequiredRunnable:42 - Message Receiver waiting for connection to be established.
2009-04-03 16:28:45,792  INFO Thread-2 com.joelpm.bidiMessages.client.ConnectionRequiredRunnable:42 - Message Sender waiting for connection to be established.
2009-04-03 16:28:45,803  INFO Thread-2 com.joelpm.bidiMessages.client.ConnectionRequiredRunnable:48 - Message Sender notified of connection, resuming execution
2009-04-03 16:28:45,806  INFO Thread-3 com.joelpm.bidiMessages.client.ConnectionRequiredRunnable:48 - Message Receiver notified of connection, resuming execution
Got msg: Message(clientName:client1, message:Hello there!)
Got msg: Message(clientName:client1, message:Message 0)
Got msg: Message(clientName:client1, message:Message 1)
Got msg: Message(clientName:client2, message:Hello there!)
Got msg: Message(clientName:client2, message:Message 0)
Got msg: Message(clientName:client1, message:Message 2)
Got msg: Message(clientName:client2, message:Message 1)
Got msg: Message(clientName:client1, message:Message 3)
Got msg: Message(clientName:client2, message:Message 2)
Got msg: Message(clientName:client1, message:Message 4)
Got msg: Message(clientName:client2, message:Message 3)
Got msg: Message(clientName:client1, message:Message 5)
2009-04-03 16:28:51,146  INFO Thread-3 com.joelpm.bidiMessages.client.ConnectionRequiredRunnable:30 - Message Receiver detected a disconnect from the server.
2009-04-03 16:28:51,148  INFO Thread-3 com.joelpm.bidiMessages.client.ConnectionRequiredRunnable:42 - Message Receiver waiting for connection to be established.
2009-04-03 16:28:51,149  INFO Thread-2 com.joelpm.bidiMessages.client.ConnectionRequiredRunnable:42 - Message Sender waiting for connection to be established.

And here’s from client2:

$ java -jar Client/target/BidiMessages.Client-0.9-jar-with-dependencies.jar client2 localhost 10101
2009-04-03 16:28:46,851  INFO Thread-2 com.joelpm.bidiMessages.client.ConnectionRequiredRunnable:42 - Message Sender waiting for connection to be established.
2009-04-03 16:28:46,854  INFO Thread-3 com.joelpm.bidiMessages.client.ConnectionRequiredRunnable:42 - Message Receiver waiting for connection to be established.
2009-04-03 16:28:46,867  INFO Thread-2 com.joelpm.bidiMessages.client.ConnectionRequiredRunnable:48 - Message Sender notified of connection, resuming execution
2009-04-03 16:28:46,879  INFO Thread-3 com.joelpm.bidiMessages.client.ConnectionRequiredRunnable:48 - Message Receiver notified of connection, resuming execution
Got msg: Message(clientName:client2, message:Hello there!)
Got msg: Message(clientName:client2, message:Message 0)
Got msg: Message(clientName:client1, message:Message 2)
Got msg: Message(clientName:client2, message:Message 1)
Got msg: Message(clientName:client1, message:Message 3)
Got msg: Message(clientName:client2, message:Message 2)
Got msg: Message(clientName:client1, message:Message 4)
Got msg: Message(clientName:client2, message:Message 3)
Got msg: Message(clientName:client1, message:Message 5)
2009-04-03 16:28:51,146  INFO Thread-3 com.joelpm.bidiMessages.client.ConnectionRequiredRunnable:30 - Message Receiver detected a disconnect from the server.
2009-04-03 16:28:51,147  INFO Thread-3 com.joelpm.bidiMessages.client.ConnectionRequiredRunnable:42 - Message Receiver waiting for connection to be established.
2009-04-03 16:28:51,147  INFO Thread-2 com.joelpm.bidiMessages.client.ConnectionRequiredRunnable:42 - Message Sender waiting for connection to be established.

You can see that client1 and client2 paused when the server was terminated. Had the server restarted the clients would have reconnected and begun sending messages again.

The source is built using Maven and requires that you’ve installed libthrift.jar in your local maven repo (see the README for details). I’m also including a tgz with the compiled jar files for those who can’t build the source.

Source: BidiMessages.tgz
Jars: BidiMessagesJars.tgz

Thrift: Reading Thrift Objects from Disk with Java

Posted in thrift on February 5th, 2009 by Joel – Be the first to comment

Reading Thrift objects is as easy as writing them to disk. Here’s the utility class I use for reading one or more Thrift objects (of the same type) serialized to disk:

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
 
import com.facebook.thrift.TBase;
import com.facebook.thrift.TException;
import com.facebook.thrift.protocol.TBinaryProtocol;
import com.facebook.thrift.transport.TIOStreamTransport;
 
/**
 * A simple class for reading Thrift objects (of a single type) from a file.
 *
 * @author Joel Meyer
 */
public class ThriftReader {
  /**
    * Thrift deserializes by taking an existing object and populating it. ThriftReader
    * needs a way of obtaining instances of the class to be populated and this interface
    * defines the mechanism by which a client provides these instances.
    */
  public static interface TBaseCreator {
    TBase create();
  }
 
  /** File containing the objects. */
  protected final File file;
 
  /** Used to create empty objects that will be initialized with values from the file. */
  protected final TBaseCreator creator;
 
  /** For reading the file. */
  private BufferedInputStream bufferedIn;
 
  /** For reading the binary thrift objects. */
  private TBinaryProtocol binaryIn;
 
  /**
    * Constructor.
    */
  public ThriftReader(File file, TBaseCreator creator) {
    this.file = file;
    this.creator = creator;
  }
 
  /**
    * Opens the file for reading. Must be called before {@link read()}.
    */
  public void open() throws FileNotFoundException {
    bufferedIn = new BufferedInputStream(new FileInputStream(file), 2048);
    binaryIn = new TBinaryProtocol(new TIOStreamTransport(bufferedIn));
  }
 
  /**
    * Checks if another objects is available by attempting to read another byte from the stream.
    */
  public boolean hasNext() throws IOException {
    bufferedIn.mark(1);
    int val = bufferedIn.read();
    bufferedIn.reset();
    return val != -1;
  }
 
  /**
    * Reads the next object from the file.
    */
  public TBase read() throws IOException {
    TBase t = creator.create();
    try {
      t.read(binaryIn);
    } catch (TException e) {
      throw new IOException(e);
    }
    return t;
  }
 
  /**
    * Close the file.
    */
  public ThriftReader close() throws IOException {
    bufferedIn.close();
    return this;
  }
}

This class is useful if you’ve got a file containing a list of Thrift objects of the same type. Let’s say you had a Thrift object called Album and a file containing a list of these Album objects. To read the file you’d do this:

// Create the reader
ThriftReader thriftIn = new ThriftReader(new File("/some/thrift/file.thrifty", new ThriftReader.TBaseCreator() {
  @Override TBase create() {
    return new Album();
  }
});
 
// Open it
thriftIn.open();
 
// Read objects
List<Album> albums = new ArrayList<Album>();
while (thriftIn.hasNext()) {
  albums.add((Album)thriftIn.read());
}
 
// Close reader
thriftIn.close();

As mentioned in the post on writing Thrift objects, TBase is the interface all Thrift objects implement that provides the read(…) and write(…) methods. When you’re dealing with generated files you’re limited to the code that’s generated, so in this case I opted to use the TBase interface since that at least guarantees that the read and write methods will exist. I thought about making the class generic and casting to TBase, but then it’s not clear (well, not contractually enforced) that the class is expecting a Thrift object. The downside of my method is that you have an unchecked cast, which I’m not a fan of.

Thrift: Writing Thrift Objects to Disk with Java

Posted in thrift on February 5th, 2009 by Joel – 1 Comment

If you’re using files to pass data around between different components of a system it may make sense to use Thrift. Doing so means you get smaller file sizes (assuming you do binary serialization) but still have files that can be easily read in many programming languages.

In Java, writing Thrift objects to disk is straightforward. Here’s a utility class that I use for doing so:

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
 
import com.facebook.thrift.TBase;
import com.facebook.thrift.TException;
import com.facebook.thrift.protocol.TBinaryProtocol;
import com.facebook.thrift.transport.TIOStreamTransport;
 
/**
 * Simple class that makes it easy to write Thrift objects to disk.
 * @author Joel Meyer
 */
public class ThriftWriter {
  /** File to write to. */
  protected final File file;
 
  /** For writing to the file. */
  private BufferedOutputStream bufferedOut;
 
  /** For binary serialization of objects. */
  private TBinaryProtocol binaryOut;
 
  /**
    * Constructor.
    */
  public ThriftWriter(File file) {
    this.file = file;
  }
 
  /**
    * Open the file for writing.
    */
  public void open() throws FileNotFoundException {
    bufferedOut = new BufferedOutputStream(new FileOutputStream(file), 2048);
    binaryOut = new TBinaryProtocol(new TIOStreamTransport(bufferedOut));
  }
 
  /**
    * Write the object to disk.
    */
  public void write(TBase t) throws IOException {
    try {
      t.write(binaryOut);
      bufferedOut.flush();
    } catch (TException e) {
      throw new IOException(e);
    }
  }
 
  /**
    * Close the file stream.
    */
  public void close() throws IOException {
    bufferedOut.close();
  }
}

If you have a Thrift object called Album and you’d like to write a list of them to file you’d do it like so:

// Create writer
ThriftWriter thriftOut = new ThriftWriter(new File("/some/thrift/file.thrifty"));
 
// Open writer
thriftOut.open();
 
// Write the objects to disk
for (Album album : albums) {
  thriftOut.write(album);
}
 
// Close the writer
thriftOut.close();

ThriftWriter uses the interface com.facebook.thrift.TBase, which defines the methods needed for reading and writing a Thrift object to a Thrift protocol. We could use a single ThriftWriter to write any number of different objects to disk, since they all implement TBase, but then you’d have to make sure you knew what order the objects came in when reading the file.

Invoking the Thrift Compiler from Maven

Posted in programming, thrift on January 28th, 2009 by Joel – Be the first to comment

Thrift and Protocol Buffers require you to invoke a custom compiler during the build process to generate source code from the message definitions in your .thrift or .proto files. You can accomplish this with Maven by using the antrun plugin. Here’s the relevant section from pom.xml:

  <profiles>
    <profile>
      <id>profile-buildthrift</id>
      <activation>
        <file>
          <exists>/usr/local/bin/thrift</exists>
        </file>
      </activation>
      <build>
        <plugins>
          <plugin>
            <artifactId>maven-antrun-plugin</artifactId>
            <executions>
              <execution>
                <id>generate-sources</id>
                <phase>generate-sources</phase>
                <configuration>
                  <tasks>
                    <mkdir dir="target/generated-sources" />
                    <exec executable="${thrift.executable}">
                      <arg value="--gen" />
                      <arg value="java:beans"/>
                      <arg value="-o"/>
                      <arg value="target/generated-sources"/>
                      <arg value="src/main/resources/MyThriftMessages.thrift"/>
                    </exec>
                    <delete>
                      <fileset dir="src/main/java/com/joelpm/generated" includes="**/*"/>
                    </delete>
                    <copy todir="src/main/java/com/joelpm/generated">
                      <fileset dir="target/generated-sources/gen-javabean/com/joelpm/generated"/>
                    </copy>
                  </tasks>
                </configuration>
                <goals>
                  <goal>run</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>

You’ll notice that the whole thing is wrapped in a profile with an activation. This is done so machines that don’t have the Thrift compiler installed can still build using the most recent checked-in version of the generated files.

Inside the antrun plugin we use four tasks to accomplish what we want:

  1. Create the output directory for the generated sources under the target directory.
  2. Invoke the thrift compiler and tell it to generate Java Bean style getters & setters, to write the output to the directory we just created, and to look for our Thrift file in the src/main/resources directory.
  3. Delete all files under src/main/java/com/joelpm/generated
  4. Copy all generated source to src/main/java/com/joelpm/generated

You may be wondering why the generated source is added to the src tree (and as a result gets checked into the SCM) instead of being passed to the Java compiler for compilation. I did it this way because I want machines that don’t have the Thrift compiler installed to be able to build the project. To be honest, I have mixed feelings about checking the generated source into Subversion, but for now this is what I’ve settled on.

The last thing to note is that the thrift compiler is going to put the generated java source in com/joelpm/generated because my thrift message definition contains the namespace directive:

namespace java com.joelpm.generated

I use ‘generated’ in the package name as a way to call out the fact that the source in that package is generated and should not be modified by hand.

Maven Assembly Plugin Woes

Posted in programming on January 23rd, 2009 by Joel – 3 Comments

In the last paragraph of my last post I mentioned a maven ‘gotcha’ that I had to work around. The problem is that when using the maven-assembly-plugin to create a jar with all dependencies the plugin unpacks all the jars and then repacks them all in a single jar. This works fine as long as there are no overlapping resource names in the set of all jars. Unfortunately, in my limited experience, this has proven to be the exception rather than the rule. If there are resources with the same name (under META-INF for example) the plugin only adds one of them to the final jar.

One way to solve the problem would be to write a ContainerDescriptorHandler for each type of resource that overlaps and merge them (or take whatever action is appropriate for that file type). There are two problems that I see with that approach:

  1. You have to do some kind of analysis to see what resources need ContainerDescriptorHandlers written, and
  2. You have to write the ContainerDescriptorHandlers. This is problematic because it’s possible that you would add a new dependency and find you now have to write a new ContainerDescriptorHandler because there’s a new type of resource conflict – now you’re doing development on your project and development on the build system that builds your project (and the latter is probably not what you’re being paid to do – also, that work probably wasn’t scoped when project dates were being set). And then there’s the fact that all my searching for how to create and register a handler didn’t turn up a single example.

After being bitten by this gotcha twice in as many days, and in each case spending a whole bunch of time debugging before identifying what the problem was (Hurray for bugs that manifest themselves in extremely varying ways! Almost as fun as multi-threaded code with timing bugs…), I gave up on using the assembly plugin to create a single jar and began looking for alternatives.

After several failed attempts at creating a jar that didn’t unpack dependencies and automatically created the manifest with a Class-Path entry pointing to the dependencies I gave up on the idea of a single jar completely. In my searches for a solution I came across the Application Assembler Plugin. This plugin creates a parent directory with sub-directories for dependencies, resources, and scripts to start your application. Combining this with the assembly plugin I was able to create a zip file that could be uploaded to the server and deployed. Here’s what the relevant section of the pom.xml looks like:

    <build>
    <plugins>
      <!-- [SNIP] -->
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>appassembler-maven-plugin</artifactId>
        <configuration>
          <assembleDirectory>${project.build.directory}/appassembler</assembleDirectory>
          <includeConfigurationDirectoryInClasspath>true</includeConfigurationDirectoryInClasspath>
          <platforms>
            <platform>unix</platform>
          </platforms>
          <programs>
            <program>
              <name>MyApp</name>
              <mainClass>path.to.my.App</mainClass>
            </program>
          </programs>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>assemble</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
 
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptors>
            <descriptor>src/assemble/DeployBuilder.xml</descriptor>
          </descriptors>
        </configuration>
        <executions>
          <execution>
            <id>simple-command</id>
            <phase>package</phase>
            <goals>
              <goal>directory-inline</goal>
              <goal>attached</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <!-- [SNIP] -->
    </plugins>
  </build>

The above snippet configures the appassembler and assembly plugins. The assembly plugin references an assembly definition under src/assemble that looks like this:

<assembly>
  <id>deploy</id>
  <formats>
    <format>zip</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <fileSets>
    <fileSet>
      <directory>src/main/resources</directory>
      <outputDirectory>etc</outputDirectory>
      <lineEnding>unix</lineEnding>
    </fileSet>
    <fileSet>
      <directory>target/appassembler/bin</directory>
      <outputDirectory>bin</outputDirectory>
      <lineEnding>unix</lineEnding>
      <fileMode>0755</fileMode>
    </fileSet>
    <fileSet>
      <directory>target/appassembler/repo</directory>
      <outputDirectory>repo</outputDirectory>
    </fileSet>
  </fileSets>
</assembly>

The assembly definition creates a zip with the output of the appassembler plugin and also includes any resources from src/main/resources under the directory etc/, which the appassembler startup script will add to the classpath. This issue in Jira was extremely helpful, though it’s a little unfortunate the information wasn’t more readily available in docs or somewhere else.

These issues with maven have made me think more about switching to Buildr when I get a chance. It seems like the amount of XML required to get my projects to build the way I want is continually increasing. Essentially what I’m doing is scripting the build by adding more and more plugins (via XML) and, to be honest, I’d rather use a scripting language for that.

Rest In a Jar: Maven, Spring, Jetty, and Jersey

Posted in programming on January 22nd, 2009 by Joel – Be the first to comment

Here’s a quick example of how to use Maven, Spring, embedded Jetty, and Jersey to build an application that provides a RESTful interface (in a single Jar file).

There are four main parts to this project:

  1. First, create and configure the project using Maven.
  2. Second, create the resources.
  3. Third, create/configure the Jetty server.
  4. Finally, tie it all together with Spring.

First, create your project using Maven:

$ mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DgroupId=com.joelpm -DartifactId=restInAJar

Now we need to configure the project – this includes adding the dependencies and telling Maven where they can be found (the repositories). We also add two plug-ins – one to tell Maven we’re using Java 1.6 and the second (the Assembly plug-in) to build a jar file that includes our code as well as all dependencies. Here’s what the finished file looks like:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.joelpm</groupId>
  <artifactId>restInAJar</artifactId>
 
  <packaging>jar</packaging>
 
  <version>1.0-SNAPSHOT</version>
  <name>restInAJar</name>
  <url>http://maven.apache.org</url>
 
  <properties>
    <gson.version>1.2.3</gson.version>
    <jersey.version>1.0.1</jersey.version>
    <jetty.version>7.0.0.pre5</jetty.version>
    <junit.version>3.8.1</junit.version>
    <spring.version>2.5.6</spring.version>
  </properties>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junit.version}</version>
      <scope>test</scope>
    </dependency>
 
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>${gson.version}</version>
      <scope>compile</scope>
    </dependency>
 
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-server</artifactId>
      <version>${jersey.version}</version>
    </dependency>
 
    <dependency>
      <groupId>com.sun.jersey.contribs</groupId>
      <artifactId>jersey-spring</artifactId>
      <version>${jersey.version}</version>
    </dependency>
 
    <dependency>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>jetty</artifactId>
      <version>${jetty.version}</version>
    </dependency>
 
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring</artifactId>
      <version>${spring.version}</version>
    </dependency>
  </dependencies>
 
  <build>
    <plugins>
      <!-- Tell Maven we're using Java 1.6 -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.0.2</version>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
        </configuration>
      </plugin>
 
      <!-- Configure the assembly plugin to build a single jar with all dependecies -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <archive>
            <manifest>
              <mainClass>com.joelpm.restInAJar.App</mainClass>
            </manifest>
          </archive>
        </configuration>
        <executions>
          <execution>
            <id>simple-command</id>
            <phase>package</phase>
            <goals>
              <goal>attached</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
 
  <repositories>
    <!-- Repository for the GSON code -->
    <repository>
      <id>gson</id>
      <url>http://google-gson.googlecode.com/svn/mavenrepo</url>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
      <releases>
        <enabled>true</enabled>
      </releases>
    </repository>
 
    <!-- Repository for the Jersey code -->
    <repository>
      <id>maven2-repository.dev.java.net</id>
      <name>Java.net Repository for Maven</name>
      <url>http://download.java.net/maven/2/</url>
      <layout>default</layout>
    </repository> 
 
    <!-- Repository for the Jetty code -->
    <repository>
      <releases>
        <enabled>true</enabled>
        <updatePolicy>never</updatePolicy>
        <checksumPolicy>warn</checksumPolicy>
      </releases>
      <id>codehaus</id>
      <name>Codehaus Maven2 Repository</name>
      <url>http://repository.codehaus.org/</url>
      <layout>default</layout>
    </repository>
  </repositories>
</project>

I’ve set the main class to be com.joelpm.restInAJar.Launcher, which we’ll create later on.

Now let’s move on to creating a resource. We’ll put resources in their own package at com.joelpm.restInAJar.resources. We’ll just create a simple resource that provides an in-memory hashmap:

package com.joelpm.restInAJar.resources;
 
import java.lang.reflect.Type;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
 
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
 
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
 
/**
 * This class provides the resource manipulated through the /map path.
 * We use Spring annotations to declare it as a Singleton and Jersey/JAX-RS
 * annotations to describe the REST interface.
 * 
 * This class is designed to work with Dojo's JsonRest and JsonRestStore,
 * which is why the PUT/POST methods function the way they do.
 * 
 * @author Joel Meyer
 *
 */
@Component
@Scope("singleton")
@Path("/map")
@Produces(MediaType.APPLICATION_JSON)
public class MapResource {
  // Map to store the values
  private final Map<String,String> map = new ConcurrentHashMap<String,String>();
 
  // Used to serialize/deserialize JSON
  private final Gson gson = new Gson();
 
  // Needed by Gson to deserialize a Map<String,String>
  Type stringMapType = new TypeToken<Map<String,String>>(){}.getType();
 
  @GET
  public String getEntireMapJson() {
    return gson.toJson(map);
  }
 
  @GET
  @Path("{key}")
  public String getValueForKeyJson(@PathParam("key") String key) {
    return gson.toJson(map.get(key));
  }
 
  @POST
  @Consumes(MediaType.APPLICATION_JSON)
  public Response addKeyValueJson(String json) {
    Map<String,String> keyValues = gson.fromJson(json, stringMapType);
    map.putAll(keyValues);
    return Response.ok().build();
  }
 
  @PUT
  @Consumes(MediaType.APPLICATION_JSON)
  @Path("{key}")
  public Response putValueJson(@PathParam("key") String key, String json) {
    String value = gson.fromJson(json, String.class);
    map.put(key, value);
    return Response.ok().build();
  }
 
  @DELETE
  @Path("{key}")
  public Response deleteKeyValue(@PathParam("key") String key) {
    map.remove(key);
    return Response.ok().build();
  }
}

I’ve omitted error checking for the sake of brevity in the example above – consider that an exercise for the reader.

With our resource defined we need a way to serve it up, which is where Jetty comes in. Jersey-server provides the com.sun.jersey.spi.spring.container.servlet.SpringServlet which is designed to work with Spring web-apps, but we’re going to use a very simple embedded Jetty that we configure programmatically so we need to extend that servlet and create our own:

package com.joelpm.restInAJar;
 
import java.util.logging.Level;
import java.util.logging.Logger;
 
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
 
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.spi.container.WebApplication;
import com.sun.jersey.spi.spring.container.SpringComponentProviderFactory;
import com.sun.jersey.spi.spring.container.servlet.SpringServlet;
 
/**
 * Extends {@link SpringServlet} so we can control what context gets passed to the
 * {@link SpringComponentFactory} and implements {@link ApplicationContextAware} so
 * that Spring can give us a reference to the application context when it instantiates
 * this class. We then pass the application context that Spring gave us to the
 * SpringComponentFactory.
 * 
 * @author Joel Meyer
 *
 */
@Component
@Scope("singleton")
public class EmbeddedJettySpringServlet extends SpringServlet implements ApplicationContextAware {
  private static final long serialVersionUID = 1L;
  private static final Logger LOGGER = Logger.getLogger(EmbeddedJettySpringServlet.class.getName());
 
  private ApplicationContext springContext;
 
  public EmbeddedJettySpringServlet() {
    super();
  }
 
  @Override
  protected void initiate(ResourceConfig rc, WebApplication wa) {
    try {
      wa.initiate(rc, new SpringComponentProviderFactory(rc, (ConfigurableApplicationContext) springContext));
    } catch( RuntimeException e ) {
      LOGGER.log(Level.SEVERE, "Exception occurred when intializing", e);
      throw e;
    }
  }
 
  /**
   * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
   */
  @Override
  public void setApplicationContext(ApplicationContext applicationContext)
      throws BeansException {
    springContext = applicationContext;
  }
}

Our EmbeddedJettySpringServlet is ApplicationContextAware so that Spring gives it a reference to the application context when Spring instantiates this class.

Now that we have our modified servlet we just need to create the Jetty server to host it, which we do in the Launcher:

package com.joelpm.restInAJar;
 
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.ContextHandlerCollection;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import org.springframework.beans.factory.annotation.Autowired;
 
/**
 * Configures Jetty.
 * 
 * @author Joel Meyer
 */
public class Launcher {
  private final Server server;
 
  @Autowired
  public Launcher(EmbeddedJettySpringServlet restServlet) {
    server = new Server(8080);
 
    ContextHandlerCollection contexts = new ContextHandlerCollection();
    server.setHandler(contexts);
 
    Context rest = new Context(contexts, "/");
    rest.getServletContext();
    rest.addServlet(new ServletHolder(restServlet), "/*");
  }
 
  public void start() {
    try {
      server.start();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
 
  public void stop() {
    try {
      server.stop();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

We’re now done with coding, we just need to set up our application-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
 
  <!-- This initializes all the classes that we annotated with @Component -->
  <context:component-scan base-package="com.joelpm.restInAJar"/>
 
  <bean name="launcher" class="com.joelpm.restInAJar.Launcher">
  </bean>
</beans>

Because we annotated the classes with @Component, @Scope, and @Autowire as we went along Spring takes care of most of the work for us. All we have to do is tell Spring to scan our classes looking for those annotations and create the Launcher. In our static main all we have to do is:

package com.joelpm.restInAJar;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
/**
 * 
 */
public class App {
  public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-context.xml");
    Launcher restInAJarLauncher = (Launcher)applicationContext.getBean("launcher");
    restInAJarLauncher.start();
  }
}

Now all that remains is to build and run our server:

$ mvn clean package
$ java -jar target/restInAJar-1.0-SNAPSHOT-jar-with-dependencies.jar

Well, I wish it was that easy. Unfortunately there’s a gotcha. When the assembly plugin creates the combined jar it overwrites some files instead of combining them. The Jersey ServiceProvider looks in META-INF/services/ for a text file that lists the classes that provide services of a given type (denoted by the name of the text file). Both jersey-core.jar and jersey-server.jar provide copies of some of these files, but the final assembly only contains the files from jersey-server.jar. The right way to solve this problem is with a ContainerDescriptorHandler that merges these files, but I couldn’t find any documentation on how to create one and have Maven use it so I resorted to a hack, which is manually merging these files and placing them in my local resources/META-INF/services directory – these copies then overwrite any provided by the dependencies.

Eclipse: Sometimes I Hate It

Posted in programming on January 21st, 2009 by Joel – Be the first to comment
It's like a recursive error...

It's like a recursive error...

I hate it most when I wait six minutes for an error message that tells me there was an error while attempting to show the details of an error.

Dojo: DataGrid element stays Editable

Posted in javascript on January 19th, 2009 by Joel – Be the first to comment

And another one while I’m thinking of it: Yesterday night I couldn’t figure out why an editable cell in my DataGrid stayed in the editable state even after the update had been applied to the store. It turns out you have to explicitly call updateRow on the row the editable cell exists in to get it to revert to the non-editable state. To do that, you have to set the onApplyCellEdit method on the DataGrid, which you do thusly:

dojo.declare("joelpm.widgets.FooWidget", [dijit._Widget, dijit._Templated], {
  // ...
  postCreate: function() {
    // this.gridAP is the dojoAttachPoint assigned to the grid.
    this.gridAP.onApplyCellEdit = dojo.hitch(this.gridAP, function(inValue, inRowIndex, inAttrName) {
      this.store.save();
      this.updateRow(inRowIndex);
    });
  }
  // ...
});

Note that I’m binding onApplyCellEdit to the grid, not to my local class, which gives me easy access to the grid’s variables (the store is what I’m interested in) and functions.

I’m also saving the data store in the process, but whether or not you do that depends on how you’ve got your widgets set up – if you’ve got a “Save” button somewhere you don’t want to do what I’m doing.