1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 #ifndef _THRIFT_TEST_SERVERTHREAD_H_
20 #define _THRIFT_TEST_SERVERTHREAD_H_ 1
21 
22 #include <thrift/TProcessor.h>
23 #include <thrift/protocol/TProtocol.h>
24 #include <thrift/server/TServer.h>
25 #include <thrift/transport/TTransport.h>
26 
27 #include "EventLog.h"
28 
29 namespace apache {
30 namespace thrift {
31 namespace test {
32 
33 /**
34  * A helper class to tell ServerThread how to create the server
35  */
36 class ServerState {
37 public:
38   virtual ~ServerState() = default;
39 
40   /**
41    * Create a server to listen on the specified port.
42    *
43    * If the server returned fails to bind to the specified port when serve() is
44    * called on it, createServer() may be called again on a different port.
45    */
46   virtual std::shared_ptr<server::TServer> createServer(uint16_t port) = 0;
47 
48   /**
49    * Get the TServerEventHandler to set on the server.
50    *
51    * This is only called after the server successfully binds and is about to
52    * start serving traffic.  It is invoked from the server thread, rather than
53    * the main thread.
54    */
getServerEventHandler()55   virtual std::shared_ptr<server::TServerEventHandler> getServerEventHandler() {
56     return std::shared_ptr<server::TServerEventHandler>();
57   }
58 
59   /**
60    * This method is called in the server thread after server binding succeeds.
61    *
62    * Subclasses may override this method if they wish to record the final
63    * port that was used for the server.
64    */
bindSuccessful(uint16_t)65   virtual void bindSuccessful(uint16_t /*port*/) {}
66 };
67 
68 /**
69  * ServerThread starts a thrift server running in a separate thread.
70  */
71 class ServerThread {
72 public:
ServerThread(const std::shared_ptr<ServerState> & state,bool autoStart)73   ServerThread(const std::shared_ptr<ServerState>& state, bool autoStart)
74     : port_(0),
75       running_(false),
76       serving_(false),
77       error_(false),
78       serverState_(state) {
79     if (autoStart) {
80       start();
81     }
82   }
83 
84   void start();
85   void stop();
86 
getPort()87   uint16_t getPort() const { return port_; }
88 
~ServerThread()89   ~ServerThread() {
90     if (running_) {
91       try {
92         stop();
93       } catch (...) {
94         GlobalOutput.printf("error shutting down server");
95       }
96     }
97   }
98 
99 protected:
100   // Annoying.  thrift forces us to use shared_ptr, so we have to use
101   // a helper class that we can allocate on the heap and give to thrift.
102   // It would be simpler if we could just make Runnable and TServerEventHandler
103   // private base classes of ServerThread.
104   class Helper : public concurrency::Runnable, public server::TServerEventHandler {
105   public:
Helper(ServerThread * serverThread)106     Helper(ServerThread* serverThread) : serverThread_(serverThread) {}
107 
run()108     void run() override { serverThread_->run(); }
109 
preServe()110     void preServe() override { serverThread_->preServe(); }
111 
112   private:
113     ServerThread* serverThread_;
114   };
115 
116   void run();
117   void preServe();
118 
119   std::shared_ptr<Helper> helper_;
120 
121   uint16_t port_;
122   bool running_;
123   bool serving_;
124   bool error_;
125   concurrency::Monitor serverMonitor_;
126 
127   std::shared_ptr<ServerState> serverState_;
128   std::shared_ptr<server::TServer> server_;
129   std::shared_ptr<concurrency::Thread> thread_;
130 };
131 }
132 }
133 } // apache::thrift::test
134 
135 #endif // _THRIFT_TEST_SERVERTHREAD_H_
136