/* * 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. */ #include #include #include #include #include #include #include "thrift/version.h" #include "thrift/platform.h" #include "thrift/generate/t_generator.h" using std::map; using std::ofstream; using std::ostream; using std::ostringstream; using std::string; using std::stringstream; using std::vector; /** * XSD generator, creates an XSD for the base types etc. * */ class t_xsd_generator : public t_generator { public: t_xsd_generator(t_program* program, const std::map& parsed_options, const std::string& option_string) : t_generator(program) { (void)option_string; std::map::const_iterator iter; /* no options yet */ for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { throw "unknown option xsd:" + iter->first; } out_dir_base_ = "gen-xsd"; } ~t_xsd_generator() override = default; /** * Init and close methods */ void init_generator() override; void close_generator() override; std::string display_name() const override; /** * Program-level generation functions */ void generate_typedef(t_typedef* ttypedef) override; void generate_enum(t_enum* tenum) override { (void)tenum; } void generate_service(t_service* tservice) override; void generate_struct(t_struct* tstruct) override; private: void generate_element(std::ostream& out, std::string name, t_type* ttype, t_struct* attrs = nullptr, bool optional = false, bool nillable = false, bool list_element = false); std::string ns(std::string in, std::string ns) { return ns + ":" + in; } std::string xsd(std::string in) { return ns(in, "xsd"); } std::string type_name(t_type* ttype); std::string base_type_name(t_base_type::t_base tbase); virtual std::string xml_autogen_comment() { return std::string("\n"; } /** * Output xsd/php file */ ofstream_with_content_based_conditional_update f_xsd_; ofstream_with_content_based_conditional_update f_php_; /** * Output string stream */ std::ostringstream s_xsd_types_; }; void t_xsd_generator::init_generator() { // Make output directory MKDIR(get_out_dir().c_str()); // Make output file string f_php_name = get_out_dir() + program_->get_name() + "_xsd.php"; f_php_.open(f_php_name.c_str()); f_php_ << "" << '\n'; f_php_.close(); } void t_xsd_generator::generate_typedef(t_typedef* ttypedef) { indent(s_xsd_types_) << "get_name() << "\">" << '\n'; indent_up(); indent(s_xsd_types_) << "get_type()) << "\" />" << '\n'; indent_down(); indent(s_xsd_types_) << "" << '\n' << '\n'; } void t_xsd_generator::generate_struct(t_struct* tstruct) { vector::const_iterator m_iter; const vector& members = tstruct->get_members(); bool xsd_all = tstruct->get_xsd_all(); indent(s_xsd_types_) << "get_name() << "\">" << '\n'; indent_up(); if (xsd_all) { indent(s_xsd_types_) << "" << '\n'; } else { indent(s_xsd_types_) << "" << '\n'; } indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { generate_element(s_xsd_types_, (*m_iter)->get_name(), (*m_iter)->get_type(), (*m_iter)->get_xsd_attrs(), (*m_iter)->get_xsd_optional() || xsd_all, (*m_iter)->get_xsd_nillable()); } indent_down(); if (xsd_all) { indent(s_xsd_types_) << "" << '\n'; } else { indent(s_xsd_types_) << "" << '\n'; } indent_down(); indent(s_xsd_types_) << "" << '\n' << '\n'; } void t_xsd_generator::generate_element(ostream& out, string name, t_type* ttype, t_struct* attrs, bool optional, bool nillable, bool list_element) { string sminOccurs = (optional || list_element) ? " minOccurs=\"0\"" : ""; string smaxOccurs = list_element ? " maxOccurs=\"unbounded\"" : ""; string soptional = sminOccurs + smaxOccurs; string snillable = nillable ? " nillable=\"true\"" : ""; if (ttype->is_void() || ttype->is_list()) { indent(out) << "" << '\n'; indent_up(); if (attrs == nullptr && ttype->is_void()) { indent(out) << "" << '\n'; } else { indent(out) << "" << '\n'; indent_up(); if (ttype->is_list()) { indent(out) << "" << '\n'; indent_up(); string subname; t_type* subtype = ((t_list*)ttype)->get_elem_type(); if (subtype->is_base_type() || subtype->is_container()) { subname = name + "_elt"; } else { subname = type_name(subtype); } f_php_ << "$GLOBALS['" << program_->get_name() << "_xsd_elt_" << name << "'] = '" << subname << "';" << '\n'; generate_element(out, subname, subtype, nullptr, false, false, true); indent_down(); indent(out) << "" << '\n'; indent(out) << "" << '\n'; } if (attrs != nullptr) { const vector& members = attrs->get_members(); vector::const_iterator a_iter; for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) { indent(out) << "get_name() << "\" type=\"" << type_name((*a_iter)->get_type()) << "\" />" << '\n'; } } indent_down(); indent(out) << "" << '\n'; } indent_down(); indent(out) << "" << '\n'; } else { if (attrs == nullptr) { indent(out) << "" << '\n'; } else { // Wow, all this work for a SIMPLE TYPE with attributes?!?!?! indent(out) << "" << '\n'; indent_up(); indent(out) << "" << '\n'; indent_up(); indent(out) << "" << '\n'; indent_up(); indent(out) << "" << '\n'; indent_up(); const vector& members = attrs->get_members(); vector::const_iterator a_iter; for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) { indent(out) << "get_name() << "\" type=\"" << type_name((*a_iter)->get_type()) << "\" />" << '\n'; } indent_down(); indent(out) << "" << '\n'; indent_down(); indent(out) << "" << '\n'; indent_down(); indent(out) << "" << '\n'; indent_down(); indent(out) << "" << '\n'; } } } void t_xsd_generator::generate_service(t_service* tservice) { // Make output file string f_xsd_name = get_out_dir() + tservice->get_name() + ".xsd"; f_xsd_.open(f_xsd_name.c_str()); string ns = program_->get_namespace("xsd"); const std::map> annot = program_->get_namespace_annotations("xsd"); const std::map>::const_iterator uri = annot.find("uri"); if (uri != annot.end() && !uri->second.empty()) { ns = uri->second.back(); } if (ns.size() > 0) { ns = " targetNamespace=\"" + ns + "\" xmlns=\"" + ns + "\" " + "elementFormDefault=\"qualified\""; } // Print the XSD header f_xsd_ << "" << '\n' << "" << '\n' << xml_autogen_comment() << '\n'; // Print out the type definitions indent(f_xsd_) << s_xsd_types_.str(); // Keep a list of all the possible exceptions that might get thrown map all_xceptions; // List the elements that you might actually get vector functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { string elemname = (*f_iter)->get_name() + "_response"; t_type* returntype = (*f_iter)->get_returntype(); generate_element(f_xsd_, elemname, returntype); f_xsd_ << '\n'; t_struct* xs = (*f_iter)->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { all_xceptions[(*x_iter)->get_name()] = (t_struct*)((*x_iter)->get_type()); } } map::iterator ax_iter; for (ax_iter = all_xceptions.begin(); ax_iter != all_xceptions.end(); ++ax_iter) { generate_element(f_xsd_, ax_iter->first, ax_iter->second); } // Close the XSD document f_xsd_ << '\n' << "" << '\n'; f_xsd_.close(); } string t_xsd_generator::type_name(t_type* ttype) { if (ttype->is_typedef()) { return ttype->get_name(); } if (ttype->is_base_type()) { return xsd(base_type_name(((t_base_type*)ttype)->get_base())); } if (ttype->is_enum()) { return xsd("int"); } if (ttype->is_struct() || ttype->is_xception()) { return ttype->get_name(); } return "container"; } /** * Returns the XSD type that corresponds to the thrift type. * * @param tbase The base type * @return Explicit XSD type, i.e. xsd:string */ string t_xsd_generator::base_type_name(t_base_type::t_base tbase) { switch (tbase) { case t_base_type::TYPE_VOID: return "void"; case t_base_type::TYPE_STRING: return "string"; case t_base_type::TYPE_BOOL: return "boolean"; case t_base_type::TYPE_I8: return "byte"; case t_base_type::TYPE_I16: return "short"; case t_base_type::TYPE_I32: return "int"; case t_base_type::TYPE_I64: return "long"; case t_base_type::TYPE_DOUBLE: return "decimal"; default: throw "compiler error: no XSD base type name for base type " + t_base_type::t_base_name(tbase); } } std::string t_xsd_generator::display_name() const { return "XSD"; } THRIFT_REGISTER_GENERATOR(xsd, "XSD", "")