Add TProtocolTap: a meta-protocol for "wiretapping".

TProtocolTap is a protocol that passes reads through to a "source" protocol,
but mirrors them as writes to a "sink" protocol.


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665643 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/cpp/Makefile.am b/lib/cpp/Makefile.am
index 07540a1..571c4ff 100644
--- a/lib/cpp/Makefile.am
+++ b/lib/cpp/Makefile.am
@@ -88,6 +88,7 @@
                          src/protocol/TDenseProtocol.h \
                          src/protocol/TDebugProtocol.h \
                          src/protocol/TOneWayProtocol.h \
+                         src/protocol/TProtocolTap.h \
                          src/protocol/TProtocolException.h \
                          src/protocol/TProtocol.h
 
diff --git a/lib/cpp/src/protocol/TOneWayProtocol.h b/lib/cpp/src/protocol/TOneWayProtocol.h
index 1765413..3c31d1e 100644
--- a/lib/cpp/src/protocol/TOneWayProtocol.h
+++ b/lib/cpp/src/protocol/TOneWayProtocol.h
@@ -146,6 +146,148 @@
   std::string subclass_;
 };
 
+
+/**
+ * Abstract class for implementing a protocol that can only be read,
+ * not written.
+ *
+ * @author David Reiss <dreiss@facebook.com>
+ */
+class TReadOnlyProtocol : public TProtocol {
+ public:
+  /**
+   * @param subclass_name  The name of the concrete subclass.
+   */
+  TReadOnlyProtocol(boost::shared_ptr<TTransport> trans,
+                    const std::string& subclass_name)
+    : TProtocol(trans)
+    , subclass_(subclass_name)
+  {}
+
+  // All reading functions remain abstract.
+
+  /**
+   * Writing functions all throw an exception.
+   */
+
+  uint32_t writeMessageBegin(const std::string& name,
+                             const TMessageType messageType,
+                             const int32_t seqid) {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeMessageEnd() {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+
+  uint32_t writeStructBegin(const std::string& name) {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeStructEnd() {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeFieldBegin(const std::string& name,
+                           const TType fieldType,
+                           const int16_t fieldId) {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeFieldEnd() {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeFieldStop() {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeMapBegin(const TType keyType,
+                         const TType valType,
+                         const uint32_t size) {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeMapEnd() {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeListBegin(const TType elemType,
+                          const uint32_t size) {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeListEnd() {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeSetBegin(const TType elemType,
+                         const uint32_t size) {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeSetEnd() {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeBool(const bool value) {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeByte(const int8_t byte) {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeI16(const int16_t i16) {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeI32(const int32_t i32) {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeI64(const int64_t i64) {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeDouble(const double dub) {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeString(const std::string& str) {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+  uint32_t writeBinary(const std::string& str) {
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
+        subclass_ + " does not support writing (yet).");
+  }
+
+ private:
+  std::string subclass_;
+};
+
 }}} // facebook::thrift::protocol
 
 #endif // #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_H_
diff --git a/lib/cpp/src/protocol/TProtocolTap.h b/lib/cpp/src/protocol/TProtocolTap.h
new file mode 100644
index 0000000..1259598
--- /dev/null
+++ b/lib/cpp/src/protocol/TProtocolTap.h
@@ -0,0 +1,175 @@
+// Copyright (c) 2006- Facebook
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+
+#ifndef _THRIFT_PROTOCOL_TPROTOCOLTAP_H_
+#define _THRIFT_PROTOCOL_TPROTOCOLTAP_H_ 1
+
+#include <protocol/TOneWayProtocol.h>
+
+namespace facebook { namespace thrift { namespace protocol {
+
+using facebook::thrift::transport::TTransport;
+
+/**
+ * Puts a wiretap on a protocol object.  Any reads to this class are passed
+ * through to an enclosed protocol object, but also mirrored as write to a
+ * second protocol object.
+ *
+ * @author David Reiss <dreiss@facebook.com>
+ */
+class TProtocolTap : public TReadOnlyProtocol {
+ public:
+   TProtocolTap(boost::shared_ptr<TProtocol> source,
+                boost::shared_ptr<TProtocol> sink)
+     : TReadOnlyProtocol(source->getTransport(), "TProtocolTap")
+     , source_(source)
+     , sink_(sink)
+  {}
+
+  virtual uint32_t readMessageBegin(std::string& name,
+                                    TMessageType& messageType,
+                                    int32_t& seqid) {
+    uint32_t rv = source_->readMessageBegin(name, messageType, seqid);
+    sink_->writeMessageBegin(name, messageType, seqid);
+    return rv;
+  }
+
+  virtual uint32_t readMessageEnd() {
+    uint32_t rv = source_->readMessageEnd();
+    sink_->writeMessageEnd();
+    return rv;
+  }
+
+  virtual uint32_t readStructBegin(std::string& name) {
+    uint32_t rv = source_->readStructBegin(name);
+    sink_->writeStructBegin(name);
+    return rv;
+  }
+
+  virtual uint32_t readStructEnd() {
+    uint32_t rv = source_->readStructEnd();
+    sink_->writeStructEnd();
+    return rv;
+  }
+
+  virtual uint32_t readFieldBegin(std::string& name,
+                                  TType& fieldType,
+                                  int16_t& fieldId) {
+    uint32_t rv = source_->readFieldBegin(name, fieldType, fieldId);
+    if (fieldType == T_STOP) {
+      sink_->writeFieldStop();
+    } else {
+      sink_->writeFieldBegin(name, fieldType, fieldId);
+    }
+    return rv;
+  }
+
+
+  virtual uint32_t readFieldEnd() {
+    uint32_t rv = source_->readFieldEnd();
+    sink_->writeFieldEnd();
+    return rv;
+  }
+
+  virtual uint32_t readMapBegin(TType& keyType,
+                                TType& valType,
+                                uint32_t& size) {
+    uint32_t rv = source_->readMapBegin(keyType, valType, size);
+    sink_->writeMapBegin(keyType, valType, size);
+    return rv;
+  }
+
+
+  virtual uint32_t readMapEnd() {
+    uint32_t rv = source_->readMapEnd();
+    sink_->writeMapEnd();
+    return rv;
+  }
+
+  virtual uint32_t readListBegin(TType& elemType,
+                                 uint32_t& size) {
+    uint32_t rv = source_->readListBegin(elemType, size);
+    sink_->writeListBegin(elemType, size);
+    return rv;
+  }
+
+
+  virtual uint32_t readListEnd() {
+    uint32_t rv = source_->readListEnd();
+    sink_->writeListEnd();
+    return rv;
+  }
+
+  virtual uint32_t readSetBegin(TType& elemType,
+                                uint32_t& size) {
+    uint32_t rv = source_->readSetBegin(elemType, size);
+    sink_->writeSetBegin(elemType, size);
+    return rv;
+  }
+
+
+  virtual uint32_t readSetEnd() {
+    uint32_t rv = source_->readSetEnd();
+    sink_->writeSetEnd();
+    return rv;
+  }
+
+  virtual uint32_t readBool(bool& value) {
+    uint32_t rv = source_->readBool(value);
+    sink_->writeBool(value);
+    return rv;
+  }
+
+  virtual uint32_t readByte(int8_t& byte) {
+    uint32_t rv = source_->readByte(byte);
+    sink_->writeByte(byte);
+    return rv;
+  }
+
+  virtual uint32_t readI16(int16_t& i16) {
+    uint32_t rv = source_->readI16(i16);
+    sink_->writeI16(i16);
+    return rv;
+  }
+
+  virtual uint32_t readI32(int32_t& i32) {
+    uint32_t rv = source_->readI32(i32);
+    sink_->writeI32(i32);
+    return rv;
+  }
+
+  virtual uint32_t readI64(int64_t& i64) {
+    uint32_t rv = source_->readI64(i64);
+    sink_->writeI64(i64);
+    return rv;
+  }
+
+  virtual uint32_t readDouble(double& dub) {
+    uint32_t rv = source_->readDouble(dub);
+    sink_->writeDouble(dub);
+    return rv;
+  }
+
+  virtual uint32_t readString(std::string& str) {
+    uint32_t rv = source_->readString(str);
+    sink_->writeString(str);
+    return rv;
+  }
+
+  virtual uint32_t readBinary(std::string& str) {
+    uint32_t rv = source_->readBinary(str);
+    sink_->writeBinary(str);
+    return rv;
+  }
+
+ private:
+  boost::shared_ptr<TProtocol> source_;
+  boost::shared_ptr<TProtocol> sink_;
+};
+
+}}} // facebook::thrift::protocol
+
+#endif // #define _THRIFT_PROTOCOL_TPROTOCOLTAP_H_ 1