Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
786 lines (756 sloc) 22.3 KB
<?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
*/
/**
* Data types that can be sent via Thrift
*/
class TType {
const STOP = 0;
const VOID = 1;
const BOOL = 2;
const BYTE = 3;
const I08 = 3;
const DOUBLE = 4;
const I16 = 6;
const I32 = 8;
const I64 = 10;
const STRING = 11;
const UTF7 = 11;
const STRUCT = 12;
const MAP = 13;
const SET = 14;
const LST = 15; // N.B. cannot use LIST keyword in PHP!
const UTF8 = 16;
const UTF16 = 17;
}
/**
* Message types for RPC
*/
class TMessageType {
const CALL = 1;
const REPLY = 2;
const EXCEPTION = 3;
const ONEWAY = 4;
}
/**
* NOTE(mcslee): This currently contains a ton of duplicated code from TBase
* because we need to save CPU cycles and this is not yet in an extension.
* Ideally we'd multiply-inherit TException from both Exception and Base, but
* that's not possible in PHP and there are no modules either, so for now we
* apologetically take a trip to HackTown.
*
* Can be called with standard Exception constructor (message, code) or with
* Thrift Base object constructor (spec, vals).
*
* @param mixed $p1 Message (string) or type-spec (array)
* @param mixed $p2 Code (integer) or values (array)
*/
class TException extends Exception {
function __construct($p1=null, $p2=0) {
if (is_array($p1) && is_array($p2)) {
$spec = $p1;
$vals = $p2;
foreach ($spec as $fid => $fspec) {
$var = $fspec['var'];
if (isset($vals[$var])) {
$this->$var = $vals[$var];
}
}
} else {
parent::__construct($p1, $p2);
}
}
static $tmethod = array(TType::BOOL => 'Bool',
TType::BYTE => 'Byte',
TType::I16 => 'I16',
TType::I32 => 'I32',
TType::I64 => 'I64',
TType::DOUBLE => 'Double',
TType::STRING => 'String');
private function _readMap(&$var, $spec, $input) {
$xfer = 0;
$ktype = $spec['ktype'];
$vtype = $spec['vtype'];
$kread = $vread = null;
if (isset(TBase::$tmethod[$ktype])) {
$kread = 'read'.TBase::$tmethod[$ktype];
} else {
$kspec = $spec['key'];
}
if (isset(TBase::$tmethod[$vtype])) {
$vread = 'read'.TBase::$tmethod[$vtype];
} else {
$vspec = $spec['val'];
}
$var = array();
$_ktype = $_vtype = $size = 0;
$xfer += $input->readMapBegin($_ktype, $_vtype, $size);
for ($i = 0; $i < $size; ++$i) {
$key = $val = null;
if ($kread !== null) {
$xfer += $input->$kread($key);
} else {
switch ($ktype) {
case TType::STRUCT:
$class = $kspec['class'];
$key = new $class();
$xfer += $key->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($key, $kspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($key, $kspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($key, $kspec, $input, true);
break;
}
}
if ($vread !== null) {
$xfer += $input->$vread($val);
} else {
switch ($vtype) {
case TType::STRUCT:
$class = $vspec['class'];
$val = new $class();
$xfer += $val->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($val, $vspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($val, $vspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($val, $vspec, $input, true);
break;
}
}
$var[$key] = $val;
}
$xfer += $input->readMapEnd();
return $xfer;
}
private function _readList(&$var, $spec, $input, $set=false) {
$xfer = 0;
$etype = $spec['etype'];
$eread = $vread = null;
if (isset(TBase::$tmethod[$etype])) {
$eread = 'read'.TBase::$tmethod[$etype];
} else {
$espec = $spec['elem'];
}
$var = array();
$_etype = $size = 0;
if ($set) {
$xfer += $input->readSetBegin($_etype, $size);
} else {
$xfer += $input->readListBegin($_etype, $size);
}
for ($i = 0; $i < $size; ++$i) {
$elem = null;
if ($eread !== null) {
$xfer += $input->$eread($elem);
} else {
$espec = $spec['elem'];
switch ($etype) {
case TType::STRUCT:
$class = $espec['class'];
$elem = new $class();
$xfer += $elem->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($elem, $espec, $input);
break;
case TType::LST:
$xfer += $this->_readList($elem, $espec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($elem, $espec, $input, true);
break;
}
}
if ($set) {
$var[$elem] = true;
} else {
$var []= $elem;
}
}
if ($set) {
$xfer += $input->readSetEnd();
} else {
$xfer += $input->readListEnd();
}
return $xfer;
}
protected function _read($class, $spec, $input) {
$xfer = 0;
$fname = null;
$ftype = 0;
$fid = 0;
$xfer += $input->readStructBegin($fname);
while (true) {
$xfer += $input->readFieldBegin($fname, $ftype, $fid);
if ($ftype == TType::STOP) {
break;
}
if (isset($spec[$fid])) {
$fspec = $spec[$fid];
$var = $fspec['var'];
if ($ftype == $fspec['type']) {
$xfer = 0;
if (isset(TBase::$tmethod[$ftype])) {
$func = 'read'.TBase::$tmethod[$ftype];
$xfer += $input->$func($this->$var);
} else {
switch ($ftype) {
case TType::STRUCT:
$class = $fspec['class'];
$this->$var = new $class();
$xfer += $this->$var->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($this->$var, $fspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($this->$var, $fspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($this->$var, $fspec, $input, true);
break;
}
}
} else {
$xfer += $input->skip($ftype);
}
} else {
$xfer += $input->skip($ftype);
}
$xfer += $input->readFieldEnd();
}
$xfer += $input->readStructEnd();
return $xfer;
}
private function _writeMap($var, $spec, $output) {
$xfer = 0;
$ktype = $spec['ktype'];
$vtype = $spec['vtype'];
$kwrite = $vwrite = null;
if (isset(TBase::$tmethod[$ktype])) {
$kwrite = 'write'.TBase::$tmethod[$ktype];
} else {
$kspec = $spec['key'];
}
if (isset(TBase::$tmethod[$vtype])) {
$vwrite = 'write'.TBase::$tmethod[$vtype];
} else {
$vspec = $spec['val'];
}
$xfer += $output->writeMapBegin($ktype, $vtype, count($var));
foreach ($var as $key => $val) {
if (isset($kwrite)) {
$xfer += $output->$kwrite($key);
} else {
switch ($ktype) {
case TType::STRUCT:
$xfer += $key->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($key, $kspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($key, $kspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($key, $kspec, $output, true);
break;
}
}
if (isset($vwrite)) {
$xfer += $output->$vwrite($val);
} else {
switch ($vtype) {
case TType::STRUCT:
$xfer += $val->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($val, $vspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($val, $vspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($val, $vspec, $output, true);
break;
}
}
}
$xfer += $output->writeMapEnd();
return $xfer;
}
private function _writeList($var, $spec, $output, $set=false) {
$xfer = 0;
$etype = $spec['etype'];
$ewrite = null;
if (isset(TBase::$tmethod[$etype])) {
$ewrite = 'write'.TBase::$tmethod[$etype];
} else {
$espec = $spec['elem'];
}
if ($set) {
$xfer += $output->writeSetBegin($etype, count($var));
} else {
$xfer += $output->writeListBegin($etype, count($var));
}
foreach ($var as $key => $val) {
$elem = $set ? $key : $val;
if (isset($ewrite)) {
$xfer += $output->$ewrite($elem);
} else {
switch ($etype) {
case TType::STRUCT:
$xfer += $elem->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($elem, $espec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($elem, $espec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($elem, $espec, $output, true);
break;
}
}
}
if ($set) {
$xfer += $output->writeSetEnd();
} else {
$xfer += $output->writeListEnd();
}
return $xfer;
}
protected function _write($class, $spec, $output) {
$xfer = 0;
$xfer += $output->writeStructBegin($class);
foreach ($spec as $fid => $fspec) {
$var = $fspec['var'];
if ($this->$var !== null) {
$ftype = $fspec['type'];
$xfer += $output->writeFieldBegin($var, $ftype, $fid);
if (isset(TBase::$tmethod[$ftype])) {
$func = 'write'.TBase::$tmethod[$ftype];
$xfer += $output->$func($this->$var);
} else {
switch ($ftype) {
case TType::STRUCT:
$xfer += $this->$var->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($this->$var, $fspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($this->$var, $fspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($this->$var, $fspec, $output, true);
break;
}
}
$xfer += $output->writeFieldEnd();
}
}
$xfer += $output->writeFieldStop();
$xfer += $output->writeStructEnd();
return $xfer;
}
}
/**
* Base class from which other Thrift structs extend. This is so that we can
* cut back on the size of the generated code which is turning out to have a
* nontrivial cost just to load thanks to the wondrously abysmal implementation
* of PHP. Note that code is intentionally duplicated in here to avoid making
* function calls for every field or member of a container..
*/
abstract class TBase {
static $tmethod = array(TType::BOOL => 'Bool',
TType::BYTE => 'Byte',
TType::I16 => 'I16',
TType::I32 => 'I32',
TType::I64 => 'I64',
TType::DOUBLE => 'Double',
TType::STRING => 'String');
abstract function read($input);
abstract function write($output);
public function __construct($spec=null, $vals=null) {
if (is_array($spec) && is_array($vals)) {
foreach ($spec as $fid => $fspec) {
$var = $fspec['var'];
if (isset($vals[$var])) {
$this->$var = $vals[$var];
}
}
}
}
private function _readMap(&$var, $spec, $input) {
$xfer = 0;
$ktype = $spec['ktype'];
$vtype = $spec['vtype'];
$kread = $vread = null;
if (isset(TBase::$tmethod[$ktype])) {
$kread = 'read'.TBase::$tmethod[$ktype];
} else {
$kspec = $spec['key'];
}
if (isset(TBase::$tmethod[$vtype])) {
$vread = 'read'.TBase::$tmethod[$vtype];
} else {
$vspec = $spec['val'];
}
$var = array();
$_ktype = $_vtype = $size = 0;
$xfer += $input->readMapBegin($_ktype, $_vtype, $size);
for ($i = 0; $i < $size; ++$i) {
$key = $val = null;
if ($kread !== null) {
$xfer += $input->$kread($key);
} else {
switch ($ktype) {
case TType::STRUCT:
$class = $kspec['class'];
$key = new $class();
$xfer += $key->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($key, $kspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($key, $kspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($key, $kspec, $input, true);
break;
}
}
if ($vread !== null) {
$xfer += $input->$vread($val);
} else {
switch ($vtype) {
case TType::STRUCT:
$class = $vspec['class'];
$val = new $class();
$xfer += $val->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($val, $vspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($val, $vspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($val, $vspec, $input, true);
break;
}
}
$var[$key] = $val;
}
$xfer += $input->readMapEnd();
return $xfer;
}
private function _readList(&$var, $spec, $input, $set=false) {
$xfer = 0;
$etype = $spec['etype'];
$eread = $vread = null;
if (isset(TBase::$tmethod[$etype])) {
$eread = 'read'.TBase::$tmethod[$etype];
} else {
$espec = $spec['elem'];
}
$var = array();
$_etype = $size = 0;
if ($set) {
$xfer += $input->readSetBegin($_etype, $size);
} else {
$xfer += $input->readListBegin($_etype, $size);
}
for ($i = 0; $i < $size; ++$i) {
$elem = null;
if ($eread !== null) {
$xfer += $input->$eread($elem);
} else {
$espec = $spec['elem'];
switch ($etype) {
case TType::STRUCT:
$class = $espec['class'];
$elem = new $class();
$xfer += $elem->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($elem, $espec, $input);
break;
case TType::LST:
$xfer += $this->_readList($elem, $espec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($elem, $espec, $input, true);
break;
}
}
if ($set) {
$var[$elem] = true;
} else {
$var []= $elem;
}
}
if ($set) {
$xfer += $input->readSetEnd();
} else {
$xfer += $input->readListEnd();
}
return $xfer;
}
protected function _read($class, $spec, $input) {
$xfer = 0;
$fname = null;
$ftype = 0;
$fid = 0;
$xfer += $input->readStructBegin($fname);
while (true) {
$xfer += $input->readFieldBegin($fname, $ftype, $fid);
if ($ftype == TType::STOP) {
break;
}
if (isset($spec[$fid])) {
$fspec = $spec[$fid];
$var = $fspec['var'];
if ($ftype == $fspec['type']) {
$xfer = 0;
if (isset(TBase::$tmethod[$ftype])) {
$func = 'read'.TBase::$tmethod[$ftype];
$xfer += $input->$func($this->$var);
} else {
switch ($ftype) {
case TType::STRUCT:
$class = $fspec['class'];
$this->$var = new $class();
$xfer += $this->$var->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($this->$var, $fspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($this->$var, $fspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($this->$var, $fspec, $input, true);
break;
}
}
} else {
$xfer += $input->skip($ftype);
}
} else {
$xfer += $input->skip($ftype);
}
$xfer += $input->readFieldEnd();
}
$xfer += $input->readStructEnd();
return $xfer;
}
private function _writeMap($var, $spec, $output) {
$xfer = 0;
$ktype = $spec['ktype'];
$vtype = $spec['vtype'];
$kwrite = $vwrite = null;
if (isset(TBase::$tmethod[$ktype])) {
$kwrite = 'write'.TBase::$tmethod[$ktype];
} else {
$kspec = $spec['key'];
}
if (isset(TBase::$tmethod[$vtype])) {
$vwrite = 'write'.TBase::$tmethod[$vtype];
} else {
$vspec = $spec['val'];
}
$xfer += $output->writeMapBegin($ktype, $vtype, count($var));
foreach ($var as $key => $val) {
if (isset($kwrite)) {
$xfer += $output->$kwrite($key);
} else {
switch ($ktype) {
case TType::STRUCT:
$xfer += $key->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($key, $kspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($key, $kspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($key, $kspec, $output, true);
break;
}
}
if (isset($vwrite)) {
$xfer += $output->$vwrite($val);
} else {
switch ($vtype) {
case TType::STRUCT:
$xfer += $val->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($val, $vspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($val, $vspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($val, $vspec, $output, true);
break;
}
}
}
$xfer += $output->writeMapEnd();
return $xfer;
}
private function _writeList($var, $spec, $output, $set=false) {
$xfer = 0;
$etype = $spec['etype'];
$ewrite = null;
if (isset(TBase::$tmethod[$etype])) {
$ewrite = 'write'.TBase::$tmethod[$etype];
} else {
$espec = $spec['elem'];
}
if ($set) {
$xfer += $output->writeSetBegin($etype, count($var));
} else {
$xfer += $output->writeListBegin($etype, count($var));
}
foreach ($var as $key => $val) {
$elem = $set ? $key : $val;
if (isset($ewrite)) {
$xfer += $output->$ewrite($elem);
} else {
switch ($etype) {
case TType::STRUCT:
$xfer += $elem->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($elem, $espec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($elem, $espec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($elem, $espec, $output, true);
break;
}
}
}
if ($set) {
$xfer += $output->writeSetEnd();
} else {
$xfer += $output->writeListEnd();
}
return $xfer;
}
protected function _write($class, $spec, $output) {
$xfer = 0;
$xfer += $output->writeStructBegin($class);
foreach ($spec as $fid => $fspec) {
$var = $fspec['var'];
if ($this->$var !== null) {
$ftype = $fspec['type'];
$xfer += $output->writeFieldBegin($var, $ftype, $fid);
if (isset(TBase::$tmethod[$ftype])) {
$func = 'write'.TBase::$tmethod[$ftype];
$xfer += $output->$func($this->$var);
} else {
switch ($ftype) {
case TType::STRUCT:
$xfer += $this->$var->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($this->$var, $fspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($this->$var, $fspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($this->$var, $fspec, $output, true);
break;
}
}
$xfer += $output->writeFieldEnd();
}
}
$xfer += $output->writeFieldStop();
$xfer += $output->writeStructEnd();
return $xfer;
}
}
class TApplicationException extends TException {
static $_TSPEC =
array(1 => array('var' => 'message',
'type' => TType::STRING),
2 => array('var' => 'code',
'type' => TType::I32));
const UNKNOWN = 0;
const UNKNOWN_METHOD = 1;
const INVALID_MESSAGE_TYPE = 2;
const WRONG_METHOD_NAME = 3;
const BAD_SEQUENCE_ID = 4;
const MISSING_RESULT = 5;
function __construct($message=null, $code=0) {
parent::__construct($message, $code);
}
public function read($output) {
return $this->_read('TApplicationException', self::$_TSPEC, $output);
}
public function write($output) {
$xfer = 0;
$xfer += $output->writeStructBegin('TApplicationException');
if ($message = $this->getMessage()) {
$xfer += $output->writeFieldBegin('message', TType::STRING, 1);
$xfer += $output->writeString($message);
$xfer += $output->writeFieldEnd();
}
if ($code = $this->getCode()) {
$xfer += $output->writeFieldBegin('type', TType::I32, 2);
$xfer += $output->writeI32($code);
$xfer += $output->writeFieldEnd();
}
$xfer += $output->writeFieldStop();
$xfer += $output->writeStructEnd();
return $xfer;
}
}
/**
* Set global THRIFT ROOT automatically via inclusion here
*/
if (!isset($GLOBALS['THRIFT_ROOT'])) {
$GLOBALS['THRIFT_ROOT'] = dirname(__FILE__);
}
include_once $GLOBALS['THRIFT_ROOT'].'/protocol/TProtocol.php';
include_once $GLOBALS['THRIFT_ROOT'].'/transport/TTransport.php';