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