1 | /* |
2 | * Licensed to the Apache Software Foundation (ASF) under one |
3 | * or more contributor license agreements. See the NOTICE file |
4 | * distributed with this work for additional information |
5 | * regarding copyright ownership. The ASF licenses this file |
6 | * to you under the Apache License, Version 2.0 (the |
7 | * "License"); you may not use this file except in compliance |
8 | * with the License. You may obtain a copy of the License at |
9 | * |
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | * |
12 | * Unless required by applicable law or agreed to in writing, |
13 | * software distributed under the License is distributed on an |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
15 | * KIND, either express or implied. See the License for the |
16 | * specific language governing permissions and limitations |
17 | * under the License. |
18 | */ |
19 | |
20 | #ifndef _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_ |
21 | #define _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_ 1 |
22 | |
23 | #include <thrift/protocol/TVirtualProtocol.h> |
24 | |
25 | #include <thrift/stdcxx.h> |
26 | |
27 | namespace apache { |
28 | namespace thrift { |
29 | namespace protocol { |
30 | |
31 | /* |
32 | |
33 | !!! EXPERIMENTAL CODE !!! |
34 | |
35 | This protocol is very much a work in progress. |
36 | It doesn't handle many cases properly. |
37 | It throws exceptions in many cases. |
38 | It probably segfaults in many cases. |
39 | Bug reports and feature requests are welcome. |
40 | Complaints are not. :R |
41 | |
42 | */ |
43 | |
44 | /** |
45 | * Protocol that prints the payload in a nice human-readable format. |
46 | * Reading from this protocol is not supported. |
47 | * |
48 | */ |
49 | class TDebugProtocol : public TVirtualProtocol<TDebugProtocol> { |
50 | private: |
51 | enum write_state_t { UNINIT, STRUCT, LIST, SET, MAP_KEY, MAP_VALUE }; |
52 | |
53 | public: |
54 | TDebugProtocol(stdcxx::shared_ptr<TTransport> trans) |
55 | : TVirtualProtocol<TDebugProtocol>(trans), |
56 | trans_(trans.get()), |
57 | string_limit_(DEFAULT_STRING_LIMIT), |
58 | string_prefix_size_(DEFAULT_STRING_PREFIX_SIZE) { |
59 | write_state_.push_back(UNINIT); |
60 | } |
61 | |
62 | static const int32_t DEFAULT_STRING_LIMIT = 256; |
63 | static const int32_t DEFAULT_STRING_PREFIX_SIZE = 16; |
64 | |
65 | void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; } |
66 | |
67 | void setStringPrefixSize(int32_t string_prefix_size) { string_prefix_size_ = string_prefix_size; } |
68 | |
69 | uint32_t writeMessageBegin(const std::string& name, |
70 | const TMessageType messageType, |
71 | const int32_t seqid); |
72 | |
73 | uint32_t writeMessageEnd(); |
74 | |
75 | uint32_t writeStructBegin(const char* name); |
76 | |
77 | uint32_t writeStructEnd(); |
78 | |
79 | uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId); |
80 | |
81 | uint32_t writeFieldEnd(); |
82 | |
83 | uint32_t writeFieldStop(); |
84 | |
85 | uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size); |
86 | |
87 | uint32_t writeMapEnd(); |
88 | |
89 | uint32_t writeListBegin(const TType elemType, const uint32_t size); |
90 | |
91 | uint32_t writeListEnd(); |
92 | |
93 | uint32_t writeSetBegin(const TType elemType, const uint32_t size); |
94 | |
95 | uint32_t writeSetEnd(); |
96 | |
97 | uint32_t writeBool(const bool value); |
98 | |
99 | uint32_t writeByte(const int8_t byte); |
100 | |
101 | uint32_t writeI16(const int16_t i16); |
102 | |
103 | uint32_t writeI32(const int32_t i32); |
104 | |
105 | uint32_t writeI64(const int64_t i64); |
106 | |
107 | uint32_t writeDouble(const double dub); |
108 | |
109 | uint32_t writeString(const std::string& str); |
110 | |
111 | uint32_t writeBinary(const std::string& str); |
112 | |
113 | private: |
114 | void indentUp(); |
115 | void indentDown(); |
116 | uint32_t writePlain(const std::string& str); |
117 | uint32_t writeIndented(const std::string& str); |
118 | uint32_t startItem(); |
119 | uint32_t endItem(); |
120 | uint32_t writeItem(const std::string& str); |
121 | |
122 | static std::string fieldTypeName(TType type); |
123 | |
124 | TTransport* trans_; |
125 | |
126 | int32_t string_limit_; |
127 | int32_t string_prefix_size_; |
128 | |
129 | std::string indent_str_; |
130 | static const int indent_inc = 2; |
131 | |
132 | std::vector<write_state_t> write_state_; |
133 | std::vector<int> list_idx_; |
134 | }; |
135 | |
136 | /** |
137 | * Constructs debug protocol handlers |
138 | */ |
139 | class TDebugProtocolFactory : public TProtocolFactory { |
140 | public: |
141 | TDebugProtocolFactory() {} |
142 | virtual ~TDebugProtocolFactory() {} |
143 | |
144 | stdcxx::shared_ptr<TProtocol> getProtocol(stdcxx::shared_ptr<TTransport> trans) { |
145 | return stdcxx::shared_ptr<TProtocol>(new TDebugProtocol(trans)); |
146 | } |
147 | }; |
148 | } |
149 | } |
150 | } // apache::thrift::protocol |
151 | |
152 | // TODO(dreiss): Move (part of) ThriftDebugString into a .cpp file and remove this. |
153 | #include <thrift/transport/TBufferTransports.h> |
154 | |
155 | namespace apache { |
156 | namespace thrift { |
157 | |
158 | template <typename ThriftStruct> |
159 | std::string ThriftDebugString(const ThriftStruct& ts) { |
160 | using namespace apache::thrift::transport; |
161 | using namespace apache::thrift::protocol; |
162 | TMemoryBuffer* buffer = new TMemoryBuffer; |
163 | stdcxx::shared_ptr<TTransport> trans(buffer); |
164 | TDebugProtocol protocol(trans); |
165 | |
166 | ts.write(&protocol); |
167 | |
168 | uint8_t* buf; |
169 | uint32_t size; |
170 | buffer->getBuffer(&buf, &size); |
171 | return std::string((char*)buf, (unsigned int)size); |
172 | } |
173 | |
174 | // TODO(dreiss): This is badly broken. Don't use it unless you are me. |
175 | #if 0 |
176 | template<typename Object> |
177 | std::string DebugString(const std::vector<Object>& vec) { |
178 | using namespace apache::thrift::transport; |
179 | using namespace apache::thrift::protocol; |
180 | TMemoryBuffer* buffer = new TMemoryBuffer; |
181 | stdcxx::shared_ptr<TTransport> trans(buffer); |
182 | TDebugProtocol protocol(trans); |
183 | |
184 | // I am gross! |
185 | protocol.writeStructBegin("SomeRandomVector" ); |
186 | |
187 | // TODO: Fix this with a trait. |
188 | protocol.writeListBegin((TType)99, vec.size()); |
189 | typename std::vector<Object>::const_iterator it; |
190 | for (it = vec.begin(); it != vec.end(); ++it) { |
191 | it->write(&protocol); |
192 | } |
193 | protocol.writeListEnd(); |
194 | |
195 | uint8_t* buf; |
196 | uint32_t size; |
197 | buffer->getBuffer(&buf, &size); |
198 | return std::string((char*)buf, (unsigned int)size); |
199 | } |
200 | #endif // 0 |
201 | } |
202 | } // apache::thrift |
203 | |
204 | #endif // #ifndef _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_ |
205 | |