Java libraries for Thrift

Summary: The basic Thrift stack implemented in Java, still in need of a lot of work but fully functional.

Reviewed By: aditya

Test Plan: Unit tests are the NEXT checkin, I swear

Notes: Perf on the Java stuff actually isn't that bad, and it's far from optimized at the moment. Barely any tweaking has been done. Testing shows that a Java server with the C++ client has RPC performance within 2x of the pure C++ implementations. This is pretty sweet, since this cost will be eclipsed by the cost of whatever processing is being done on an actual server doing real work.




git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664715 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/java/build.xml b/lib/java/build.xml
new file mode 100644
index 0000000..d2a4df6
--- /dev/null
+++ b/lib/java/build.xml
@@ -0,0 +1,32 @@
+<project name="libthrift" default="dist" basedir=".">
+
+  <description>Thrift Build File</description>
+
+  <property name="src" location="src" />
+  <property name="build" location="build" />
+
+  <target name="init">
+    <tstamp />
+    <mkdir dir="${build}"/>
+  </target>
+
+  <target name="compile" depends="init">
+    <javac srcdir="${src}" destdir="${build}" />
+  </target>
+
+  <target name="dist" depends="compile">
+    <jar jarfile="libthrift.jar" basedir="${build}"/>
+  </target>
+
+  <target name="install" depends="dist">
+    <exec executable="sudo">
+      <arg line="install libthrift.jar /usr/local/lib/" />
+    </exec>
+  </target>
+
+  <target name="clean">
+    <delete dir="${build}" />
+    <delete file="libthrift.jar" />
+  </target>
+
+</project>
diff --git a/lib/java/src/TException.java b/lib/java/src/TException.java
new file mode 100644
index 0000000..2dbcf39
--- /dev/null
+++ b/lib/java/src/TException.java
@@ -0,0 +1,24 @@
+package com.facebook.thrift;
+
+/**
+ * Generic exception class for Thrift.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TException extends Exception {
+  public TException() {
+    super();
+  }
+
+  public TException(String message) {
+    super(message);
+  }
+ 
+  public TException(Throwable cause) {
+    super(cause);
+  }
+
+  public TException(String message, Throwable cause) {
+    super(message, cause);
+  }
+}
diff --git a/lib/java/src/TProcessor.java b/lib/java/src/TProcessor.java
new file mode 100644
index 0000000..dd6ae85
--- /dev/null
+++ b/lib/java/src/TProcessor.java
@@ -0,0 +1,14 @@
+package com.facebook.thrift;
+
+import com.facebook.thrift.transport.TTransport;
+
+/**
+ * A processor is a generic object which operates upon an input stream and
+ * writes to some output stream.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public interface TProcessor {
+  public boolean process(TTransport in, TTransport out)
+    throws TException;
+}
diff --git a/lib/java/src/protocol/TBinaryProtocol.java b/lib/java/src/protocol/TBinaryProtocol.java
new file mode 100644
index 0000000..3aaa06b
--- /dev/null
+++ b/lib/java/src/protocol/TBinaryProtocol.java
@@ -0,0 +1,236 @@
+package com.facebook.thrift.protocol;
+
+import com.facebook.thrift.TException;
+import com.facebook.thrift.transport.TTransport;
+import com.facebook.thrift.types.*;
+
+/**
+ * Binary protocol implementation for thrift.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TBinaryProtocol implements TProtocol {
+  public int writeStructBegin (TTransport out,
+                               TStruct    struct)  throws TException {
+    return 0;
+  }
+
+  public int writeStructEnd   (TTransport out)     throws TException {
+    return 0;
+  }
+
+  public int writeFieldBegin  (TTransport out,
+                               TField     field)   throws TException {
+    return
+      writeByte(out, field.type.getCode()) +
+      writeU32(out, field.id);
+  }
+
+  public int writeFieldEnd    (TTransport out)     throws TException {
+    return 0;
+  }
+
+  public int writeFieldStop   (TTransport out)     throws TException {
+    return
+      writeByte(out, TType.STOP.getCode());
+  }
+
+  public int writeMapBegin    (TTransport out,
+                               TMap       map)     throws TException {
+    return
+      writeByte(out, map.keyType.getCode()) +
+      writeByte(out, map.valueType.getCode()) +
+      writeU32(out, map.size);
+  }
+
+  public int writeMapEnd      (TTransport out)     throws TException {
+    return 0;
+  }
+
+  public int writeListBegin   (TTransport out,
+                               TList      list)    throws TException {
+    return
+      writeByte(out, list.elemType.getCode()) +
+      writeU32(out, list.size);
+  }
+
+  public int writeListEnd     (TTransport out)     throws TException {
+    return 0;
+  }
+
+  public int writeSetBegin    (TTransport out,
+                               TSet       set)     throws TException {
+    return
+      writeByte(out, set.elemType.getCode()) +
+      writeU32(out, set.size);
+  }
+
+  public int writeSetEnd      (TTransport out)     throws TException {
+    return 0;
+  }
+
+  public int writeByte        (TTransport out,
+                               UInt8      b)       throws TException {
+    out.write(b.data(), 0, 1);
+    return 1;
+  }
+
+  public int writeU32         (TTransport out,
+                               UInt32     u32)     throws TException {
+    out.write(u32.data(), 0, 4);
+    return 4;
+  }
+
+  public int writeI32         (TTransport out,
+                               Int32      i32)     throws TException {
+    out.write(i32.data(), 0, 4);
+    return 4;
+  }
+
+  public int writeU64         (TTransport out,
+                               UInt64     u64)     throws TException {
+    out.write(u64.data(), 0, 8);
+    return 8;
+  }
+
+  public int writeI64         (TTransport out,
+                               Int64      i64)     throws TException {
+    out.write(i64.data(), 0, 8);
+    return 8;
+  }
+
+  public int writeString      (TTransport out,
+                               TString    str)     throws TException {
+    byte[] dat = str.value.getBytes();
+    int sent = writeU32(out, new UInt32(dat.length));
+    out.write(dat, 0, dat.length);
+    return sent + dat.length;
+  }
+
+  /**
+   * Reading methods.
+   */
+
+  public int readStructBegin  (TTransport in,
+                               TStruct    struct)  throws TException {
+    struct.name = "";
+    return 0;
+  }
+
+  public int readStructEnd    (TTransport  in)     throws TException {
+    return 0;
+  }
+
+  public int readFieldBegin   (TTransport  in,
+                               TField      field)  throws TException {
+    int recv = 0;
+    UInt8 t = new UInt8();
+
+    recv += readByte(in, t);
+    field.type = TType.getType(t);
+    if (field.type.equals(TType.STOP)) {
+      field.id = new UInt32(0);
+      return recv;
+    }
+    recv += readU32(in, field.id);
+    return recv;
+  }
+  
+  public int readFieldEnd     (TTransport  in)     throws TException {
+    return 0;
+  }
+ 
+  public int readMapBegin     (TTransport  in,
+                               TMap        map)    throws TException {
+    int recv = 0;
+    UInt8 t = new UInt8();
+    recv += readByte(in, t);
+    map.keyType = TType.getType(t);
+    recv += readByte(in, t);
+    map.valueType = TType.getType(t);
+    recv += readU32(in, map.size);
+    return recv;
+  }
+
+  public int readMapEnd       (TTransport  in)     throws TException {
+    return 0;
+  }
+
+  public int readListBegin    (TTransport  in,
+                               TList       list)   throws TException {
+    int recv = 0;
+    UInt8 t = new UInt8();
+    recv += readByte(in, t);
+    list.elemType = TType.getType(t);
+    recv += readU32(in, list.size);
+    return recv;
+  }
+
+  public int readListEnd      (TTransport  in)     throws TException {
+    return 0;
+  }
+
+  public int readSetBegin     (TTransport  in,
+                               TSet        set)    throws TException {
+    int recv = 0;
+    UInt8 t = new UInt8();
+    recv += readByte(in, t);
+    set.elemType = TType.getType(t);
+    recv += readU32(in, set.size);
+    return recv;
+  }
+
+  public int readSetEnd       (TTransport  in)     throws TException {
+    return 0;
+  }
+
+  public int readByte         (TTransport  in,
+                               UInt8       b)      throws TException {
+    byte[] buf = new byte[1];
+    in.readAll(buf, 0, 1);
+    b.read(buf, 0);
+    return 1;
+  }
+
+  public int readU32          (TTransport  in,
+                               UInt32      u32)    throws TException {
+    byte[] buf = new byte[4];
+    in.readAll(buf, 0, 4);
+    u32.read(buf, 0);
+    return 4;
+  }
+
+  public int readI32          (TTransport  in,
+                               Int32       i32)    throws TException {
+    byte[] buf = new byte[4];
+    in.readAll(buf, 0, 4);
+    i32.read(buf, 0);
+    return 4;
+  }
+
+  public int readU64          (TTransport  in,
+                               UInt64      u64)    throws TException {
+    byte[] buf = new byte[8];
+    in.readAll(buf, 0, 8);
+    u64.read(buf, 0);
+    return 8;
+  }
+  
+  public int readI64          (TTransport  in,
+                               Int64       i64)    throws TException {
+    byte[] buf = new byte[8];
+    in.readAll(buf, 0, 8);
+    i64.read(buf, 0);
+    return 8;
+  }
+
+  public int readString       (TTransport  in,
+                               TString     s)      throws TException {
+    UInt32 size = new UInt32();
+    int recv = readU32(in, size);
+    byte[] buf = new byte[size.toInt()];
+    in.readAll(buf, 0, size.toInt());
+    s.value = new String(buf);
+    return recv + size.toInt();
+  }
+}
diff --git a/lib/java/src/protocol/TField.java b/lib/java/src/protocol/TField.java
new file mode 100644
index 0000000..83f1fc3
--- /dev/null
+++ b/lib/java/src/protocol/TField.java
@@ -0,0 +1,26 @@
+package com.facebook.thrift.protocol;
+
+import com.facebook.thrift.types.*;
+
+/**
+ * Helper class that encapsulates field metadata.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TField {
+  public TField() {}
+
+  public TField(String n, TType t, int i) {
+    this(n, t, new UInt32(i));
+  }
+
+  public TField(String n, TType t, UInt32 i) {
+    name = n;
+    type = t;
+    id = i;
+  }
+
+  public String name = "";
+  public TType  type = TType.STOP;
+  public UInt32 id = new UInt32();
+}
diff --git a/lib/java/src/protocol/TList.java b/lib/java/src/protocol/TList.java
new file mode 100644
index 0000000..6eac06b
--- /dev/null
+++ b/lib/java/src/protocol/TList.java
@@ -0,0 +1,24 @@
+package com.facebook.thrift.protocol;
+
+import com.facebook.thrift.types.*;
+
+/**
+ * Helper class that encapsulates list metadata.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TList {
+  public TList() {}
+  
+  public TList(TType t, int s) {
+    this(t, new UInt32(s));
+  }
+
+  public TList(TType t, UInt32 s) {
+    elemType = t;
+    size = s;
+  }
+
+  public TType  elemType = TType.STOP;
+  public UInt32 size = new UInt32();
+}
diff --git a/lib/java/src/protocol/TMap.java b/lib/java/src/protocol/TMap.java
new file mode 100644
index 0000000..84eb468
--- /dev/null
+++ b/lib/java/src/protocol/TMap.java
@@ -0,0 +1,26 @@
+package com.facebook.thrift.protocol;
+
+import com.facebook.thrift.types.*;
+
+/**
+ * Helper class that encapsulates map metadata.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TMap {
+  public TMap() {}
+  
+  public TMap(TType k, TType v, int s) {
+    this(k, v, new UInt32(s));
+  }
+
+  public TMap(TType k, TType v, UInt32 s) {
+    keyType = k;
+    valueType = v;
+    size = s;
+  }
+
+  public TType  keyType = TType.STOP;
+  public TType  valueType = TType.STOP;
+  public UInt32 size = new UInt32();;
+}
diff --git a/lib/java/src/protocol/TProtocol.java b/lib/java/src/protocol/TProtocol.java
new file mode 100644
index 0000000..f44eb9e
--- /dev/null
+++ b/lib/java/src/protocol/TProtocol.java
@@ -0,0 +1,109 @@
+package com.facebook.thrift.protocol;
+
+import com.facebook.thrift.types.*;
+import com.facebook.thrift.TException;
+import com.facebook.thrift.transport.TTransport;
+
+/**
+ * Protocol interface definition.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public interface TProtocol {
+
+  /**
+   * Writing methods.
+   */
+
+  public int writeStructBegin (TTransport out,
+                               TStruct    struct)  throws TException;
+  public int writeStructEnd   (TTransport out)     throws TException;
+
+  public int writeFieldBegin  (TTransport out,
+                               TField     field)   throws TException;
+
+  public int writeFieldEnd    (TTransport out)     throws TException;
+
+  public int writeFieldStop   (TTransport out)     throws TException;
+
+  public int writeMapBegin    (TTransport out,
+                               TMap       map)     throws TException;
+
+  public int writeMapEnd      (TTransport out)     throws TException;
+
+  public int writeListBegin   (TTransport out,
+                               TList      list)    throws TException;
+
+  public int writeListEnd     (TTransport out)     throws TException;
+
+  public int writeSetBegin    (TTransport out,
+                               TSet       set)     throws TException;
+
+  public int writeSetEnd      (TTransport out)     throws TException;
+
+  public int writeByte        (TTransport out,
+                               UInt8      b)       throws TException;
+
+  public int writeU32         (TTransport out,
+                               UInt32     u32)     throws TException;
+
+  public int writeI32         (TTransport out,
+                               Int32      i32)     throws TException;
+
+  public int writeU64         (TTransport out,
+                               UInt64     u64)     throws TException;
+
+  public int writeI64         (TTransport out,
+                               Int64      i64)     throws TException;
+
+  public int writeString      (TTransport out,
+                               TString    str)     throws TException;
+
+  /**
+   * Reading methods.
+   */
+
+  public int readStructBegin  (TTransport in,
+                               TStruct    struct)  throws TException;
+
+  public int readStructEnd    (TTransport  in)     throws TException;
+
+  public int readFieldBegin   (TTransport  in,
+                               TField      field)  throws TException;
+  
+  public int readFieldEnd     (TTransport  in)     throws TException;
+ 
+  public int readMapBegin     (TTransport  in,
+                               TMap        map)    throws TException;
+
+  public int readMapEnd       (TTransport  in)     throws TException;
+
+  public int readListBegin    (TTransport  in,
+                               TList       list)   throws TException;
+
+  public int readListEnd      (TTransport  in)     throws TException;
+
+  public int readSetBegin     (TTransport  in,
+                               TSet        set)    throws TException;
+
+  public int readSetEnd       (TTransport  in)     throws TException;
+
+  public int readByte         (TTransport  in,
+                               UInt8       b)      throws TException;
+
+  public int readU32          (TTransport  in,
+                               UInt32      u32)    throws TException;
+
+  public int readI32          (TTransport  in,
+                               Int32       i32)    throws TException;
+
+  public int readU64          (TTransport  in,
+                               UInt64      u64)    throws TException;
+  
+  public int readI64          (TTransport  in,
+                               Int64       i64)    throws TException;
+
+  public int readString       (TTransport  in,
+                               TString     s)      throws TException;
+
+}
diff --git a/lib/java/src/protocol/TProtocolUtil.java b/lib/java/src/protocol/TProtocolUtil.java
new file mode 100644
index 0000000..b182139
--- /dev/null
+++ b/lib/java/src/protocol/TProtocolUtil.java
@@ -0,0 +1,104 @@
+package com.facebook.thrift.protocol;
+
+import com.facebook.thrift.types.*;
+import com.facebook.thrift.TException;
+import com.facebook.thrift.transport.TTransport;
+
+/**
+ * Utility class with static methods for interacting with protocol data
+ * streams.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TProtocolUtil {
+  public static int skip(TProtocol prot, TTransport in, TType type)
+    throws TException {
+
+    switch (type) {
+    case BYTE:
+      {
+        UInt8 b = new UInt8();
+        return prot.readByte(in, b);
+      }
+    case U32:
+      {
+        UInt32 u32 = new UInt32();
+        return prot.readU32(in, u32);
+      }
+    case I32:
+      {
+        Int32 i32 = new Int32();
+        return prot.readI32(in, i32);
+      }
+    case U64:
+      {
+        UInt64 u64 = new UInt64();
+        return prot.readU64(in, u64);
+      }
+    case I64:
+      {
+        Int64 i64 = new Int64();
+        return prot.readI64(in, i64);
+      }
+    case STRING:
+      {
+        TString s = new TString();
+        return prot.readString(in, s);
+      }
+    case STRUCT:
+      {
+        int result = 0;
+        TString name = new TString();
+        TStruct struct = new TStruct();
+        TField field = new TField();
+        result += prot.readStructBegin(in, struct);
+        while (true) {
+          result += prot.readFieldBegin(in, field);
+          if (field.type.equals(TType.STOP)) {
+            break;
+          }
+          result += skip(prot, in, field.type);
+          result += prot.readFieldEnd(in);
+        }
+        result += prot.readStructEnd(in);
+        return result;
+      }
+    case MAP:
+      {
+        int result = 0;
+        TMap map = new TMap();
+        result += prot.readMapBegin(in, map);
+        for (int i = 0; i < map.size.get(); i++) {
+          result += skip(prot, in, map.keyType);
+          result += skip(prot, in, map.valueType);
+        }
+        result += prot.readMapEnd(in);
+        return result;
+      }
+    case SET:
+      {
+        int result = 0;
+        TSet set = new TSet();
+        result += prot.readSetBegin(in, set);
+        for (int i = 0; i < set.size.get(); i++) {
+          result += skip(prot, in, set.elemType);
+        }
+        result += prot.readSetEnd(in);
+        return result;
+      }
+    case LIST:
+      {
+        int result = 0;
+        TList list = new TList();
+        result += prot.readListBegin(in, list);
+        for (int i = 0; i < list.size.get(); i++) {
+          result += skip(prot, in, list.elemType);
+        }
+        result += prot.readListEnd(in);
+        return result;
+      }
+    default:
+      return 0;
+    }
+  }
+}
diff --git a/lib/java/src/protocol/TSet.java b/lib/java/src/protocol/TSet.java
new file mode 100644
index 0000000..e0dcf76
--- /dev/null
+++ b/lib/java/src/protocol/TSet.java
@@ -0,0 +1,24 @@
+package com.facebook.thrift.protocol;
+
+import com.facebook.thrift.types.*;
+
+/**
+ * Helper class that encapsulates set metadata.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TSet {
+  public TSet() {}
+
+  public TSet(TType t, int s) {
+    this(t, new UInt32(s));
+  }
+
+  public TSet(TType t, UInt32 s) {
+    elemType = t;
+    size = s;
+  }
+
+  public TType  elemType = TType.STOP;
+  public UInt32 size = new UInt32();
+}
diff --git a/lib/java/src/protocol/TString.java b/lib/java/src/protocol/TString.java
new file mode 100644
index 0000000..04fcc1d
--- /dev/null
+++ b/lib/java/src/protocol/TString.java
@@ -0,0 +1,17 @@
+package com.facebook.thrift.protocol;
+
+/**
+ * Wrapper around String so that you can pass this object to a function and
+ * have it set the internal string value.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TString {
+  public TString() {}
+
+  public TString(String v) {
+    value = v;
+  }
+
+  public String value = "";
+}
diff --git a/lib/java/src/protocol/TStruct.java b/lib/java/src/protocol/TStruct.java
new file mode 100644
index 0000000..2fbcb8f
--- /dev/null
+++ b/lib/java/src/protocol/TStruct.java
@@ -0,0 +1,18 @@
+package com.facebook.thrift.protocol;
+
+import com.facebook.thrift.types.*;
+
+/**
+ * Helper class that encapsulates struct metadata.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TStruct {
+  public TStruct() {}
+
+  public TStruct(String n) {
+    name = n;
+  }
+
+  public String name = "";
+}
diff --git a/lib/java/src/protocol/TType.java b/lib/java/src/protocol/TType.java
new file mode 100644
index 0000000..21b7914
--- /dev/null
+++ b/lib/java/src/protocol/TType.java
@@ -0,0 +1,82 @@
+package com.facebook.thrift.protocol;
+
+import com.facebook.thrift.types.UInt8;
+
+/**
+ * Type constants in the Thrift protocol.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public enum TType {
+  STOP   (1),
+  BYTE   (2),
+  U16    (3),
+  I16    (4),
+  U32    (5),
+  I32    (6),
+  U64    (7),
+  I64    (8),
+  STRING (9),
+  STRUCT (10),
+  MAP    (11),
+  SET    (12),
+  LIST   (13);
+
+  /** U8 identifier */
+  private UInt8 code_;
+
+  /**
+   * Constructor to create a TType object from its code.
+   *
+   * @param code The identifier code for this type
+   */
+  private TType(int code) {
+    code_ = new UInt8((byte)code);
+  }
+
+  /**
+   * Accessor for the code.
+   */
+  public UInt8 getCode() {
+    return code_;
+  }
+
+  /**
+   * Static method to get a type object from a byte.
+   *
+   * @param code The type code
+   */
+  public static TType getType(UInt8 code) {
+    switch (code.get()) {
+    case 1:
+      return STOP;
+    case 2:
+      return BYTE;
+    case 3:
+      return U16;
+    case 4:
+      return I16;
+    case 5:
+      return U32;
+    case 6:
+      return I32;
+    case 7:
+      return U64;
+    case 8:
+      return I64;
+    case 9:
+      return STRING;
+    case 10:
+      return STRUCT;
+    case 11:
+      return MAP;
+    case 12:
+      return SET;
+    case 13:
+      return LIST;
+    default:
+      System.err.println("WARNING: Unidentified type code: " + code.get());
+      return STOP;
+    }
+  }
+}
diff --git a/lib/java/src/server/TServer.java b/lib/java/src/server/TServer.java
new file mode 100644
index 0000000..38ef81f
--- /dev/null
+++ b/lib/java/src/server/TServer.java
@@ -0,0 +1,38 @@
+package com.facebook.thrift.server;
+
+import com.facebook.thrift.TProcessor;
+
+/**
+ * Generic interface for a Thrift server.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public abstract class TServer {
+
+  /**
+   * The options class should be subclassed by particular servers which have
+   * specific options needs, while the general options should live here.
+   */
+  public static class Options {
+    public Options() {}
+  }
+
+  /** Core processor */
+  protected TProcessor processor_;
+
+  /** Server options */
+  protected Options options_;
+
+  /**
+   * Default constructor, all servers take a processor and some options.
+   */
+  protected TServer(TProcessor processor, Options options) {
+    processor_ = processor;
+    options_ = options;
+  }
+  
+  /**
+   * The run method fires up the server and gets things going.
+   */
+  public abstract void run();
+}
diff --git a/lib/java/src/server/TSimpleServer.java b/lib/java/src/server/TSimpleServer.java
new file mode 100644
index 0000000..352a6de
--- /dev/null
+++ b/lib/java/src/server/TSimpleServer.java
@@ -0,0 +1,50 @@
+package com.facebook.thrift.server;
+
+import com.facebook.thrift.TException;
+import com.facebook.thrift.TProcessor;
+import com.facebook.thrift.transport.TServerTransport;
+import com.facebook.thrift.transport.TTransport;
+import com.facebook.thrift.transport.TTransportException;
+
+/**
+ * Simple singlethreaded server for testing.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TSimpleServer extends TServer {
+
+  private TServerTransport serverTransport_;
+
+  public TSimpleServer(TProcessor processor,
+                       TServer.Options options,
+                       TServerTransport serverTransport) {
+    super(processor, options);
+    serverTransport_ = serverTransport;
+  }
+
+  public void run() {
+    try {
+      serverTransport_.listen();
+    } catch (TTransportException ttx) {
+      ttx.printStackTrace();
+      return;
+    }
+
+    while (true) {
+      TTransport client = null;
+      try {
+        client = serverTransport_.accept();
+        if (client != null) {
+          while (processor_.process(client, client));
+        }
+      } catch (TException tx) {
+        tx.printStackTrace();
+      }
+
+      if (client != null) {
+        client.close();
+        client = null;
+      }
+    }
+  }
+}
diff --git a/lib/java/src/transport/TIOStreamTransport.java b/lib/java/src/transport/TIOStreamTransport.java
new file mode 100644
index 0000000..aa4adf1
--- /dev/null
+++ b/lib/java/src/transport/TIOStreamTransport.java
@@ -0,0 +1,138 @@
+package com.facebook.thrift.transport;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * This is the most commonly used base transport. It takes an InputStream
+ * and an OutputStream and uses those to perform all transport operations.
+ * This allows for compatibility with all the nice constructs Java already
+ * has to provide a variety of types of streams.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TIOStreamTransport extends TTransport {
+
+  /** Underlying inputStream */
+  protected InputStream inputStream_ = null;
+
+  /** Underlying outputStream */
+  protected OutputStream outputStream_ = null;
+
+  /**
+   * Subclasses can invoke the default constructor and then assign the input
+   * streams in the open method.
+   */
+  protected TIOStreamTransport() {}
+
+  /**
+   * Input stream constructor.
+   *
+   * @param is Input stream to read from
+   */
+  public TIOStreamTransport(InputStream is) {
+    inputStream_ = is;
+  }
+
+  /**
+   * Output stream constructor.
+   *
+   * @param os Output stream to read from
+   */
+  public TIOStreamTransport(OutputStream os) {
+    outputStream_ = os;
+  }
+
+  /**
+   * Two-way stream constructor.
+   *
+   * @param is Input stream to read from
+   * @param os Output stream to read from
+   */ 
+  public TIOStreamTransport(InputStream is, OutputStream os) {
+    inputStream_ = is;
+    outputStream_ = os;
+  }
+
+  /**
+   * The streams must already be open at construction time, so this should
+   * always return true.
+   *
+   * @return true
+   */
+  public boolean isOpen() {
+    return true;
+  }
+
+  /**
+   * The streams must already be open. This method does nothing.
+   */
+  public void open() throws TTransportException {}
+
+  /**
+   * Closes both the input and output streams.
+   */
+  public void close() {
+    if (inputStream_ != null) {
+      try {
+        inputStream_.close();
+      } catch (IOException iox) {
+        System.err.println("WARNING: Error closing input stream: " +
+                           iox.getMessage());
+      }
+      inputStream_ = null;
+    }
+    if (outputStream_ != null) {
+      try {
+        outputStream_.close();
+      } catch (IOException iox) {
+        System.err.println("WARNING: Error closing output stream: " +
+                           iox.getMessage());
+      }
+      outputStream_ = null;
+    }
+  }
+
+  /**
+   * Reads from the underlying input stream if not null.
+   */
+  public int read(byte[] buf, int off, int len) throws TTransportException {
+    if (inputStream_ == null) {
+      throw new TTransportException("Cannot read from null inputStream");
+    }
+    try {
+      return inputStream_.read(buf, off, len);
+    } catch (IOException iox) {
+      throw new TTransportException(iox);
+    }
+  }
+
+  /**
+   * Writes to the underlying output stream if not null.
+   */
+  public void write(byte[] buf, int off, int len) throws TTransportException {
+    if (outputStream_ == null) {
+      throw new TTransportException("Cannot write to null outputStream");
+    }
+    try {
+      outputStream_.write(buf, off, len);
+    } catch (IOException iox) {
+      throw new TTransportException(iox);
+    }
+  }
+
+  /**
+   * Flushes the underlying output stream if not null.
+   */
+  public void flush() throws TTransportException {
+    if (outputStream_ == null) {
+      throw new TTransportException("Cannot flush null outputStream");
+    }
+    try {
+      outputStream_.flush();
+    } catch (IOException iox) {
+      throw new TTransportException(iox);
+    }
+  }
+}
diff --git a/lib/java/src/transport/TServerSocket.java b/lib/java/src/transport/TServerSocket.java
new file mode 100644
index 0000000..a885fa1
--- /dev/null
+++ b/lib/java/src/transport/TServerSocket.java
@@ -0,0 +1,46 @@
+package com.facebook.thrift.transport;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/**
+ * Wrapper around ServerSocket for Thrift.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TServerSocket extends TServerTransport {
+  
+  private ServerSocket serverSocket_;
+  
+  public TServerSocket(ServerSocket serverSocket) {
+    serverSocket_ = serverSocket;
+  }
+
+  public void listen() throws TTransportException {}
+  
+  protected TSocket acceptImpl() throws TTransportException {
+    if (serverSocket_ == null) {
+      throw new TTransportException("No underlying server socket.");
+    }
+    try {
+      Socket result = serverSocket_.accept();
+      return new TSocket(result);
+    } catch (IOException iox) {
+      throw new TTransportException(iox);
+    }
+  }
+
+  public void close() {
+    if (serverSocket_ != null) {
+      try {
+        serverSocket_.close();
+      } catch (IOException iox) {
+        System.err.println("WARNING: Could not close server socket: " +
+                           iox.getMessage());
+      }
+      serverSocket_ = null;
+    }
+  }
+
+}
diff --git a/lib/java/src/transport/TServerTransport.java b/lib/java/src/transport/TServerTransport.java
new file mode 100644
index 0000000..6faeaab
--- /dev/null
+++ b/lib/java/src/transport/TServerTransport.java
@@ -0,0 +1,23 @@
+package com.facebook.thrift.transport;
+
+/**
+ * Server transport. Object which provides client transports.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public abstract class TServerTransport {
+
+  public abstract void listen() throws TTransportException;
+
+  public final TTransport accept() throws TTransportException {
+    TTransport transport = acceptImpl();
+    if (transport == null) {
+      throw new TTransportException("accept() may not return NULL");
+    }
+    return transport;
+  }
+
+  public abstract void close();
+
+  protected abstract TTransport acceptImpl() throws TTransportException;
+}
diff --git a/lib/java/src/transport/TSocket.java b/lib/java/src/transport/TSocket.java
new file mode 100644
index 0000000..2092f11
--- /dev/null
+++ b/lib/java/src/transport/TSocket.java
@@ -0,0 +1,126 @@
+package com.facebook.thrift.transport;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+/**
+ * Socket implementation of the TTransport interface. To be commented soon!
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TSocket extends TIOStreamTransport {
+
+  /** Wrapped Socket object */
+  private Socket socket_ = null;
+  
+  /** Remote host */
+  private String host_  = null;
+
+  /** Remote port */
+  private int port_ = 0;
+
+  /**
+   * Constructor that takes an already created socket.
+   *
+   * @param socket Already created socket object
+   * @throws TTransportException if there is an error setting up the streams
+   */
+  public TSocket(Socket socket) throws TTransportException {
+    socket_ = socket;
+    if (isOpen()) {
+      try {
+        inputStream_ = new BufferedInputStream(socket_.getInputStream());
+        outputStream_ = new BufferedOutputStream(socket_.getOutputStream());
+      } catch (IOException iox) {
+        close();
+        throw new TTransportException(iox);
+      }
+    }
+  }
+
+  /**
+   * Creates a new unconnected socket that will connect to the given host
+   * on the given port.
+   *
+   * @param host Remote host
+   * @param port Remote port
+   */
+  public TSocket(String host, int port) {
+    socket_ = new Socket();
+    host_ = host;
+    port_ = port;
+  }
+
+  /**
+   * Returns a reference to the underlying socket. Can be used to set
+   * socket options, etc. If an underlying socket does not exist yet, this
+   * will create one.
+   */
+  public Socket getSocket() {
+    if (socket_ == null) {
+      socket_ = new Socket();
+    }
+    return socket_;
+  }
+
+  /**
+   * Checks whether the socket is connected.
+   */
+  public boolean isOpen() {
+    if (socket_ == null) {
+      return false;
+    }
+    return socket_.isConnected();
+  }
+
+  /**
+   * Connects the socket, creating a new socket object if necessary.
+   */
+  public void open() throws TTransportException {
+    if (socket_ == null) {
+      if (host_.length() == 0) {
+        throw new TTransportException("Cannot open null host.");
+      }
+      if (port_ <= 0) {
+        throw new TTransportException("Cannot open without port.");
+      }
+      socket_ = new Socket();
+    }
+
+    if (isOpen()) {
+      throw new TTransportException("Socket already connected.");
+    }
+
+    try {
+      socket_.connect(new InetSocketAddress(host_, port_));
+      inputStream_ = new BufferedInputStream(socket_.getInputStream());
+      outputStream_ = new BufferedOutputStream(socket_.getOutputStream());
+    } catch (IOException iox) {
+      close();
+      throw new TTransportException(iox);
+    }
+  }
+
+  /**
+   * Closes the socket.
+   */
+  public void close() {
+    // Close the underlying streams
+    super.close();
+
+    // Close the socket
+    if (socket_ != null) {
+      try {
+        socket_.close();
+      } catch (IOException iox) {
+        System.err.println("WARNING: exception closing socket: " +
+                           iox.getMessage());
+      }
+      socket_ = null;
+    }
+  }
+
+}
diff --git a/lib/java/src/transport/TTransport.java b/lib/java/src/transport/TTransport.java
new file mode 100644
index 0000000..00610df
--- /dev/null
+++ b/lib/java/src/transport/TTransport.java
@@ -0,0 +1,84 @@
+package com.facebook.thrift.transport;
+
+/**
+ * Generic class that encapsulates the I/O layer. This is basically a thin
+ * wrapper around the combined functionality of Java input/output streams.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public abstract class TTransport {
+
+  /**
+   * Queries whether the transport is open.
+   *
+   * @return True if the transport is open.
+   */
+  public abstract boolean isOpen();
+
+  /**
+   * Opens the transport for reading/writing.
+   *
+   * @throws TTransportException if the transport could not be opened
+   */
+  public abstract void open()
+    throws TTransportException;
+
+  /**
+   * Closes the transport.
+   */
+  public abstract void close();
+
+  /**
+   * Reads up to len bytes into buffer buf, starting att offset off.
+   *
+   * @param buf Array to read into
+   * @param off Index to start reading at
+   * @param len Maximum number of bytes to read
+   * @return The number of bytes actually read
+   * @throws TTransportException if there was an error reading data
+   */
+  public abstract int read(byte[] buf, int off, int len)
+    throws TTransportException;
+
+  /**
+   * Guarantees that all of len bytes are 
+   *
+   * @param buf Array to read into
+   * @param off Index to start reading at
+   * @param len Maximum number of bytes to read
+   * @return The number of bytes actually read, which must be equal to len
+   * @throws TTransportException if there was an error reading data
+   */
+  public int readAll(byte[] buf, int off, int len)
+    throws TTransportException {
+    int got = 0;
+    int ret = 0;
+    while (got < len) {
+      ret = read(buf, off+got, len-got);
+      if (ret == -1) {
+        throw new TTransportException("Cannot read. Remote side has closed.");
+      }
+      got += ret;
+    }
+    return got;
+  }
+
+  /**
+   * Writes up to len bytes from the buffer.
+   *
+   * @param buf The output data buffer
+   * @param off The offset to start writing from
+   * @param len The number of bytes to write
+   * @throws TTransportException if there was an error writing data
+   */
+  public abstract void write(byte[] buf, int off, int len)
+    throws TTransportException;
+
+  /**
+   * Flush any pending data out of a transport buffer.
+   *
+   * @throws TTransportException if there was an error writing out data.
+   */
+  public void flush() 
+    throws TTransportException {}
+}
diff --git a/lib/java/src/transport/TTransportException.java b/lib/java/src/transport/TTransportException.java
new file mode 100644
index 0000000..a67b6ed
--- /dev/null
+++ b/lib/java/src/transport/TTransportException.java
@@ -0,0 +1,26 @@
+package com.facebook.thrift.transport;
+
+import com.facebook.thrift.TException;
+
+/**
+ * Transport exceptions.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TTransportException extends TException {
+  public TTransportException() {
+    super();
+  }
+
+  public TTransportException(String message) {
+    super(message);
+  }
+
+  public TTransportException(Throwable cause) {
+    super(cause);
+  }
+
+  public TTransportException(String message, Throwable cause) {
+    super(message, cause);
+  }
+}
diff --git a/lib/java/src/types/Int32.java b/lib/java/src/types/Int32.java
new file mode 100644
index 0000000..e6a8cf2
--- /dev/null
+++ b/lib/java/src/types/Int32.java
@@ -0,0 +1,75 @@
+package com.facebook.thrift.types;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * Wrapper for Pillar TyInt32. We have to flip the byte order in here
+ * because Pillar is little endian.
+ *
+ * @author Mark Slee (mcslee@facebook.com)
+ *
+ * See: http://darksleep.com/player/JavaAndUnsignedTypes.html
+ *
+ */
+public class Int32 {
+  private int intValue_ = 0;
+  private byte[] data_ = new byte[4];
+  
+  public int get() {
+    return intValue_;
+  }
+
+  public byte[] data() {
+    return data_;
+  }
+
+  public Int32() {
+    for (int i = 0; i < 4; i++) {
+      data_[i] = 0;
+    }
+  }
+
+  public Int32(byte[] buf, int offset) {
+    read(buf, offset);
+  }
+
+  public Int32(int value) {
+    set(value);
+  }
+
+  public void set(int value) {
+    intValue_ = value;    
+    data_[0] = (byte)((intValue_ & 0xFF000000L) >> 24);
+    data_[1] = (byte)((intValue_ & 0x00FF0000L) >> 16);
+    data_[2] = (byte)((intValue_ & 0x0000FF00L) >> 8);
+    data_[3] = (byte)((intValue_ & 0x000000FFL));
+  }
+
+  public void read(byte[] buf, int offset) {
+    for (int i = 0; i < 4; i++) {
+      data_[i] = buf[offset+i];
+    }
+
+    int[] bytes = new int[4];
+    bytes[0] = (0x000000FF & ((int)data_[0]));
+    bytes[1] = (0x000000FF & ((int)data_[1]));
+    bytes[2] = (0x000000FF & ((int)data_[2]));
+    bytes[3] = (0x000000FF & ((int)data_[3]));
+    intValue_ = ((int) (bytes[0] << 24 | bytes[1] << 16 |
+                        bytes[2] << 8 | bytes[3]));
+  }
+
+  public String toString() {
+    return String.valueOf(intValue_);
+  }
+
+  public int hashCode() {
+    return intValue_;
+  }
+
+  public boolean equals(Object that) {
+    return ((that instanceof Int32) &&
+            (this.intValue_ == ((Int32) that).intValue_));
+  }
+
+}
diff --git a/lib/java/src/types/Int64.java b/lib/java/src/types/Int64.java
new file mode 100644
index 0000000..12bef4b
--- /dev/null
+++ b/lib/java/src/types/Int64.java
@@ -0,0 +1,90 @@
+package com.facebook.thrift.types;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * 64-bit integers, just a wrapper around a long, and a byte-order
+ * reverser.
+ *
+ * @author Mark Slee (mcslee@facebook.com)
+ *
+ */
+public class Int64 {
+  private long longValue_ = 0L;
+  private byte[] data_ = new byte[8];
+
+  public long get() {
+    return longValue_;
+  }
+
+  public byte[] data() {
+    return data_;
+  }
+
+  public Int64() {
+    for (int i = 0; i < 8; i++) data_[i] = (byte) 0;
+  }
+
+  public Int64(long value) {
+    set(value);
+  }
+
+  public Int64(byte[] buf, int offset) {
+    read(buf, offset);
+  }
+
+
+  /**
+   * Yes, this could be done in a loop, but written out this way makes
+   * it easier to see how the bytes are actually generated.
+   */
+  public void set(long value) {
+    longValue_ = value;
+    data_[0] = (byte)((longValue_ & 0xFF00000000000000L) >> 56);
+    data_[1] = (byte)((longValue_ & 0x00FF000000000000L) >> 48);
+    data_[2] = (byte)((longValue_ & 0x0000FF0000000000L) >> 40);
+    data_[3] = (byte)((longValue_ & 0x000000FF00000000L) >> 32);
+    data_[4] = (byte)((longValue_ & 0x00000000FF000000L) >> 24);
+    data_[5] = (byte)((longValue_ & 0x0000000000FF0000L) >> 16);
+    data_[6] = (byte)((longValue_ & 0x000000000000FF00L) >> 8);
+    data_[7] = (byte)((longValue_ & 0x00000000000000FFL));
+  }
+
+  /**
+   * Reverse byte order to calculate the value.
+   */
+  public void read(byte[] buf, int offset) {
+    for (int i = 0; i < 8; i++) {
+      data_[i] = buf[offset+i];
+    }
+
+    long[] bytes = new long[8];
+    bytes[0] = (0xFF & ((long)data_[0]));
+    bytes[1] = (0xFF & ((long)data_[1]));
+    bytes[2] = (0xFF & ((long)data_[2]));
+    bytes[3] = (0xFF & ((long)data_[3]));
+    bytes[4] = (0xFF & ((long)data_[4]));
+    bytes[5] = (0xFF & ((long)data_[5]));
+    bytes[6] = (0xFF & ((long)data_[6]));
+    bytes[7] = (0xFF & ((long)data_[7]));
+
+    longValue_ = ((long) ((bytes[0] << 56) | (bytes[1] << 48) |
+                          (bytes[2] << 40) | (bytes[3] << 32) |
+                          (bytes[4] << 24) | (bytes[5] << 16) |
+                          (bytes[6] << 8)  | (bytes[7])));
+  }
+
+  public String toString() {
+    return String.valueOf(longValue_);
+  }
+
+  public int hashCode() {
+    return (int)longValue_;
+  }
+
+  public boolean equals(Object that) {
+    return ((that instanceof Int64) &&
+            (this.longValue_ == ((Int64) that).longValue_));
+  }
+
+}
diff --git a/lib/java/src/types/UInt32.java b/lib/java/src/types/UInt32.java
new file mode 100644
index 0000000..52c6da0
--- /dev/null
+++ b/lib/java/src/types/UInt32.java
@@ -0,0 +1,89 @@
+package com.facebook.thrift.types;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * Bit-twiddling bullshit because java doesn't have unsigned types.
+ * Also, the JVM is big-endian, but Pillar is written on the little
+ * endian architecture, and it doesn't translated numbers to network
+ * byte order (also big-endian) when it transmits them.
+ *
+ * So, a UInt32 received by pillar will come over the net in little
+ * endian byte order, which means we have to reverse it for Java.
+ *
+ * @author Mark Slee (mcslee@facebook.com)
+ *
+ * See: http://darksleep.com/player/JavaAndUnsignedTypes.html
+ *
+ */
+public class UInt32 {
+  private long longValue_ = 0;
+  private byte[] data_ = new byte[4];
+  
+  public long get() {
+    return longValue_;
+  }
+
+  public int toInt() {
+    return (int) longValue_;
+  }
+
+  public byte[] data() {
+    return data_;
+  }
+
+  public UInt32() {
+    for (int i = 0; i < 4; i++) data_[i] = (byte) 0;
+  }
+
+  public UInt32(byte[] buf, int offset) {
+    read(buf, offset);
+  }
+
+  public UInt32(long value) {
+    set(value);
+  }
+
+  public UInt32(int value) {
+    this((long)value);
+  }
+
+  public void set(long value) {
+    if (value < 0) {
+      throw new RuntimeException("Cannot assign negative value to UInt32.");
+    }
+    longValue_ = value;
+    data_[0] = (byte)((longValue_ & 0xFF000000L) >> 24);
+    data_[1] = (byte)((longValue_ & 0x00FF0000L) >> 16);
+    data_[2] = (byte)((longValue_ & 0x0000FF00L) >> 8);
+    data_[3] = (byte)((longValue_ & 0x000000FFL));
+  }
+
+  public void read(byte[] buf, int offset) {
+    for (int i = 0; i < 4; i++) {
+      data_[i] = buf[offset+i];
+    }
+
+    int[] bytes = new int[4];
+    bytes[0] = (0x000000FF & ((int)data_[0]));
+    bytes[1] = (0x000000FF & ((int)data_[1]));
+    bytes[2] = (0x000000FF & ((int)data_[2]));
+    bytes[3] = (0x000000FF & ((int)data_[3]));
+    longValue_ = ((long) ((bytes[0] << 24) | (bytes[1] << 16) |
+                          (bytes[2] << 8) | (bytes[3]))) & 0xFFFFFFFFL;
+  }
+
+  public String toString() {
+    return String.valueOf(longValue_);
+  }
+
+  public int hashCode() {
+    return toInt();
+  }
+
+  public boolean equals(Object that) {
+    return ((that instanceof UInt32) &&
+            (this.longValue_ == ((UInt32) that).longValue_));
+  }
+
+}
diff --git a/lib/java/src/types/UInt64.java b/lib/java/src/types/UInt64.java
new file mode 100644
index 0000000..18cf44a
--- /dev/null
+++ b/lib/java/src/types/UInt64.java
@@ -0,0 +1,126 @@
+package com.facebook.thrift.types;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * More bit-twiddling bullshit. Take a look at UInt32 for details about
+ * the endian difference between Pillar and the JVM.
+ *
+ * Since we don't do arithmetic on unsigned longs, we just implement
+ * them here as a raw byte array. The only caveat is the constructor
+ * that takes an integer value. That value will be big-endian (JVM)
+ * but the byte array needs to be little-endian (Pillar)
+ *
+ * @author Mark Slee (mcslee@facebook.com)
+ *
+ */
+public class UInt64 {
+  private byte[] data_ = new byte[8];
+
+  public byte[] data() {
+    return data_;
+  }
+
+  public UInt64() {
+    for (int i = 0; i < 8; i++) {
+      data_[i] = (byte) 0;
+    }
+  }
+
+  public UInt64(long value) {
+    set(value);
+  }
+
+  public UInt64(byte[] buf, int offset) {
+    read(buf, offset);
+  }
+
+  public long toLong() {
+    long[] bytes = new long[8];
+    bytes[0] = (0xFF & ((long)data_[0]));
+    bytes[1] = (0xFF & ((long)data_[1]));
+    bytes[2] = (0xFF & ((long)data_[2]));
+    bytes[3] = (0xFF & ((long)data_[3]));
+    bytes[4] = (0xFF & ((long)data_[4]));
+    bytes[5] = (0xFF & ((long)data_[5]));
+    bytes[6] = (0xFF & ((long)data_[6]));
+    bytes[7] = (0xFF & ((long)data_[7]));
+
+    return ((long) ((bytes[0] << 56) | (bytes[1] << 48) |
+                    (bytes[2] << 40) | (bytes[3] << 32) |
+                    (bytes[4] << 24) | (bytes[5] << 16) |
+                    (bytes[6] << 8)  | (bytes[7])));
+  }
+
+  /**
+   * "HOLD IT! Pay close attention..." -Prodigy - Out of Space
+   *
+   * This is some wacky business. We want to take the integer value
+   * represented JVM style and put it into an 8-byte array that mirrors
+   * Intel/Pillar endianness (little). To do this, we graduate the
+   * integer to a long and then reverse the byte order, so bytes
+   * 5-8 in the JVM long become bytes 3-0 in the Pillar representation.
+   *
+   * NOTE: value MUST be positive, or else shit gets ill.
+   */
+  public void set(long longValue) {
+    if (longValue < 0) {
+      throw new RuntimeException("Cannot make UInt64 from a negative value.");
+    }
+    data_[0] = (byte)((longValue & 0xFF00000000000000L) >> 56);
+    data_[1] = (byte)((longValue & 0x00FF000000000000L) >> 48);
+    data_[2] = (byte)((longValue & 0x0000FF0000000000L) >> 40);
+    data_[3] = (byte)((longValue & 0x000000FF00000000L) >> 32);
+    data_[4] = (byte)((longValue & 0x00000000FF000000L) >> 24);
+    data_[5] = (byte)((longValue & 0x0000000000FF0000L) >> 16);
+    data_[6] = (byte)((longValue & 0x000000000000FF00L) >> 8);
+    data_[7] = (byte)((longValue & 0x00000000000000FFL));
+  }
+
+  public void read(byte[] buf, int offset) {
+    for (int i = 0; i < 8; i++) {
+      data_[i] = buf[offset+i];
+    }
+  }
+
+  /**
+   * Equivalent to << 8, shifting left by a byte.
+   */
+  public UInt64 lshift() {
+    for (int i = 7; i > 0; i--) {
+      data_[i] = data_[i-1];
+    }
+    data_[0] = (byte) 0;
+    return this;
+  }
+
+  /**
+   * Equivalent to |, logical or across all bytes
+   */
+  public UInt64 lor(UInt64 that) {
+    for (int i = 0; i < 8; i++) {
+      this.data_[i] = (byte) (this.data_[i] | that.data_[i]);
+    }
+    return this;
+  }
+
+  public int hashCode() {
+    return ((0xFF & (int)data_[3]) << 24) |
+           ((0xFF & (int)data_[2]) << 16) |
+           ((0xFF & (int)data_[1]) << 8) |
+           ((0xFF & (int)data_[0]));
+  }
+
+  public boolean equals(Object that) {
+    if (that instanceof UInt64) {
+      for (int i = 0; i < 8; i++) {
+        if (this.data_[i] != ((UInt64)that).data_[i]) {
+          return false;
+        }
+      }
+      return true;
+    }
+    return false;
+  }
+
+}
diff --git a/lib/java/src/types/UInt8.java b/lib/java/src/types/UInt8.java
new file mode 100644
index 0000000..640a7e1
--- /dev/null
+++ b/lib/java/src/types/UInt8.java
@@ -0,0 +1,60 @@
+package com.facebook.thrift.types;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * WILL IT EVER END? Even 'byte' is signed in Java, so we must use
+ * a short to represent bytes. 
+ *
+ * @author Mark Slee (mcslee@facebook.com)
+ *
+ */
+public class UInt8 {
+  private short shortValue_;
+  private byte[] data_ = new byte[1];
+  
+  public short get() {
+    return shortValue_;
+  }
+
+  public byte[] data() {
+    return data_;
+  }
+
+  public UInt8() {
+    data_[0] = (byte)0;
+  }
+
+  public UInt8(byte[] buf, int offset) {
+    read(buf, offset);
+  }
+
+  public UInt8(short value) {
+    set(value);
+  }
+
+  public void set(short value) {
+    if (value < 0) throw new RuntimeException("Cannot apply negative value to UInt8");
+    shortValue_ = value;
+    data_[0] = (byte)((shortValue_ & 0x00FF));
+  }
+
+  public void read(byte[] buf, int offset) {
+    data_[0] = buf[offset];
+    shortValue_ = (short) (0x00FF & (short)data_[0]);
+  }
+
+  public String toString() {
+    return String.valueOf(shortValue_);
+  }
+
+  public int hashCode() {
+    return (int)shortValue_;
+  }
+
+  public boolean equals(Object that) {
+    return ((that instanceof UInt8) &&
+            (this.shortValue_ == ((UInt8) that).shortValue_));
+  }
+
+}