OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
t_xsd_generator.cc
Go to the documentation of this file.
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 
36 class t_xsd_generator : public t_generator {
37  public:
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  (void) parsed_options;
45  (void) option_string;
46  out_dir_base_ = "gen-xsd";
47  }
48 
49  virtual ~t_xsd_generator() {}
50 
55  void init_generator();
56  void close_generator();
57 
62  void generate_typedef(t_typedef* ttypedef);
63  void generate_enum(t_enum* tenum) {
64  (void) tenum;
65  }
66 
67  void generate_service(t_service* tservice);
68  void generate_struct(t_struct* tstruct);
69 
70 #ifdef SANDESH
71  void generate_sandesh(t_sandesh* tsandesh);
72 #endif
73 
74  private:
75 
76  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);
77 
78  std::string ns(std::string in, std::string ns) {
79  return ns + ":" + in;
80  }
81 
82  std::string xsd(std::string in) {
83  return ns(in, "xsd");
84  }
85 
86  std::string type_name(t_type* ttype);
87  std::string base_type_name(t_base_type::t_base tbase);
88 
92  std::ofstream f_xsd_;
93  std::ofstream f_php_;
94 
98  std::ostringstream s_xsd_types_;
99 
100 };
101 
102 
104  // Make output directory
105  MKDIR(get_out_dir().c_str());
106 
107 #ifndef SANDESH
108  // Make output file
109  string f_php_name = get_out_dir()+program_->get_name()+"_xsd.php";
110  f_php_.open(f_php_name.c_str());
111 
112  f_php_ <<
113  "<?php" << endl;
114 #else
115  // Make xsd output file
116  string f_xsd_name = get_out_dir()+program_->get_name()+".xsd";
117  f_xsd_.open(f_xsd_name.c_str());
118 #endif
119 }
120 
122 #ifndef SANDESH
123  f_php_ << "?>" << endl;
124  f_php_.close();
125 #else
126  f_xsd_ << s_xsd_types_.str();
127  f_xsd_.close();
128 #endif
129 }
130 
132  indent(s_xsd_types_) <<
133  "<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_) <<
137  "<xsd:restriction base=\"" << type_name(ttypedef->get_type()) << "\">" << 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_) <<
143  "<xsd:enumeration value=\"" << (*v_iter) << "\" />" << endl;
144  }
145  indent_down();
146  indent(s_xsd_types_) <<
147  "</xsd:restriction>" << endl;
148  } else {
149  indent(s_xsd_types_) <<
150  "<xsd:restriction base=\"" << type_name(ttypedef->get_type()) << "\" />" << endl;
151  }
152  indent_down();
153  indent(s_xsd_types_) <<
154  "</xsd:simpleType>" << endl << endl;
155 }
156 
158  vector<t_field*>::const_iterator m_iter;
159  const vector<t_field*>& members = tstruct->get_members();
160  bool xsd_all = tstruct->get_xsd_all();
161 
162  indent(s_xsd_types_) << "<xsd:complexType name=\"" << tstruct->get_name() << "\">" << endl;
163  indent_up();
164  if (xsd_all) {
165  indent(s_xsd_types_) << "<xsd:all>" << endl;
166  } else {
167  indent(s_xsd_types_) << "<xsd:sequence>" << endl;
168  }
169  indent_up();
170 
171  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
172  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());
173  }
174 
175  indent_down();
176  if (xsd_all) {
177  indent(s_xsd_types_) << "</xsd:all>" << endl;
178  } else {
179  indent(s_xsd_types_) << "</xsd:sequence>" << endl;
180  }
181  indent_down();
182  indent(s_xsd_types_) <<
183  "</xsd:complexType>" << endl <<
184  endl;
185 }
186 
187 #ifdef SANDESH
188 void t_xsd_generator::generate_sandesh(t_sandesh* tsandesh) {
189  vector<t_field*>::const_iterator m_iter;
190  const vector<t_field*>& members = tsandesh->get_members();
191  bool xsd_all = false;
192 
193  indent(s_xsd_types_) << "<xsd:complexType name=\"" << tsandesh->get_name() << "\">" << endl;
194  indent_up();
195  if (xsd_all) {
196  indent(s_xsd_types_) << "<xsd:all>" << endl;
197  } else {
198  indent(s_xsd_types_) << "<xsd:sequence>" << endl;
199  }
200  indent_up();
201 
202  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
203  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());
204  }
205 
206  indent_down();
207  if (xsd_all) {
208  indent(s_xsd_types_) << "</xsd:all>" << endl;
209  } else {
210  indent(s_xsd_types_) << "</xsd:sequence>" << endl;
211  }
212  indent_down();
213  indent(s_xsd_types_) <<
214  "</xsd:complexType>" << endl <<
215  endl;
216 }
217 #endif
218 
220  string name,
221  t_type* ttype,
222  t_struct* attrs,
223  bool optional,
224  bool nillable,
225  bool list_element) {
226  string sminOccurs = (optional || list_element) ? " minOccurs=\"0\"" : "";
227  string smaxOccurs = list_element ? " maxOccurs=\"unbounded\"" : "";
228  string soptional = sminOccurs + smaxOccurs;
229  string snillable = nillable ? " nillable=\"true\"" : "";
230 
231  if (ttype->is_void() || ttype->is_list()) {
232  indent(out) <<
233  "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">" << endl;
234  indent_up();
235  if (attrs == NULL && ttype->is_void()) {
236  indent(out) <<
237  "<xsd:complexType />" << endl;
238  } else {
239  indent(out) <<
240  "<xsd:complexType>" << endl;
241  indent_up();
242  if (ttype->is_list()) {
243  indent(out) << "<xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">" << endl;
244  indent_up();
245  string subname;
246  t_type* subtype = ((t_list*)ttype)->get_elem_type();
247  if (subtype->is_base_type() || subtype->is_container()) {
248  subname = name + "_elt";
249  } else {
250  subname = type_name(subtype);
251  }
252  f_php_ << "$GLOBALS['" << program_->get_name() << "_xsd_elt_" << name << "'] = '" << subname << "';" << endl;
253  generate_element(out, subname, subtype, NULL, false, false, true);
254  indent_down();
255  indent(out) << "</xsd:sequence>" << endl;
256  indent(out) << "<xsd:attribute name=\"list\" type=\"xsd:boolean\" />" << endl;
257  }
258  if (attrs != NULL) {
259  const vector<t_field*>& members = attrs->get_members();
260  vector<t_field*>::const_iterator a_iter;
261  for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) {
262  indent(out) << "<xsd:attribute name=\"" << (*a_iter)->get_name() << "\" type=\"" << type_name((*a_iter)->get_type()) << "\" />" << endl;
263  }
264  }
265  indent_down();
266  indent(out) <<
267  "</xsd:complexType>" << endl;
268  }
269  indent_down();
270  indent(out) <<
271  "</xsd:element>" << endl;
272  } else {
273  if (attrs == NULL) {
274  indent(out) <<
275  "<xsd:element name=\"" << name << "\"" << " type=\"" << type_name(ttype) << "\"" << soptional << snillable << " />" << endl;
276  } else {
277  // Wow, all this work for a SIMPLE TYPE with attributes?!?!?!
278  indent(out) << "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">" << endl;
279  indent_up();
280  indent(out) << "<xsd:complexType>" << endl;
281  indent_up();
282  indent(out) << "<xsd:complexContent>" << endl;
283  indent_up();
284  indent(out) << "<xsd:extension base=\"" << type_name(ttype) << "\">" << endl;
285  indent_up();
286  const vector<t_field*>& members = attrs->get_members();
287  vector<t_field*>::const_iterator a_iter;
288  for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) {
289  indent(out) << "<xsd:attribute name=\"" << (*a_iter)->get_name() << "\" type=\"" << type_name((*a_iter)->get_type()) << "\" />" << endl;
290  }
291  indent_down();
292  indent(out) << "</xsd:extension>" << endl;
293  indent_down();
294  indent(out) << "</xsd:complexContent>" << endl;
295  indent_down();
296  indent(out) << "</xsd:complexType>" << endl;
297  indent_down();
298  indent(out) << "</xsd:element>" << endl;
299  }
300  }
301 }
302 
304  // Make output file
305  string f_xsd_name = get_out_dir()+tservice->get_name()+".xsd";
306  f_xsd_.open(f_xsd_name.c_str());
307 
308  string ns = program_->get_namespace("xsd");
309  if (ns.size() > 0) {
310  ns = " targetNamespace=\"" + ns + "\" xmlns=\"" + ns + "\" " +
311  "elementFormDefault=\"qualified\"";
312  }
313 
314  // Print the XSD header
315  f_xsd_ <<
316  "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" << endl <<
317  "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" << ns << ">" << endl <<
318  endl <<
319  "<!-- Yo yo yo, this XSD woz be generated by Thrift. -->" << endl <<
320  endl;
321 
322  // Print out the type definitions
323  indent(f_xsd_) << s_xsd_types_.str();
324 
325  // Keep a list of all the possible exceptions that might get thrown
326  map<string, t_struct*> all_xceptions;
327 
328  // List the elements that you might actually get
329  vector<t_function*> functions = tservice->get_functions();
330  vector<t_function*>::iterator f_iter;
331  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
332  string elemname = (*f_iter)->get_name() + "_response";
333  t_type* returntype = (*f_iter)->get_returntype();
334  generate_element(f_xsd_, elemname, returntype);
335  f_xsd_ << endl;
336 
337  t_struct* xs = (*f_iter)->get_xceptions();
338  const std::vector<t_field*>& xceptions = xs->get_members();
339  vector<t_field*>::const_iterator x_iter;
340  for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
341  all_xceptions[(*x_iter)->get_name()] = (t_struct*)((*x_iter)->get_type());
342  }
343  }
344 
345  map<string, t_struct*>::iterator ax_iter;
346  for (ax_iter = all_xceptions.begin(); ax_iter != all_xceptions.end(); ++ax_iter) {
347  generate_element(f_xsd_, ax_iter->first, ax_iter->second);
348  }
349 
350  // Close the XSD document
351  f_xsd_ << endl << "</xsd:schema>" << endl;
352  f_xsd_.close();
353 }
354 
356  if (ttype->is_typedef()) {
357  return ttype->get_name();
358  }
359 
360  if (ttype->is_base_type()) {
361  return xsd(base_type_name(((t_base_type*)ttype)->get_base()));
362  }
363 
364  if (ttype->is_enum()) {
365  return xsd("int");
366  }
367 
368  if (ttype->is_struct() || ttype->is_xception()) {
369  return ttype->get_name();
370  }
371 
372 #ifdef SANDESH
373  if (ttype->is_sandesh()) {
374  return ttype->get_name();
375  }
376 #endif
377 
378  return "container";
379 }
380 
388  switch (tbase) {
390  return "void";
391 #ifdef SANDESH
392  case t_base_type::TYPE_STATIC_CONST_STRING:
393 #endif
395  return "string";
397  return "boolean";
399  return "byte";
401  return "short";
403  return "int";
405  return "long";
407  return "decimal";
408  default:
409  throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase);
410  }
411 }
412 
413 THRIFT_REGISTER_GENERATOR(xsd, "XSD", "")
virtual bool is_xception() const
Definition: t_type.h:74
t_type * get_type() const
Definition: t_typedef.h:42
Definition: t_enum.h:30
std::string base_type_name(t_base_type::t_base tbase)
Definition: t_type.h:48
std::ofstream f_xsd_
static std::string t_base_name(t_base tbase)
Definition: t_base_type.h:218
virtual bool is_enum() const
Definition: t_type.h:72
virtual bool is_base_type() const
Definition: t_type.h:61
void generate_typedef(t_typedef *ttypedef)
const members_type & get_members()
virtual ~t_xsd_generator()
virtual bool is_container() const
Definition: t_type.h:75
virtual bool is_typedef() const
Definition: t_type.h:71
#define MKDIR(x)
Definition: platform.h:28
std::string xsd(std::string in)
std::ofstream f_php_
virtual bool is_void() const
Definition: t_type.h:60
void generate_enum(t_enum *tenum)
void generate_struct(t_struct *tstruct)
const std::vector< t_function * > & get_functions() const
Definition: t_service.h:56
std::ostringstream s_xsd_types_
virtual const std::string & get_name() const
Definition: t_type.h:56
virtual bool is_list() const
Definition: t_type.h:76
virtual bool is_struct() const
Definition: t_type.h:73
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 type_name(t_type *ttype)
Definition: t_list.h:29
t_xsd_generator(t_program *program, const std::map< std::string, std::string > &parsed_options, const std::string &option_string)
void generate_service(t_service *tservice)
virtual bool is_string() const
Definition: t_type.h:62
#define THRIFT_REGISTER_GENERATOR(language, long_name, doc)
std::string ns(std::string in, std::string ns)
bool get_xsd_all() const
Definition: t_struct.h:65