]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/thrift/compiler/cpp/src/thrift/generate/t_xsd_generator.cc
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / thrift / compiler / cpp / src / thrift / generate / t_xsd_generator.cc
CommitLineData
f67539c2
TL
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
20#include <fstream>
21#include <iostream>
22#include <sstream>
23
24#include <stdlib.h>
25#include <sys/stat.h>
26#include <sstream>
27#include "thrift/version.h"
28#include "thrift/platform.h"
29#include "thrift/generate/t_generator.h"
30
31using std::map;
32using std::ofstream;
33using std::ostream;
34using std::ostringstream;
35using std::string;
36using std::stringstream;
37using std::vector;
38
39static const string endl = "\n"; // avoid ostream << std::endl flushes
40
41/**
42 * XSD generator, creates an XSD for the base types etc.
43 *
44 */
45class t_xsd_generator : public t_generator {
46public:
47 t_xsd_generator(t_program* program,
48 const std::map<std::string, std::string>& parsed_options,
49 const std::string& option_string)
50 : t_generator(program) {
51 (void)option_string;
52 std::map<std::string, std::string>::const_iterator iter;
53
54 /* no options yet */
55 for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
56 throw "unknown option xsd:" + iter->first;
57 }
58
59 out_dir_base_ = "gen-xsd";
60 }
61
62 ~t_xsd_generator() override = default;
63
64 /**
65 * Init and close methods
66 */
67
68 void init_generator() override;
69 void close_generator() override;
70
71 /**
72 * Program-level generation functions
73 */
74
75 void generate_typedef(t_typedef* ttypedef) override;
76 void generate_enum(t_enum* tenum) override { (void)tenum; }
77
78 void generate_service(t_service* tservice) override;
79 void generate_struct(t_struct* tstruct) override;
80
81private:
82 void generate_element(std::ostream& out,
83 std::string name,
84 t_type* ttype,
85 t_struct* attrs = NULL,
86 bool optional = false,
87 bool nillable = false,
88 bool list_element = false);
89
90 std::string ns(std::string in, std::string ns) { return ns + ":" + in; }
91
92 std::string xsd(std::string in) { return ns(in, "xsd"); }
93
94 std::string type_name(t_type* ttype);
95 std::string base_type_name(t_base_type::t_base tbase);
96
97 virtual std::string xml_autogen_comment() {
98 return std::string("<!--\n") + " * Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
99 + " *\n" + " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n"
100 + " -->\n";
101 }
102
103 /**
104 * Output xsd/php file
105 */
106 ofstream_with_content_based_conditional_update f_xsd_;
107 ofstream_with_content_based_conditional_update f_php_;
108
109 /**
110 * Output string stream
111 */
112 std::ostringstream s_xsd_types_;
113};
114
115void t_xsd_generator::init_generator() {
116 // Make output directory
117 MKDIR(get_out_dir().c_str());
118
119 // Make output file
120 string f_php_name = get_out_dir() + program_->get_name() + "_xsd.php";
121 f_php_.open(f_php_name.c_str());
122
123 f_php_ << "<?php" << endl
124 << autogen_comment() << endl;
125}
126
127void t_xsd_generator::close_generator() {
128 f_php_ << "?>" << endl;
129 f_php_.close();
130}
131
132void t_xsd_generator::generate_typedef(t_typedef* ttypedef) {
133 indent(s_xsd_types_) << "<xsd:simpleType name=\"" << ttypedef->get_name() << "\">" << endl;
134 indent_up();
135 if (ttypedef->get_type()->is_string() && ((t_base_type*)ttypedef->get_type())->is_string_enum()) {
136 indent(s_xsd_types_) << "<xsd:restriction base=\"" << type_name(ttypedef->get_type()) << "\">"
137 << endl;
138 indent_up();
139 const vector<string>& values = ((t_base_type*)ttypedef->get_type())->get_string_enum_vals();
140 vector<string>::const_iterator v_iter;
141 for (v_iter = values.begin(); v_iter != values.end(); ++v_iter) {
142 indent(s_xsd_types_) << "<xsd:enumeration value=\"" << (*v_iter) << "\" />" << endl;
143 }
144 indent_down();
145 indent(s_xsd_types_) << "</xsd:restriction>" << endl;
146 } else {
147 indent(s_xsd_types_) << "<xsd:restriction base=\"" << type_name(ttypedef->get_type()) << "\" />"
148 << endl;
149 }
150 indent_down();
151 indent(s_xsd_types_) << "</xsd:simpleType>" << endl << endl;
152}
153
154void t_xsd_generator::generate_struct(t_struct* tstruct) {
155 vector<t_field*>::const_iterator m_iter;
156 const vector<t_field*>& members = tstruct->get_members();
157 bool xsd_all = tstruct->get_xsd_all();
158
159 indent(s_xsd_types_) << "<xsd:complexType name=\"" << tstruct->get_name() << "\">" << endl;
160 indent_up();
161 if (xsd_all) {
162 indent(s_xsd_types_) << "<xsd:all>" << endl;
163 } else {
164 indent(s_xsd_types_) << "<xsd:sequence>" << endl;
165 }
166 indent_up();
167
168 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
169 generate_element(s_xsd_types_,
170 (*m_iter)->get_name(),
171 (*m_iter)->get_type(),
172 (*m_iter)->get_xsd_attrs(),
173 (*m_iter)->get_xsd_optional() || xsd_all,
174 (*m_iter)->get_xsd_nillable());
175 }
176
177 indent_down();
178 if (xsd_all) {
179 indent(s_xsd_types_) << "</xsd:all>" << endl;
180 } else {
181 indent(s_xsd_types_) << "</xsd:sequence>" << endl;
182 }
183 indent_down();
184 indent(s_xsd_types_) << "</xsd:complexType>" << endl << endl;
185}
186
187void t_xsd_generator::generate_element(ostream& out,
188 string name,
189 t_type* ttype,
190 t_struct* attrs,
191 bool optional,
192 bool nillable,
193 bool list_element) {
194 string sminOccurs = (optional || list_element) ? " minOccurs=\"0\"" : "";
195 string smaxOccurs = list_element ? " maxOccurs=\"unbounded\"" : "";
196 string soptional = sminOccurs + smaxOccurs;
197 string snillable = nillable ? " nillable=\"true\"" : "";
198
199 if (ttype->is_void() || ttype->is_list()) {
200 indent(out) << "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">" << endl;
201 indent_up();
202 if (attrs == NULL && ttype->is_void()) {
203 indent(out) << "<xsd:complexType />" << endl;
204 } else {
205 indent(out) << "<xsd:complexType>" << endl;
206 indent_up();
207 if (ttype->is_list()) {
208 indent(out) << "<xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">" << endl;
209 indent_up();
210 string subname;
211 t_type* subtype = ((t_list*)ttype)->get_elem_type();
212 if (subtype->is_base_type() || subtype->is_container()) {
213 subname = name + "_elt";
214 } else {
215 subname = type_name(subtype);
216 }
217 f_php_ << "$GLOBALS['" << program_->get_name() << "_xsd_elt_" << name << "'] = '" << subname
218 << "';" << endl;
219 generate_element(out, subname, subtype, NULL, false, false, true);
220 indent_down();
221 indent(out) << "</xsd:sequence>" << endl;
222 indent(out) << "<xsd:attribute name=\"list\" type=\"xsd:boolean\" />" << endl;
223 }
224 if (attrs != NULL) {
225 const vector<t_field*>& members = attrs->get_members();
226 vector<t_field*>::const_iterator a_iter;
227 for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) {
228 indent(out) << "<xsd:attribute name=\"" << (*a_iter)->get_name() << "\" type=\""
229 << type_name((*a_iter)->get_type()) << "\" />" << endl;
230 }
231 }
232 indent_down();
233 indent(out) << "</xsd:complexType>" << endl;
234 }
235 indent_down();
236 indent(out) << "</xsd:element>" << endl;
237 } else {
238 if (attrs == NULL) {
239 indent(out) << "<xsd:element name=\"" << name << "\""
240 << " type=\"" << type_name(ttype) << "\"" << soptional << snillable << " />"
241 << endl;
242 } else {
243 // Wow, all this work for a SIMPLE TYPE with attributes?!?!?!
244 indent(out) << "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">"
245 << endl;
246 indent_up();
247 indent(out) << "<xsd:complexType>" << endl;
248 indent_up();
249 indent(out) << "<xsd:complexContent>" << endl;
250 indent_up();
251 indent(out) << "<xsd:extension base=\"" << type_name(ttype) << "\">" << endl;
252 indent_up();
253 const vector<t_field*>& members = attrs->get_members();
254 vector<t_field*>::const_iterator a_iter;
255 for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) {
256 indent(out) << "<xsd:attribute name=\"" << (*a_iter)->get_name() << "\" type=\""
257 << type_name((*a_iter)->get_type()) << "\" />" << endl;
258 }
259 indent_down();
260 indent(out) << "</xsd:extension>" << endl;
261 indent_down();
262 indent(out) << "</xsd:complexContent>" << endl;
263 indent_down();
264 indent(out) << "</xsd:complexType>" << endl;
265 indent_down();
266 indent(out) << "</xsd:element>" << endl;
267 }
268 }
269}
270
271
272void t_xsd_generator::generate_service(t_service* tservice) {
273 // Make output file
274 string f_xsd_name = get_out_dir() + tservice->get_name() + ".xsd";
275 f_xsd_.open(f_xsd_name.c_str());
276
277 string ns = program_->get_namespace("xsd");
278 const std::map<std::string, std::string> annot = program_->get_namespace_annotations("xsd");
279 const std::map<std::string, std::string>::const_iterator uri = annot.find("uri");
280 if (uri != annot.end()) {
281 ns = uri->second;
282 }
283 if (ns.size() > 0) {
284 ns = " targetNamespace=\"" + ns + "\" xmlns=\"" + ns + "\" "
285 + "elementFormDefault=\"qualified\"";
286 }
287
288 // Print the XSD header
289 f_xsd_ << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" << endl
290 << "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" << ns << ">" << endl
291 << xml_autogen_comment()
292 << endl;
293
294 // Print out the type definitions
295 indent(f_xsd_) << s_xsd_types_.str();
296
297 // Keep a list of all the possible exceptions that might get thrown
298 map<string, t_struct*> all_xceptions;
299
300 // List the elements that you might actually get
301 vector<t_function*> functions = tservice->get_functions();
302 vector<t_function*>::iterator f_iter;
303 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
304 string elemname = (*f_iter)->get_name() + "_response";
305 t_type* returntype = (*f_iter)->get_returntype();
306 generate_element(f_xsd_, elemname, returntype);
307 f_xsd_ << endl;
308
309 t_struct* xs = (*f_iter)->get_xceptions();
310 const std::vector<t_field*>& xceptions = xs->get_members();
311 vector<t_field*>::const_iterator x_iter;
312 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
313 all_xceptions[(*x_iter)->get_name()] = (t_struct*)((*x_iter)->get_type());
314 }
315 }
316
317 map<string, t_struct*>::iterator ax_iter;
318 for (ax_iter = all_xceptions.begin(); ax_iter != all_xceptions.end(); ++ax_iter) {
319 generate_element(f_xsd_, ax_iter->first, ax_iter->second);
320 }
321
322 // Close the XSD document
323 f_xsd_ << endl << "</xsd:schema>" << endl;
324 f_xsd_.close();
325}
326
327string t_xsd_generator::type_name(t_type* ttype) {
328 if (ttype->is_typedef()) {
329 return ttype->get_name();
330 }
331
332 if (ttype->is_base_type()) {
333 return xsd(base_type_name(((t_base_type*)ttype)->get_base()));
334 }
335
336 if (ttype->is_enum()) {
337 return xsd("int");
338 }
339
340 if (ttype->is_struct() || ttype->is_xception()) {
341 return ttype->get_name();
342 }
343
344 return "container";
345}
346
347/**
348 * Returns the XSD type that corresponds to the thrift type.
349 *
350 * @param tbase The base type
351 * @return Explicit XSD type, i.e. xsd:string
352 */
353string t_xsd_generator::base_type_name(t_base_type::t_base tbase) {
354 switch (tbase) {
355 case t_base_type::TYPE_VOID:
356 return "void";
357 case t_base_type::TYPE_STRING:
358 return "string";
359 case t_base_type::TYPE_BOOL:
360 return "boolean";
361 case t_base_type::TYPE_I8:
362 return "byte";
363 case t_base_type::TYPE_I16:
364 return "short";
365 case t_base_type::TYPE_I32:
366 return "int";
367 case t_base_type::TYPE_I64:
368 return "long";
369 case t_base_type::TYPE_DOUBLE:
370 return "decimal";
371 default:
372 throw "compiler error: no XSD base type name for base type " + t_base_type::t_base_name(tbase);
373 }
374}
375
376THRIFT_REGISTER_GENERATOR(xsd, "XSD", "")