THRIFT-1315. cpp: generate server interface factory classes
Patch: Adam Simpkins
git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1164187 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc
index 97afe86..cb4aa8b 100755
--- a/compiler/cpp/src/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/generate/t_cpp_generator.cc
@@ -111,6 +111,7 @@
*/
void generate_service_interface (t_service* tservice, string style);
+ void generate_service_interface_factory (t_service* tservice, string style);
void generate_service_null (t_service* tservice, string style);
void generate_service_multiface (t_service* tservice);
void generate_service_helpers (t_service* tservice);
@@ -1560,6 +1561,7 @@
// Generate all the components
generate_service_interface(tservice, "");
+ generate_service_interface_factory(tservice, "");
generate_service_null(tservice, "");
generate_service_helpers(tservice);
generate_service_client(tservice, "");
@@ -1571,6 +1573,7 @@
if (gen_cob_style_) {
generate_service_interface(tservice, "CobCl");
generate_service_interface(tservice, "CobSv");
+ generate_service_interface_factory(tservice, "CobSv");
generate_service_null(tservice, "CobSv");
generate_service_client(tservice, "Cob");
generate_service_processor(tservice, "Cob");
@@ -1702,6 +1705,95 @@
}
/**
+ * Generates a service interface factory.
+ *
+ * @param tservice The service to generate an interface factory for.
+ */
+void t_cpp_generator::generate_service_interface_factory(t_service* tservice,
+ string style) {
+ string service_if_name = service_name_ + style + "If";
+
+ // Figure out the name of the upper-most parent class.
+ // Getting everything to work out properly with inheritance is annoying.
+ // Here's what we're doing for now:
+ //
+ // - All handlers implement getHandler(), but subclasses use covariant return
+ // types to return their specific service interface class type. We have to
+ // use raw pointers because of this; shared_ptr<> can't be used for
+ // covariant return types.
+ //
+ // - Since we're not using shared_ptr<>, we also provide a releaseHandler()
+ // function that must be called to release a pointer to a handler obtained
+ // via getHandler().
+ //
+ // releaseHandler() always accepts a pointer to the upper-most parent class
+ // type. This is necessary since the parent versions of releaseHandler()
+ // may accept any of the parent types, not just the most specific subclass
+ // type. Implementations can use dynamic_cast to cast the pointer to the
+ // subclass type if desired.
+ t_service* base_service = tservice;
+ while (base_service->get_extends() != NULL) {
+ base_service = base_service->get_extends();
+ }
+ string base_if_name = type_name(base_service) + style + "If";
+
+ // Generate the abstract factory class
+ string factory_name = service_if_name + "Factory";
+ string extends;
+ if (tservice->get_extends() != NULL) {
+ extends = " : virtual public " + type_name(tservice->get_extends()) +
+ style + "IfFactory";
+ }
+
+ f_header_ <<
+ "class " << factory_name << extends << " {" << endl <<
+ " public:" << endl;
+ indent_up();
+ f_header_ <<
+ indent() << "typedef " << service_if_name << " Handler;" << endl <<
+ endl <<
+ indent() << "virtual ~" << factory_name << "() {}" << endl <<
+ endl <<
+ indent() << "virtual " << service_if_name << "* getHandler(" <<
+ "const ::apache::thrift::TConnectionInfo& connInfo) = 0;" <<
+ endl <<
+ indent() << "virtual void releaseHandler(" << base_if_name <<
+ "* handler) = 0;" << endl;
+
+ indent_down();
+ f_header_ <<
+ "};" << endl << endl;
+
+ // Generate the singleton factory class
+ string singleton_factory_name = service_if_name + "SingletonFactory";
+ f_header_ <<
+ "class " << singleton_factory_name <<
+ " : virtual public " << factory_name << " {" << endl <<
+ " public:" << endl;
+ indent_up();
+ f_header_ <<
+ indent() << singleton_factory_name << "(const boost::shared_ptr<" <<
+ service_if_name << ">& iface) : iface_(iface) {}" << endl <<
+ indent() << "virtual ~" << singleton_factory_name << "() {}" << endl <<
+ endl <<
+ indent() << "virtual " << service_if_name << "* getHandler(" <<
+ "const ::apache::thrift::TConnectionInfo&) {" << endl <<
+ indent() << " return iface_.get();" << endl <<
+ indent() << "}" << endl <<
+ indent() << "virtual void releaseHandler(" << base_if_name <<
+ "* handler) {}" << endl;
+
+ f_header_ <<
+ endl <<
+ " protected:" << endl <<
+ indent() << "boost::shared_ptr<" << service_if_name << "> iface_;" << endl;
+
+ indent_down();
+ f_header_ <<
+ "};" << endl << endl;
+}
+
+/**
* Generates a null implementation of the service.
*
* @param tservice The service to generate a header definition for
@@ -2479,12 +2571,15 @@
generate_process_fn();
// Generate all of the process subfunctions
generate_process_functions();
+
+ generate_factory();
}
void generate_class_definition();
void generate_process();
void generate_process_fn();
void generate_process_functions();
+ void generate_factory();
protected:
std::string type_name(t_type* ttype, bool in_typedef=false, bool arg=false) {
@@ -2514,6 +2609,7 @@
string pstyle_;
string class_name_;
string if_name_;
+ string factory_class_name_;
string finish_cob_;
string finish_cob_decl_;
string ret_type_;
@@ -2559,11 +2655,14 @@
call_context_decl_ = ", void*";
}
+ factory_class_name_ = class_name_ + "Factory";
+
if (generator->gen_templates_) {
template_header_ = "template <class Protocol_>\n";
template_suffix_ = "<Protocol_>";
typename_str_ = "typename ";
class_name_ += "T";
+ factory_class_name_ += "T";
}
if (service_->get_extends() != NULL) {
@@ -2820,6 +2919,68 @@
}
}
+void ProcessorGenerator::generate_factory() {
+ string if_factory_name = if_name_ + "Factory";
+
+ // Generate the factory class definition
+ f_header_ <<
+ template_header_ <<
+ "class " << factory_class_name_ <<
+ " : public ::apache::thrift::TProcessorFactory {" << endl <<
+ " public:" << endl;
+ indent_up();
+
+ f_header_ <<
+ indent() << factory_class_name_ << "(const ::boost::shared_ptr< " <<
+ if_factory_name << " >& handlerFactory) :" << endl <<
+ indent() << " handlerFactory_(handlerFactory) {}" << endl <<
+ endl <<
+ indent() << "::boost::shared_ptr< ::apache::thrift::TProcessor > " <<
+ "getProcessor(const ::apache::thrift::TConnectionInfo& connInfo);" <<
+ endl;
+
+ f_header_ <<
+ endl <<
+ " protected:" << endl <<
+ indent() << "::boost::shared_ptr< " << if_factory_name <<
+ " > handlerFactory_;" << endl;
+
+ indent_down();
+ f_header_ <<
+ "};" << endl << endl;
+
+ // If we are generating templates, output a typedef for the plain
+ // factory name.
+ if (generator_->gen_templates_) {
+ f_header_ <<
+ "typedef " << factory_class_name_ <<
+ "< ::apache::thrift::protocol::TDummyProtocol > " <<
+ service_name_ << pstyle_ << "ProcessorFactory;" << endl << endl;
+ }
+
+ // Generate the getProcessor() method
+ f_out_ <<
+ template_header_ <<
+ indent() << "::boost::shared_ptr< ::apache::thrift::TProcessor > " <<
+ factory_class_name_ << template_suffix_ << "::getProcessor(" <<
+ "const ::apache::thrift::TConnectionInfo& connInfo) {" << endl;
+ indent_up();
+
+ f_out_ <<
+ indent() << "::apache::thrift::ReleaseHandler< " << if_factory_name <<
+ " > cleanup(handlerFactory_);" << endl <<
+ indent() << "::boost::shared_ptr< " << if_name_ << " > handler(" <<
+ "handlerFactory_->getHandler(connInfo), cleanup);" << endl <<
+ indent() << "::boost::shared_ptr< ::apache::thrift::TProcessor > " <<
+ "processor(new " << class_name_ << template_suffix_ <<
+ "(handler));" << endl <<
+ indent() << "return processor;" << endl;
+
+ indent_down();
+ f_out_ <<
+ indent() << "}" << endl;
+}
+
/**
* Generates a service processor definition.
*
diff --git a/lib/cpp/src/TProcessor.h b/lib/cpp/src/TProcessor.h
index cf4f3b8..a593776 100644
--- a/lib/cpp/src/TProcessor.h
+++ b/lib/cpp/src/TProcessor.h
@@ -161,6 +161,34 @@
boost::shared_ptr<TProcessorEventHandler> eventHandler_;
};
+/**
+ * This is a helper class to allow boost::shared_ptr to be used with handler
+ * pointers returned by the generated handler factories.
+ *
+ * The handler factory classes generated by the thrift compiler return raw
+ * pointers, and factory->releaseHandler() must be called when the handler is
+ * no longer needed.
+ *
+ * A ReleaseHandler object can be instantiated and passed as the second
+ * parameter to a shared_ptr, so that factory->releaseHandler() will be called
+ * when the object is no longer needed, instead of deleting the pointer.
+ */
+template<typename HandlerFactory_>
+class ReleaseHandler {
+ public:
+ ReleaseHandler(const boost::shared_ptr<HandlerFactory_>& handlerFactory) :
+ handlerFactory_(handlerFactory) {}
+
+ void operator()(typename HandlerFactory_::Handler* handler) {
+ if (handler) {
+ handlerFactory_->releaseHandler(handler);
+ }
+ }
+
+ private:
+ boost::shared_ptr<HandlerFactory_> handlerFactory_;
+};
+
}} // apache::thrift
#endif // #ifndef _THRIFT_TPROCESSOR_H_