]>
Commit | Line | Data |
---|---|---|
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 | ||
31 | using std::map; | |
32 | using std::ofstream; | |
33 | using std::ostream; | |
34 | using std::ostringstream; | |
35 | using std::string; | |
36 | using std::stringstream; | |
37 | using std::vector; | |
38 | ||
39 | static const string endl = "\n"; // avoid ostream << std::endl flushes | |
40 | ||
41 | /** | |
42 | * XSD generator, creates an XSD for the base types etc. | |
43 | * | |
44 | */ | |
45 | class t_xsd_generator : public t_generator { | |
46 | public: | |
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 | ||
81 | private: | |
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 | ||
115 | void 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 | ||
127 | void t_xsd_generator::close_generator() { | |
128 | f_php_ << "?>" << endl; | |
129 | f_php_.close(); | |
130 | } | |
131 | ||
132 | void 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 | ||
154 | void 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 | ||
187 | void 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 | ||
272 | void 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 | ||
327 | string 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 | */ | |
353 | string 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 | ||
376 | THRIFT_REGISTER_GENERATOR(xsd, "XSD", "") |