http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/Protocol/TCompactProtocol.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/Protocol/TCompactProtocol.php b/app/libraries/Thrift/Protocol/TCompactProtocol.php new file mode 100644 index 0000000..b8a71d6 --- /dev/null +++ b/app/libraries/Thrift/Protocol/TCompactProtocol.php @@ -0,0 +1,669 @@ +<?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\Protocol\TProtocol; +use Thrift\Type\TType; +use Thrift\Exception\TProtocolException; +use Thrift\Factory\TStringFuncFactory; + +/** + * Compact implementation of the Thrift protocol. + * + */ +class TCompactProtocol extends TProtocol { + + const COMPACT_STOP = 0x00; + const COMPACT_TRUE = 0x01; + const COMPACT_FALSE = 0x02; + const COMPACT_BYTE = 0x03; + const COMPACT_I16 = 0x04; + const COMPACT_I32 = 0x05; + const COMPACT_I64 = 0x06; + const COMPACT_DOUBLE = 0x07; + const COMPACT_BINARY = 0x08; + const COMPACT_LIST = 0x09; + const COMPACT_SET = 0x0A; + const COMPACT_MAP = 0x0B; + const COMPACT_STRUCT = 0x0C; + + const STATE_CLEAR = 0; + const STATE_FIELD_WRITE = 1; + const STATE_VALUE_WRITE = 2; + const STATE_CONTAINER_WRITE = 3; + const STATE_BOOL_WRITE = 4; + const STATE_FIELD_READ = 5; + const STATE_CONTAINER_READ = 6; + const STATE_VALUE_READ = 7; + const STATE_BOOL_READ = 8; + + const VERSION_MASK = 0x1f; + const VERSION = 1; + const PROTOCOL_ID = 0x82; + const TYPE_MASK = 0xe0; + const TYPE_BITS = 0x07; + const TYPE_SHIFT_AMOUNT = 5; + + protected static $ctypes = array( + TType::STOP => TCompactProtocol::COMPACT_STOP, + TType::BOOL => TCompactProtocol::COMPACT_TRUE, // used for collection + TType::BYTE => TCompactProtocol::COMPACT_BYTE, + TType::I16 => TCompactProtocol::COMPACT_I16, + TType::I32 => TCompactProtocol::COMPACT_I32, + TType::I64 => TCompactProtocol::COMPACT_I64, + TType::DOUBLE => TCompactProtocol::COMPACT_DOUBLE, + TType::STRING => TCompactProtocol::COMPACT_BINARY, + TType::STRUCT => TCompactProtocol::COMPACT_STRUCT, + TType::LST => TCompactProtocol::COMPACT_LIST, + TType::SET => TCompactProtocol::COMPACT_SET, + TType::MAP => TCompactProtocol::COMPACT_MAP, + ); + + protected static $ttypes = array( + TCompactProtocol::COMPACT_STOP => TType::STOP , + TCompactProtocol::COMPACT_TRUE => TType::BOOL, // used for collection + TCompactProtocol::COMPACT_FALSE => TType::BOOL, + TCompactProtocol::COMPACT_BYTE => TType::BYTE, + TCompactProtocol::COMPACT_I16 => TType::I16, + TCompactProtocol::COMPACT_I32 => TType::I32, + TCompactProtocol::COMPACT_I64 => TType::I64, + TCompactProtocol::COMPACT_DOUBLE => TType::DOUBLE, + TCompactProtocol::COMPACT_BINARY => TType::STRING, + TCompactProtocol::COMPACT_STRUCT => TType::STRUCT, + TCompactProtocol::COMPACT_LIST => TType::LST, + TCompactProtocol::COMPACT_SET => TType::SET, + TCompactProtocol::COMPACT_MAP => TType::MAP, + ); + + protected $state = TCompactProtocol::STATE_CLEAR; + protected $lastFid = 0; + protected $boolFid = null; + protected $boolValue = null; + protected $structs = array(); + protected $containers = array(); + + // Some varint / zigzag helper methods + public function toZigZag($n, $bits) { + return ($n << 1) ^ ($n >> ($bits - 1)); + } + + public function fromZigZag($n) { + return ($n >> 1) ^ -($n & 1); + } + + public function getVarint($data) { + $out = ""; + while (true) { + if (($data & ~0x7f) === 0) { + $out .= chr($data); + break; + } else { + $out .= chr(($data & 0xff) | 0x80); + $data = $data >> 7; + } + } + return $out; + } + + public function writeVarint($data) { + $out = $this->getVarint($data); + $result = TStringFuncFactory::create()->strlen($out); + $this->trans_->write($out, $result); + return $result; + } + + public function readVarint(&$result) { + $idx = 0; + $shift = 0; + $result = 0; + while (true) { + $x = $this->trans_->readAll(1); + $arr = unpack('C', $x); + $byte = $arr[1]; + $idx += 1; + $result |= ($byte & 0x7f) << $shift; + if (($byte >> 7) === 0) { + return $idx; + } + $shift += 7; + } + + return $idx; + } + + public function __construct($trans) { + parent::__construct($trans); + } + + public function writeMessageBegin($name, $type, $seqid) { + $written = + $this->writeUByte(TCompactProtocol::PROTOCOL_ID) + + $this->writeUByte(TCompactProtocol::VERSION | + ($type << TCompactProtocol::TYPE_SHIFT_AMOUNT)) + + $this->writeVarint($seqid) + + $this->writeString($name); + $this->state = TCompactProtocol::STATE_VALUE_WRITE; + return $written; + } + + public function writeMessageEnd() { + $this->state = TCompactProtocol::STATE_CLEAR; + return 0; + } + + public function writeStructBegin($name) { + $this->structs[] = array($this->state, $this->lastFid); + $this->state = TCompactProtocol::STATE_FIELD_WRITE; + $this->lastFid = 0; + return 0; + } + + public function writeStructEnd() { + $old_values = array_pop($this->structs); + $this->state = $old_values[0]; + $this->lastFid = $old_values[1]; + return 0; + } + + public function writeFieldStop() { + return $this->writeByte(0); + } + + public function writeFieldHeader($type, $fid) { + $written = 0; + $delta = $fid - $this->lastFid; + if (0 < $delta && $delta <= 15) { + $written = $this->writeUByte(($delta << 4) | $type); + } else { + $written = $this->writeByte($type) + + $this->writeI16($fid); + } + $this->lastFid = $fid; + return $written; + } + + public function writeFieldBegin($field_name, $field_type, $field_id) { + if ($field_type == TTYPE::BOOL) { + $this->state = TCompactProtocol::STATE_BOOL_WRITE; + $this->boolFid = $field_id; + return 0; + } else { + $this->state = TCompactProtocol::STATE_VALUE_WRITE; + return $this->writeFieldHeader(self::$ctypes[$field_type], $field_id); + } + } + + public function writeFieldEnd() { + $this->state = TCompactProtocol::STATE_FIELD_WRITE; + return 0; + } + + public function writeCollectionBegin($etype, $size) { + $written = 0; + if ($size <= 14) { + $written = $this->writeUByte($size << 4 | + self::$ctypes[$etype]); + } else { + $written = $this->writeUByte(0xf0 | + self::$ctypes[$etype]) + + $this->writeVarint($size); + } + $this->containers[] = $this->state; + $this->state = TCompactProtocol::STATE_CONTAINER_WRITE; + + return $written; + } + + public function writeMapBegin($key_type, $val_type, $size) { + $written = 0; + if ($size == 0) { + $written = $this->writeByte(0); + } else { + $written = $this->writeVarint($size) + + $this->writeUByte(self::$ctypes[$key_type] << 4 | + self::$ctypes[$val_type]); + } + $this->containers[] = $this->state; + return $written; + } + + public function writeCollectionEnd() { + $this->state = array_pop($this->containers); + return 0; + } + + public function writeMapEnd() { + return $this->writeCollectionEnd(); + } + + public function writeListBegin($elem_type, $size) { + return $this->writeCollectionBegin($elem_type, $size); + } + + public function writeListEnd() { + return $this->writeCollectionEnd(); + } + + public function writeSetBegin($elem_type, $size) { + return $this->writeCollectionBegin($elem_type, $size); + } + + public function writeSetEnd() { + return $this->writeCollectionEnd(); + } + + public function writeBool($value) { + if ($this->state == TCompactProtocol::STATE_BOOL_WRITE) { + $ctype = TCompactProtocol::COMPACT_FALSE; + if ($value) { + $ctype = TCompactProtocol::COMPACT_TRUE; + } + return $this->writeFieldHeader($ctype, $this->boolFid); + } else if ($this->state == TCompactProtocol::STATE_CONTAINER_WRITE) { + return $this->writeByte($value ? 1 : 0); + } else { + throw new TProtocolException('Invalid state in compact protocol'); + } + } + + public function writeByte($value) { + $data = pack('c', $value); + $this->trans_->write($data, 1); + return 1; + } + + public function writeUByte($byte) { + $this->trans_->write(pack('C', $byte), 1); + return 1; + } + + public function writeI16($value) { + $thing = $this->toZigZag($value, 16); + return $this->writeVarint($thing); + } + + public function writeI32($value) { + $thing = $this->toZigZag($value, 32); + return $this->writeVarint($thing); + } + + public function writeDouble($value) { + $data = pack('d', $value); + $this->trans_->write($data, 8); + return 8; + } + + public function writeString($value) { + $len = TStringFuncFactory::create()->strlen($value); + $result = $this->writeVarint($len); + if ($len) { + $this->trans_->write($value, $len); + } + return $result + $len; + } + + public function readFieldBegin(&$name, &$field_type, &$field_id) { + $result = $this->readUByte($field_type); + + if (($field_type & 0x0f) == TType::STOP) { + $field_id = 0; + return $result; + } + $delta = $field_type >> 4; + if ($delta == 0) { + $result += $this->readI16($field_id); + } else { + $field_id = $this->lastFid + $delta; + } + $this->lastFid = $field_id; + $field_type = $this->getTType($field_type & 0x0f); + if ($field_type == TCompactProtocol::COMPACT_TRUE) { + $this->state = TCompactProtocol::STATE_BOOL_READ; + $this->boolValue = true; + } else if ($field_type == TCompactProtocol::COMPACT_FALSE) { + $this->state = TCompactProtocol::STATE_BOOL_READ; + $this->boolValue = false; + } else { + $this->state = TCompactProtocol::STATE_VALUE_READ; + } + return $result; + } + + public function readFieldEnd() { + $this->state = TCompactProtocol::STATE_FIELD_READ; + return 0; + } + + public function readUByte(&$value) { + $data = $this->trans_->readAll(1); + $arr = unpack('C', $data); + $value = $arr[1]; + return 1; + } + + public function readByte(&$value) { + $data = $this->trans_->readAll(1); + $arr = unpack('c', $data); + $value = $arr[1]; + return 1; + } + + public function readZigZag(&$value) { + $result = $this->readVarint($value); + $value = $this->fromZigZag($value); + return $result; + } + + public function readMessageBegin(&$name, &$type, &$seqid) { + $protoId = 0; + $result = $this->readUByte($protoId); + if ($protoId != TCompactProtocol::PROTOCOL_ID) { + throw new TProtocolException('Bad protocol id in TCompact message'); + } + $verType = 0; + $result += $this->readUByte($verType); + $type = ($verType >> TCompactProtocol::TYPE_SHIFT_AMOUNT) & TCompactProtocol::TYPE_BITS; + $version = $verType & TCompactProtocol::VERSION_MASK; + if ($version != TCompactProtocol::VERSION) { + throw new TProtocolException('Bad version in TCompact message'); + } + $result += $this->readVarint($seqid); + $result += $this->readString($name); + + return $result; + } + + public function readMessageEnd() { + return 0; + } + + public function readStructBegin(&$name) { + $name = ''; // unused + $this->structs[] = array($this->state, $this->lastFid); + $this->state = TCompactProtocol::STATE_FIELD_READ; + $this->lastFid = 0; + return 0; + } + + public function readStructEnd() { + $last = array_pop($this->structs); + $this->state = $last[0]; + $this->lastFid = $last[1]; + return 0; + } + + public function readCollectionBegin(&$type, &$size) { + $sizeType = 0; + $result = $this->readUByte($sizeType); + $size = $sizeType >> 4; + $type = $this->getTType($sizeType); + if ($size == 15) { + $result += $this->readVarint($size); + } + $this->containers[] = $this->state; + $this->state = TCompactProtocol::STATE_CONTAINER_READ; + + return $result; + } + + public function readMapBegin(&$key_type, &$val_type, &$size) { + $result = $this->readVarint($size); + $types = 0; + if ($size > 0) { + $result += $this->readUByte($types); + } + $val_type = $this->getTType($types); + $key_type = $this->getTType($types >> 4); + $this->containers[] = $this->state; + $this->state = TCompactProtocol::STATE_CONTAINER_READ; + + return $result; + } + + public function readCollectionEnd() { + $this->state = array_pop($this->containers); + return 0; + } + + public function readMapEnd() { + return $this->readCollectionEnd(); + } + + public function readListBegin(&$elem_type, &$size) { + return $this->readCollectionBegin($elem_type, $size); + } + + public function readListEnd() { + return $this->readCollectionEnd(); + } + + public function readSetBegin(&$elem_type, &$size) { + return $this->readCollectionBegin($elem_type, $size); + } + + public function readSetEnd() { + return $this->readCollectionEnd(); + } + + public function readBool(&$value) { + if ($this->state == TCompactProtocol::STATE_BOOL_READ) { + $value = $this->boolValue; + return 0; + } else if ($this->state == TCompactProtocol::STATE_CONTAINER_READ) { + return $this->readByte($value); + } else { + throw new TProtocolException('Invalid state in compact protocol'); + } + } + + public function readI16(&$value) { + return $this->readZigZag($value); + } + + public function readI32(&$value) { + return $this->readZigZag($value); + } + + public function readDouble(&$value) { + $data = $this->trans_->readAll(8); + $arr = unpack('d', $data); + $value = $arr[1]; + return 8; + } + + public function readString(&$value) { + $result = $this->readVarint($len); + if ($len) { + $value = $this->trans_->readAll($len); + } else { + $value = ''; + } + return $result + $len; + } + + public function getTType($byte) { + return self::$ttypes[$byte & 0x0f]; + } + + // If we are on a 32bit architecture we have to explicitly deal with + // 64-bit twos-complement arithmetic since PHP wants to treat all ints + // as signed and any int over 2^31 - 1 as a float + + // Read and write I64 as two 32 bit numbers $hi and $lo + + public function readI64(&$value) { + // Read varint from wire + $hi = 0; + $lo = 0; + + $idx = 0; + $shift = 0; + + while (true) { + $x = $this->trans_->readAll(1); + $arr = unpack('C', $x); + $byte = $arr[1]; + $idx += 1; + if ($shift < 32) { + $lo |= (($byte & 0x7f) << $shift) & + 0x00000000ffffffff; + } + // Shift hi and lo together. + if ($shift >= 32) { + $hi |= (($byte & 0x7f) << ($shift - 32)); + } else if ($shift > 25) { + $hi |= (($byte & 0x7f) >> ($shift - 25)); + } + if (($byte >> 7) === 0) { + break; + } + $shift += 7; + } + + // Now, unzig it. + $xorer = 0; + if ($lo & 1) { + $xorer = 0xffffffff; + } + $lo = ($lo >> 1) & 0x7fffffff; + $lo = $lo | (($hi & 1) << 31); + $hi = ($hi >> 1) ^ $xorer; + $lo = $lo ^ $xorer; + + // Now put $hi and $lo back together + if (true) { + $isNeg = $hi < 0; + + // Check for a negative + if ($isNeg) { + $hi = ~$hi & (int)0xffffffff; + $lo = ~$lo & (int)0xffffffff; + + if ($lo == (int)0xffffffff) { + $hi++; + $lo = 0; + } else { + $lo++; + } + } + + // Force 32bit words in excess of 2G to be positive - we deal with sign + // explicitly below + + if ($hi & (int)0x80000000) { + $hi &= (int)0x7fffffff; + $hi += 0x80000000; + } + + if ($lo & (int)0x80000000) { + $lo &= (int)0x7fffffff; + $lo += 0x80000000; + } + + $value = $hi * 4294967296 + $lo; + + if ($isNeg) { + $value = 0 - $value; + } + } else { + + // Upcast negatives in LSB bit + if ($arr[2] & 0x80000000) { + $arr[2] = $arr[2] & 0xffffffff; + } + + // Check for a negative + if ($arr[1] & 0x80000000) { + $arr[1] = $arr[1] & 0xffffffff; + $arr[1] = $arr[1] ^ 0xffffffff; + $arr[2] = $arr[2] ^ 0xffffffff; + $value = 0 - $arr[1] * 4294967296 - $arr[2] - 1; + } else { + $value = $arr[1] * 4294967296 + $arr[2]; + } + } + + return $idx; + } + + public function writeI64($value) { + // If we are in an I32 range, use the easy method below. + if (($value > 4294967296) || ($value < -4294967296)) { + // Convert $value to $hi and $lo + $neg = $value < 0; + + if ($neg) { + $value *= -1; + } + + $hi = (int)$value >> 32; + $lo = (int)$value & 0xffffffff; + + if ($neg) { + $hi = ~$hi; + $lo = ~$lo; + if (($lo & (int)0xffffffff) == (int)0xffffffff) { + $lo = 0; + $hi++; + } else { + $lo++; + } + } + + // Now do the zigging and zagging. + $xorer = 0; + if ($neg) { + $xorer = 0xffffffff; + } + $lowbit = ($lo >> 31) & 1; + $hi = ($hi << 1) | $lowbit; + $lo = ($lo << 1); + $lo = ($lo ^ $xorer) & 0xffffffff; + $hi = ($hi ^ $xorer) & 0xffffffff; + + // now write out the varint, ensuring we shift both hi and lo + $out = ""; + while (true) { + if (($lo & ~0x7f) === 0 && + $hi === 0) { + $out .= chr($lo); + break; + } else { + $out .= chr(($lo & 0xff) | 0x80); + $lo = $lo >> 7; + $lo = $lo | ($hi << 25); + $hi = $hi >> 7; + // Right shift carries sign, but we don't want it to. + $hi = $hi & (127 << 25); + } + } + + $ret = TStringFuncFactory::create()->strlen($out); + $this->trans_->write($out, $ret); + + return $ret; + } else { + return $this->writeVarint($this->toZigZag($value, 64)); + } + } +}
http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/Protocol/TJSONProtocol.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/Protocol/TJSONProtocol.php b/app/libraries/Thrift/Protocol/TJSONProtocol.php new file mode 100644 index 0000000..402401a --- /dev/null +++ b/app/libraries/Thrift/Protocol/TJSONProtocol.php @@ -0,0 +1,694 @@ +<?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\Protocol\TProtocol; +use Thrift\Type\TType; +use Thrift\Exception\TProtocolException; +use Thrift\Protocol\JSON\BaseContext; +use Thrift\Protocol\JSON\LookaheadReader; +use Thrift\Protocol\JSON\PairContext; +use Thrift\Protocol\JSON\ListContext; + +/** + * JSON implementation of thrift protocol, ported from Java. + */ +class TJSONProtocol extends TProtocol +{ + const COMMA = ','; + const COLON = ':'; + const LBRACE = '{'; + const RBRACE = '}'; + const LBRACKET = '['; + const RBRACKET = ']'; + const QUOTE = '"'; + const BACKSLASH = '\\'; + const ZERO = '0'; + const ESCSEQ = '\\'; + const DOUBLEESC = '__DOUBLE_ESCAPE_SEQUENCE__'; + + const VERSION = 1; + + public static $JSON_CHAR_TABLE = array( + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + 1, 1, '"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + ); + + public static $ESCAPE_CHARS = array('"', '\\', '/', "b", "f", "n", "r", "t"); + + public static $ESCAPE_CHAR_VALS = array( + '"', '\\', '/', "\x08", "\f", "\n", "\r", "\t", + ); + + const NAME_BOOL = "tf"; + const NAME_BYTE = "i8"; + const NAME_I16 = "i16"; + const NAME_I32 = "i32"; + const NAME_I64 = "i64"; + const NAME_DOUBLE = "dbl"; + const NAME_STRUCT = "rec"; + const NAME_STRING = "str"; + const NAME_MAP = "map"; + const NAME_LIST = "lst"; + const NAME_SET = "set"; + + private function getTypeNameForTypeID($typeID) + { + switch ($typeID) { + case TType::BOOL: + return self::NAME_BOOL; + case TType::BYTE: + return self::NAME_BYTE; + case TType::I16: + return self::NAME_I16; + case TType::I32: + return self::NAME_I32; + case TType::I64: + return self::NAME_I64; + case TType::DOUBLE: + return self::NAME_DOUBLE; + case TType::STRING: + return self::NAME_STRING; + case TType::STRUCT: + return self::NAME_STRUCT; + case TType::MAP: + return self::NAME_MAP; + case TType::SET: + return self::NAME_SET; + case TType::LST: + return self::NAME_LIST; + default: + throw new TProtocolException("Unrecognized type", TProtocolException::UNKNOWN); + } + } + + private function getTypeIDForTypeName($name) + { + $result = TType::STOP; + + if (strlen($name) > 1) { + switch (substr($name, 0, 1)) { + case 'd': + $result = TType::DOUBLE; + break; + case 'i': + switch (substr($name, 1, 1)) { + case '8': + $result = TType::BYTE; + break; + case '1': + $result = TType::I16; + break; + case '3': + $result = TType::I32; + break; + case '6': + $result = TType::I64; + break; + } + break; + case 'l': + $result = TType::LST; + break; + case 'm': + $result = TType::MAP; + break; + case 'r': + $result = TType::STRUCT; + break; + case 's': + if (substr($name, 1, 1) == 't') { + $result = TType::STRING; + } + else if (substr($name, 1, 1) == 'e') { + $result = TType::SET; + } + break; + case 't': + $result = TType::BOOL; + break; + } + } + if ($result == TType::STOP) { + throw new TProtocolException("Unrecognized type", TProtocolException::INVALID_DATA); + } + return $result; + } + + public $contextStack_ = array(); + public $context_; + public $reader_; + + private function pushContext($c) { + array_push($this->contextStack_, $this->context_); + $this->context_ = $c; + } + + private function popContext() { + $this->context_ = array_pop($this->contextStack_); + } + + public function __construct($trans) { + parent::__construct($trans); + $this->context_ = new BaseContext(); + $this->reader_ = new LookaheadReader($this); + } + + public function reset() { + $this->contextStack_ = array(); + $this->context_ = new BaseContext(); + $this->reader_ = new LookaheadReader($this); + } + + private $tmpbuf_ = array(4); + + public function readJSONSyntaxChar($b) { + $ch = $this->reader_->read(); + + if (substr($ch, 0, 1) != $b) { + throw new TProtocolException("Unexpected character: " . $ch, TProtocolException::INVALID_DATA); + } + } + + private function hexVal($s) { + for ($i = 0; $i < strlen($s); $i++) { + $ch = substr($s, $i, 1); + + if (!($ch >= "a" && $ch <= "f") && !($ch >= "0" && $ch <= "9")) { + throw new TProtocolException("Expected hex character " . $ch, TProtocolException::INVALID_DATA); + } + } + + return hexdec($s); + } + + private function hexChar($val) { + return dechex($val); + } + + private function writeJSONString($b) { + $this->context_->write(); + + if (is_numeric($b) && $this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + + $this->trans_->write(json_encode($b)); + + if (is_numeric($b) && $this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + } + + private function writeJSONInteger($num) { + $this->context_->write(); + + if ($this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + + $this->trans_->write($num); + + if ($this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + } + + private function writeJSONDouble($num) { + $this->context_->write(); + + if ($this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + + $this->trans_->write(json_encode($num)); + + if ($this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + } + + private function writeJSONBase64($data) { + $this->context_->write(); + $this->trans_->write(self::QUOTE); + $this->trans_->write(json_encode(base64_encode($data))); + $this->trans_->write(self::QUOTE); + } + + private function writeJSONObjectStart() { + $this->context_->write(); + $this->trans_->write(self::LBRACE); + $this->pushContext(new PairContext($this)); + } + + private function writeJSONObjectEnd() { + $this->popContext(); + $this->trans_->write(self::RBRACE); + } + + private function writeJSONArrayStart() { + $this->context_->write(); + $this->trans_->write(self::LBRACKET); + $this->pushContext(new ListContext($this)); + } + + private function writeJSONArrayEnd() { + $this->popContext(); + $this->trans_->write(self::RBRACKET); + } + + private function readJSONString($skipContext) { + if (!$skipContext) { + $this->context_->read(); + } + + $jsonString = ''; + $lastChar = NULL; + while (true) { + $ch = $this->reader_->read(); + $jsonString .= $ch; + if ($ch == self::QUOTE && + $lastChar !== NULL && + $lastChar !== self::ESCSEQ) { + break; + } + if ($ch == self::ESCSEQ && $lastChar == self::ESCSEQ) { + $lastChar = self::DOUBLEESC; + } else { + $lastChar = $ch; + } + } + return json_decode($jsonString); + } + + private function isJSONNumeric($b) { + switch ($b) { + case '+': + case '-': + case '.': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'E': + case 'e': + return true; + } + return false; + } + + private function readJSONNumericChars() { + $strbld = array(); + + while (true) { + $ch = $this->reader_->peek(); + + if (!$this->isJSONNumeric($ch)) { + break; + } + + $strbld[] = $this->reader_->read(); + } + + return implode("", $strbld); + } + + private function readJSONInteger() { + $this->context_->read(); + + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + $str = $this->readJSONNumericChars(); + + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + if (!is_numeric($str)) { + throw new TProtocolException("Invalid data in numeric: " . $str, TProtocolException::INVALID_DATA); + } + + return intval($str); + } + + /** + * Identical to readJSONInteger but without the final cast. + * Needed for proper handling of i64 on 32 bit machines. Why a + * separate function? So we don't have to force the rest of the + * use cases through the extra conditional. + */ + private function readJSONIntegerAsString() { + $this->context_->read(); + + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + $str = $this->readJSONNumericChars(); + + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + if (!is_numeric($str)) { + throw new TProtocolException("Invalid data in numeric: " . $str, TProtocolException::INVALID_DATA); + } + + return $str; + } + + private function readJSONDouble() { + $this->context_->read(); + + if (substr($this->reader_->peek(), 0, 1) == self::QUOTE) { + $arr = $this->readJSONString(true); + + if ($arr == "NaN") { + return NAN; + } else if ($arr == "Infinity") { + return INF; + } else if (!$this->context_->escapeNum()) { + throw new TProtocolException("Numeric data unexpectedly quoted " . $arr, + TProtocolException::INVALID_DATA); + } + + return floatval($arr); + } else { + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + return floatval($this->readJSONNumericChars()); + } + } + + private function readJSONBase64() { + $arr = $this->readJSONString(false); + $data = base64_decode($arr, true); + + if ($data === false) { + throw new TProtocolException("Invalid base64 data " . $arr, TProtocolException::INVALID_DATA); + } + + return $data; + } + + private function readJSONObjectStart() { + $this->context_->read(); + $this->readJSONSyntaxChar(self::LBRACE); + $this->pushContext(new PairContext($this)); + } + + private function readJSONObjectEnd() { + $this->readJSONSyntaxChar(self::RBRACE); + $this->popContext(); + } + + private function readJSONArrayStart() + { + $this->context_->read(); + $this->readJSONSyntaxChar(self::LBRACKET); + $this->pushContext(new ListContext($this)); + } + + private function readJSONArrayEnd() { + $this->readJSONSyntaxChar(self::RBRACKET); + $this->popContext(); + } + + /** + * 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->writeJSONArrayStart(); + $this->writeJSONInteger(self::VERSION); + $this->writeJSONString($name); + $this->writeJSONInteger($type); + $this->writeJSONInteger($seqid); + } + + /** + * Close the message + */ + public function writeMessageEnd() { + $this->writeJSONArrayEnd(); + } + + /** + * Writes a struct header. + * + * @param string $name Struct name + * @throws TException on write error + * @return int How many bytes written + */ + public function writeStructBegin($name) { + $this->writeJSONObjectStart(); + } + + /** + * Close a struct. + * + * @throws TException on write error + * @return int How many bytes written + */ + public function writeStructEnd() { + $this->writeJSONObjectEnd(); + } + + public function writeFieldBegin($fieldName, $fieldType, $fieldId) { + $this->writeJSONInteger($fieldId); + $this->writeJSONObjectStart(); + $this->writeJSONString($this->getTypeNameForTypeID($fieldType)); + } + + public function writeFieldEnd() { + $this->writeJsonObjectEnd(); + } + + public function writeFieldStop() { + } + + public function writeMapBegin($keyType, $valType, $size) { + $this->writeJSONArrayStart(); + $this->writeJSONString($this->getTypeNameForTypeID($keyType)); + $this->writeJSONString($this->getTypeNameForTypeID($valType)); + $this->writeJSONInteger($size); + $this->writeJSONObjectStart(); + } + + public function writeMapEnd() { + $this->writeJSONObjectEnd(); + $this->writeJSONArrayEnd(); + } + + public function writeListBegin($elemType, $size) { + $this->writeJSONArrayStart(); + $this->writeJSONString($this->getTypeNameForTypeID($elemType)); + $this->writeJSONInteger($size); + } + + public function writeListEnd() { + $this->writeJSONArrayEnd(); + } + + public function writeSetBegin($elemType, $size) { + $this->writeJSONArrayStart(); + $this->writeJSONString($this->getTypeNameForTypeID($elemType)); + $this->writeJSONInteger($size); + } + + public function writeSetEnd() { + $this->writeJSONArrayEnd(); + } + + 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); + } + + /** + * Reads the message header + * + * @param string $name Function name + * @param int $type message type TMessageType::CALL or TMessageType::REPLY + * @parem int $seqid The sequence id of this message + */ + public function readMessageBegin(&$name, &$type, &$seqid) { + $this->readJSONArrayStart(); + + if ($this->readJSONInteger() != self::VERSION) { + throw new TProtocolException("Message contained bad version", TProtocolException::BAD_VERSION); + } + + $name = $this->readJSONString(false); + $type = $this->readJSONInteger(); + $seqid = $this->readJSONInteger(); + + return true; + } + + /** + * Read the close of message + */ + public function readMessageEnd() { + $this->readJSONArrayEnd(); + } + + public function readStructBegin(&$name) { + $this->readJSONObjectStart(); + return 0; + } + + public function readStructEnd() { + $this->readJSONObjectEnd(); + } + + public function readFieldBegin(&$name, &$fieldType, &$fieldId) { + $ch = $this->reader_->peek(); + $name = ""; + + if (substr($ch, 0, 1) == self::RBRACE) { + $fieldType = TType::STOP; + } else { + $fieldId = $this->readJSONInteger(); + $this->readJSONObjectStart(); + $fieldType = $this->getTypeIDForTypeName($this->readJSONString(false)); + } + } + + public function readFieldEnd() { + $this->readJSONObjectEnd(); + } + + public function readMapBegin(&$keyType, &$valType, &$size) { + $this->readJSONArrayStart(); + $keyType = $this->getTypeIDForTypeName($this->readJSONString(false)); + $valType = $this->getTypeIDForTypeName($this->readJSONString(false)); + $size = $this->readJSONInteger(); + $this->readJSONObjectStart(); + } + + public function readMapEnd() { + $this->readJSONObjectEnd(); + $this->readJSONArrayEnd(); + } + + public function readListBegin(&$elemType, &$size) { + $this->readJSONArrayStart(); + $elemType = $this->getTypeIDForTypeName($this->readJSONString(false)); + $size = $this->readJSONInteger(); + return true; + } + + public function readListEnd() { + $this->readJSONArrayEnd(); + } + + public function readSetBegin(&$elemType, &$size) { + $this->readJSONArrayStart(); + $elemType = $this->getTypeIDForTypeName($this->readJSONString(false)); + $size = $this->readJSONInteger(); + return true; + } + + public function readSetEnd() { + $this->readJSONArrayEnd(); + } + + public function readBool(&$bool) { + $bool = $this->readJSONInteger() == 0 ? false : true; + return true; + } + + public function readByte(&$byte) { + $byte = $this->readJSONInteger(); + return true; + } + + public function readI16(&$i16) { + $i16 = $this->readJSONInteger(); + return true; + } + + public function readI32(&$i32) { + $i32 = $this->readJSONInteger(); + return true; + } + + public function readI64(&$i64) { + if ( PHP_INT_SIZE === 4 ) { + $i64 = $this->readJSONIntegerAsString(); + } else { + $i64 = $this->readJSONInteger(); + } + return true; + } + + public function readDouble(&$dub) { + $dub = $this->readJSONDouble(); + return true; + } + + public function readString(&$str) { + $str = $this->readJSONString(false); + return true; + } +} http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/Protocol/TMultiplexedProtocol.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/Protocol/TMultiplexedProtocol.php b/app/libraries/Thrift/Protocol/TMultiplexedProtocol.php new file mode 100644 index 0000000..50f869f --- /dev/null +++ b/app/libraries/Thrift/Protocol/TMultiplexedProtocol.php @@ -0,0 +1,86 @@ +<?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\Type\TMessageType; + +/** + * <code>TMultiplexedProtocol</code> is a protocol-independent concrete decorator + * that allows a Thrift client to communicate with a multiplexing Thrift server, + * by prepending the service name to the function name during function calls. + * + * @package Thrift\Protocol + */ +class TMultiplexedProtocol extends TProtocolDecorator +{ + /** + * Separator between service name and function name. + * Should be the same as used at multiplexed Thrift server. + * + * @var string + */ + const SEPARATOR = ":"; + + /** + * The name of service. + * + * @var string + */ + private $serviceName_; + + /** + * Constructor of <code>TMultiplexedProtocol</code> class. + * + * Wrap the specified protocol, allowing it to be used to communicate with a + * multiplexing server. The <code>$serviceName</code> is required as it is + * prepended to the message header so that the multiplexing server can broker + * the function call to the proper service. + * + * @param TProtocol $protocol + * @param string $serviceName The name of service. + */ + public function __construct(TProtocol $protocol, $serviceName) + { + parent::__construct($protocol); + $this->serviceName_ = $serviceName; + } + + /** + * Writes the message header. + * Prepends the service name to the function name, separated by <code>TMultiplexedProtocol::SEPARATOR</code>. + * + * @param string $name Function name. + * @param int $type Message type. + * @param int $seqid The sequence id of this message. + */ + public function writeMessageBegin($name, $type, $seqid) + { + if ($type == TMessageType::CALL || $type == TMessageType::ONEWAY) { + $nameWithService = $this->serviceName_ . self::SEPARATOR . $name; + parent::writeMessageBegin($nameWithService, $type, $seqid); + } else { + parent::writeMessageBegin($name, $type, $seqid); + } + } +} + \ No newline at end of file http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/Protocol/TProtocol.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/Protocol/TProtocol.php b/app/libraries/Thrift/Protocol/TProtocol.php new file mode 100644 index 0000000..380ff10 --- /dev/null +++ b/app/libraries/Thrift/Protocol/TProtocol.php @@ -0,0 +1,340 @@ +<?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\Type\TType; +use Thrift\Exception\TProtocolException; + +/** + * Protocol base class module. + */ +abstract class TProtocol { + + /** + * Underlying transport + * + * @var TTransport + */ + protected $trans_; + + /** + * Constructor + */ + protected function __construct($trans) { + $this->trans_ = $trans; + } + + /** + * Accessor for transport + * + * @return TTransport + */ + public function getTransport() { + return $this->trans_; + } + + /** + * 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 abstract function writeMessageBegin($name, $type, $seqid); + + /** + * Close the message + */ + public abstract function writeMessageEnd(); + + /** + * Writes a struct header. + * + * @param string $name Struct name + * @throws TException on write error + * @return int How many bytes written + */ + public abstract function writeStructBegin($name); + + /** + * Close a struct. + * + * @throws TException on write error + * @return int How many bytes written + */ + public abstract function writeStructEnd(); + + /* + * Starts a field. + * + * @param string $name Field name + * @param int $type Field type + * @param int $fid Field id + * @throws TException on write error + * @return int How many bytes written + */ + public abstract function writeFieldBegin($fieldName, $fieldType, $fieldId); + + public abstract function writeFieldEnd(); + + public abstract function writeFieldStop(); + + public abstract function writeMapBegin($keyType, $valType, $size); + + public abstract function writeMapEnd(); + + public abstract function writeListBegin($elemType, $size); + + public abstract function writeListEnd(); + + public abstract function writeSetBegin($elemType, $size); + + public abstract function writeSetEnd(); + + public abstract function writeBool($bool); + + public abstract function writeByte($byte); + + public abstract function writeI16($i16); + + public abstract function writeI32($i32); + + public abstract function writeI64($i64); + + public abstract function writeDouble($dub); + + public abstract function writeString($str); + + /** + * Reads the message header + * + * @param string $name Function name + * @param int $type message type TMessageType::CALL or TMessageType::REPLY + * @parem int $seqid The sequence id of this message + */ + public abstract function readMessageBegin(&$name, &$type, &$seqid); + + /** + * Read the close of message + */ + public abstract function readMessageEnd(); + + public abstract function readStructBegin(&$name); + + public abstract function readStructEnd(); + + public abstract function readFieldBegin(&$name, &$fieldType, &$fieldId); + + public abstract function readFieldEnd(); + + public abstract function readMapBegin(&$keyType, &$valType, &$size); + + public abstract function readMapEnd(); + + public abstract function readListBegin(&$elemType, &$size); + + public abstract function readListEnd(); + + public abstract function readSetBegin(&$elemType, &$size); + + public abstract function readSetEnd(); + + public abstract function readBool(&$bool); + + public abstract function readByte(&$byte); + + public abstract function readI16(&$i16); + + public abstract function readI32(&$i32); + + public abstract function readI64(&$i64); + + public abstract function readDouble(&$dub); + + public abstract function readString(&$str); + + /** + * The skip function is a utility to parse over unrecognized date without + * causing corruption. + * + * @param TType $type What type is it + */ + public function skip($type) { + switch ($type) { + case TType::BOOL: + return $this->readBool($bool); + case TType::BYTE: + return $this->readByte($byte); + case TType::I16: + return $this->readI16($i16); + case TType::I32: + return $this->readI32($i32); + case TType::I64: + return $this->readI64($i64); + case TType::DOUBLE: + return $this->readDouble($dub); + case TType::STRING: + return $this->readString($str); + case TType::STRUCT: + { + $result = $this->readStructBegin($name); + while (true) { + $result += $this->readFieldBegin($name, $ftype, $fid); + if ($ftype == TType::STOP) { + break; + } + $result += $this->skip($ftype); + $result += $this->readFieldEnd(); + } + $result += $this->readStructEnd(); + return $result; + } + case TType::MAP: + { + $result = $this->readMapBegin($keyType, $valType, $size); + for ($i = 0; $i < $size; $i++) { + $result += $this->skip($keyType); + $result += $this->skip($valType); + } + $result += $this->readMapEnd(); + return $result; + } + case TType::SET: + { + $result = $this->readSetBegin($elemType, $size); + for ($i = 0; $i < $size; $i++) { + $result += $this->skip($elemType); + } + $result += $this->readSetEnd(); + return $result; + } + case TType::LST: + { + $result = $this->readListBegin($elemType, $size); + for ($i = 0; $i < $size; $i++) { + $result += $this->skip($elemType); + } + $result += $this->readListEnd(); + return $result; + } + default: + throw new TProtocolException('Unknown field type: '.$type, + TProtocolException::INVALID_DATA); + } + } + + /** + * Utility for skipping binary data + * + * @param TTransport $itrans TTransport object + * @param int $type Field type + */ + public static function skipBinary($itrans, $type) { + switch ($type) { + case TType::BOOL: + return $itrans->readAll(1); + case TType::BYTE: + return $itrans->readAll(1); + case TType::I16: + return $itrans->readAll(2); + case TType::I32: + return $itrans->readAll(4); + case TType::I64: + return $itrans->readAll(8); + case TType::DOUBLE: + return $itrans->readAll(8); + case TType::STRING: + $len = unpack('N', $itrans->readAll(4)); + $len = $len[1]; + if ($len > 0x7fffffff) { + $len = 0 - (($len - 1) ^ 0xffffffff); + } + return 4 + $itrans->readAll($len); + case TType::STRUCT: + { + $result = 0; + while (true) { + $ftype = 0; + $fid = 0; + $data = $itrans->readAll(1); + $arr = unpack('c', $data); + $ftype = $arr[1]; + if ($ftype == TType::STOP) { + break; + } + // I16 field id + $result += $itrans->readAll(2); + $result += self::skipBinary($itrans, $ftype); + } + return $result; + } + case TType::MAP: + { + // Ktype + $data = $itrans->readAll(1); + $arr = unpack('c', $data); + $ktype = $arr[1]; + // Vtype + $data = $itrans->readAll(1); + $arr = unpack('c', $data); + $vtype = $arr[1]; + // Size + $data = $itrans->readAll(4); + $arr = unpack('N', $data); + $size = $arr[1]; + if ($size > 0x7fffffff) { + $size = 0 - (($size - 1) ^ 0xffffffff); + } + $result = 6; + for ($i = 0; $i < $size; $i++) { + $result += self::skipBinary($itrans, $ktype); + $result += self::skipBinary($itrans, $vtype); + } + return $result; + } + case TType::SET: + case TType::LST: + { + // Vtype + $data = $itrans->readAll(1); + $arr = unpack('c', $data); + $vtype = $arr[1]; + // Size + $data = $itrans->readAll(4); + $arr = unpack('N', $data); + $size = $arr[1]; + if ($size > 0x7fffffff) { + $size = 0 - (($size - 1) ^ 0xffffffff); + } + $result = 5; + for ($i = 0; $i < $size; $i++) { + $result += self::skipBinary($itrans, $vtype); + } + return $result; + } + default: + throw new TProtocolException('Unknown field type: '.$type, + TProtocolException::INVALID_DATA); + } + } +} http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/Protocol/TProtocolDecorator.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/Protocol/TProtocolDecorator.php b/app/libraries/Thrift/Protocol/TProtocolDecorator.php new file mode 100644 index 0000000..4f1746c --- /dev/null +++ b/app/libraries/Thrift/Protocol/TProtocolDecorator.php @@ -0,0 +1,284 @@ +<?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; + +/** + * <code>TProtocolDecorator</code> forwards all requests to an enclosed + * <code>TProtocol</code> instance, providing a way to author concise + * concrete decorator subclasses. While it has no abstract methods, it + * is marked abstract as a reminder that by itself, it does not modify + * the behaviour of the enclosed <code>TProtocol</code>. + * + * @package Thrift\Protocol + */ +abstract class TProtocolDecorator extends TProtocol +{ + /** + * Instance of protocol, to which all operations will be forwarded. + * + * @var TProtocol + */ + private $concreteProtocol_; + + /** + * Constructor of <code>TProtocolDecorator</code> class. + * Encloses the specified protocol. + * + * @param TProtocol $protocol All operations will be forward to this instance. Must be non-null. + */ + protected function __construct(TProtocol $protocol) + { + parent::__construct($protocol->getTransport()); + $this->concreteProtocol_ = $protocol; + } + + /** + * 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) + { + return $this->concreteProtocol_->writeMessageBegin($name, $type, $seqid); + } + + /** + * Closes the message. + */ + public function writeMessageEnd() + { + return $this->concreteProtocol_->writeMessageEnd(); + } + + /** + * Writes a struct header. + * + * @param string $name Struct name + * + * @throws TException on write error + * @return int How many bytes written + */ + public function writeStructBegin($name) + { + return $this->concreteProtocol_->writeStructBegin($name); + } + + /** + * Close a struct. + * + * @throws TException on write error + * @return int How many bytes written + */ + public function writeStructEnd() + { + return $this->concreteProtocol_->writeStructEnd(); + } + + public function writeFieldBegin($fieldName, $fieldType, $fieldId) + { + return $this->concreteProtocol_->writeFieldBegin($fieldName, $fieldType, $fieldId); + } + + public function writeFieldEnd() + { + return $this->concreteProtocol_->writeFieldEnd(); + } + + public function writeFieldStop() + { + return $this->concreteProtocol_->writeFieldStop(); + } + + public function writeMapBegin($keyType, $valType, $size) + { + return $this->concreteProtocol_->writeMapBegin($keyType, $valType, $size); + } + + public function writeMapEnd() + { + return $this->concreteProtocol_->writeMapEnd(); + } + + public function writeListBegin($elemType, $size) + { + return $this->concreteProtocol_->writeListBegin($elemType, $size); + } + + public function writeListEnd() + { + return $this->concreteProtocol_->writeListEnd(); + } + + public function writeSetBegin($elemType, $size) + { + return $this->concreteProtocol_->writeSetBegin($elemType, $size); + } + + public function writeSetEnd() + { + return $this->concreteProtocol_->writeSetEnd(); + } + + public function writeBool($bool) + { + return $this->concreteProtocol_->writeBool($bool); + } + + public function writeByte($byte) + { + return $this->concreteProtocol_->writeByte($byte); + } + + public function writeI16($i16) + { + return $this->concreteProtocol_->writeI16($i16); + } + + public function writeI32($i32) + { + return $this->concreteProtocol_->writeI32($i32); + } + + public function writeI64($i64) + { + return $this->concreteProtocol_->writeI64($i64); + } + + public function writeDouble($dub) + { + return $this->concreteProtocol_->writeDouble($dub); + } + + public function writeString($str) + { + return $this->concreteProtocol_->writeString($str); + } + + /** + * Reads 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 readMessageBegin(&$name, &$type, &$seqid) + { + return $this->concreteProtocol_->readMessageBegin($name, $type, $seqid); + } + + /** + * Read the close of message + */ + public function readMessageEnd() + { + return $this->concreteProtocol_->readMessageEnd(); + } + + public function readStructBegin(&$name) + { + return $this->concreteProtocol_->readStructBegin($name); + } + + public function readStructEnd() + { + return $this->concreteProtocol_->readStructEnd(); + } + + public function readFieldBegin(&$name, &$fieldType, &$fieldId) + { + return $this->concreteProtocol_->readFieldBegin($name, $fieldType, $fieldId); + } + + public function readFieldEnd() + { + return $this->concreteProtocol_->readFieldEnd(); + } + + public function readMapBegin(&$keyType, &$valType, &$size) + { + $this->concreteProtocol_->readMapBegin($keyType, $valType, $size); + } + + public function readMapEnd() + { + return $this->concreteProtocol_->readMapEnd(); + } + + public function readListBegin(&$elemType, &$size) + { + $this->concreteProtocol_->readListBegin($elemType, $size); + } + + public function readListEnd() + { + return $this->concreteProtocol_->readListEnd(); + } + + public function readSetBegin(&$elemType, &$size) + { + return $this->concreteProtocol_->readSetBegin($elemType, $size); + } + + public function readSetEnd() + { + return $this->concreteProtocol_->readSetEnd(); + } + + public function readBool(&$bool) + { + return $this->concreteProtocol_->readBool($bool); + } + + public function readByte(&$byte) + { + return $this->concreteProtocol_->readByte($byte); + } + + public function readI16(&$i16) + { + return $this->concreteProtocol_->readI16($i16); + } + + public function readI32(&$i32) + { + return $this->concreteProtocol_->readI32($i32); + } + + public function readI64(&$i64) + { + return $this->concreteProtocol_->readI64($i64); + } + + public function readDouble(&$dub) + { + return $this->concreteProtocol_->readDouble($dub); + } + + public function readString(&$str) + { + return $this->concreteProtocol_->readString($str); + } +} http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/Serializer/TBinarySerializer.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/Serializer/TBinarySerializer.php b/app/libraries/Thrift/Serializer/TBinarySerializer.php new file mode 100644 index 0000000..4e0af87 --- /dev/null +++ b/app/libraries/Thrift/Serializer/TBinarySerializer.php @@ -0,0 +1,79 @@ +<?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 + * @author: rmarin ([email protected]) + */ + +namespace Thrift\Serializer; + +use Thrift\Transport\TMemoryBuffer; +use Thrift\Protocol\TBinaryProtocolAccelerated; +use Thrift\Type\TMessageType; + +/** + * Utility class for serializing and deserializing + * a thrift object using TBinaryProtocolAccelerated. + */ +class TBinarySerializer { + + // NOTE(rmarin): Because thrift_protocol_write_binary + // adds a begin message prefix, you cannot specify + // a transport in which to serialize an object. It has to + // be a string. Otherwise we will break the compatibility with + // normal deserialization. + public static function serialize($object) { + $transport = new TMemoryBuffer(); + $protocol = new TBinaryProtocolAccelerated($transport); + if (function_exists('thrift_protocol_write_binary')) { + thrift_protocol_write_binary($protocol, $object->getName(), + TMessageType::REPLY, $object, + 0, $protocol->isStrictWrite()); + + $protocol->readMessageBegin($unused_name, $unused_type, + $unused_seqid); + } else { + $object->write($protocol); + } + $protocol->getTransport()->flush(); + return $transport->getBuffer(); + } + + public static function deserialize($string_object, $class_name) { + $transport = new TMemoryBuffer(); + $protocol = new TBinaryProtocolAccelerated($transport); + if (function_exists('thrift_protocol_read_binary')) { + // NOTE (t.heintz) TBinaryProtocolAccelerated internally wraps our TMemoryBuffer in a + // TBufferedTransport, so we have to retrieve it again or risk losing data when writing + // less than 512 bytes to the transport (see the comment there as well). + // @see THRIFT-1579 + $protocol->writeMessageBegin('', TMessageType::REPLY, 0); + $protocolTransport = $protocol->getTransport(); + $protocolTransport->write($string_object); + $protocolTransport->flush(); + return thrift_protocol_read_binary($protocol, $class_name, + $protocol->isStrictRead()); + } else { + $transport->write($string_object); + $object = new $class_name(); + $object->read($protocol); + return $object; + } + } +} http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/Server/TForkingServer.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/Server/TForkingServer.php b/app/libraries/Thrift/Server/TForkingServer.php new file mode 100644 index 0000000..6fca305 --- /dev/null +++ b/app/libraries/Thrift/Server/TForkingServer.php @@ -0,0 +1,119 @@ +<?php + +namespace Thrift\Server; + +use Thrift\Server\TServer; +use Thrift\Transport\TTransport; +use Thrift\Exception\TException; +use Thrift\Exception\TTransportException; + +/** + * A forking implementation of a Thrift server. + * + * @package thrift.server + */ +class TForkingServer extends TServer { + /** + * Flag for the main serving loop + * + * @var bool + */ + private $stop_ = false; + + /** + * List of children. + * + * @var array + */ + protected $children_ = array(); + + /** + * Listens for new client using the supplied + * transport. We fork when a new connection + * arrives. + * + * @return void + */ + public function serve() { + $this->transport_->listen(); + + while (!$this->stop_) { + try { + $transport = $this->transport_->accept(); + + if ($transport != null) { + $pid = pcntl_fork(); + + if ($pid > 0) { + $this->handleParent($transport, $pid); + } + else if ($pid === 0) { + $this->handleChild($transport); + } + else { + throw new TException('Failed to fork'); + } + } + } + catch (TTransportException $e) { } + + $this->collectChildren(); + } + } + + /** + * Code run by the parent + * + * @param TTransport $transport + * @param int $pid + * @return void + */ + private function handleParent(TTransport $transport, $pid) { + $this->children_[$pid] = $transport; + } + + /** + * Code run by the child. + * + * @param TTransport $transport + * @return void + */ + private function handleChild(TTransport $transport) { + try { + $inputTransport = $this->inputTransportFactory_->getTransport($transport); + $outputTransport = $this->outputTransportFactory_->getTransport($transport); + $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport); + $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport); + while ($this->processor_->process($inputProtocol, $outputProtocol)) { } + @$transport->close(); + } + catch (TTransportException $e) { } + + exit(0); + } + + /** + * Collects any children we may have + * + * @return void + */ + private function collectChildren() { + foreach ($this->children_ as $pid => $transport) { + if (pcntl_waitpid($pid, $status, WNOHANG) > 0) { + unset($this->children_[$pid]); + if ($transport) @$transport->close(); + } + } + } + + /** + * Stops the server running. Kills the transport + * and then stops the main serving loop + * + * @return void + */ + public function stop() { + $this->transport_->close(); + $this->stop_ = true; + } +} http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/Server/TServer.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/Server/TServer.php b/app/libraries/Thrift/Server/TServer.php new file mode 100644 index 0000000..343bf4b --- /dev/null +++ b/app/libraries/Thrift/Server/TServer.php @@ -0,0 +1,101 @@ +<?php + +namespace Thrift\Server; + +use Thrift\Server\TServerTransport; +use Thrift\Factory\TTransportFactory; +use Thrift\Factory\TProtocolFactory; + +/** + * Generic class for a Thrift server. + * + * @package thrift.server + */ +abstract class TServer { + + /** + * Processor to handle new clients + * + * @var TProcessor + */ + protected $processor_; + + /** + * Server transport to be used for listening + * and accepting new clients + * + * @var TServerTransport + */ + protected $transport_; + + /** + * Input transport factory + * + * @var TTransportFactory + */ + protected $inputTransportFactory_; + + /** + * Output transport factory + * + * @var TTransportFactory + */ + protected $outputTransportFactory_; + + /** + * Input protocol factory + * + * @var TProtocolFactory + */ + protected $inputProtocolFactory_; + + /** + * Output protocol factory + * + * @var TProtocolFactory + */ + protected $outputProtocolFactory_; + + /** + * Sets up all the factories, etc + * + * @param object $processor + * @param TServerTransport $transport + * @param TTransportFactory $inputTransportFactory + * @param TTransportFactory $outputTransportFactory + * @param TProtocolFactory $inputProtocolFactory + * @param TProtocolFactory $outputProtocolFactory + * @return void + */ + public function __construct($processor, + TServerTransport $transport, + TTransportFactory $inputTransportFactory, + TTransportFactory $outputTransportFactory, + TProtocolFactory $inputProtocolFactory, + TProtocolFactory $outputProtocolFactory) { + $this->processor_ = $processor; + $this->transport_ = $transport; + $this->inputTransportFactory_ = $inputTransportFactory; + $this->outputTransportFactory_ = $outputTransportFactory; + $this->inputProtocolFactory_ = $inputProtocolFactory; + $this->outputProtocolFactory_ = $outputProtocolFactory; + } + + /** + * Serves the server. This should never return + * unless a problem permits it to do so or it + * is interrupted intentionally + * + * @abstract + * @return void + */ + abstract public function serve(); + + /** + * Stops the server serving + * + * @abstract + * @return void + */ + abstract public function stop(); +} http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/Server/TServerSocket.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/Server/TServerSocket.php b/app/libraries/Thrift/Server/TServerSocket.php new file mode 100644 index 0000000..00a6fb9 --- /dev/null +++ b/app/libraries/Thrift/Server/TServerSocket.php @@ -0,0 +1,98 @@ +<?php + +namespace Thrift\Server; + +use Thrift\Server\TServerTransport; +use Thrift\Transport\TSocket; + +/** + * Socket implementation of a server agent. + * + * @package thrift.transport + */ +class TServerSocket extends TServerTransport { + + /** + * Handle for the listener socket + * + * @var resource + */ + private $listener_; + + /** + * Port for the listener to listen on + * + * @var int + */ + private $port_; + + /** + * Timeout when listening for a new client + * + * @var int + */ + private $acceptTimeout_ = 30000; + + /** + * Host to listen on + * + * @var string + */ + private $host_; + + /** + * ServerSocket constructor + * + * @param string $host Host to listen on + * @param int $port Port to listen on + * @return void + */ + public function __construct($host = 'localhost', $port = 9090) { + $this->host_ = $host; + $this->port_ = $port; + } + + /** + * Sets the accept timeout + * + * @param int $acceptTimeout + * @return void + */ + public function setAcceptTimeout($acceptTimeout) { + $this->acceptTimeout_ = $acceptTimeout; + } + + /** + * Opens a new socket server handle + * + * @return void + */ + public function listen() { + $this->listener_ = stream_socket_server('tcp://' . $this->host_ . ':' . $this->port_); + } + + /** + * Closes the socket server handle + * + * @return void + */ + public function close() { + @fclose($this->listener_); + $this->listener_ = null; + } + + /** + * Implementation of accept. If not client is accepted in the given time + * + * @return TSocket + */ + protected function acceptImpl() { + $handle = @stream_socket_accept($this->listener_, $this->acceptTimeout_ / 1000.0); + if(!$handle) return null; + + $socket = new TSocket(); + $socket->setHandle($handle); + + return $socket; + } +} http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/Server/TServerTransport.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/Server/TServerTransport.php b/app/libraries/Thrift/Server/TServerTransport.php new file mode 100644 index 0000000..5324712 --- /dev/null +++ b/app/libraries/Thrift/Server/TServerTransport.php @@ -0,0 +1,54 @@ +<?php + +namespace Thrift\Server; + +use Thrift\Exception\TTransportException; + +/** + * Generic class for Server agent. + * + * @package thrift.transport + */ +abstract class TServerTransport { + /** + * List for new clients + * + * @abstract + * @return void + */ + abstract public function listen(); + + /** + * Close the server + * + * @abstract + * @return void + */ + abstract public function close(); + + /** + * Subclasses should use this to implement + * accept. + * + * @abstract + * @return TTransport + */ + protected abstract function acceptImpl(); + + /** + * Uses the accept implemtation. If null is returned, an + * exception is thrown. + * + * @throws TTransportException + * @return TTransport + */ + public function accept() { + $transport = $this->acceptImpl(); + + if ($transport == null) { + throw new TTransportException("accept() may not return NULL"); + } + + return $transport; + } +} http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/Server/TSimpleServer.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/Server/TSimpleServer.php b/app/libraries/Thrift/Server/TSimpleServer.php new file mode 100644 index 0000000..790e48f --- /dev/null +++ b/app/libraries/Thrift/Server/TSimpleServer.php @@ -0,0 +1,57 @@ +<?php + +namespace Thrift\Server; + +use Thrift\Server\TServer; +use Thrift\Exception\TTransportException; + +/** + * Simple implemtation of a Thrift server. + * + * @package thrift.server + */ +class TSimpleServer extends TServer { + /** + * Flag for the main serving loop + * + * @var bool + */ + private $stop_ = false; + + /** + * Listens for new client using the supplied + * transport. It handles TTransportExceptions + * to avoid timeouts etc killing it + * + * @return void + */ + public function serve() { + $this->transport_->listen(); + + while (!$this->stop_) { + try { + $transport = $this->transport_->accept(); + + if ($transport != null) { + $inputTransport = $this->inputTransportFactory_->getTransport($transport); + $outputTransport = $this->outputTransportFactory_->getTransport($transport); + $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport); + $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport); + while ($this->processor_->process($inputProtocol, $outputProtocol)) { } + } + } + catch (TTransportException $e) { } + } + } + + /** + * Stops the server running. Kills the transport + * and then stops the main serving loop + * + * @return void + */ + public function stop() { + $this->transport_->close(); + $this->stop_ = true; + } +} http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/StringFunc/Core.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/StringFunc/Core.php b/app/libraries/Thrift/StringFunc/Core.php new file mode 100644 index 0000000..e38a5b2 --- /dev/null +++ b/app/libraries/Thrift/StringFunc/Core.php @@ -0,0 +1,38 @@ +<?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. + * + */ + +namespace Thrift\StringFunc; + +use Thrift\StringFunc\TStringFunc; + +class Core implements TStringFunc { + public function substr($str, $start, $length = null) { + // specifying a null $length would return an empty string + if($length === null) { + return substr($str, $start); + } + return substr($str, $start, $length); + } + + public function strlen($str) { + return strlen($str); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/StringFunc/Mbstring.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/StringFunc/Mbstring.php b/app/libraries/Thrift/StringFunc/Mbstring.php new file mode 100644 index 0000000..c1ace13 --- /dev/null +++ b/app/libraries/Thrift/StringFunc/Mbstring.php @@ -0,0 +1,45 @@ +<?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. + * + */ + +namespace Thrift\StringFunc; + +use Thrift\StringFunc\TStringFunc; + +class Mbstring implements TStringFunc { + public function substr($str, $start, $length = null) { + /** + * We need to set the charset parameter, which is the second + * optional parameter and the first optional parameter can't + * be null or false as a "magic" value because that would + * cause an empty string to be returned, so we need to + * actually calculate the proper length value. + */ + if($length === null) { + $length = $this->strlen($str) - $start; + } + + return mb_substr($str, $start, $length, '8bit'); + } + + public function strlen($str) { + return mb_strlen($str, '8bit'); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/StringFunc/TStringFunc.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/StringFunc/TStringFunc.php b/app/libraries/Thrift/StringFunc/TStringFunc.php new file mode 100644 index 0000000..c5bb390 --- /dev/null +++ b/app/libraries/Thrift/StringFunc/TStringFunc.php @@ -0,0 +1,27 @@ +<?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. + * + */ + +namespace Thrift\StringFunc; + +interface TStringFunc { + public function substr($str, $start, $length = null); + public function strlen($str); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/airavata-php-gateway/blob/89236650/app/libraries/Thrift/TMultiplexedProcessor.php ---------------------------------------------------------------------- diff --git a/app/libraries/Thrift/TMultiplexedProcessor.php b/app/libraries/Thrift/TMultiplexedProcessor.php new file mode 100644 index 0000000..c62e325 --- /dev/null +++ b/app/libraries/Thrift/TMultiplexedProcessor.php @@ -0,0 +1,136 @@ +<?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.processor + */ + +namespace Thrift; + +use Thrift\Exception\TException; +use Thrift\Protocol\TProtocol; +use Thrift\Protocol\TMultiplexedProtocol; +use Thrift\Protocol\TProtocolDecorator; +use Thrift\Type\TMessageType; + +/** + * <code>TMultiplexedProcessor</code> is a Processor allowing + * a single <code>TServer</code> to provide multiple services. + * + * <p>To do so, you instantiate the processor and then register additional + * processors with it, as shown in the following example:</p> + * + * <blockquote><code> + * $processor = new TMultiplexedProcessor(); + * + * processor->registerProcessor( + * "Calculator", + * new \tutorial\CalculatorProcessor(new CalculatorHandler())); + * + * processor->registerProcessor( + * "WeatherReport", + * new \tutorial\WeatherReportProcessor(new WeatherReportHandler())); + * + * $processor->process($protocol, $protocol); + * </code></blockquote> + */ + +class TMultiplexedProcessor { + private $serviceProcessorMap_; + + /** + * 'Register' a service with this <code>TMultiplexedProcessor</code>. This + * allows us to broker requests to individual services by using the service + * name to select them at request time. + * + * @param serviceName Name of a service, has to be identical to the name + * declared in the Thrift IDL, e.g. "WeatherReport". + * @param processor Implementation of a service, ususally referred to + * as "handlers", e.g. WeatherReportHandler implementing WeatherReport.Iface. + */ + public function registerProcessor($serviceName, $processor) { + $this->serviceProcessorMap_[$serviceName] = $processor; + } + + /** + * This implementation of <code>process</code> performs the following steps: + * + * <ol> + * <li>Read the beginning of the message.</li> + * <li>Extract the service name from the message.</li> + * <li>Using the service name to locate the appropriate processor.</li> + * <li>Dispatch to the processor, with a decorated instance of TProtocol + * that allows readMessageBegin() to return the original Message.</li> + * </ol> + * + * @throws TException If the message type is not CALL or ONEWAY, if + * the service name was not found in the message, or if the service + * name was not found in the service map. + */ + public function process(TProtocol $input, TProtocol $output) { + /* + Use the actual underlying protocol (e.g. TBinaryProtocol) to read the + message header. This pulls the message "off the wire", which we'll + deal with at the end of this method. + */ + $input->readMessageBegin($fname, $mtype, $rseqid); + + if ($mtype !== TMessageType::CALL && $mtype != TMessageType::ONEWAY) { + throw new TException("This should not have happened!?"); + } + + // Extract the service name and the new Message name. + if (strpos($fname, TMultiplexedProtocol::SEPARATOR) === false) { + throw new TException("Service name not found in message name: {$fname}. Did you " . + "forget to use a TMultiplexProtocol in your client?"); + } + list($serviceName, $messageName) = explode(':', $fname, 2); + if (!array_key_exists($serviceName, $this->serviceProcessorMap_)) { + throw new TException("Service name not found: {$serviceName}. Did you forget " . + "to call registerProcessor()?"); + } + + // Dispatch processing to the stored processor + $processor = $this->serviceProcessorMap_[$serviceName]; + return $processor->process( + new StoredMessageProtocol($input, $messageName, $mtype, $rseqid), $output + ); + } +} + +/** + * Our goal was to work with any protocol. In order to do that, we needed + * to allow them to call readMessageBegin() and get the Message in exactly + * the standard format, without the service name prepended to the Message name. + */ +class StoredMessageProtocol extends TProtocolDecorator { + private $fname_, $mtype_, $rseqid_; + + public function __construct(TProtocol $protocol, $fname, $mtype, $rseqid) { + parent::__construct($protocol); + $this->fname_ = $fname; + $this->mtype_ = $mtype; + $this->rseqid_ = $rseqid; + } + + public function readMessageBegin(&$name, &$type, &$seqid) { + $name = $this->fname_; + $type = $this->mtype_; + $seqid = $this->rseqid_; + } +}
