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
10 # http://www.apache.org/licenses/LICENSE-2.0
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
20 from TProtocol import TType, TProtocolBase, TProtocolException, \
26 __all__ = ['TJSONProtocol',
27 'TJSONProtocolFactory',
28 'TSimpleJSONProtocol',
29 'TSimpleJSONProtocolFactory']
44 ESCAPE_CHAR = '"\\bfnrt'
45 ESCAPE_CHAR_VALS = ['"', '\\', '\b', '\f', '\n', '\r', '\t']
46 NUMERIC_CHAR = '+-.0123456789Ee'
48 CTYPES = {TType.BOOL: 'tf',
61 for key in CTYPES.keys():
62 JTYPES[CTYPES[key]] = key
65 class JSONBaseContext(object):
67 def __init__(self, protocol):
68 self.protocol = protocol
71 def doIO(self, function):
84 return self.__class__.__name__
87 class JSONListContext(JSONBaseContext):
89 def doIO(self, function):
90 if self.first is True:
96 self.doIO(self.protocol.trans.write)
99 self.doIO(self.protocol.readJSONSyntaxChar)
102 class JSONPairContext(JSONBaseContext):
104 def __init__(self, protocol):
105 super(JSONPairContext, self).__init__(protocol)
108 def doIO(self, function):
113 function(COLON if self.colon else COMMA)
114 self.colon = not self.colon
117 self.doIO(self.protocol.trans.write)
120 self.doIO(self.protocol.readJSONSyntaxChar)
126 return '%s, colon=%s' % (self.__class__.__name__, self.colon)
129 class LookaheadReader():
133 def __init__(self, protocol):
134 self.protocol = protocol
137 if self.hasData is True:
140 self.data = self.protocol.trans.read(1)
144 if self.hasData is False:
145 self.data = self.protocol.trans.read(1)
149 class TJSONProtocolBase(TProtocolBase):
151 def __init__(self, trans):
152 TProtocolBase.__init__(self, trans)
153 self.resetWriteContext()
154 self.resetReadContext()
156 def resetWriteContext(self):
157 self.context = JSONBaseContext(self)
158 self.contextStack = [self.context]
160 def resetReadContext(self):
161 self.resetWriteContext()
162 self.reader = LookaheadReader(self)
164 def pushContext(self, ctx):
165 self.contextStack.append(ctx)
168 def popContext(self):
169 self.contextStack.pop()
170 if self.contextStack:
171 self.context = self.contextStack[-1]
173 self.context = JSONBaseContext(self)
175 def writeJSONString(self, string):
177 self.trans.write(json.dumps(string))
179 def writeJSONNumber(self, number):
181 jsNumber = str(number)
182 if self.context.escapeNum():
183 jsNumber = "%s%s%s" % (QUOTE, jsNumber, QUOTE)
184 self.trans.write(jsNumber)
186 def writeJSONBase64(self, binary):
188 self.trans.write(QUOTE)
189 self.trans.write(base64.b64encode(binary))
190 self.trans.write(QUOTE)
192 def writeJSONObjectStart(self):
194 self.trans.write(LBRACE)
195 self.pushContext(JSONPairContext(self))
197 def writeJSONObjectEnd(self):
199 self.trans.write(RBRACE)
201 def writeJSONArrayStart(self):
203 self.trans.write(LBRACKET)
204 self.pushContext(JSONListContext(self))
206 def writeJSONArrayEnd(self):
208 self.trans.write(RBRACKET)
210 def readJSONSyntaxChar(self, character):
211 current = self.reader.read()
212 if character != current:
213 raise TProtocolException(TProtocolException.INVALID_DATA,
214 "Unexpected character: %s" % current)
216 def readJSONString(self, skipContext):
218 if skipContext is False:
220 self.readJSONSyntaxChar(QUOTE)
222 character = self.reader.read()
223 if character == QUOTE:
225 if character == ESCSEQ[0]:
226 character = self.reader.read()
227 if character == ESCSEQ[1]:
228 self.readJSONSyntaxChar(ZERO)
229 self.readJSONSyntaxChar(ZERO)
230 character = json.JSONDecoder().decode('"\u00%s"' % self.trans.read(2))
232 off = ESCAPE_CHAR.find(character)
234 raise TProtocolException(TProtocolException.INVALID_DATA,
235 "Expected control char")
236 character = ESCAPE_CHAR_VALS[off]
237 string.append(character)
238 return ''.join(string)
240 def isJSONNumeric(self, character):
241 return (True if NUMERIC_CHAR.find(character) != - 1 else False)
243 def readJSONQuotes(self):
244 if (self.context.escapeNum()):
245 self.readJSONSyntaxChar(QUOTE)
247 def readJSONNumericChars(self):
250 character = self.reader.peek()
251 if self.isJSONNumeric(character) is False:
253 numeric.append(self.reader.read())
254 return ''.join(numeric)
256 def readJSONInteger(self):
258 self.readJSONQuotes()
259 numeric = self.readJSONNumericChars()
260 self.readJSONQuotes()
264 raise TProtocolException(TProtocolException.INVALID_DATA,
265 "Bad data encounted in numeric data")
267 def readJSONDouble(self):
269 if self.reader.peek() == QUOTE:
270 string = self.readJSONString(True)
272 double = float(string)
273 if (self.context.escapeNum is False and
274 not math.isinf(double) and
275 not math.isnan(double)):
276 raise TProtocolException(TProtocolException.INVALID_DATA,
277 "Numeric data unexpectedly quoted")
280 raise TProtocolException(TProtocolException.INVALID_DATA,
281 "Bad data encounted in numeric data")
283 if self.context.escapeNum() is True:
284 self.readJSONSyntaxChar(QUOTE)
286 return float(self.readJSONNumericChars())
288 raise TProtocolException(TProtocolException.INVALID_DATA,
289 "Bad data encounted in numeric data")
291 def readJSONBase64(self):
292 string = self.readJSONString(False)
293 return base64.b64decode(string)
295 def readJSONObjectStart(self):
297 self.readJSONSyntaxChar(LBRACE)
298 self.pushContext(JSONPairContext(self))
300 def readJSONObjectEnd(self):
301 self.readJSONSyntaxChar(RBRACE)
304 def readJSONArrayStart(self):
306 self.readJSONSyntaxChar(LBRACKET)
307 self.pushContext(JSONListContext(self))
309 def readJSONArrayEnd(self):
310 self.readJSONSyntaxChar(RBRACKET)
314 class TJSONProtocol(TJSONProtocolBase):
316 def readMessageBegin(self):
317 self.resetReadContext()
318 self.readJSONArrayStart()
319 if self.readJSONInteger() != VERSION:
320 raise TProtocolException(TProtocolException.BAD_VERSION,
321 "Message contained bad version.")
322 name = self.readJSONString(False)
323 typen = self.readJSONInteger()
324 seqid = self.readJSONInteger()
325 return (name, typen, seqid)
327 def readMessageEnd(self):
328 self.readJSONArrayEnd()
330 def readStructBegin(self):
331 self.readJSONObjectStart()
333 def readStructEnd(self):
334 self.readJSONObjectEnd()
336 def readFieldBegin(self):
337 character = self.reader.peek()
340 if character == RBRACE:
343 id = self.readJSONInteger()
344 self.readJSONObjectStart()
345 ttype = JTYPES[self.readJSONString(False)]
346 return (None, ttype, id)
348 def readFieldEnd(self):
349 self.readJSONObjectEnd()
351 def readMapBegin(self):
352 self.readJSONArrayStart()
353 keyType = JTYPES[self.readJSONString(False)]
354 valueType = JTYPES[self.readJSONString(False)]
355 size = self.readJSONInteger()
356 self.readJSONObjectStart()
357 return (keyType, valueType, size)
359 def readMapEnd(self):
360 self.readJSONObjectEnd()
361 self.readJSONArrayEnd()
363 def readCollectionBegin(self):
364 self.readJSONArrayStart()
365 elemType = JTYPES[self.readJSONString(False)]
366 size = self.readJSONInteger()
367 return (elemType, size)
368 readListBegin = readCollectionBegin
369 readSetBegin = readCollectionBegin
371 def readCollectionEnd(self):
372 self.readJSONArrayEnd()
373 readSetEnd = readCollectionEnd
374 readListEnd = readCollectionEnd
377 return (False if self.readJSONInteger() == 0 else True)
379 def readNumber(self):
380 return self.readJSONInteger()
381 readByte = readNumber
386 def readDouble(self):
387 return self.readJSONDouble()
389 def readString(self):
390 return self.readJSONString(False)
392 def readBinary(self):
393 return self.readJSONBase64()
395 def writeMessageBegin(self, name, request_type, seqid):
396 self.resetWriteContext()
397 self.writeJSONArrayStart()
398 self.writeJSONNumber(VERSION)
399 self.writeJSONString(name)
400 self.writeJSONNumber(request_type)
401 self.writeJSONNumber(seqid)
403 def writeMessageEnd(self):
404 self.writeJSONArrayEnd()
406 def writeStructBegin(self, name):
407 self.writeJSONObjectStart()
409 def writeStructEnd(self):
410 self.writeJSONObjectEnd()
412 def writeFieldBegin(self, name, ttype, id):
413 self.writeJSONNumber(id)
414 self.writeJSONObjectStart()
415 self.writeJSONString(CTYPES[ttype])
417 def writeFieldEnd(self):
418 self.writeJSONObjectEnd()
420 def writeFieldStop(self):
423 def writeMapBegin(self, ktype, vtype, size):
424 self.writeJSONArrayStart()
425 self.writeJSONString(CTYPES[ktype])
426 self.writeJSONString(CTYPES[vtype])
427 self.writeJSONNumber(size)
428 self.writeJSONObjectStart()
430 def writeMapEnd(self):
431 self.writeJSONObjectEnd()
432 self.writeJSONArrayEnd()
434 def writeListBegin(self, etype, size):
435 self.writeJSONArrayStart()
436 self.writeJSONString(CTYPES[etype])
437 self.writeJSONNumber(size)
439 def writeListEnd(self):
440 self.writeJSONArrayEnd()
442 def writeSetBegin(self, etype, size):
443 self.writeJSONArrayStart()
444 self.writeJSONString(CTYPES[etype])
445 self.writeJSONNumber(size)
447 def writeSetEnd(self):
448 self.writeJSONArrayEnd()
450 def writeBool(self, boolean):
451 self.writeJSONNumber(1 if boolean is True else 0)
453 def writeByte(self, byte):
454 checkIntegerLimits(byte, 8)
455 self.writeJSONNumber(byte)
457 def writeI16(self, i16):
458 checkIntegerLimits(i16, 16)
459 self.writeJSONNumber(i16)
461 def writeI32(self, i32):
462 checkIntegerLimits(i32, 32)
463 self.writeJSONNumber(i32)
465 def writeI64(self, i64):
466 checkIntegerLimits(i64, 64)
467 self.writeJSONNumber(i64)
469 def writeDouble(self, dbl):
470 self.writeJSONNumber(dbl)
472 def writeString(self, string):
473 self.writeJSONString(string)
475 def writeBinary(self, binary):
476 self.writeJSONBase64(binary)
479 class TJSONProtocolFactory:
481 def getProtocol(self, trans):
482 return TJSONProtocol(trans)
485 class TSimpleJSONProtocol(TJSONProtocolBase):
486 """Simple, readable, write-only JSON protocol.
488 Useful for interacting with scripting languages.
491 def readMessageBegin(self):
492 raise NotImplementedError()
494 def readMessageEnd(self):
495 raise NotImplementedError()
497 def readStructBegin(self):
498 raise NotImplementedError()
500 def readStructEnd(self):
501 raise NotImplementedError()
503 def writeMessageBegin(self, name, request_type, seqid):
504 self.resetWriteContext()
506 def writeMessageEnd(self):
509 def writeStructBegin(self, name):
510 self.writeJSONObjectStart()
512 def writeStructEnd(self):
513 self.writeJSONObjectEnd()
515 def writeFieldBegin(self, name, ttype, fid):
516 self.writeJSONString(name)
518 def writeFieldEnd(self):
521 def writeMapBegin(self, ktype, vtype, size):
522 self.writeJSONObjectStart()
524 def writeMapEnd(self):
525 self.writeJSONObjectEnd()
527 def _writeCollectionBegin(self, etype, size):
528 self.writeJSONArrayStart()
530 def _writeCollectionEnd(self):
531 self.writeJSONArrayEnd()
532 writeListBegin = _writeCollectionBegin
533 writeListEnd = _writeCollectionEnd
534 writeSetBegin = _writeCollectionBegin
535 writeSetEnd = _writeCollectionEnd
537 def writeByte(self, byte):
538 checkIntegerLimits(byte, 8)
539 self.writeJSONNumber(byte)
541 def writeI16(self, i16):
542 checkIntegerLimits(i16, 16)
543 self.writeJSONNumber(i16)
545 def writeI32(self, i32):
546 checkIntegerLimits(i32, 32)
547 self.writeJSONNumber(i32)
549 def writeI64(self, i64):
550 checkIntegerLimits(i64, 64)
551 self.writeJSONNumber(i64)
553 def writeBool(self, boolean):
554 self.writeJSONNumber(1 if boolean is True else 0)
556 def writeDouble(self, dbl):
557 self.writeJSONNumber(dbl)
559 def writeString(self, string):
560 self.writeJSONString(string)
562 def writeBinary(self, binary):
563 self.writeJSONBase64(binary)
566 class TSimpleJSONProtocolFactory(object):
568 def getProtocol(self, trans):
569 return TSimpleJSONProtocol(trans)