From e8ca73f62f97fe1cf05425727a9831d14316e4d4 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Mon, 24 Mar 2014 21:41:12 +0200 Subject: [PATCH] THRIFT-2425 PHP: Server-side support for Multiplexing Services Patch: Aldo Armiento --- lib/php/lib/Thrift/TMultiplexedProcessor.php | 135 +++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 lib/php/lib/Thrift/TMultiplexedProcessor.php diff --git a/lib/php/lib/Thrift/TMultiplexedProcessor.php b/lib/php/lib/Thrift/TMultiplexedProcessor.php new file mode 100644 index 00000000..9146ab6a --- /dev/null +++ b/lib/php/lib/Thrift/TMultiplexedProcessor.php @@ -0,0 +1,135 @@ +TMultiplexedProcessor is a Processor allowing + * a single TServer to provide multiple services. + * + *

To do so, you instantiate the processor and then register additional + * processors with it, as shown in the following example:

+ * + *
+ * $processor = new TMultiplexedProcessor(); + * + * processor->registerProcessor( + * "Calculator", + * new \tutorial\CalculatorProcessor(new CalculatorHandler())); + * + * processor->registerProcessor( + * "WeatherReport", + * new \tutorial\WeatherReportProcessor(new WeatherReportHandler())); + * + * $processor->process($protocol, $protocol); + *
+ */ + +class TMultiplexedProcessor { + private $serviceProcessorMap_; + + /** + * 'Register' a service with this TMultiplexedProcessor. 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 process performs the following steps: + * + *
    + *
  1. Read the beginning of the message.
  2. + *
  3. Extract the service name from the message.
  4. + *
  5. Using the service name to locate the appropriate processor.
  6. + *
  7. Dispatch to the processor, with a decorated instance of TProtocol + * that allows readMessageBegin() to return the original Message.
  8. + *
+ * + * @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_; + } +} -- 2.17.1