Adding XSD attribute support

Reviewed By: dave


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664974 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_php_generator.cc b/compiler/cpp/src/generate/t_php_generator.cc
index 903aac0..936156b 100644
--- a/compiler/cpp/src/generate/t_php_generator.cc
+++ b/compiler/cpp/src/generate/t_php_generator.cc
@@ -844,9 +844,14 @@
   f_service_ <<
     "class " << service_name_ << "Rest" << extends_if << " {" << endl;
   indent_up();
+
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "protected $impl_;" << endl <<
+      endl;
+  }
+
   f_service_ <<
-    indent() << "private $impl_;" << endl <<
-    endl <<
     indent() << "public function __construct($impl) {" << endl <<
     indent() << "  $this->impl_ = $impl;" << endl <<
     indent() << "}" << endl <<
@@ -865,8 +870,9 @@
       while (atype->is_typedef()) {
         atype = ((t_typedef*)atype)->get_type();
       }
+      string req = "$request['" + (*a_iter)->get_name() + "']";
       f_service_ <<
-        indent() << "$" << (*a_iter)->get_name() << " = $request['" << (*a_iter)->get_name() << "'];" << endl;
+        indent() << "$" << (*a_iter)->get_name() << " = isset(" << req << ") ? " << req << " : null;" << endl;
       if (atype->is_string() &&
           ((t_base_type*)atype)->is_string_list()) {
         f_service_ << 
diff --git a/compiler/cpp/src/generate/t_rb_generator.cc b/compiler/cpp/src/generate/t_rb_generator.cc
index 4636e43..d89bbb0 100644
--- a/compiler/cpp/src/generate/t_rb_generator.cc
+++ b/compiler/cpp/src/generate/t_rb_generator.cc
@@ -514,7 +514,6 @@
   generate_service_client(tservice);
   generate_service_server(tservice);
   generate_service_helpers(tservice);
-  generate_service_remote(tservice);
 
   indent_down();
   f_service_ << "end" << endl <<
@@ -750,143 +749,6 @@
 }
 
 /**
- * Generates a command line tool for making remote requests
- *
- * @param tservice The service to generate a remote for.
- */
-void t_rb_generator::generate_service_remote(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter; 
-
-  string f_remote_name = string(T_RB_DIR)+"/"+service_name_+"-remote";
-  ofstream f_remote;
-  f_remote.open(f_remote_name.c_str());
-
-  f_remote <<
-    "#!/usr/bin/ruby" << endl <<
-    rb_autogen_comment() << endl <<
-    "import sys" << endl <<
-    "import pprint" << endl <<
-    "from thrift.transport import TTransport" << endl <<
-    "from thrift.transport import TSocket" << endl <<
-    "from thrift.protocol import TBinaryProtocol" << endl <<
-    endl;
-
-  f_remote <<
-    "import " << service_name_ << endl <<
-    "from " << program_name_ << "_types import *" << endl << 
-    endl;
-
-  f_remote <<
-    "if len(sys.argv) <= 1 or sys.argv[1] == '--help':" << endl <<
-    "  print ''" << endl <<
-    "  print 'Usage: ' + sys.argv[0] + ' [-h host:port] [-f[ramed]] function [arg1,[arg2...]]'" << endl <<
-    "  print ''" << endl <<
-    "  print 'Functions:'" << endl;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_remote <<
-      "  print '  " << (*f_iter)->get_returntype()->get_name() << " " << (*f_iter)->get_name() << "(";
-    t_struct* arg_struct = (*f_iter)->get_arglist();
-    const std::vector<t_field*>& args = arg_struct->get_members();
-    vector<t_field*>::const_iterator a_iter;
-    int num_args = args.size();
-    bool first = true;
-    for (int i = 0; i < num_args; ++i) {
-      if (first) {
-        first = false;
-      } else {
-        f_remote << ", ";
-      }
-      f_remote << 
-        args[i]->get_type()->get_name() << " " << args[i]->get_name();
-    }
-    f_remote << ")'" << endl;
-  }  
-  f_remote <<
-    "  print ''" << endl <<
-    "  sys.exit(0)" << endl <<
-    endl;
-
-  f_remote <<
-    "pp = pprint.PrettyPrinter(indent = 2)" << endl <<
-    "host = 'localhost'" << endl <<
-    "port = 9090" << endl <<
-    "framed = False" << endl <<
-    "argi = 1" << endl <<
-    endl <<
-    "if sys.argv[1] == '-h':" << endl <<
-    "  parts = sys.argv[2].split(':') " << endl <<
-    "  host = parts[0]" << endl <<
-    "  port = int(parts[1])" << endl <<
-    "  argi = 3" << endl <<
-    endl <<
-    "if sys.argv[argi] == '-f' or sys.argv[argi] == '-framed':" << endl <<
-    "  framed = True" << endl <<
-    "  argi += 1" << endl <<
-    endl <<
-    "cmd = sys.argv[argi]" << endl <<
-    "args = sys.argv[argi+1:]" << endl <<
-    endl <<
-    "socket = TSocket.TSocket(host, port)" << endl <<
-    "if framed:" << endl <<
-    "  transport = TTransport.TFramedTransport(socket)" << endl <<
-    "else:" << endl <<
-    "  transport = TTransport.TBufferedTransport(socket)" << endl <<
-    "protocol = TBinaryProtocol.TBinaryProtocol(transport)" << endl <<
-    "client = " << service_name_ << ".Client(protocol)" << endl <<
-    "transport.open()" << endl <<
-    endl;
-  
-  // Generate the dispatch methods
-  bool first = true;
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    if (first) {
-      first = false;
-    } else {
-      f_remote << "el";
-    }
-
-    t_struct* arg_struct = (*f_iter)->get_arglist();
-    const std::vector<t_field*>& args = arg_struct->get_members();
-    vector<t_field*>::const_iterator a_iter;
-    int num_args = args.size();
-
-    f_remote <<
-      "if cmd == '" << (*f_iter)->get_name() << "':" << endl <<
-      "  if len(args) != " << num_args << ":" << endl <<
-      "    print '" << (*f_iter)->get_name() << " requires " << num_args << " args'" << endl <<
-      "    sys.exit(1)" << endl <<
-      "  pp.pprint(client." << (*f_iter)->get_name() << "(";
-    for (int i = 0; i < num_args; ++i) {
-      if (args[i]->get_type()->is_string()) {
-        f_remote << "args[" << i << "],";
-      } else {
-        f_remote << "eval(args[" << i << "]),";
-      }
-    }
-    f_remote << "))" << endl;
-   
-    f_remote << endl;
-  }
-
-  f_remote << "transport.close()" << endl;
-  
-  // Close service file
-  f_remote.close();
-  
-  // Make file executable, love that bitwise OR action
-  chmod(f_remote_name.c_str(),
-        S_IRUSR |
-        S_IWUSR |
-        S_IXUSR |
-        S_IRGRP |
-        S_IXGRP |
-        S_IROTH |
-        S_IXOTH);
-}
-
-/**
  * Generates a service server definition.
  *
  * @param tservice The service to generate a server for.
diff --git a/compiler/cpp/src/generate/t_rb_generator.h b/compiler/cpp/src/generate/t_rb_generator.h
index bb74db6..97c0834 100644
--- a/compiler/cpp/src/generate/t_rb_generator.h
+++ b/compiler/cpp/src/generate/t_rb_generator.h
@@ -57,7 +57,6 @@
   void generate_service_helpers   (t_service*  tservice);
   void generate_service_interface (t_service* tservice);
   void generate_service_client    (t_service* tservice);
-  void generate_service_remote    (t_service* tservice);
   void generate_service_server    (t_service* tservice);
   void generate_process_function  (t_service* tservice, t_function* tfunction);
 
diff --git a/compiler/cpp/src/generate/t_xsd_generator.cc b/compiler/cpp/src/generate/t_xsd_generator.cc
index 7f53f9f..49550b1 100644
--- a/compiler/cpp/src/generate/t_xsd_generator.cc
+++ b/compiler/cpp/src/generate/t_xsd_generator.cc
@@ -48,7 +48,7 @@
   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_optional() || xsd_all, false);
+    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);
   } 
 
   indent_down();
@@ -66,46 +66,80 @@
 void t_xsd_generator::generate_element(ostream& out,
                                        string name,
                                        t_type* ttype,
+                                       vector<string> attrs,
                                        bool optional,
                                        bool list_element) {
   string sminOccurs = (optional || list_element) ? " minOccurs=\"0\"" : "";
   string smaxOccurs = list_element ? " maxOccurs=\"unbounded\"" : "";
-
   string soptional = sminOccurs + smaxOccurs;
 
   if (ttype->is_void() || ttype->is_list()) {
     indent(out) <<
       "<xsd:element name=\"" << name << "\"" << soptional << ">" << endl;
     indent_up();
-    if (ttype->is_void()) {
+    if (attrs.size() == 0 && ttype->is_void()) {
       indent(out) << 
         "<xsd:complexType />" << endl;
-    } else if (ttype->is_list()) {
-      indent(out) << "<xsd:complexType>" << endl;
+    } else {
+      indent(out) <<
+        "<xsd:complexType>" << endl;
       indent_up();
-      indent(out) << "<xsd:sequence>" << 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);
+      
+      vector<string>::iterator a_iter;
+      for (a_iter = attrs.begin(); a_iter != attrs.end(); ++a_iter) {
+        indent(out) << "<xsd:attribute name=\"" << (*a_iter) << "\" type=\"xsd:boolean\" />" << endl;
       }
-      f_php_ << "$GLOBALS['" << program_->get_name() << "_xsd_elt_" << name << "'] = '" << subname << "';" << endl;
-      generate_element(out, subname, subtype, false, true); 
+      
+      if (ttype->is_list()) {
+        indent(out) << "<xsd:attribute name=\"list\" type=\"xsd:boolean\" />" << endl;       
+        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, vector<string>(), false, true);
+        indent_down();
+        indent(out) << "</xsd:sequence>" << endl;
+      }
       indent_down();
-      indent(out) << "</xsd:sequence>" << endl;
-      indent(out) << "<xsd:attribute name=\"list\" type=\"xsd:boolean\" />" << endl;
-      indent_down();
-      indent(out) << "</xsd:complexType>" << endl;
+      indent(out) <<
+        "</xsd:complexType>" << endl;
     }
     indent_down();
     indent(out) <<
       "</xsd:element>" << endl;
   } else {
-    indent(out) <<
-      "<xsd:element name=\"" << name << "\"" << soptional << " type=\"" << type_name(ttype) << "\" />" << endl;
+    if (attrs.size() == 0) {
+      indent(out) <<
+        "<xsd:element name=\"" << name << "\"" << soptional << " type=\"" << type_name(ttype) << "\" />" << endl;
+    } else {
+      // Wow, all this work for a SIMPLE TYPE with attributes?!?!?!
+      indent(out) << "<xsd:element name=\"" << name << "\"" << soptional << ">" << 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();
+      vector<string>::iterator a_iter;
+      for (a_iter = attrs.begin(); a_iter != attrs.end(); ++a_iter) {
+        indent(out) << "<xsd:attribute name=\"" << (*a_iter) << "\" type=\"xsd:boolean\" />" << 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;
+    }
   }
 }
 
@@ -140,7 +174,7 @@
   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, false, false);
+    generate_element(f_xsd_, elemname, returntype);
     f_xsd_ << endl;
 
     t_struct* xs = (*f_iter)->get_xceptions();
@@ -153,7 +187,7 @@
 
   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, false, false);
+    generate_element(f_xsd_, ax_iter->first, ax_iter->second);
   }
 
   // Close the XSD document
diff --git a/compiler/cpp/src/generate/t_xsd_generator.h b/compiler/cpp/src/generate/t_xsd_generator.h
index 0413670..7a60283 100644
--- a/compiler/cpp/src/generate/t_xsd_generator.h
+++ b/compiler/cpp/src/generate/t_xsd_generator.h
@@ -40,7 +40,7 @@
 
  private:
 
-  void generate_element(std::ostream& out, std::string name, t_type* ttype, bool optional, bool list_element);
+  void generate_element(std::ostream& out, std::string name, t_type* ttype, std::vector<std::string> attrs=std::vector<std::string>(), bool optional=false, bool list_element=false);
 
   std::string ns(std::string in, std::string ns) {
     return ns + ":" + in;
diff --git a/compiler/cpp/src/parse/t_field.h b/compiler/cpp/src/parse/t_field.h
index 03d4ba7..090426a 100644
--- a/compiler/cpp/src/parse/t_field.h
+++ b/compiler/cpp/src/parse/t_field.h
@@ -39,6 +39,14 @@
     return key_;
   }
 
+  void set_value(t_const_value* value) {
+    value_ = value;
+  }
+
+  t_const_value* get_value() {
+    return value_;
+  }
+
   void set_xsd_optional(bool xsd_optional) {
     xsd_optional_ = xsd_optional;
   }
@@ -47,12 +55,12 @@
     return xsd_optional_;
   }
 
-  void set_value(t_const_value* value) {
-    value_ = value;
+  void add_xsd_attr(std::string attr) {
+    xsd_attrs_.push_back(attr);
   }
 
-  t_const_value* get_value() {
-    return value_;
+  const std::vector<std::string>& get_xsd_attrs() {
+    return xsd_attrs_;
   }
 
   const std::string& get_doc() const {
@@ -75,6 +83,7 @@
   t_const_value* value_;
 
   bool xsd_optional_;
+  std::vector<std::string> xsd_attrs_;
 
   std::string doc_;                                           
   bool has_doc_;                                              
diff --git a/compiler/cpp/src/thriftl.ll b/compiler/cpp/src/thriftl.ll
index 5450ad2..5486ada 100644
--- a/compiler/cpp/src/thriftl.ll
+++ b/compiler/cpp/src/thriftl.ll
@@ -64,6 +64,7 @@
 "xsd_all"       { return tok_xsd_all;       }
 "xsd_optional"  { return tok_xsd_optional;  }
 "xsd_namespace" { return tok_xsd_namespace; }
+"xsd_attrs"     { return tok_xsd_attrs;     }
 "include"       { return tok_include;       }
 
 "void"          { return tok_void;          }
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
index 9c38996..a53d002 100644
--- a/compiler/cpp/src/thrifty.yy
+++ b/compiler/cpp/src/thrifty.yy
@@ -71,6 +71,7 @@
 %token tok_xsd_all
 %token tok_xsd_optional
 %token tok_xsd_namespace
+%token tok_xsd_attrs
 
 /**
  * Base datatype keywords
@@ -154,6 +155,7 @@
 %type<tbool>     Async
 %type<tbool>     XsdAll
 %type<tbool>     XsdOptional
+%type<id>        XsdAttributes
 %type<id>        CppType
 
 %type<tdoc>      DocTextOptional
@@ -515,6 +517,16 @@
       $$ = false;
     }
 
+XsdAttributes:
+  tok_xsd_attrs tok_identifier
+    {
+      $$ = $2;
+    }
+|
+    {
+      $$ = NULL;
+    }
+
 Xception:
   tok_xception tok_identifier '{' FieldList '}'
     {
@@ -619,11 +631,11 @@
     }
 
 Field:
-  DocTextOptional FieldIdentifier FieldType tok_identifier FieldValue XsdOptional CommaOrSemicolonOptional
+  DocTextOptional FieldIdentifier FieldType tok_identifier FieldValue XsdOptional XsdAttributes CommaOrSemicolonOptional
     {
       pdebug("tok_int_constant : Field -> FieldType tok_identifier");
       if ($2 < 0) {
-        pwarning(2, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $3);
+        pwarning(2, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $4);
       }
       $$ = new t_field($3, $4, $2);
       if ($5 != NULL) {
@@ -634,6 +646,9 @@
       if ($1 != NULL) {
         $$->set_doc($1);
       }
+      if ($7 != NULL) {
+        $$->add_xsd_attr($7);
+      }
     }
 
 FieldIdentifier: