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/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;
+    }
+  }
+}