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