<?php /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * @package thrift.protocol */ namespace Thrift\Protocol; use Thrift\Exception\TException; use Thrift\Exception\TProtocolException; use Thrift\Protocol\SimpleJSON\Context; use Thrift\Protocol\SimpleJSON\ListContext; use Thrift\Protocol\SimpleJSON\StructContext; use Thrift\Protocol\SimpleJSON\MapContext; use Thrift\Protocol\SimpleJSON\CollectionMapKeyException; /** * SimpleJSON implementation of thrift protocol, ported from Java. */ class TSimpleJSONProtocol extends TProtocol { const COMMA = ','; const COLON = ':'; const LBRACE = '{'; const RBRACE = '}'; const LBRACKET = '['; const RBRACKET = ']'; const QUOTE = '"'; const NAME_MAP = "map"; const NAME_LIST = "lst"; const NAME_SET = "set"; protected $writeContext_ = null; protected $writeContextStack_ = []; /** * Push a new write context onto the stack. */ protected function pushWriteContext(Context $c) { $this->writeContextStack_[] = $this->writeContext_; $this->writeContext_ = $c; } /** * Pop the last write context off the stack */ protected function popWriteContext() { $this->writeContext_ = array_pop($this->writeContextStack_); } /** * Used to make sure that we are not encountering a map whose keys are containers */ protected function assertContextIsNotMapKey($invalidKeyType) { if ($this->writeContext_->isMapKey()) { throw new CollectionMapKeyException( "Cannot serialize a map with keys that are of type " . $invalidKeyType ); } } private function writeJSONString($b) { $this->writeContext_->write(); $this->trans_->write(json_encode((string)$b)); } private function writeJSONInteger($num) { $isMapKey = $this->writeContext_->isMapKey(); $this->writeContext_->write(); if ($isMapKey) { $this->trans_->write(self::QUOTE); } $this->trans_->write((int)$num); if ($isMapKey) { $this->trans_->write(self::QUOTE); } } private function writeJSONDouble($num) { $isMapKey = $this->writeContext_->isMapKey(); $this->writeContext_->write(); if ($isMapKey) { $this->trans_->write(self::QUOTE); } $this->trans_->write(json_encode((float)$num)); if ($isMapKey) { $this->trans_->write(self::QUOTE); } } /** * Constructor */ public function __construct($trans) { parent::__construct($trans); $this->writeContext_ = new Context(); } /** * Writes the message header * * @param string $name Function name * @param int $type message type TMessageType::CALL or TMessageType::REPLY * @param int $seqid The sequence id of this message */ public function writeMessageBegin($name, $type, $seqid) { $this->trans_->write(self::LBRACKET); $this->pushWriteContext(new ListContext($this)); $this->writeJSONString($name); $this->writeJSONInteger($type); $this->writeJSONInteger($seqid); } /** * Close the message */ public function writeMessageEnd() { $this->popWriteContext(); $this->trans_->write(self::RBRACKET); } /** * Writes a struct header. * * @param string $name Struct name */ public function writeStructBegin($name) { $this->writeContext_->write(); $this->trans_->write(self::LBRACE); $this->pushWriteContext(new StructContext($this)); } /** * Close a struct. */ public function writeStructEnd() { $this->popWriteContext(); $this->trans_->write(self::RBRACE); } public function writeFieldBegin($fieldName, $fieldType, $fieldId) { $this->writeJSONString($fieldName); } public function writeFieldEnd() { } public function writeFieldStop() { } public function writeMapBegin($keyType, $valType, $size) { $this->assertContextIsNotMapKey(self::NAME_MAP); $this->writeContext_->write(); $this->trans_->write(self::LBRACE); $this->pushWriteContext(new MapContext($this)); } public function writeMapEnd() { $this->popWriteContext(); $this->trans_->write(self::RBRACE); } public function writeListBegin($elemType, $size) { $this->assertContextIsNotMapKey(self::NAME_LIST); $this->writeContext_->write(); $this->trans_->write(self::LBRACKET); $this->pushWriteContext(new ListContext($this)); // No metadata! } public function writeListEnd() { $this->popWriteContext(); $this->trans_->write(self::RBRACKET); } public function writeSetBegin($elemType, $size) { $this->assertContextIsNotMapKey(self::NAME_SET); $this->writeContext_->write(); $this->trans_->write(self::LBRACKET); $this->pushWriteContext(new ListContext($this)); // No metadata! } public function writeSetEnd() { $this->popWriteContext(); $this->trans_->write(self::RBRACKET); } public function writeBool($bool) { $this->writeJSONInteger($bool ? 1 : 0); } public function writeByte($byte) { $this->writeJSONInteger($byte); } public function writeI16($i16) { $this->writeJSONInteger($i16); } public function writeI32($i32) { $this->writeJSONInteger($i32); } public function writeI64($i64) { $this->writeJSONInteger($i64); } public function writeDouble($dub) { $this->writeJSONDouble($dub); } public function writeString($str) { $this->writeJSONString($str); } /** * Reading methods. * * simplejson is not meant to be read back into thrift * - see http://wiki.apache.org/thrift/ThriftUsageJava * - use JSON instead */ public function readMessageBegin(&$name, &$type, &$seqid) { throw new TException("Not implemented"); } public function readMessageEnd() { throw new TException("Not implemented"); } public function readStructBegin(&$name) { throw new TException("Not implemented"); } public function readStructEnd() { throw new TException("Not implemented"); } public function readFieldBegin(&$name, &$fieldType, &$fieldId) { throw new TException("Not implemented"); } public function readFieldEnd() { throw new TException("Not implemented"); } public function readMapBegin(&$keyType, &$valType, &$size) { throw new TException("Not implemented"); } public function readMapEnd() { throw new TException("Not implemented"); } public function readListBegin(&$elemType, &$size) { throw new TException("Not implemented"); } public function readListEnd() { throw new TException("Not implemented"); } public function readSetBegin(&$elemType, &$size) { throw new TException("Not implemented"); } public function readSetEnd() { throw new TException("Not implemented"); } public function readBool(&$bool) { throw new TException("Not implemented"); } public function readByte(&$byte) { throw new TException("Not implemented"); } public function readI16(&$i16) { throw new TException("Not implemented"); } public function readI32(&$i32) { throw new TException("Not implemented"); } public function readI64(&$i64) { throw new TException("Not implemented"); } public function readDouble(&$dub) { throw new TException("Not implemented"); } public function readString(&$str) { throw new TException("Not implemented"); } }