TMultiplexedProcessor.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. <?php
  2. /*
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing,
  14. * software distributed under the License is distributed on an
  15. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  16. * KIND, either express or implied. See the License for the
  17. * specific language governing permissions and limitations
  18. * under the License.
  19. *
  20. * @package thrift.processor
  21. */
  22. namespace Thrift;
  23. use Thrift\Exception\TException;
  24. use Thrift\Protocol\TProtocol;
  25. use Thrift\Protocol\TMultiplexedProtocol;
  26. use Thrift\Protocol\TProtocolDecorator;
  27. use Thrift\Type\TMessageType;
  28. /**
  29. * <code>TMultiplexedProcessor</code> is a Processor allowing
  30. * a single <code>TServer</code> to provide multiple services.
  31. *
  32. * <p>To do so, you instantiate the processor and then register additional
  33. * processors with it, as shown in the following example:</p>
  34. *
  35. * <blockquote><code>
  36. * $processor = new TMultiplexedProcessor();
  37. *
  38. * processor->registerProcessor(
  39. * "Calculator",
  40. * new \tutorial\CalculatorProcessor(new CalculatorHandler()));
  41. *
  42. * processor->registerProcessor(
  43. * "WeatherReport",
  44. * new \tutorial\WeatherReportProcessor(new WeatherReportHandler()));
  45. *
  46. * $processor->process($protocol, $protocol);
  47. * </code></blockquote>
  48. */
  49. class TMultiplexedProcessor
  50. {
  51. private $serviceProcessorMap_;
  52. /**
  53. * 'Register' a service with this <code>TMultiplexedProcessor</code>. This
  54. * allows us to broker requests to individual services by using the service
  55. * name to select them at request time.
  56. *
  57. * @param serviceName Name of a service, has to be identical to the name
  58. * declared in the Thrift IDL, e.g. "WeatherReport".
  59. * @param processor Implementation of a service, usually referred to
  60. * as "handlers", e.g. WeatherReportHandler implementing WeatherReport.Iface.
  61. */
  62. public function registerProcessor($serviceName, $processor)
  63. {
  64. $this->serviceProcessorMap_[$serviceName] = $processor;
  65. }
  66. /**
  67. * This implementation of <code>process</code> performs the following steps:
  68. *
  69. * <ol>
  70. * <li>Read the beginning of the message.</li>
  71. * <li>Extract the service name from the message.</li>
  72. * <li>Using the service name to locate the appropriate processor.</li>
  73. * <li>Dispatch to the processor, with a decorated instance of TProtocol
  74. * that allows readMessageBegin() to return the original Message.</li>
  75. * </ol>
  76. *
  77. * @throws TException If the message type is not CALL or ONEWAY, if
  78. * the service name was not found in the message, or if the service
  79. * name was not found in the service map.
  80. */
  81. public function process(TProtocol $input, TProtocol $output)
  82. {
  83. /*
  84. Use the actual underlying protocol (e.g. TBinaryProtocol) to read the
  85. message header. This pulls the message "off the wire", which we'll
  86. deal with at the end of this method.
  87. */
  88. $input->readMessageBegin($fname, $mtype, $rseqid);
  89. if ($mtype !== TMessageType::CALL && $mtype != TMessageType::ONEWAY) {
  90. throw new TException("This should not have happened!?");
  91. }
  92. // Extract the service name and the new Message name.
  93. if (strpos($fname, TMultiplexedProtocol::SEPARATOR) === false) {
  94. throw new TException("Service name not found in message name: {$fname}. Did you " .
  95. "forget to use a TMultiplexProtocol in your client?");
  96. }
  97. list($serviceName, $messageName) = explode(':', $fname, 2);
  98. if (!array_key_exists($serviceName, $this->serviceProcessorMap_)) {
  99. throw new TException("Service name not found: {$serviceName}. Did you forget " .
  100. "to call registerProcessor()?");
  101. }
  102. // Dispatch processing to the stored processor
  103. $processor = $this->serviceProcessorMap_[$serviceName];
  104. return $processor->process(
  105. new StoredMessageProtocol($input, $messageName, $mtype, $rseqid), $output
  106. );
  107. }
  108. }
  109. /**
  110. * Our goal was to work with any protocol. In order to do that, we needed
  111. * to allow them to call readMessageBegin() and get the Message in exactly
  112. * the standard format, without the service name prepended to the Message name.
  113. */
  114. class StoredMessageProtocol extends TProtocolDecorator
  115. {
  116. private $fname_, $mtype_, $rseqid_;
  117. public function __construct(TProtocol $protocol, $fname, $mtype, $rseqid)
  118. {
  119. parent::__construct($protocol);
  120. $this->fname_ = $fname;
  121. $this->mtype_ = $mtype;
  122. $this->rseqid_ = $rseqid;
  123. }
  124. public function readMessageBegin(&$name, &$type, &$seqid)
  125. {
  126. $name = $this->fname_;
  127. $type = $this->mtype_;
  128. $seqid = $this->rseqid_;
  129. }
  130. }