1<?php 2 3/* 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 * 21 * @package thrift.protocol 22 */ 23 24namespace Thrift\Protocol; 25 26use Thrift\Exception\TException; 27use Thrift\Exception\TProtocolException; 28use Thrift\Protocol\SimpleJSON\Context; 29use Thrift\Protocol\SimpleJSON\ListContext; 30use Thrift\Protocol\SimpleJSON\StructContext; 31use Thrift\Protocol\SimpleJSON\MapContext; 32use Thrift\Protocol\SimpleJSON\CollectionMapKeyException; 33 34/** 35 * SimpleJSON implementation of thrift protocol, ported from Java. 36 */ 37class TSimpleJSONProtocol extends TProtocol 38{ 39 const COMMA = ','; 40 const COLON = ':'; 41 const LBRACE = '{'; 42 const RBRACE = '}'; 43 const LBRACKET = '['; 44 const RBRACKET = ']'; 45 const QUOTE = '"'; 46 47 const NAME_MAP = "map"; 48 const NAME_LIST = "lst"; 49 const NAME_SET = "set"; 50 51 protected $writeContext_ = null; 52 protected $writeContextStack_ = []; 53 54 /** 55 * Push a new write context onto the stack. 56 */ 57 protected function pushWriteContext(Context $c) 58 { 59 $this->writeContextStack_[] = $this->writeContext_; 60 $this->writeContext_ = $c; 61 } 62 63 /** 64 * Pop the last write context off the stack 65 */ 66 protected function popWriteContext() 67 { 68 $this->writeContext_ = array_pop($this->writeContextStack_); 69 } 70 71 /** 72 * Used to make sure that we are not encountering a map whose keys are containers 73 */ 74 protected function assertContextIsNotMapKey($invalidKeyType) 75 { 76 if ($this->writeContext_->isMapKey()) { 77 throw new CollectionMapKeyException( 78 "Cannot serialize a map with keys that are of type " . 79 $invalidKeyType 80 ); 81 } 82 } 83 84 private function writeJSONString($b) 85 { 86 $this->writeContext_->write(); 87 88 $this->trans_->write(json_encode((string)$b)); 89 } 90 91 private function writeJSONInteger($num) 92 { 93 $isMapKey = $this->writeContext_->isMapKey(); 94 95 $this->writeContext_->write(); 96 97 if ($isMapKey) { 98 $this->trans_->write(self::QUOTE); 99 } 100 101 $this->trans_->write((int)$num); 102 103 if ($isMapKey) { 104 $this->trans_->write(self::QUOTE); 105 } 106 } 107 108 private function writeJSONDouble($num) 109 { 110 $isMapKey = $this->writeContext_->isMapKey(); 111 112 $this->writeContext_->write(); 113 114 if ($isMapKey) { 115 $this->trans_->write(self::QUOTE); 116 } 117 118 $this->trans_->write(json_encode((float)$num)); 119 120 if ($isMapKey) { 121 $this->trans_->write(self::QUOTE); 122 } 123 } 124 125 /** 126 * Constructor 127 */ 128 public function __construct($trans) 129 { 130 parent::__construct($trans); 131 $this->writeContext_ = new Context(); 132 } 133 134 /** 135 * Writes the message header 136 * 137 * @param string $name Function name 138 * @param int $type message type TMessageType::CALL or TMessageType::REPLY 139 * @param int $seqid The sequence id of this message 140 */ 141 public function writeMessageBegin($name, $type, $seqid) 142 { 143 $this->trans_->write(self::LBRACKET); 144 $this->pushWriteContext(new ListContext($this)); 145 $this->writeJSONString($name); 146 $this->writeJSONInteger($type); 147 $this->writeJSONInteger($seqid); 148 } 149 150 /** 151 * Close the message 152 */ 153 public function writeMessageEnd() 154 { 155 $this->popWriteContext(); 156 $this->trans_->write(self::RBRACKET); 157 } 158 159 /** 160 * Writes a struct header. 161 * 162 * @param string $name Struct name 163 */ 164 public function writeStructBegin($name) 165 { 166 $this->writeContext_->write(); 167 $this->trans_->write(self::LBRACE); 168 $this->pushWriteContext(new StructContext($this)); 169 } 170 171 /** 172 * Close a struct. 173 */ 174 public function writeStructEnd() 175 { 176 $this->popWriteContext(); 177 $this->trans_->write(self::RBRACE); 178 } 179 180 public function writeFieldBegin($fieldName, $fieldType, $fieldId) 181 { 182 $this->writeJSONString($fieldName); 183 } 184 185 public function writeFieldEnd() 186 { 187 } 188 189 public function writeFieldStop() 190 { 191 } 192 193 public function writeMapBegin($keyType, $valType, $size) 194 { 195 $this->assertContextIsNotMapKey(self::NAME_MAP); 196 $this->writeContext_->write(); 197 $this->trans_->write(self::LBRACE); 198 $this->pushWriteContext(new MapContext($this)); 199 } 200 201 public function writeMapEnd() 202 { 203 $this->popWriteContext(); 204 $this->trans_->write(self::RBRACE); 205 } 206 207 public function writeListBegin($elemType, $size) 208 { 209 $this->assertContextIsNotMapKey(self::NAME_LIST); 210 $this->writeContext_->write(); 211 $this->trans_->write(self::LBRACKET); 212 $this->pushWriteContext(new ListContext($this)); 213 // No metadata! 214 } 215 216 public function writeListEnd() 217 { 218 $this->popWriteContext(); 219 $this->trans_->write(self::RBRACKET); 220 } 221 222 public function writeSetBegin($elemType, $size) 223 { 224 $this->assertContextIsNotMapKey(self::NAME_SET); 225 $this->writeContext_->write(); 226 $this->trans_->write(self::LBRACKET); 227 $this->pushWriteContext(new ListContext($this)); 228 // No metadata! 229 } 230 231 public function writeSetEnd() 232 { 233 $this->popWriteContext(); 234 $this->trans_->write(self::RBRACKET); 235 } 236 237 public function writeBool($bool) 238 { 239 $this->writeJSONInteger($bool ? 1 : 0); 240 } 241 242 public function writeByte($byte) 243 { 244 $this->writeJSONInteger($byte); 245 } 246 247 public function writeI16($i16) 248 { 249 $this->writeJSONInteger($i16); 250 } 251 252 public function writeI32($i32) 253 { 254 $this->writeJSONInteger($i32); 255 } 256 257 public function writeI64($i64) 258 { 259 $this->writeJSONInteger($i64); 260 } 261 262 public function writeDouble($dub) 263 { 264 $this->writeJSONDouble($dub); 265 } 266 267 public function writeString($str) 268 { 269 $this->writeJSONString($str); 270 } 271 272 /** 273 * Reading methods. 274 * 275 * simplejson is not meant to be read back into thrift 276 * - see http://wiki.apache.org/thrift/ThriftUsageJava 277 * - use JSON instead 278 */ 279 280 public function readMessageBegin(&$name, &$type, &$seqid) 281 { 282 throw new TException("Not implemented"); 283 } 284 285 public function readMessageEnd() 286 { 287 throw new TException("Not implemented"); 288 } 289 290 public function readStructBegin(&$name) 291 { 292 throw new TException("Not implemented"); 293 } 294 295 public function readStructEnd() 296 { 297 throw new TException("Not implemented"); 298 } 299 300 public function readFieldBegin(&$name, &$fieldType, &$fieldId) 301 { 302 throw new TException("Not implemented"); 303 } 304 305 public function readFieldEnd() 306 { 307 throw new TException("Not implemented"); 308 } 309 310 public function readMapBegin(&$keyType, &$valType, &$size) 311 { 312 throw new TException("Not implemented"); 313 } 314 315 public function readMapEnd() 316 { 317 throw new TException("Not implemented"); 318 } 319 320 public function readListBegin(&$elemType, &$size) 321 { 322 throw new TException("Not implemented"); 323 } 324 325 public function readListEnd() 326 { 327 throw new TException("Not implemented"); 328 } 329 330 public function readSetBegin(&$elemType, &$size) 331 { 332 throw new TException("Not implemented"); 333 } 334 335 public function readSetEnd() 336 { 337 throw new TException("Not implemented"); 338 } 339 340 public function readBool(&$bool) 341 { 342 throw new TException("Not implemented"); 343 } 344 345 public function readByte(&$byte) 346 { 347 throw new TException("Not implemented"); 348 } 349 350 public function readI16(&$i16) 351 { 352 throw new TException("Not implemented"); 353 } 354 355 public function readI32(&$i32) 356 { 357 throw new TException("Not implemented"); 358 } 359 360 public function readI64(&$i64) 361 { 362 throw new TException("Not implemented"); 363 } 364 365 public function readDouble(&$dub) 366 { 367 throw new TException("Not implemented"); 368 } 369 370 public function readString(&$str) 371 { 372 throw new TException("Not implemented"); 373 } 374} 375