summaryrefslogtreecommitdiff
path: root/compiler/cpp/src/generate/t_xsd_generator.cc
diff options
context:
space:
mode:
authorGavin McDonald <gmcdonald@apache.org>2010-10-28 02:12:01 +0000
committerGavin McDonald <gmcdonald@apache.org>2010-10-28 02:12:01 +0000
commit0b75e1ac7643787e201fd62628823e6d51ca6353 (patch)
tree4417fd3f2bc201f0f34c2344f0923df1485bc419 /compiler/cpp/src/generate/t_xsd_generator.cc
downloadthrift-0.1.x.tar.gz
Thrift now a TLP - INFRA-31160.1.x
git-svn-id: https://svn.apache.org/repos/asf/thrift/branches/0.1.x@1028168 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'compiler/cpp/src/generate/t_xsd_generator.cc')
-rw-r--r--compiler/cpp/src/generate/t_xsd_generator.cc354
1 files changed, 354 insertions, 0 deletions
diff --git a/compiler/cpp/src/generate/t_xsd_generator.cc b/compiler/cpp/src/generate/t_xsd_generator.cc
new file mode 100644
index 000000000..729a91aed
--- /dev/null
+++ b/compiler/cpp/src/generate/t_xsd_generator.cc
@@ -0,0 +1,354 @@
+/*
+ * 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 <fstream>
+#include <iostream>
+#include <sstream>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "t_generator.h"
+#include "platform.h"
+using namespace std;
+
+
+/**
+ * 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<std::string, std::string>& parsed_options,
+ const std::string& option_string)
+ : t_generator(program)
+ {
+ out_dir_base_ = "gen-xsd";
+ }
+
+ virtual ~t_xsd_generator() {}
+
+ /**
+ * Init and close methods
+ */
+
+ void init_generator();
+ void close_generator();
+
+ /**
+ * Program-level generation functions
+ */
+
+ void generate_typedef(t_typedef* ttypedef);
+ void generate_enum(t_enum* tenum) {}
+
+ void generate_service(t_service* tservice);
+ void generate_struct(t_struct* tstruct);
+
+ private:
+
+ void generate_element(std::ostream& out, std::string name, t_type* ttype, t_struct* attrs=NULL, 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);
+
+ /**
+ * Output xsd/php file
+ */
+ std::ofstream f_xsd_;
+ std::ofstream 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_ <<
+ "<?php" << endl;
+
+}
+
+void t_xsd_generator::close_generator() {
+ f_php_ << "?>" << endl;
+ f_php_.close();
+}
+
+void t_xsd_generator::generate_typedef(t_typedef* ttypedef) {
+ indent(s_xsd_types_) <<
+ "<xsd:simpleType name=\"" << ttypedef->get_name() << "\">" << endl;
+ indent_up();
+ if (ttypedef->get_type()->is_string() && ((t_base_type*)ttypedef->get_type())->is_string_enum()) {
+ indent(s_xsd_types_) <<
+ "<xsd:restriction base=\"" << type_name(ttypedef->get_type()) << "\">" << endl;
+ indent_up();
+ const vector<string>& values = ((t_base_type*)ttypedef->get_type())->get_string_enum_vals();
+ vector<string>::const_iterator v_iter;
+ for (v_iter = values.begin(); v_iter != values.end(); ++v_iter) {
+ indent(s_xsd_types_) <<
+ "<xsd:enumeration value=\"" << (*v_iter) << "\" />" << endl;
+ }
+ indent_down();
+ indent(s_xsd_types_) <<
+ "</xsd:restriction>" << endl;
+ } else {
+ indent(s_xsd_types_) <<
+ "<xsd:restriction base=\"" << type_name(ttypedef->get_type()) << "\" />" << endl;
+ }
+ indent_down();
+ indent(s_xsd_types_) <<
+ "</xsd:simpleType>" << endl << endl;
+}
+
+void t_xsd_generator::generate_struct(t_struct* tstruct) {
+ vector<t_field*>::const_iterator m_iter;
+ const vector<t_field*>& members = tstruct->get_members();
+ bool xsd_all = tstruct->get_xsd_all();
+
+ indent(s_xsd_types_) << "<xsd:complexType name=\"" << tstruct->get_name() << "\">" << endl;
+ indent_up();
+ if (xsd_all) {
+ indent(s_xsd_types_) << "<xsd:all>" << endl;
+ } else {
+ indent(s_xsd_types_) << "<xsd:sequence>" << endl;
+ }
+ 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_) << "</xsd:all>" << endl;
+ } else {
+ indent(s_xsd_types_) << "</xsd:sequence>" << endl;
+ }
+ indent_down();
+ indent(s_xsd_types_) <<
+ "</xsd:complexType>" << endl <<
+ endl;
+}
+
+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) <<
+ "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">" << endl;
+ indent_up();
+ if (attrs == NULL && ttype->is_void()) {
+ indent(out) <<
+ "<xsd:complexType />" << endl;
+ } else {
+ indent(out) <<
+ "<xsd:complexType>" << endl;
+ indent_up();
+ if (ttype->is_list()) {
+ indent(out) << "<xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">" << endl;
+ 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 << "';" << endl;
+ generate_element(out, subname, subtype, NULL, false, false, true);
+ indent_down();
+ indent(out) << "</xsd:sequence>" << endl;
+ indent(out) << "<xsd:attribute name=\"list\" type=\"xsd:boolean\" />" << endl;
+ }
+ if (attrs != NULL) {
+ const vector<t_field*>& members = attrs->get_members();
+ vector<t_field*>::const_iterator a_iter;
+ for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) {
+ indent(out) << "<xsd:attribute name=\"" << (*a_iter)->get_name() << "\" type=\"" << type_name((*a_iter)->get_type()) << "\" />" << endl;
+ }
+ }
+ indent_down();
+ indent(out) <<
+ "</xsd:complexType>" << endl;
+ }
+ indent_down();
+ indent(out) <<
+ "</xsd:element>" << endl;
+ } else {
+ if (attrs == NULL) {
+ indent(out) <<
+ "<xsd:element name=\"" << name << "\"" << " type=\"" << type_name(ttype) << "\"" << soptional << snillable << " />" << endl;
+ } else {
+ // Wow, all this work for a SIMPLE TYPE with attributes?!?!?!
+ indent(out) << "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">" << endl;
+ indent_up();
+ indent(out) << "<xsd:complexType>" << endl;
+ indent_up();
+ indent(out) << "<xsd:complexContent>" << endl;
+ indent_up();
+ indent(out) << "<xsd:extension base=\"" << type_name(ttype) << "\">" << endl;
+ indent_up();
+ const vector<t_field*>& members = attrs->get_members();
+ vector<t_field*>::const_iterator a_iter;
+ for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) {
+ indent(out) << "<xsd:attribute name=\"" << (*a_iter)->get_name() << "\" type=\"" << type_name((*a_iter)->get_type()) << "\" />" << endl;
+ }
+ indent_down();
+ indent(out) << "</xsd:extension>" << endl;
+ indent_down();
+ indent(out) << "</xsd:complexContent>" << endl;
+ indent_down();
+ indent(out) << "</xsd:complexType>" << endl;
+ indent_down();
+ indent(out) << "</xsd:element>" << endl;
+ }
+ }
+}
+
+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");
+ if (ns.size() > 0) {
+ ns = " targetNamespace=\"" + ns + "\" xmlns=\"" + ns + "\" " +
+ "elementFormDefault=\"qualified\"";
+ }
+
+ // Print the XSD header
+ f_xsd_ <<
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" << endl <<
+ "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" << ns << ">" << endl <<
+ endl <<
+ "<!-- Yo yo yo, this XSD woz be generated by Thrift. -->" << endl <<
+ endl;
+
+ // 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<string, t_struct*> all_xceptions;
+
+ // List the elements that you might actually get
+ vector<t_function*> functions = tservice->get_functions();
+ vector<t_function*>::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_ << endl;
+
+ t_struct* xs = (*f_iter)->get_xceptions();
+ const std::vector<t_field*>& xceptions = xs->get_members();
+ vector<t_field*>::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<string, t_struct*>::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_ << endl << "</xsd:schema>" << endl;
+ 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_BYTE:
+ 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 C++ base type name for base type " + t_base_type::t_base_name(tbase);
+ }
+}
+
+THRIFT_REGISTER_GENERATOR(xsd, "XSD", "");