librelist archives

« back to archive

Java Mongrel2 Handler

Java Mongrel2 Handler

From:
Armando Singer
Date:
2010-12-28 @ 08:50
Hi,

I've implemented a Java Mongrel2 Handler:

http://www.paperculture.com/code/java-mongrel2-handler.html

It's the same object model as the reference Python handler but the 
accessors are named in the java convention with getX (getSender(), etc). 
Some implementation notes:

- All objects (Request and Connection instances) are deeply immutable
- It should be impossible to get a null from any accessor, so there's no 
need to check for null when iterating over maps, arrays, or checking if 
strings are empty
- It should be impossible to construct an invalid request or connection. 
The constructors enforce preconditions.
- The 0mq messages are parsed from the raw byte[] to prevent unnecessary 
copying and encoding to a java String, which is not ascii as in some other
languages. Requests and replies can be sent/received as either byte[] or 
java Strings. Care is taken to encode/decode properly to ascii.

The requisite sample chat backend that uses the Handler impl is also 
included at the bottom of the page.

Feedback is welcome!

Cheers,
Armando

Example usage:

public final class Chat {

  private static final String SENDER_ID = "82209006-86FF-4982-B5EA-D1E29E55D481";
  private static final Connection CONN = Handler.connection(SENDER_ID,
    "tcp://127.0.0.1:9999", "tcp://127.0.0.1:9998");
  private static final ConcurrentMap<String, Object> USERS = 
Maps.newConcurrentMap();
  
  public static void main(String[] args) {
    
    for (;;) {
      final Request req = CONN.recvJson();
      
      final Map<String, Object> data = req.getData();
      final Object type = data.get("type");
      if ("join".equals(type)) {
        CONN.deliverJson(req.getSender(), USERS.keySet(), data);
        USERS.put(req.getConnId(), data.get("user"));
        CONN.replyJson(req, ImmutableMap.of(
          "type", "userList",
          "users", USERS.values()
        ));
      } else if ("disconnect".equals(type)) {
        System.out.println("DISCONNECTED" + req.getConnId());
        final Object removedUser = USERS.remove(req.getConnId());
        final Map<String, Object> updateData = Maps.newLinkedHashMap(data);
        updateData.put("user", removedUser);
        CONN.deliverJson(req.getSender(), USERS.keySet(), updateData);
      } else if (!USERS.containsKey(req.getConnId())) {
        USERS.put(req.getConnId(), data.get("user"));
      } else if ("msg".equals(type)) {
        CONN.deliverJson(req.getSender(), USERS.keySet(), data);
      }
      
      System.out.println("REGISTERED USERS: " + USERS.size());
    }
  }
}