THRIFT-2644 Haxe support
Client: Haxe
Patch: Jens Geyer
This closes #214
diff --git a/.gitignore b/.gitignore
index d0f93f7..e9d5d9a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -229,6 +229,7 @@
/test/go/src/code.google.com/
/test/go/src/gen/
/test/go/src/thrift
+/test/haxe/bin
/test/hs/TestClient
/test/hs/TestServer
/test/py.twisted/_trial_temp/
@@ -250,6 +251,7 @@
/tutorial/go/src/shared
/tutorial/go/src/tutorial
/tutorial/go/src/git.apache.org
+/tutorial/haxe/bin
/tutorial/hs/dist/
/tutorial/java/build/
/tutorial/js/build/
diff --git a/compiler/cpp/CMakeLists.txt b/compiler/cpp/CMakeLists.txt
index 606bfcd..4ed8b2b 100644
--- a/compiler/cpp/CMakeLists.txt
+++ b/compiler/cpp/CMakeLists.txt
@@ -120,6 +120,7 @@
THRIFT_ADD_COMPILER(cpp "Enable compiler for C++" ON)
THRIFT_ADD_COMPILER(java "Enable compiler for Java" ON)
THRIFT_ADD_COMPILER(as3 "Enable compiler for ActionScript 3" ON)
+THRIFT_ADD_COMPILER(haxe "Enable compiler for Haxe" ON)
THRIFT_ADD_COMPILER(csharp "Enable compiler for C#" ON)
THRIFT_ADD_COMPILER(py "Enable compiler for Python 2.0" ON)
THRIFT_ADD_COMPILER(rb "Enable compiler for Ruby" ON)
diff --git a/compiler/cpp/Makefile.am b/compiler/cpp/Makefile.am
index ee28d0c..d3dadab 100644
--- a/compiler/cpp/Makefile.am
+++ b/compiler/cpp/Makefile.am
@@ -72,6 +72,7 @@
src/generate/t_java_generator.cc \
src/generate/t_json_generator.cc \
src/generate/t_as3_generator.cc \
+ src/generate/t_haxe_generator.cc \
src/generate/t_csharp_generator.cc \
src/generate/t_py_generator.cc \
src/generate/t_rb_generator.cc \
diff --git a/compiler/cpp/compiler.vcxproj b/compiler/cpp/compiler.vcxproj
index 1f0bee3..f49106f 100644
--- a/compiler/cpp/compiler.vcxproj
+++ b/compiler/cpp/compiler.vcxproj
@@ -60,7 +60,8 @@
<ClCompile Include="src\generate\t_erl_generator.cc" />
<ClCompile Include="src\generate\t_generator.cc" />
<ClCompile Include="src\generate\t_go_generator.cc" />
- <ClCompile Include="src\generate\t_gv_generator.cc" />
+ <ClCompile Include="src\generate\t_gv_generator.cc" />
+ <ClCompile Include="src\generate\t_haxe_generator.cc" />
<ClCompile Include="src\generate\t_hs_generator.cc" />
<ClCompile Include="src\generate\t_html_generator.cc" />
<ClCompile Include="src\generate\t_javame_generator.cc" />
diff --git a/compiler/cpp/compiler.vcxproj.filters b/compiler/cpp/compiler.vcxproj.filters
index b31918e..c400f7e 100644
--- a/compiler/cpp/compiler.vcxproj.filters
+++ b/compiler/cpp/compiler.vcxproj.filters
@@ -124,6 +124,9 @@
<ClCompile Include="src\generate\t_gv_generator.cc">
<Filter>generate</Filter>
</ClCompile>
+ <ClCompile Include="src\generate\t_haxe_generator.cc">
+ <Filter>generate</Filter>
+ </ClCompile>
<ClCompile Include="src\generate\t_hs_generator.cc">
<Filter>generate</Filter>
</ClCompile>
diff --git a/compiler/cpp/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc
new file mode 100644
index 0000000..24457e5
--- /dev/null
+++ b/compiler/cpp/src/generate/t_haxe_generator.cc
@@ -0,0 +1,2949 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <sstream>
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <cctype>
+
+#include <sys/stat.h>
+#include <stdexcept>
+
+#include "platform.h"
+#include "t_oop_generator.h"
+
+using std::map;
+using std::ofstream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * Haxe code generator.
+ *
+ */
+class t_haxe_generator : public t_oop_generator {
+ public:
+ t_haxe_generator(
+ t_program* program,
+ const std::map<std::string, std::string>& parsed_options,
+ const std::string& option_string)
+ : t_oop_generator(program)
+ {
+ (void) option_string;
+ std::map<std::string, std::string>::const_iterator iter;
+
+ iter = parsed_options.find("callbacks");
+ callbacks_ = (iter != parsed_options.end());
+
+ out_dir_base_ = "gen-haxe";
+ }
+
+ /**
+ * Init and close methods
+ */
+
+ void init_generator();
+ void close_generator();
+
+ void generate_consts(std::vector<t_const*> consts);
+
+ /**
+ * Program-level generation functions
+ */
+
+ void generate_typedef (t_typedef* ttypedef);
+ void generate_enum (t_enum* tenum);
+ void generate_struct (t_struct* tstruct);
+ void generate_xception(t_struct* txception);
+ void generate_service (t_service* tservice);
+
+ void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool in_static, bool defval=false);
+ std::string render_const_value(ofstream& out, std::string name, t_type* type, t_const_value* value);
+
+ /**
+ * Service-level generation functions
+ */
+
+ void generate_haxe_struct(t_struct* tstruct, bool is_exception);
+
+ void generate_haxe_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool in_class=false, bool is_result=false);
+ //removed -- equality,compare_to
+ void generate_haxe_struct_reader(std::ofstream& out, t_struct* tstruct);
+ void generate_haxe_validator(std::ofstream& out, t_struct* tstruct);
+ void generate_haxe_struct_result_writer(std::ofstream& out, t_struct* tstruct);
+ void generate_haxe_struct_writer(std::ofstream& out, t_struct* tstruct);
+ void generate_haxe_struct_tostring(std::ofstream& out, t_struct* tstruct);
+ void generate_haxe_meta_data_map(std::ofstream& out, t_struct* tstruct);
+ void generate_field_value_meta_data(std::ofstream& out, t_type* type);
+ std::string get_haxe_type_string(t_type* type);
+ void generate_reflection_setters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name);
+ void generate_reflection_getters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name);
+ void generate_generic_field_getters_setters(std::ofstream& out, t_struct* tstruct);
+ void generate_generic_isset_method(std::ofstream& out, t_struct* tstruct);
+ void generate_property_getters_setters(std::ofstream& out, t_struct* tstruct);
+
+ void generate_function_helpers(t_function* tfunction);
+ std::string get_cap_name(std::string name);
+ std::string generate_isset_check(t_field* field);
+ std::string generate_isset_check(std::string field);
+ void generate_isset_set(ofstream& out, t_field* field);
+ //removed std::string isset_field_id(t_field* field);
+
+ void generate_service_interface (t_service* tservice);
+ void generate_service_helpers (t_service* tservice);
+ void generate_service_client (t_service* tservice);
+ void generate_service_server (t_service* tservice);
+ void generate_process_function (t_service* tservice, t_function* tfunction);
+ void generate_service_method_signature(t_function* tfunction, bool is_interface);
+
+ /**
+ * Serialization constructs
+ */
+
+ void generate_deserialize_field (std::ofstream& out,
+ t_field* tfield,
+ std::string prefix="");
+
+ void generate_deserialize_struct (std::ofstream& out,
+ t_struct* tstruct,
+ std::string prefix="");
+
+ void generate_deserialize_container (std::ofstream& out,
+ t_type* ttype,
+ std::string prefix="");
+
+ void generate_deserialize_set_element (std::ofstream& out,
+ t_set* tset,
+ std::string prefix="");
+
+ void generate_deserialize_map_element (std::ofstream& out,
+ t_map* tmap,
+ std::string prefix="");
+
+ void generate_deserialize_list_element (std::ofstream& out,
+ t_list* tlist,
+ std::string prefix="");
+
+ void generate_serialize_field (std::ofstream& out,
+ t_field* tfield,
+ std::string prefix="");
+
+ void generate_serialize_struct (std::ofstream& out,
+ t_struct* tstruct,
+ std::string prefix="");
+
+ void generate_serialize_container (std::ofstream& out,
+ t_type* ttype,
+ std::string prefix="");
+
+ void generate_serialize_map_element (std::ofstream& out,
+ t_map* tmap,
+ std::string iter,
+ std::string map);
+
+ void generate_serialize_set_element (std::ofstream& out,
+ t_set* tmap,
+ std::string iter);
+
+ void generate_serialize_list_element (std::ofstream& out,
+ t_list* tlist,
+ std::string iter);
+
+ void generate_haxe_doc (std::ofstream& out,
+ t_doc* tdoc);
+
+ void generate_haxe_doc (std::ofstream& out,
+ t_function* tdoc);
+
+ /**
+ * Helper rendering functions
+ */
+
+ std::string haxe_package();
+ std::string haxe_type_imports();
+ std::string haxe_thrift_imports();
+ std::string haxe_thrift_gen_imports(t_struct* tstruct, string& imports);
+ std::string haxe_thrift_gen_imports(t_service* tservice);
+ std::string type_name(t_type* ttype, bool in_container=false, bool in_init=false);
+ std::string base_type_name(t_base_type* tbase, bool in_container=false);
+ std::string declare_field(t_field* tfield, bool init=false);
+ std::string function_signature_callback(t_function* tfunction);
+ std::string function_signature_normal(t_function* tfunction);
+ std::string argument_list(t_struct* tstruct);
+ std::string type_to_enum(t_type* ttype);
+ std::string get_enum_class_name(t_type* type);
+ string generate_service_method_onsuccess(t_function* tfunction, bool as_type, bool omit_name);
+ void generate_service_method_signature_callback(t_function* tfunction, bool is_interface);
+ void generate_service_method_signature_normal(t_function* tfunction, bool is_interface);
+
+ bool type_can_be_null(t_type* ttype) {
+ ttype = get_true_type(ttype);
+
+ if (ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string()) {
+ return true;
+ }
+
+ if (ttype->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_STRING:
+ case t_base_type::TYPE_I64:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ std::string constant_name(std::string name);
+
+ private:
+ bool callbacks_;
+
+ /**
+ * File streams
+ */
+
+ std::string package_name_;
+ std::ofstream f_service_;
+ std::string package_dir_;
+
+};
+
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_haxe_generator::init_generator() {
+ // Make output directory
+ MKDIR(get_out_dir().c_str());
+ package_name_ = program_->get_namespace("haxe");
+
+ string dir = package_name_;
+ string subdir = get_out_dir();
+ string::size_type loc;
+ while ((loc = dir.find(".")) != string::npos) {
+ subdir = subdir + "/" + dir.substr(0, loc);
+ MKDIR(subdir.c_str());
+ dir = dir.substr(loc+1);
+ }
+ if (dir.size() > 0) {
+ subdir = subdir + "/" + dir;
+ MKDIR(subdir.c_str());
+ }
+
+ package_dir_ = subdir;
+}
+
+/**
+ * Packages the generated file
+ *
+ * @return String of the package, i.e. "package org.apache.thriftdemo;"
+ */
+string t_haxe_generator::haxe_package() {
+ if (!package_name_.empty()) {
+ return string("package ") + package_name_;
+ }
+ return "package";
+}
+
+/**
+ * Prints standard haxe imports
+ *
+ * @return List of imports for haxe types that are used in here
+ */
+string t_haxe_generator::haxe_type_imports() {
+ return
+ string() +
+ "import org.apache.thrift.helper.*;\n" +
+ "import haxe.io.Bytes;\n" +
+ "import haxe.ds.IntMap;\n" +
+ "import haxe.ds.StringMap;\n" +
+ "import haxe.ds.ObjectMap;\n" +
+ "\n" +
+ "#if flash\n" +
+ "import flash.errors.ArgumentError;\n" +
+ "#end\n" +
+ "\n";
+}
+
+/**
+ * Prints standard haxe imports
+ *
+ * @return List of imports necessary for thrift
+ */
+string t_haxe_generator::haxe_thrift_imports() {
+ return
+ string() +
+ "import org.apache.thrift.*;\n" +
+ "import org.apache.thrift.meta_data.*;\n" +
+ "import org.apache.thrift.protocol.*;\n" +
+ "\n";
+}
+
+/**
+ * Prints imports needed for a given type
+ *
+ * @return List of imports necessary for a given t_struct
+ */
+string t_haxe_generator::haxe_thrift_gen_imports(t_struct* tstruct, string& imports) {
+
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
+
+ //For each type check if it is from a different namespace
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ t_program* program = (*m_iter)->get_type()->get_program();
+ if (program != NULL && program != program_) {
+ string package = program->get_namespace("haxe");
+ if (!package.empty()) {
+ if (imports.find(package + "." + (*m_iter)->get_type()->get_name()) == string::npos) {
+ imports.append("import " + package + "." + (*m_iter)->get_type()->get_name() + ";\n");
+ }
+ }
+ }
+ }
+ return imports;
+}
+
+
+/**
+ * Prints imports needed for a given type
+ *
+ * @return List of imports necessary for a given t_service
+ */
+string t_haxe_generator::haxe_thrift_gen_imports(t_service* tservice) {
+ string imports;
+ const vector<t_function*>& functions = tservice->get_functions();
+ vector<t_function*>::const_iterator f_iter;
+
+ //For each type check if it is from a different namespace
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ t_program* program = (*f_iter)->get_returntype()->get_program();
+ if (program != NULL && program != program_) {
+ string package = program->get_namespace("haxe");
+ if (!package.empty()) {
+ if (imports.find(package + "." + (*f_iter)->get_returntype()->get_name()) == string::npos) {
+ imports.append("import " + package + "." + (*f_iter)->get_returntype()->get_name() + ";\n");
+ }
+ }
+ }
+
+ haxe_thrift_gen_imports((*f_iter)->get_arglist(), imports);
+ haxe_thrift_gen_imports((*f_iter)->get_xceptions(), imports);
+
+ }
+
+ return imports;
+
+}
+
+/**
+ * Nothing in haxe
+ */
+void t_haxe_generator::close_generator() {}
+
+/**
+ * Generates a typedef. This is not done in haxe, since it does
+ * not support arbitrary name replacements, and it'd be a wacky waste
+ * of overhead to make wrapper classes.
+ *
+ * @param ttypedef The type definition
+ */
+void t_haxe_generator::generate_typedef(t_typedef* ttypedef) {
+ (void) ttypedef;
+}
+
+/**
+ * Enums are a class with a set of static constants.
+ *
+ * @param tenum The enumeration
+ */
+void t_haxe_generator::generate_enum(t_enum* tenum) {
+ // Make output file
+ string f_enum_name = package_dir_+"/"+(tenum->get_name()) + ".hx";
+ ofstream f_enum;
+ f_enum.open(f_enum_name.c_str());
+
+ // Comment and package it
+ f_enum <<
+ autogen_comment() <<
+ haxe_package() << ";" << endl;
+
+ // Add haxe imports
+ f_enum << string() +
+ "import org.apache.thrift.helper.*;" << endl <<
+ endl;
+
+ indent(f_enum) <<
+ "class " << tenum->get_name() << " ";
+ scope_up(f_enum);
+
+ vector<t_enum_value*> constants = tenum->get_constants();
+ vector<t_enum_value*>::iterator c_iter;
+ for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+ int value = (*c_iter)->get_value();
+ indent(f_enum) <<
+ "public static inline var " << (*c_iter)->get_name() <<
+ " : Int = " << value << ";" << endl;
+ }
+
+ // Create a static Set with all valid values for this enum
+ f_enum << endl;
+
+ indent(f_enum) << "public static var VALID_VALUES = { new IntSet( [";
+ indent_up();
+ bool firstValue = true;
+ for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+ // populate set
+ f_enum << (firstValue ? "" : ", ") << (*c_iter)->get_name();
+ firstValue = false;
+ }
+ indent_down();
+ f_enum << "]); };" << endl;
+
+ indent(f_enum) << "public static var VALUES_TO_NAMES = { [";
+ indent_up();
+ firstValue = true;
+ for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+ f_enum << (firstValue ? "" : ",") << endl;
+ indent(f_enum) << (*c_iter)->get_name() << " => \"" << (*c_iter)->get_name() << "\"";
+ firstValue = false;
+ }
+ f_enum << endl;
+ indent_down();
+ indent(f_enum) << "]; };" << endl;
+
+ scope_down(f_enum); // end class
+
+ f_enum.close();
+}
+
+/**
+ * Generates a class that holds all the constants.
+ */
+void t_haxe_generator::generate_consts(std::vector<t_const*> consts) {
+ if (consts.empty()) {
+ return;
+ }
+
+ string f_consts_name = package_dir_+ "/" + program_name_ + "Constants.hx";
+ ofstream f_consts;
+ f_consts.open(f_consts_name.c_str());
+
+ // Print header
+ f_consts <<
+ autogen_comment() << haxe_package() << ";" << endl;
+
+ f_consts << endl;
+
+ f_consts << haxe_type_imports();
+
+
+
+ indent(f_consts) <<
+ "class " << program_name_ <<
+ "Constants {" << endl << endl;
+ indent_up();
+ vector<t_const*>::iterator c_iter;
+ for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+ print_const_value(f_consts,
+ (*c_iter)->get_name(),
+ (*c_iter)->get_type(),
+ (*c_iter)->get_value(),
+ false);
+ }
+ indent_down();
+ indent(f_consts) <<
+ "}" << endl;
+ f_consts.close();
+}
+
+void t_haxe_generator::print_const_value(std::ofstream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval) {
+ type = get_true_type(type);
+
+ indent(out);
+ if (!defval) {
+ out <<
+ (in_static ? "var " : "public static inline var ");
+ }
+ if (type->is_base_type()) {
+ string v2 = render_const_value(out, name, type, value);
+ out << name;
+ if (!defval) {
+ out << ":" << type_name(type);
+ }
+ out << " = " << v2 << ";" << endl << endl;
+ } else if (type->is_enum()) {
+ out << name;
+ if(!defval) {
+ out << ":" << type_name(type);
+ }
+ out << " = " << value->get_integer() << ";" << endl << endl;
+ } else if (type->is_struct() || type->is_xception()) {
+ const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+ vector<t_field*>::const_iterator f_iter;
+ const map<t_const_value*, t_const_value*>& val = value->get_map();
+ map<t_const_value*, t_const_value*>::const_iterator v_iter;
+ out << name << ":" << type_name(type) << " = new " << type_name(type, false, true) << "();" << endl;
+ if (!in_static) {
+ indent(out) << "{" << endl;
+ indent_up();
+ indent(out) << "new function() : Void {" << endl;
+ indent_up();
+ }
+ for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+ t_type* field_type = NULL;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+ field_type = (*f_iter)->get_type();
+ }
+ }
+ if (field_type == NULL) {
+ throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+ }
+ string val = render_const_value(out, name, field_type, v_iter->second);
+ indent(out) << name << ".";
+ out << v_iter->first->get_string() << " = " << val << ";" << endl;
+ }
+ if (!in_static) {
+ indent_down();
+ indent(out) << "}();" << endl;
+ indent_down();
+ indent(out) << "}" << endl;
+ }
+ out << endl;
+ } else if (type->is_map()) {
+ out << name;
+ if(!defval){
+ out << ":" << type_name(type);
+ }
+ out << " = new " << type_name(type, false, true) << "();" << endl;
+ if (!in_static) {
+ indent(out) << "{" << endl;
+ indent_up();
+ indent(out) << "new function() : Void {" << endl;
+ indent_up();
+ }
+ t_type* ktype = ((t_map*)type)->get_key_type();
+ t_type* vtype = ((t_map*)type)->get_val_type();
+ const map<t_const_value*, t_const_value*>& val = value->get_map();
+ map<t_const_value*, t_const_value*>::const_iterator v_iter;
+ for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+ string key = render_const_value(out, name, ktype, v_iter->first);
+ string val = render_const_value(out, name, vtype, v_iter->second);
+ indent(out) << name << "[" << key << "] = " << val << ";" << endl;
+ }
+ if (!in_static) {
+ indent_down();
+ indent(out) << "}();" << endl;
+ indent_down();
+ indent(out) << "}" << endl;
+ }
+ out << endl;
+ } else if (type->is_list() || type->is_set()) {
+ out << name;
+ if(!defval) {
+ out << ":" << type_name(type);
+ }
+ out << " = new " << type_name(type, false, true) << "();" << endl;
+ if (!in_static) {
+ indent(out) << "{" << endl;
+ indent_up();
+ indent(out) << "new function() : Void {" << endl;
+ indent_up();
+ }
+ t_type* etype;
+ if (type->is_list()) {
+ etype = ((t_list*)type)->get_elem_type();
+ } else {
+ etype = ((t_set*)type)->get_elem_type();
+ }
+ const vector<t_const_value*>& val = value->get_list();
+ vector<t_const_value*>::const_iterator v_iter;
+ for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+ string val = render_const_value(out, name, etype, *v_iter);
+ indent(out) << name << "." << (type->is_list() ? "push" : "add") << "(" << val << ");" << endl;
+ }
+ if (!in_static) {
+ indent_down();
+ indent(out) << "}();" << endl;
+ indent_down();
+ indent(out) << "}" << endl;
+ }
+ out << endl;
+ } else {
+ throw "compiler error: no const of type " + type->get_name();
+ }
+}
+
+string t_haxe_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
+ (void) name;
+ type = get_true_type(type);
+ std::ostringstream render;
+
+ if (type->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_STRING:
+ render << '"' << get_escaped_string(value) << '"';
+ break;
+ case t_base_type::TYPE_BOOL:
+ render << ((value->get_integer() > 0) ? "true" : "false");
+ break;
+ case t_base_type::TYPE_BYTE:
+ render << "(byte)" << value->get_integer();
+ break;
+ case t_base_type::TYPE_I16:
+ render << "(short)" << value->get_integer();
+ break;
+ case t_base_type::TYPE_I32:
+ render << value->get_integer();
+ break;
+ case t_base_type::TYPE_I64:
+ render << value->get_integer() << "L";
+ break;
+ case t_base_type::TYPE_DOUBLE:
+ if (value->get_type() == t_const_value::CV_INTEGER) {
+ render << "(double)" << value->get_integer();
+ } else {
+ render << value->get_double();
+ }
+ break;
+ default:
+ throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+ }
+ } else if (type->is_enum()) {
+ render << value->get_integer();
+ } else {
+ string t = tmp("tmp");
+ print_const_value(out, t, type, value, true);
+ render << t;
+ }
+
+ return render.str();
+}
+
+
+/**
+ * Generates a struct definition for a thrift data type. This is a class
+ * with data members, read(), write(), and an inner Isset class.
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_struct(t_struct* tstruct) {
+ generate_haxe_struct(tstruct, false);
+}
+
+/**
+ * Exceptions are structs, but they inherit from Exception
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_xception(t_struct* txception) {
+ generate_haxe_struct(txception, true);
+}
+
+
+/**
+ * Haxe struct definition.
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_haxe_struct(t_struct* tstruct,
+ bool is_exception) {
+ // Make output file
+ string f_struct_name = package_dir_+"/"+(tstruct->get_name()) + ".hx";
+ ofstream f_struct;
+ f_struct.open(f_struct_name.c_str());
+
+ f_struct <<
+ autogen_comment() <<
+ haxe_package() << ";" << endl;
+
+ f_struct << endl;
+
+ string imports;
+
+ f_struct <<
+ haxe_type_imports() <<
+ haxe_thrift_imports() <<
+ haxe_thrift_gen_imports(tstruct, imports) << endl;
+
+ generate_haxe_struct_definition(f_struct,
+ tstruct,
+ is_exception);
+
+ f_struct.close();
+}
+
+/**
+ * haxe struct definition. This has various parameters, as it could be
+ * generated standalone or inside another class as a helper. If it
+ * is a helper than it is a static class.
+ *
+ * @param tstruct The struct definition
+ * @param is_exception Is this an exception?
+ * @param in_class If inside a class, needs to be static class
+ * @param is_result If this is a result it needs a different writer
+ */
+void t_haxe_generator::generate_haxe_struct_definition(ofstream &out,
+ t_struct* tstruct,
+ bool is_exception,
+ bool in_class,
+ bool is_result) {
+ generate_haxe_doc(out, tstruct);
+
+ string clsname = get_cap_name( tstruct->get_name());
+
+ indent(out) <<
+ "class " << clsname << " ";
+
+ if (is_exception) {
+ out << "extends TException ";
+ }
+ out << "implements TBase ";
+
+ scope_up(out);
+ indent(out) << endl;
+
+ indent(out) <<
+ "static var STRUCT_DESC = { new TStruct(\"" << tstruct->get_name() << "\"); };" << endl;
+
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
+
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ indent(out) <<
+ "static var " << constant_name((*m_iter)->get_name()) <<
+ "_FIELD_DESC = { new TField(\"" << (*m_iter)->get_name() << "\", " <<
+ type_to_enum((*m_iter)->get_type()) << ", " <<
+ (*m_iter)->get_key() << "); };" << endl;
+ }
+ out << endl;
+
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ generate_haxe_doc(out, *m_iter);
+ //indent(out) << "private var _" << (*m_iter)->get_name() + " : " + type_name((*m_iter)->get_type()) << ";" << endl;
+ indent(out) << "@:isVar" << endl;
+ indent(out) << "public var " << (*m_iter)->get_name() + "(get,set) : " + type_name((*m_iter)->get_type()) << ";" << endl;
+ }
+
+ out << endl;
+
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ indent(out) << "inline static var " << upcase_string((*m_iter)->get_name()) << " : Int = " << (*m_iter)->get_key() << ";" << endl;
+ }
+
+ out << endl;
+
+ // Inner Isset class
+ if (members.size() > 0) {
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ if (!type_can_be_null((*m_iter)->get_type())){
+ indent(out) <<
+ "private var __isset_" << (*m_iter)->get_name() << " : Bool = false;" << endl;
+ }
+ }
+ }
+
+ out << endl;
+
+
+ // Static initializer to populate global class to struct metadata map
+ if( false) {
+ // TODO: reactivate when needed
+ generate_haxe_meta_data_map(out, tstruct);
+ indent(out) << "{" << endl;
+ indent_up();
+ indent(out) << "FieldMetaData.addStructMetaDataMap(" << type_name(tstruct) << ", metaDataMap);" << endl;
+ indent_down();
+ indent(out) << "}" << endl;
+ indent(out) << "}" << endl;
+ }
+
+ // Default constructor
+ indent(out) <<
+ "public function new() {" << endl;
+ indent_up();
+ if( is_exception) {
+ indent(out) <<
+ "super();" << endl;
+ }
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ if ((*m_iter)->get_value() != NULL) {
+ indent(out) << "this." << (*m_iter)->get_name() << " = " << (*m_iter)->get_value()->get_integer() << ";" <<
+ endl;
+ }
+ }
+ indent_down();
+ indent(out) << "}" << endl << endl;
+
+ generate_property_getters_setters(out, tstruct);
+ generate_generic_field_getters_setters(out, tstruct);
+ generate_generic_isset_method(out, tstruct);
+
+ generate_haxe_struct_reader(out, tstruct);
+ if (is_result) {
+ generate_haxe_struct_result_writer(out, tstruct);
+ } else {
+ generate_haxe_struct_writer(out, tstruct);
+ }
+ generate_haxe_struct_tostring(out, tstruct);
+ generate_haxe_validator(out, tstruct);
+ scope_down(out);
+ out << endl;
+}
+
+/**
+ * Generates a function to read all the fields of the struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_haxe_struct_reader(ofstream& out,
+ t_struct* tstruct) {
+ out <<
+ indent() << "public function read( iprot : TProtocol) : Void {" << endl;
+ indent_up();
+
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ // Declare stack tmp variables and read struct header
+ out <<
+ indent() << "var field : TField;" << endl <<
+ indent() << "iprot.readStructBegin();" << endl;
+
+ // Loop over reading in fields
+ indent(out) <<
+ "while (true)" << endl;
+ scope_up(out);
+
+ // Read beginning field marker
+ indent(out) <<
+ "field = iprot.readFieldBegin();" << endl;
+
+ // Check for field STOP marker and break
+ indent(out) <<
+ "if (field.type == TType.STOP) { " << endl;
+ indent_up();
+ indent(out) <<
+ "break;" << endl;
+ indent_down();
+ indent(out) <<
+ "}" << endl;
+
+ // Switch statement on the field we are reading
+ indent(out) <<
+ "switch (field.id)" << endl;
+
+ scope_up(out);
+
+ // Generate deserialization code for known cases
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ indent(out) <<
+ "case " << upcase_string((*f_iter)->get_name()) << ":" << endl;
+ indent_up();
+ indent(out) <<
+ "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+ indent_up();
+
+ generate_deserialize_field(out, *f_iter, "this.");
+ generate_isset_set(out, *f_iter);
+ indent_down();
+ out <<
+ indent() << "} else { " << endl <<
+ indent() << " TProtocolUtil.skip(iprot, field.type);" << endl <<
+ indent() << "}" << endl;
+ indent_down();
+ }
+
+ // In the default case we skip the field
+ out <<
+ indent() << "default:" << endl <<
+ indent() << " TProtocolUtil.skip(iprot, field.type);" << endl;
+
+ scope_down(out);
+
+ // Read field end marker
+ indent(out) <<
+ "iprot.readFieldEnd();" << endl;
+
+ scope_down(out);
+
+ out <<
+ indent() << "iprot.readStructEnd();" << endl << endl;
+
+ // in non-beans style, check for required fields of primitive type
+ // (which can be checked here but not in the general validate method)
+ out << endl << indent() << "// check for required fields of primitive type, which can't be checked in the validate method" << endl;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) {
+ out <<
+ indent() << "if (!__isset_" << (*f_iter)->get_name() << ") {" << endl <<
+ indent() << " throw new TProtocolException(TProtocolException.UNKNOWN, \"Required field '" << (*f_iter)->get_name() << "' was not found in serialized data! Struct: \" + toString());" << endl <<
+ indent() << "}" << endl;
+ }
+ }
+
+ // performs various checks (e.g. check that all required fields are set)
+ indent(out) << "validate();" << endl;
+
+ indent_down();
+ out <<
+ indent() << "}" << endl <<
+ endl;
+}
+
+// generates haxe method to perform various checks
+// (e.g. check that all required fields are set)
+void t_haxe_generator::generate_haxe_validator(ofstream& out,
+ t_struct* tstruct){
+ indent(out) << "public function validate() : Void {" << endl;
+ indent_up();
+
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ out << indent() << "// check for required fields" << endl;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+ if (type_can_be_null((*f_iter)->get_type())) {
+ indent(out) << "if (" << (*f_iter)->get_name() << " == null) {" << endl;
+ indent(out) << " throw new TProtocolException(TProtocolException.UNKNOWN, \"Required field '" << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());" << endl;
+ indent(out) << "}" << endl;
+ } else {
+ indent(out) << "// alas, we cannot check '" << (*f_iter)->get_name() << "' because it's a primitive and you chose the non-beans generator." << endl;
+ }
+ }
+ }
+
+ // check that fields of type enum have valid values
+ out << indent() << "// check that fields of type enum have valid values" << endl;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ t_field* field = (*f_iter);
+ t_type* type = field->get_type();
+ // if field is an enum, check that its value is valid
+ if (type->is_enum()){
+ indent(out) << "if (" << generate_isset_check(field) << " && !" << get_enum_class_name(type) << ".VALID_VALUES.contains(" << field->get_name() << ")){" << endl;
+ indent_up();
+ indent(out) << "throw new TProtocolException(TProtocolException.UNKNOWN, \"The field '" << field->get_name() << "' has been assigned the invalid value \" + " << field->get_name() << ");" << endl;
+ indent_down();
+ indent(out) << "}" << endl;
+ }
+ }
+
+ indent_down();
+ indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_haxe_struct_writer(ofstream& out,
+ t_struct* tstruct) {
+ out <<
+ indent() << "public function write(oprot:TProtocol) : Void {" << endl;
+ indent_up();
+
+ string name = tstruct->get_name();
+ const vector<t_field*>& fields = tstruct->get_sorted_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ // performs various checks (e.g. check that all required fields are set)
+ indent(out) << "validate();" << endl << endl;
+
+ indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
+
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ bool null_allowed = type_can_be_null((*f_iter)->get_type());
+ if (null_allowed) {
+ out <<
+ indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
+ indent_up();
+ }
+
+ indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl;
+
+ // Write field contents
+ generate_serialize_field(out, *f_iter, "this.");
+
+ // Write field closer
+ indent(out) <<
+ "oprot.writeFieldEnd();" << endl;
+
+ if (null_allowed) {
+ indent_down();
+ indent(out) << "}" << endl;
+ }
+ }
+ // Write the struct map
+ out <<
+ indent() << "oprot.writeFieldStop();" << endl <<
+ indent() << "oprot.writeStructEnd();" << endl;
+
+ indent_down();
+ out <<
+ indent() << "}" << endl <<
+ endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct,
+ * which is a function result. These fields are only written
+ * if they are set in the Isset array, and only one of them
+ * can be set at a time.
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_haxe_struct_result_writer(ofstream& out,
+ t_struct* tstruct) {
+ out <<
+ indent() << "public function write(oprot:TProtocol) : Void {" << endl;
+ indent_up();
+
+ string name = tstruct->get_name();
+ const vector<t_field*>& fields = tstruct->get_sorted_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
+
+ bool first = true;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if (first) {
+ first = false;
+ out <<
+ endl <<
+ indent() << "if ";
+ } else {
+ out << " else if ";
+ }
+
+ out << "(this." << generate_isset_check(*f_iter) << ") {" << endl;
+
+ indent_up();
+
+ indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl;
+
+ // Write field contents
+ generate_serialize_field(out, *f_iter, "this.");
+
+ // Write field closer
+ indent(out) <<
+ "oprot.writeFieldEnd();" << endl;
+
+ indent_down();
+ indent(out) << "}";
+ }
+ // Write the struct map
+ out <<
+ endl <<
+ indent() << "oprot.writeFieldStop();" << endl <<
+ indent() << "oprot.writeStructEnd();" << endl;
+
+ indent_down();
+ out <<
+ indent() << "}" << endl <<
+ endl;
+}
+
+void t_haxe_generator::generate_reflection_getters(ostringstream& out, t_type* type, string field_name, string cap_name) {
+ (void) type;
+ (void) cap_name;
+ indent(out) << "case " << upcase_string(field_name) << ":" << endl;
+ indent_up();
+ indent(out) << "return this." << field_name << ";" << endl;
+ indent_down();
+}
+
+void t_haxe_generator::generate_reflection_setters(ostringstream& out, t_type* type, string field_name, string cap_name) {
+ (void) type;
+ (void) cap_name;
+ indent(out) << "case " << upcase_string(field_name) << ":" << endl;
+ indent_up();
+ indent(out) << "if (value == null) {" << endl;
+ indent(out) << " unset" << get_cap_name(field_name) << "();" << endl;
+ indent(out) << "} else {" << endl;
+ indent(out) << " this." << field_name << " = value;" << endl;
+ indent(out) << "}" << endl << endl;
+
+ indent_down();
+}
+
+void t_haxe_generator::generate_generic_field_getters_setters(std::ofstream& out, t_struct* tstruct) {
+
+ std::ostringstream getter_stream;
+ std::ostringstream setter_stream;
+
+ // build up the bodies of both the getter and setter at once
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ t_field* field = *f_iter;
+ t_type* type = get_true_type(field->get_type());
+ std::string field_name = field->get_name();
+ std::string cap_name = get_cap_name(field_name);
+
+ indent_up();
+ generate_reflection_setters(setter_stream, type, field_name, cap_name);
+ generate_reflection_getters(getter_stream, type, field_name, cap_name);
+ indent_down();
+ }
+
+
+ // create the setter
+ indent(out) << "public function setFieldValue(fieldID : Int, value : Dynamic) : Void {" << endl;
+ indent_up();
+
+ if (fields.size() > 0) {
+ indent(out) << "switch (fieldID) {" << endl;
+ out << setter_stream.str();
+ indent(out) << "default:" << endl;
+ indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+ indent(out) << "}" << endl;
+ } else {
+ indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+ }
+
+ indent_down();
+ indent(out) << "}" << endl << endl;
+
+ // create the getter
+ indent(out) << "public function getFieldValue(fieldID : Int) : Dynamic {" << endl;
+ indent_up();
+
+ if (fields.size() > 0) {
+ indent(out) << "switch (fieldID) {" << endl;
+ out << getter_stream.str();
+ indent(out) << "default:" << endl;
+ indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+ indent(out) << "}" << endl;
+ } else {
+ indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+ }
+
+ indent_down();
+
+ indent(out) << "}" << endl << endl;
+}
+
+// Creates a generic isSet method that takes the field number as argument
+void t_haxe_generator::generate_generic_isset_method(std::ofstream& out, t_struct* tstruct){
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ // create the isSet method
+ indent(out) << "// Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise" << endl;
+ indent(out) << "public function isSet(fieldID : Int) : Bool {" << endl;
+ indent_up();
+ if (fields.size() > 0) {
+ indent(out) << "switch (fieldID) {" << endl;
+
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ t_field* field = *f_iter;
+ indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl;
+ indent_up();
+ indent(out) << "return " << generate_isset_check(field) << ";" << endl;
+ indent_down();
+ }
+
+ indent(out) << "default:" << endl;
+ indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+ indent(out) << "}" << endl;
+ } else {
+ indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+ }
+
+ indent_down();
+ indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a set of property setters/getters for the given struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_property_getters_setters(ofstream& out,
+ t_struct* tstruct) {
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ t_field* field = *f_iter;
+ t_type* type = get_true_type(field->get_type());
+ std::string field_name = field->get_name();
+ std::string cap_name = get_cap_name(field_name);
+
+ // Simple getter
+ generate_haxe_doc(out, field);
+ indent(out) << "public function get_" << field_name << "():" <<
+ type_name(type) << " {" << endl;
+ indent_up();
+ indent(out) << "return this." << field_name << ";" << endl;
+ indent_down();
+ indent(out) << "}" << endl << endl;
+
+ // Simple setter
+ generate_haxe_doc(out, field);
+ indent(out) <<
+ "public function set_" << field_name <<
+ "(" << field_name << ":" << type_name(type) << ") : " <<
+ type_name(type) << " {" << endl;
+ indent_up();
+ indent(out) <<
+ "this." << field_name << " = " << field_name << ";" << endl;
+ generate_isset_set(out, field);
+ indent(out) <<
+ "return this." << field_name << ";" << endl;
+
+ indent_down();
+ indent(out) << "}" << endl << endl;
+
+ // Unsetter
+ indent(out) << "public function unset" << cap_name << "() : Void {" << endl;
+ indent_up();
+ if (type_can_be_null(type)) {
+ indent(out) << "this." << field_name << " = null;" << endl;
+ } else {
+ indent(out) << "this.__isset_" << field_name << " = false;" << endl;
+ }
+ indent_down();
+ indent(out) << "}" << endl << endl;
+
+ // isSet method
+ indent(out) << "// Returns true if field " << field_name << " is set (has been assigned a value) and false otherwise" << endl;
+ indent(out) << "public function is" << get_cap_name("set") << cap_name << "() : Bool {" << endl;
+ indent_up();
+ if (type_can_be_null(type)) {
+ indent(out) << "return this." << field_name << " != null;" << endl;
+ } else {
+ indent(out) << "return this.__isset_" << field_name << ";" << endl;
+ }
+ indent_down();
+ indent(out) << "}" << endl << endl;
+ }
+}
+
+/**
+ * Generates a toString() method for the given struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_haxe_struct_tostring(ofstream& out,
+ t_struct* tstruct) {
+ out << indent() << "public " << "function toString() : String {" << endl;
+ indent_up();
+
+ out <<
+ indent() << "var ret : String = \"" << tstruct->get_name() << "(\";" << endl;
+ out << indent() << "var first : Bool = true;" << endl << endl;
+
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+ bool first = true;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
+ if(could_be_unset) {
+ indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl;
+ indent_up();
+ }
+
+ t_field* field = (*f_iter);
+
+ if (!first) {
+ indent(out) << "if (!first) ret += \", \";" << endl;
+ }
+ indent(out) << "ret += \"" << (*f_iter)->get_name() << ":\";" << endl;
+ bool can_be_null = type_can_be_null(field->get_type());
+ if (can_be_null) {
+ indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl;
+ indent(out) << " ret += \"null\";" << endl;
+ indent(out) << "} else {" << endl;
+ indent_up();
+ }
+
+ if (field->get_type()->is_base_type() && ((t_base_type*)(field->get_type()))->is_binary()) {
+ indent(out) << " ret += \"BINARY\";" << endl;
+ } else if(field->get_type()->is_enum()) {
+ indent(out) << "var " << field->get_name() << "_name : String = " << get_enum_class_name(field->get_type()) << ".VALUES_TO_NAMES[this." << (*f_iter)->get_name() << "];"<< endl;
+ indent(out) << "if (" << field->get_name() << "_name != null) {" << endl;
+ indent(out) << " ret += " << field->get_name() << "_name;" << endl;
+ indent(out) << " ret += \" (\";" << endl;
+ indent(out) << "}" << endl;
+ indent(out) << "ret += this." << field->get_name() << ";" << endl;
+ indent(out) << "if (" << field->get_name() << "_name != null) {" << endl;
+ indent(out) << " ret += \")\";" << endl;
+ indent(out) << "}" << endl;
+ } else {
+ indent(out) << "ret += this." << (*f_iter)->get_name() << ";" << endl;
+ }
+
+ if (can_be_null) {
+ indent_down();
+ indent(out) << "}" << endl;
+ }
+ indent(out) << "first = false;" << endl;
+
+ if(could_be_unset) {
+ indent_down();
+ indent(out) << "}" << endl;
+ }
+ first = false;
+ }
+ out <<
+ indent() << "ret += \")\";" << endl <<
+ indent() << "return ret;" << endl;
+
+ indent_down();
+ indent(out) << "}" << endl <<
+ endl;
+}
+
+/**
+ * Generates a static map with meta data to store information such as fieldID to
+ * fieldName mapping
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_haxe_meta_data_map(ofstream& out,
+ t_struct* tstruct) {
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ // Static Map with fieldID -> FieldMetaData mappings
+ indent(out) << "inline static var metaDataMap : IntMap = new IntMap();" << endl;
+
+ if (fields.size() > 0) {
+ // Populate map
+ scope_up(out);
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ t_field* field = *f_iter;
+ std::string field_name = field->get_name();
+ indent(out) << "metaDataMap[" << upcase_string(field_name) << "] = new FieldMetaData(\"" << field_name << "\", ";
+
+ // Set field requirement type (required, optional, etc.)
+ if (field->get_req() == t_field::T_REQUIRED) {
+ out << "TFieldRequirementType.REQUIRED, ";
+ } else if (field->get_req() == t_field::T_OPTIONAL) {
+ out << "TFieldRequirementType.OPTIONAL, ";
+ } else {
+ out << "TFieldRequirementType.DEFAULT, ";
+ }
+
+ // Create value meta data
+ generate_field_value_meta_data(out, field->get_type());
+ out << ");" << endl;
+ }
+ scope_down(out);
+ }
+}
+
+/**
+ * Returns a string with the haxe representation of the given thrift type
+ * (e.g. for the type struct it returns "TType.STRUCT")
+ */
+std::string t_haxe_generator::get_haxe_type_string(t_type* type) {
+ if (type->is_list()){
+ return "TType.LIST";
+ } else if (type->is_map()) {
+ return "TType.MAP";
+ } else if (type->is_set()) {
+ return "TType.SET";
+ } else if (type->is_struct() || type->is_xception()) {
+ return "TType.STRUCT";
+ } else if (type->is_enum()) {
+ return "TType.I32";
+ } else if (type->is_typedef()) {
+ return get_haxe_type_string(((t_typedef*)type)->get_type());
+ } else if (type->is_base_type()) {
+ switch (((t_base_type*)type)->get_base()) {
+ case t_base_type::TYPE_VOID : return "TType.VOID"; break;
+ case t_base_type::TYPE_STRING : return "TType.STRING"; break;
+ case t_base_type::TYPE_BOOL : return "TType.BOOL"; break;
+ case t_base_type::TYPE_BYTE : return "TType.BYTE"; break;
+ case t_base_type::TYPE_I16 : return "TType.I16"; break;
+ case t_base_type::TYPE_I32 : return "TType.I32"; break;
+ case t_base_type::TYPE_I64 : return "TType.I64"; break;
+ case t_base_type::TYPE_DOUBLE : return "TType.DOUBLE"; break;
+ default : throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_haxe_generator::get_haxe_type_string!"); break; // This should never happen!
+ }
+ } else {
+ throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_haxe_generator::get_haxe_type_string!"); // This should never happen!
+ }
+}
+
+void t_haxe_generator::generate_field_value_meta_data(std::ofstream& out, t_type* type){
+ out << endl;
+ indent_up();
+ indent_up();
+ if (type->is_struct()){
+ indent(out) << "new StructMetaData(TType.STRUCT, " << type_name(type);
+ } else if (type->is_container()){
+ if (type->is_list()){
+ indent(out) << "new ListMetaData(TType.LIST, ";
+ t_type* elem_type = ((t_list*)type)->get_elem_type();
+ generate_field_value_meta_data(out, elem_type);
+ } else if (type->is_set()){
+ indent(out) << "new SetMetaData(TType.SET, ";
+ t_type* elem_type = ((t_list*)type)->get_elem_type();
+ generate_field_value_meta_data(out, elem_type);
+ } else{ // map
+ indent(out) << "new MapMetaData(TType.MAP, ";
+ t_type* key_type = ((t_map*)type)->get_key_type();
+ t_type* val_type = ((t_map*)type)->get_val_type();
+ generate_field_value_meta_data(out, key_type);
+ out << ", ";
+ generate_field_value_meta_data(out, val_type);
+ }
+ } else {
+ indent(out) << "new FieldValueMetaData(" << get_haxe_type_string(type);
+ }
+ out << ")";
+ indent_down();
+ indent_down();
+}
+
+
+/**
+ * Generates a thrift service. In C++, this comprises an entirely separate
+ * header and source file. The header file defines the methods and includes
+ * the data types defined in the main header file, and the implementation
+ * file contains implementations of the basic printer and default interfaces.
+ *
+ * @param tservice The service definition
+ */
+void t_haxe_generator::generate_service(t_service* tservice) {
+ // Make interface file
+ string f_service_name = package_dir_+"/"+service_name_ + ".hx";
+ f_service_.open(f_service_name.c_str());
+
+ f_service_ <<
+ autogen_comment() << haxe_package() << ";" << endl;
+
+ f_service_ << endl <<
+ haxe_type_imports() <<
+ haxe_thrift_imports() <<
+ haxe_thrift_gen_imports(tservice);
+
+ if(tservice->get_extends() != NULL) {
+ t_type* parent = tservice->get_extends();
+ string parent_namespace = parent->get_program()->get_namespace("haxe");
+ if(!parent_namespace.empty() && parent_namespace != package_name_) {
+ f_service_ << "import " << type_name(parent) << ";" << endl;
+ }
+ }
+
+ f_service_ << endl;
+
+ generate_service_interface(tservice);
+
+ f_service_.close();
+
+ // Now make the implementation/client file
+ f_service_name = package_dir_+"/"+service_name_+"Impl.hx";
+ f_service_.open(f_service_name.c_str());
+
+ f_service_ <<
+ autogen_comment() << haxe_package() << ";" << endl <<
+ endl <<
+ haxe_type_imports() <<
+ haxe_thrift_imports() <<
+ haxe_thrift_gen_imports(tservice) << endl;
+
+
+ if(tservice->get_extends() != NULL) {
+ t_type* parent = tservice->get_extends();
+ string parent_namespace = parent->get_program()->get_namespace("haxe");
+ if(!parent_namespace.empty() && parent_namespace != package_name_) {
+ f_service_ << "import " << type_name(parent) << "Impl;" << endl;
+ }
+ }
+
+ f_service_ << endl;
+
+ generate_service_client(tservice);
+ generate_service_helpers(tservice);
+
+ f_service_.close();
+
+ // Now make the processor/server file
+ f_service_name = package_dir_+"/"+service_name_+"Processor.hx";
+ f_service_.open(f_service_name.c_str());
+
+ f_service_ <<
+ autogen_comment() << haxe_package() << ";" << endl <<
+ endl <<
+ haxe_type_imports() <<
+ haxe_thrift_imports() <<
+ haxe_thrift_gen_imports(tservice) << endl;
+
+ if(!package_name_.empty()) {
+ f_service_ << "import " << package_name_ << ".*;" << endl;
+ f_service_ << "import " << package_name_ << "." << service_name_.c_str() << "Impl;" << endl;
+ f_service_ << endl;
+ }
+
+ generate_service_server(tservice);
+ //generate_service_helpers(tservice); - once is enough, see client file
+
+ f_service_.close();
+
+}
+
+/**
+ * Generates the code snippet for the onSuccess callbacks
+ *
+ * @param tfunction The service function to generate code for.
+ */
+string t_haxe_generator::generate_service_method_onsuccess(t_function* tfunction, bool as_type, bool omit_name) {
+ if( tfunction->is_oneway()) {
+ return "";
+ }
+
+ string name = "";
+ if( ! omit_name) {
+ name = "onSuccess";
+ if( as_type) {
+ name += " : ";
+ }
+ }
+
+ if( tfunction->get_returntype()->is_void()) {
+ if( as_type) {
+ return name + "Void->Void = null";
+ } else {
+ return name + "() : Void";
+ }
+ }
+
+ if( as_type) {
+ return name + type_name(tfunction->get_returntype()) + "->Void = null";
+ } else {
+ return name + "( retval : " + type_name(tfunction->get_returntype()) + ")";
+ }
+}
+
+/**
+ * Generates a service method header
+ *
+ * @param tfunction The service function to generate code for.
+ */
+void t_haxe_generator::generate_service_method_signature(t_function* tfunction, bool is_interface) {
+ if( callbacks_) {
+ generate_service_method_signature_callback( tfunction, is_interface);
+ } else {
+ generate_service_method_signature_normal( tfunction, is_interface);
+ }
+}
+
+/**
+ * Generates a service method header in "normal" style
+ *
+ * @param tfunction The service function to generate code for.
+ */
+void t_haxe_generator::generate_service_method_signature_normal(t_function* tfunction, bool is_interface) {
+ if( is_interface) {
+ indent(f_service_) << function_signature_normal(tfunction) << ";" << endl << endl;
+ } else {
+ indent(f_service_) <<
+ "public " << function_signature_normal(tfunction) << " {" << endl;
+ }
+}
+
+/**
+ * Generates a service method header in "callback" style
+ *
+ * @param tfunction The service function to generate code for.
+ */
+void t_haxe_generator::generate_service_method_signature_callback(t_function* tfunction, bool is_interface) {
+ if (!tfunction->is_oneway()) {
+ std::string on_success_impl = generate_service_method_onsuccess(tfunction, false, false);
+ indent(f_service_) << "// function onError(Dynamic) : Void;" << endl;
+ indent(f_service_) << "// function " << on_success_impl.c_str() << ";" << endl;
+ }
+
+ if( is_interface) {
+ indent(f_service_) << function_signature_callback(tfunction) << ";" <<
+ endl << endl;
+ } else {
+ indent(f_service_) <<
+ "public " << function_signature_callback(tfunction) << " {" << endl;
+ }
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_haxe_generator::generate_service_interface(t_service* tservice) {
+ string extends_iface = "";
+ if (tservice->get_extends() != NULL) {
+ extends_iface = " extends " + tservice->get_extends()->get_name();
+ }
+
+ generate_haxe_doc(f_service_, tservice);
+ f_service_ << indent() << "interface " << service_name_ << extends_iface <<
+ " {" << endl << endl;
+ indent_up();
+ vector<t_function*> functions = tservice->get_functions();
+ vector<t_function*>::iterator f_iter;
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ generate_haxe_doc(f_service_, *f_iter);
+ generate_service_method_signature(*f_iter,true);
+ }
+ indent_down();
+ f_service_ <<
+ indent() << "}" << endl <<
+ endl;
+}
+
+/**
+ * Generates structs for all the service args and return types
+ *
+ * @param tservice The service
+ */
+void t_haxe_generator::generate_service_helpers(t_service* tservice) {
+ f_service_ << endl << endl;
+ vector<t_function*> functions = tservice->get_functions();
+ vector<t_function*>::iterator f_iter;
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ t_struct* ts = (*f_iter)->get_arglist();
+ generate_haxe_struct_definition(f_service_, ts, false, true);
+ generate_function_helpers(*f_iter);
+ }
+}
+
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_haxe_generator::generate_service_client(t_service* tservice) {
+ string extends = "";
+ string extends_client = "";
+ if (tservice->get_extends() != NULL) {
+ extends = tservice->get_extends()->get_name();
+ extends_client = " extends " + extends + "Impl";
+ }
+
+ indent(f_service_) <<
+ "class " << service_name_ <<
+ "Impl" << extends_client <<
+ " implements " << service_name_ <<
+ " {" << endl << endl;
+ indent_up();
+
+ indent(f_service_) <<
+ "public function new( iprot : TProtocol, oprot : TProtocol = null)" << endl;
+ scope_up(f_service_);
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << "iprot_ = iprot;" << endl;
+ f_service_ << indent() << "if (oprot == null) {" << endl;
+ indent_up();
+ f_service_ << indent() << "oprot_ = iprot;" << endl;
+ indent_down();
+ f_service_ << indent() << "} else {" << endl;
+ indent_up();
+ f_service_ << indent() << "oprot_ = oprot;" << endl;
+ indent_down();
+ f_service_ << indent() << "}" << endl;
+ } else {
+ f_service_ <<
+ indent() << "super(iprot, oprot);" << endl;
+ }
+ scope_down(f_service_);
+ f_service_ << endl;
+
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << "private var iprot_ : TProtocol;" << endl <<
+ indent() << "private var oprot_ : TProtocol;" << endl <<
+ indent() << "private var seqid_ : Int;" << endl <<
+ endl;
+
+ indent(f_service_) <<
+ "public function getInputProtocol() : TProtocol" << endl;
+ scope_up(f_service_);
+ indent(f_service_) <<
+ "return this.iprot_;" << endl;
+ scope_down(f_service_);
+ f_service_ << endl;
+
+ indent(f_service_) <<
+ "public function getOutputProtocol() : TProtocol" << endl;
+ scope_up(f_service_);
+ indent(f_service_) <<
+ "return this.oprot_;" << endl;
+ scope_down(f_service_);
+ f_service_ << endl;
+
+ }
+
+ // Generate client method implementations
+ vector<t_function*> functions = tservice->get_functions();
+ vector<t_function*>::const_iterator f_iter;
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ string funname = (*f_iter)->get_name();
+
+ // Open function
+ generate_service_method_signature(*f_iter,false);
+
+ indent_up();
+
+
+ // Get the struct of function call params
+ t_struct* arg_struct = (*f_iter)->get_arglist();
+
+ string argsname = get_cap_name( (*f_iter)->get_name() + "_args");
+ vector<t_field*>::const_iterator fld_iter;
+ const vector<t_field*>& fields = arg_struct->get_members();
+
+ // Serialize the request
+ string calltype = (*f_iter)->is_oneway() ? "ONEWAY" : "CALL";
+ f_service_ <<
+ indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", TMessageType." << calltype << ", seqid_));" << endl <<
+ indent() << "var args : " << argsname << " = new " << argsname << "();" << endl;
+
+ for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+ f_service_ <<
+ indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl;
+ }
+
+ f_service_ <<
+ indent() << "args.write(oprot_);" << endl <<
+ indent() << "oprot_.writeMessageEnd();" << endl;
+
+ if( ! ((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) {
+ f_service_ << indent() << "var retval : " << type_name((*f_iter)->get_returntype()) <<";" << endl;
+ }
+
+ if ((*f_iter)->is_oneway()) {
+ f_service_ << indent() << "oprot_.getTransport().flush();" << endl;
+ }
+ else {
+ indent(f_service_) << "oprot_.getTransport().flush(function(error:Dynamic) : Void {" << endl;
+ indent_up();
+ if( callbacks_) {
+ indent(f_service_) << "try {" << endl;
+ indent_up();
+ }
+ string resultname = get_cap_name( (*f_iter)->get_name() + "_result");
+ indent(f_service_) << "if (error != null) {" << endl;
+ indent_up();
+ if( callbacks_) {
+ indent(f_service_) << "if (onError != null) onError(error);" << endl;
+ indent(f_service_) << "return;" << endl;
+ } else {
+ indent(f_service_) << "throw error;" << endl;
+ }
+ indent_down();
+ indent(f_service_) << "}" << endl;
+ indent(f_service_) << "var msg : TMessage = iprot_.readMessageBegin();" << endl;
+ indent(f_service_) << "if (msg.type == TMessageType.EXCEPTION) {" << endl;
+ indent_up();
+ indent(f_service_) << "var x = TApplicationException.read(iprot_);" << endl;
+ indent(f_service_) << "iprot_.readMessageEnd();" << endl;
+ if( callbacks_) {
+ indent(f_service_) << "if (onError != null) onError(x);" << endl;
+ indent(f_service_) << "return;" << endl;
+ } else {
+ indent(f_service_) << "throw x;" << endl;
+ }
+ indent_down();
+ indent(f_service_) << "}" << endl;
+ indent(f_service_) << "var result : " << resultname << " = new " << resultname << "();" << endl;
+ indent(f_service_) << "result.read(iprot_);" << endl;
+ indent(f_service_) << "iprot_.readMessageEnd();" << endl;
+
+ // Careful, only return _result if not a void function
+ if (!(*f_iter)->get_returntype()->is_void()) {
+ indent(f_service_) << "if (result." << generate_isset_check("success") << ") {" << endl;
+ indent_up();
+ if( callbacks_) {
+ indent(f_service_) << "if (onSuccess != null) onSuccess(result.success);" << endl;
+ indent(f_service_) << "return;" << endl;
+ } else {
+ indent(f_service_) << "retval = result.success;" << endl;
+ indent(f_service_) << "return;" << endl;
+ }
+ indent_down();
+ indent(f_service_) << "}" << endl;
+ }
+
+ t_struct* xs = (*f_iter)->get_xceptions();
+ const std::vector<t_field*>& xceptions = xs->get_members();
+ vector<t_field*>::const_iterator x_iter;
+ for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+ indent(f_service_) << "if (result." << (*x_iter)->get_name() << " != null) {" << endl;
+ indent_up();
+ if( callbacks_) {
+ indent(f_service_) << "if (onError != null) onError(result." << (*x_iter)->get_name() << ");" << endl;
+ indent(f_service_) << "return;" << endl;
+ } else {
+ indent(f_service_) << "throw result." << (*x_iter)->get_name() << ";" << endl;
+ }
+ indent_down();
+ indent(f_service_) << "}" << endl;
+ }
+
+ // If you get here it's an exception, unless a void function
+ if ((*f_iter)->get_returntype()->is_void()) {
+ if( callbacks_) {
+ indent(f_service_) << "if (onSuccess != null) onSuccess();" << endl;
+ }
+ indent(f_service_) << "return;" << endl;
+ } else {
+ if( callbacks_) {
+ indent(f_service_) << "if (onError != null)" << endl;
+ indent_up();
+ indent(f_service_) << "onError( new TApplicationException(TApplicationException.MISSING_RESULT," << endl;
+ indent(f_service_) << " \"" << (*f_iter)->get_name() << " failed: unknown result\"));" << endl;
+ indent_down();
+ } else {
+ indent(f_service_) << "throw new TApplicationException(TApplicationException.MISSING_RESULT," << endl;
+ indent(f_service_) << " \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
+ }
+ }
+
+ if( callbacks_) {
+ indent_down();
+ indent(f_service_) << "} catch( e : TException) {" << endl;
+ indent_up();
+ indent(f_service_) << "if (onError != null) onError(e);" << endl;
+ indent_down();
+ indent(f_service_) << "}" << endl;
+ }
+
+ indent_down();
+ indent(f_service_) <<
+ "});" << endl;
+ }
+
+ if( ! ((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) {
+ f_service_ << indent() << "return retval;" << endl;
+ }
+
+ // Close function
+ scope_down(f_service_);
+ f_service_ << endl;
+ }
+
+ indent_down();
+ indent(f_service_) <<
+ "}" << endl;
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_haxe_generator::generate_service_server(t_service* tservice) {
+ // Generate the dispatch methods
+ vector<t_function*> functions = tservice->get_functions();
+ vector<t_function*>::iterator f_iter;
+
+ // Extends stuff
+ string extends = "";
+ string extends_processor = "";
+ if (tservice->get_extends() != NULL) {
+ extends = type_name(tservice->get_extends());
+ extends_processor = " extends " + extends + "Processor";
+ }
+
+ // Generate the header portion
+ indent(f_service_) <<
+ "class " << service_name_ <<
+ "Processor" << extends_processor <<
+ " implements TProcessor {" <<
+ endl << endl;
+ indent_up();
+
+ f_service_ <<
+ indent() << "private var " << service_name_ << "_iface_ : " << service_name_ << ";" << endl;
+
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << "private var PROCESS_MAP = new StringMap< Int->TProtocol->TProtocol->Void >();" << endl;
+ }
+
+ f_service_ << endl;
+
+ indent(f_service_) <<
+ "public function new( iface : " << service_name_ << ")" << endl;
+ scope_up(f_service_);
+ if (!extends.empty()) {
+ f_service_ <<
+ indent() << "super(iface);" << endl;
+ }
+ f_service_ <<
+ indent() << service_name_ << "_iface_ = iface;" << endl;
+
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ f_service_ <<
+ indent() << "PROCESS_MAP.set(\"" << (*f_iter)->get_name() << "\", " << (*f_iter)->get_name() << "());" << endl;
+ }
+
+ scope_down(f_service_);
+ f_service_ << endl;
+
+ // Generate the server implementation
+ string override = "";
+ if (tservice->get_extends() != NULL) {
+ override = "override ";
+ }
+ indent(f_service_) << override << "public function process( iprot : TProtocol, oprot : TProtocol) : Bool" << endl;
+ scope_up(f_service_);
+
+ f_service_ <<
+ indent() << "var msg : TMessage = iprot.readMessageBegin();" << endl;
+
+ // TODO(mcslee): validate message, was the seqid etc. legit?
+ // AS- If all method is oneway:
+ // do you have an oprot?
+ // do you you need nullcheck?
+ f_service_ <<
+ indent() << "var fn = PROCESS_MAP.get(msg.name);" << endl <<
+ indent() << "if (fn == null) {" << endl <<
+ indent() << " TProtocolUtil.skip(iprot, TType.STRUCT);" << endl <<
+ indent() << " iprot.readMessageEnd();" << endl <<
+ indent() << " var x = new TApplicationException(TApplicationException.UNKNOWN_METHOD, \"Invalid method name: '\"+msg.name+\"'\");" << endl <<
+ indent() << " oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" << endl <<
+ indent() << " x.write(oprot);" << endl <<
+ indent() << " oprot.writeMessageEnd();" << endl <<
+ indent() << " oprot.getTransport().flush();" << endl <<
+ indent() << " return true;" << endl <<
+ indent() << "}" << endl <<
+ indent() << "fn( msg.seqid, iprot, oprot);" << endl;
+
+ f_service_ <<
+ indent() << "return true;" << endl;
+
+ scope_down(f_service_);
+ f_service_ << endl;
+
+ // Generate the process subfunctions
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ generate_process_function(tservice, *f_iter);
+ }
+
+ indent_down();
+ indent(f_service_) <<
+ "}" << endl <<
+ endl;
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_haxe_generator::generate_function_helpers(t_function* tfunction) {
+ if (tfunction->is_oneway()) {
+ return;
+ }
+
+ string resultname = get_cap_name( tfunction->get_name() + "_result");
+ t_struct result(program_, resultname);
+ t_field success(tfunction->get_returntype(), "success", 0);
+ if (!tfunction->get_returntype()->is_void()) {
+ result.append(&success);
+ }
+
+ t_struct* xs = tfunction->get_xceptions();
+ const vector<t_field*>& fields = xs->get_members();
+ vector<t_field*>::const_iterator f_iter;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ result.append(*f_iter);
+ }
+
+ generate_haxe_struct_definition(f_service_, &result, false, true, true);
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_haxe_generator::generate_process_function(t_service* tservice,
+ t_function* tfunction) {
+ (void) tservice;
+ // Open class
+ indent(f_service_) <<
+ "private function " << tfunction->get_name() << "() : Int->TProtocol->TProtocol->Void {" << endl;
+ indent_up();
+
+ // Open function
+ indent(f_service_) <<
+ "return function( seqid : Int, iprot : TProtocol, oprot : TProtocol) : Void"
+ << endl;
+ scope_up(f_service_);
+
+ string argsname = get_cap_name( tfunction->get_name() + "_args");
+ string resultname = get_cap_name( tfunction->get_name() + "_result");
+
+ f_service_ <<
+ indent() << "var args : "<< argsname << " = new " << argsname << "();" << endl <<
+ indent() << "args.read(iprot);" << endl <<
+ indent() << "iprot.readMessageEnd();" << endl;
+
+ t_struct* xs = tfunction->get_xceptions();
+ const std::vector<t_field*>& xceptions = xs->get_members();
+ vector<t_field*>::const_iterator x_iter;
+
+ // Declare result for non oneway function
+ if (!tfunction->is_oneway()) {
+ f_service_ <<
+ indent() << "var result : " << resultname << " = new " << resultname << "();" << endl;
+ }
+
+ // Try block for any function to catch (defined or undefined) exceptions
+ f_service_ <<
+ indent() << "try {" << endl;
+ indent_up();
+
+ if(callbacks_) {
+ // callback function style onError/onSuccess
+
+ // Generate the function call
+ t_struct* arg_struct = tfunction->get_arglist();
+ const std::vector<t_field*>& fields = arg_struct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ f_service_ << indent();
+ f_service_ <<
+ service_name_ << "_iface_." << tfunction->get_name() << "(";
+ bool first = true;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if (first) {
+ first = false;
+ } else {
+ f_service_ << ", ";
+ }
+ f_service_ << "args." << (*f_iter)->get_name();
+ }
+
+ if( tfunction->is_oneway()) {
+ f_service_ << ");" << endl;
+ } else {
+ if (first) {
+ first = false;
+ } else {
+ f_service_ << ", ";
+ }
+ string on_success = generate_service_method_onsuccess(tfunction, false, true);
+ indent_up();
+ f_service_ << endl;
+ indent(f_service_) << "null, // errors are thrown by the handler" << endl;
+ if( tfunction->get_returntype()->is_void()) {
+ indent(f_service_) << "null); // no retval" << endl;
+ } else {
+ indent(f_service_) << "function" << on_success.c_str() << " {" << endl;
+ if( ! tfunction->get_returntype()->is_void()) {
+ indent_up();
+ indent(f_service_) << "result.success = retval;" << endl;
+ indent_down();
+ }
+ indent(f_service_) << "});" << endl;
+ }
+ indent_down();
+ }
+
+ } else {
+ // normal function():result style
+
+ // Generate the function call
+ t_struct* arg_struct = tfunction->get_arglist();
+ const std::vector<t_field*>& fields = arg_struct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ f_service_ << indent();
+ if( ! (tfunction->is_oneway() || tfunction->get_returntype()->is_void())) {
+ f_service_ << "result.success = ";
+ }
+ f_service_ <<
+ service_name_ << "_iface_." << tfunction->get_name() << "(";
+ bool first = true;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if (first) {
+ first = false;
+ } else {
+ f_service_ << ", ";
+ }
+ f_service_ << "args." << (*f_iter)->get_name();
+ }
+ f_service_ << ");" << endl;
+
+ }
+
+ indent_down();
+ f_service_ << indent() << "}";
+ if( ! tfunction->is_oneway()) {
+ // catch exceptions defined in the IDL
+ for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+ f_service_ << " catch (" << (*x_iter)->get_name() << ":" << type_name((*x_iter)->get_type(), false, false) << ") {" << endl;
+ if (!tfunction->is_oneway()) {
+ indent_up();
+ f_service_ <<
+ indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl;
+ indent_down();
+ f_service_ << indent() << "}";
+ } else {
+ f_service_ << "}";
+ }
+ }
+ }
+
+ // always catch all exceptions to prevent from service denial
+ f_service_ << " catch (th : Dynamic) {" << endl;
+ indent_up();
+ indent(f_service_) << "trace(\"Internal error processing " << tfunction->get_name() << "\", th);" << endl;
+ if( ! tfunction->is_oneway()) {
+ indent(f_service_) << "var x = new TApplicationException(TApplicationException.INTERNAL_ERROR, \"Internal error processing " << tfunction->get_name() << "\");" << endl;
+ indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl;
+ indent(f_service_) << "x.write(oprot);" << endl;
+ indent(f_service_) << "oprot.writeMessageEnd();" << endl;
+ indent(f_service_) << "oprot.getTransport().flush();" << endl;
+ }
+ indent(f_service_) << "return;" << endl;
+ indent_down();
+ f_service_ << indent() << "}" << endl;
+
+ // Shortcut out here for oneway functions
+ if (tfunction->is_oneway()) {
+ f_service_ <<
+ indent() << "return;" << endl;
+ scope_down(f_service_);
+
+ // Close class
+ indent_down();
+ f_service_ <<
+ indent() << "}" << endl <<
+ endl;
+ return;
+ }
+
+ f_service_ <<
+ indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid));" << endl <<
+ indent() << "result.write(oprot);" << endl <<
+ indent() << "oprot.writeMessageEnd();" << endl <<
+ indent() << "oprot.getTransport().flush();" << endl;
+
+ // Close function
+ scope_down(f_service_);
+ f_service_ << endl;
+
+ // Close class
+ indent_down();
+ f_service_ <<
+ indent() << "}" << endl <<
+ endl;
+}
+
+/**
+ * Deserializes a field of any type.
+ *
+ * @param tfield The field
+ * @param prefix The variable name or container for this field
+ */
+void t_haxe_generator::generate_deserialize_field(ofstream& out,
+ t_field* tfield,
+ string prefix) {
+ t_type* type = get_true_type(tfield->get_type());
+
+ if (type->is_void()) {
+ throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
+ prefix + tfield->get_name();
+ }
+
+ string name = prefix + tfield->get_name();
+
+ if (type->is_struct() || type->is_xception()) {
+ generate_deserialize_struct(out,
+ (t_struct*)type,
+ name);
+ } else if (type->is_container()) {
+ generate_deserialize_container(out, type, name);
+ } else if (type->is_base_type() || type->is_enum()) {
+
+ indent(out) <<
+ name << " = iprot.";
+
+ if (type->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_VOID:
+ throw "compiler error: cannot serialize void field in a struct: " +
+ name;
+ break;
+ case t_base_type::TYPE_STRING:
+ if (((t_base_type*)type)->is_binary()) {
+ out << "readBinary();";
+ } else {
+ out << "readString();";
+ }
+ break;
+ case t_base_type::TYPE_BOOL:
+ out << "readBool();";
+ break;
+ case t_base_type::TYPE_BYTE:
+ out << "readByte();";
+ break;
+ case t_base_type::TYPE_I16:
+ out << "readI16();";
+ break;
+ case t_base_type::TYPE_I32:
+ out << "readI32();";
+ break;
+ case t_base_type::TYPE_I64:
+ out << "readI64();";
+ break;
+ case t_base_type::TYPE_DOUBLE:
+ out << "readDouble();";
+ break;
+ default:
+ throw "compiler error: no Haxe name for base type " + t_base_type::t_base_name(tbase);
+ }
+ } else if (type->is_enum()) {
+ out << "readI32();";
+ }
+ out <<
+ endl;
+ } else {
+ printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+ tfield->get_name().c_str(), type_name(type).c_str());
+ }
+}
+
+/**
+ * Generates an unserializer for a struct, invokes read()
+ */
+void t_haxe_generator::generate_deserialize_struct(ofstream& out,
+ t_struct* tstruct,
+ string prefix) {
+ out <<
+ indent() << prefix << " = new " << type_name(tstruct) << "();" << endl <<
+ indent() << prefix << ".read(iprot);" << endl;
+}
+
+/**
+ * Deserializes a container by reading its size and then iterating
+ */
+void t_haxe_generator::generate_deserialize_container(ofstream& out,
+ t_type* ttype,
+ string prefix) {
+ scope_up(out);
+
+ string obj;
+
+ if (ttype->is_map()) {
+ obj = tmp("_map");
+ } else if (ttype->is_set()) {
+ obj = tmp("_set");
+ } else if (ttype->is_list()) {
+ obj = tmp("_list");
+ }
+
+ // Declare variables, read header
+ if (ttype->is_map()) {
+ indent(out) << "var " << obj << " = iprot.readMapBegin();" << endl;
+ } else if (ttype->is_set()) {
+ indent(out) << "var " << obj << " = iprot.readSetBegin();" << endl;
+ } else if (ttype->is_list()) {
+ indent(out) << "var " << obj << " = iprot.readListBegin();" << endl;
+ }
+
+ indent(out)
+ << prefix << " = new " << type_name(ttype, false, true)
+ // size the collection correctly
+ << "("
+ << ");" << endl;
+
+ // For loop iterates over elements
+ string i = tmp("_i");
+ indent(out) <<
+ "for( " << i << " in 0 ... " << obj << ".size)" << endl;
+
+ scope_up(out);
+
+ if (ttype->is_map()) {
+ generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+ } else if (ttype->is_set()) {
+ generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+ } else if (ttype->is_list()) {
+ generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+ }
+
+ scope_down(out);
+
+ // Read container end
+ if (ttype->is_map()) {
+ indent(out) << "iprot.readMapEnd();" << endl;
+ } else if (ttype->is_set()) {
+ indent(out) << "iprot.readSetEnd();" << endl;
+ } else if (ttype->is_list()) {
+ indent(out) << "iprot.readListEnd();" << endl;
+ }
+
+ scope_down(out);
+}
+
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_haxe_generator::generate_deserialize_map_element(ofstream& out,
+ t_map* tmap,
+ string prefix) {
+ string key = tmp("_key");
+ string val = tmp("_val");
+ t_field fkey(tmap->get_key_type(), key);
+ t_field fval(tmap->get_val_type(), val);
+
+ indent(out) <<
+ declare_field(&fkey) << endl;
+ indent(out) <<
+ declare_field(&fval) << endl;
+
+ generate_deserialize_field(out, &fkey);
+ generate_deserialize_field(out, &fval);
+
+ indent(out) <<
+ prefix << ".set( " << key << ", " << val << ");" << endl;
+}
+
+/**
+ * Deserializes a set element
+ */
+void t_haxe_generator::generate_deserialize_set_element(ofstream& out,
+ t_set* tset,
+ string prefix) {
+ string elem = tmp("_elem");
+ t_field felem(tset->get_elem_type(), elem);
+
+ indent(out) <<
+ declare_field(&felem) << endl;
+
+ generate_deserialize_field(out, &felem);
+
+ indent(out) <<
+ prefix << ".add(" << elem << ");" << endl;
+}
+
+/**
+ * Deserializes a list element
+ */
+void t_haxe_generator::generate_deserialize_list_element(ofstream& out,
+ t_list* tlist,
+ string prefix) {
+ string elem = tmp("_elem");
+ t_field felem(tlist->get_elem_type(), elem);
+
+ indent(out) <<
+ declare_field(&felem) << endl;
+
+ generate_deserialize_field(out, &felem);
+
+ indent(out) <<
+ prefix << ".add(" << elem << ");" << endl;
+}
+
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_haxe_generator::generate_serialize_field(ofstream& out,
+ t_field* tfield,
+ string prefix) {
+ t_type* type = get_true_type(tfield->get_type());
+
+ // Do nothing for void types
+ if (type->is_void()) {
+ throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
+ prefix + tfield->get_name();
+ }
+
+ if (type->is_struct() || type->is_xception()) {
+ generate_serialize_struct(out,
+ (t_struct*)type,
+ prefix + tfield->get_name());
+ } else if (type->is_container()) {
+ generate_serialize_container(out,
+ type,
+ prefix + tfield->get_name());
+ } else if (type->is_base_type() || type->is_enum()) {
+
+ string name = prefix + tfield->get_name();
+ indent(out) <<
+ "oprot.";
+
+ if (type->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_VOID:
+ throw
+ "compiler error: cannot serialize void field in a struct: " + name;
+ break;
+ case t_base_type::TYPE_STRING:
+ if (((t_base_type*)type)->is_binary()) {
+ out << "writeBinary(" << name << ");";
+ } else {
+ out << "writeString(" << name << ");";
+ }
+ break;
+ case t_base_type::TYPE_BOOL:
+ out << "writeBool(" << name << ");";
+ break;
+ case t_base_type::TYPE_BYTE:
+ out << "writeByte(" << name << ");";
+ break;
+ case t_base_type::TYPE_I16:
+ out << "writeI16(" << name << ");";
+ break;
+ case t_base_type::TYPE_I32:
+ out << "writeI32(" << name << ");";
+ break;
+ case t_base_type::TYPE_I64:
+ out << "writeI64(" << name << ");";
+ break;
+ case t_base_type::TYPE_DOUBLE:
+ out << "writeDouble(" << name << ");";
+ break;
+ default:
+ throw "compiler error: no Haxe name for base type " + t_base_type::t_base_name(tbase);
+ }
+ } else if (type->is_enum()) {
+ out << "writeI32(" << name << ");";
+ }
+ out << endl;
+ } else {
+ printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+ prefix.c_str(),
+ tfield->get_name().c_str(),
+ type_name(type).c_str());
+ }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix String prefix to attach to all fields
+ */
+void t_haxe_generator::generate_serialize_struct(ofstream& out,
+ t_struct* tstruct,
+ string prefix) {
+ (void) tstruct;
+ out <<
+ indent() << prefix << ".write(oprot);" << endl;
+}
+
+/**
+ * Serializes a container by writing its size then the elements.
+ *
+ * @param ttype The type of container
+ * @param prefix String prefix for fields
+ */
+void t_haxe_generator::generate_serialize_container(ofstream& out,
+ t_type* ttype,
+ string prefix) {
+ scope_up(out);
+
+ if (ttype->is_map()) {
+ string iter = tmp("_key");
+ string counter = tmp("_sizeCounter");
+ indent(out) << "var " << counter << " : Int = 0;" << endl;
+ indent(out) << "for( " << iter << " in " << prefix << ") {" << endl;
+ indent(out) << " " << counter << +"++;" << endl;
+ indent(out) << "}" << endl;
+
+ indent(out) <<
+ "oprot.writeMapBegin(new TMap(" <<
+ type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
+ type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
+ counter << "));" << endl;
+ } else if (ttype->is_set()) {
+ indent(out) <<
+ "oprot.writeSetBegin(new TSet(" <<
+ type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
+ prefix << ".size));" << endl;
+ } else if (ttype->is_list()) {
+ indent(out) <<
+ "oprot.writeListBegin(new TList(" <<
+ type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
+ prefix << ".length));" << endl;
+ }
+
+ string iter = tmp("elem");
+ if (ttype->is_map()) {
+ indent(out) <<
+ "for( " << iter << " in " << prefix << ".keys())" << endl;
+ } else if (ttype->is_set()) {
+ indent(out) <<
+ "for( " << iter << " in " << prefix << ".toArray())" << endl;
+ } else if (ttype->is_list()) {
+ indent(out) <<
+ "for( " << iter << " in " << prefix << ")" << endl;
+ }
+
+ scope_up(out);
+
+ if (ttype->is_map()) {
+ generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
+ } else if (ttype->is_set()) {
+ generate_serialize_set_element(out, (t_set*)ttype, iter);
+ } else if (ttype->is_list()) {
+ generate_serialize_list_element(out, (t_list*)ttype, iter);
+ }
+
+ scope_down(out);
+
+ if (ttype->is_map()) {
+ indent(out) <<
+ "oprot.writeMapEnd();" << endl;
+ } else if (ttype->is_set()) {
+ indent(out) <<
+ "oprot.writeSetEnd();" << endl;
+ } else if (ttype->is_list()) {
+ indent(out) <<
+ "oprot.writeListEnd();" << endl;
+ }
+
+ scope_down(out);
+}
+
+/**
+ * Serializes the members of a map.
+ */
+void t_haxe_generator::generate_serialize_map_element(ofstream& out,
+ t_map* tmap,
+ string iter,
+ string map) {
+ t_field kfield(tmap->get_key_type(), iter);
+ generate_serialize_field(out, &kfield, "");
+ t_field vfield(tmap->get_val_type(), map + ".get(" + iter + ")");
+ generate_serialize_field(out, &vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_haxe_generator::generate_serialize_set_element(ofstream& out,
+ t_set* tset,
+ string iter) {
+ t_field efield(tset->get_elem_type(), iter);
+ generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_haxe_generator::generate_serialize_list_element(ofstream& out,
+ t_list* tlist,
+ string iter) {
+ t_field efield(tlist->get_elem_type(), iter);
+ generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Returns a haxe type name
+ *
+ * @param ttype The type
+ * @param container Is the type going inside a container?
+ * @return haxe type name, i.e. HashMap<Key,Value>
+ */
+string t_haxe_generator::type_name(t_type* ttype, bool in_container, bool in_init) {
+ (void) in_init;
+
+ // typedefs are just resolved to their real type
+ ttype = get_true_type(ttype);
+ string prefix;
+
+ if (ttype->is_base_type()) {
+ return base_type_name((t_base_type*)ttype, in_container);
+ }
+
+ if (ttype->is_enum()) {
+ return "Int";
+ }
+
+ if (ttype->is_map()) {
+ t_type* tkey = get_true_type(((t_map*)ttype)->get_key_type());
+ t_type* tval = get_true_type(((t_map*)ttype)->get_val_type());
+ if (tkey->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)tkey)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_STRING:
+ if( ! (((t_base_type*)tkey)->is_binary())) {
+ return "StringMap< "+type_name(tval)+">";
+ }
+ case t_base_type::TYPE_BYTE:
+ case t_base_type::TYPE_I16:
+ case t_base_type::TYPE_I32:
+ return "IntMap< " + type_name(tval) + ">";
+ case t_base_type::TYPE_I64:
+ return "Int64Map< " + type_name(tval) + ">";
+ default:
+ break; // default to ObjectMap<>
+ }
+ }
+ if (tkey->is_enum()) {
+ return "IntMap< " + type_name(tval) + ">";
+ }
+ return "ObjectMap< " + type_name(tkey) + ", " + type_name(tval) + ">";
+ }
+
+ if (ttype->is_set()) {
+ t_type* tkey = get_true_type(((t_list*)ttype)->get_elem_type());
+ if( tkey->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)tkey)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_STRING:
+ if( ! (((t_base_type*)tkey)->is_binary())) {
+ return "StringSet";
+ }
+ case t_base_type::TYPE_BYTE:
+ case t_base_type::TYPE_I16:
+ case t_base_type::TYPE_I32:
+ return "IntSet";
+ case t_base_type::TYPE_I64:
+ return "Int64Set";
+ default:
+ break; // default to ObjectSet
+ }
+ }
+ if (tkey->is_enum()) {
+ return "IntSet";
+ }
+ return "ObjectSet< " + type_name(tkey) + ">";
+ }
+
+ if (ttype->is_list()) {
+ t_type* telm = ((t_list*)ttype)->get_elem_type();
+ return "List< "+type_name(telm)+">";
+ }
+
+ // Check for namespacing
+ t_program* program = ttype->get_program();
+ if (program != NULL && program != program_) {
+ string package = program->get_namespace("haxe");
+ if (!package.empty()) {
+ return package + "." + ttype->get_name();
+ }
+ }
+
+ return ttype->get_name();
+}
+
+/**
+ * Returns the haxe type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ * @param container Is it going in a haxe container?
+ */
+string t_haxe_generator::base_type_name(t_base_type* type,
+ bool in_container) {
+ (void) in_container;
+ t_base_type::t_base tbase = type->get_base();
+
+ switch (tbase) {
+ case t_base_type::TYPE_VOID:
+ return "Void";
+ case t_base_type::TYPE_STRING:
+ if (type->is_binary()) {
+ return "haxe.io.Bytes";
+ } else {
+ return "String";
+ }
+ case t_base_type::TYPE_BOOL:
+ return "Bool";
+ case t_base_type::TYPE_BYTE:
+ case t_base_type::TYPE_I16:
+ case t_base_type::TYPE_I32:
+ return "haxe.Int32";
+ case t_base_type::TYPE_I64:
+ return "haxe.Int64";
+ case t_base_type::TYPE_DOUBLE:
+ return "Float";
+ default:
+ throw "compiler error: no Haxe name for base type " + t_base_type::t_base_name(tbase);
+ }
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_haxe_generator::declare_field(t_field* tfield, bool init) {
+ // TODO(mcslee): do we ever need to initialize the field?
+ string result = "var " + tfield->get_name() + " : " + type_name(tfield->get_type());
+ if (init) {
+ t_type* ttype = get_true_type(tfield->get_type());
+ if (ttype->is_base_type() && tfield->get_value() != NULL) {
+ ofstream dummy;
+ result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
+ } else if (ttype->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_VOID:
+ throw "NO T_VOID CONSTRUCT";
+ case t_base_type::TYPE_STRING:
+ result += " = null";
+ break;
+ case t_base_type::TYPE_BOOL:
+ result += " = false";
+ break;
+ case t_base_type::TYPE_BYTE:
+ case t_base_type::TYPE_I16:
+ case t_base_type::TYPE_I32:
+ case t_base_type::TYPE_I64:
+ result += " = 0";
+ break;
+ case t_base_type::TYPE_DOUBLE:
+ result += " = (double)0";
+ break;
+ }
+
+ } else if (ttype->is_enum()) {
+ result += " = 0";
+ } else if (ttype->is_container()) {
+ result += " = new " + type_name(ttype, false, true) + "()";
+ } else {
+ result += " = new " + type_name(ttype, false, true) + "()";;
+ }
+ }
+ return result + ";";
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_haxe_generator::function_signature_callback( t_function* tfunction) {
+ std::string on_error_success = "onError : Dynamic->Void = null, "
+ + generate_service_method_onsuccess(tfunction, true, false);
+
+ std::string arguments = argument_list(tfunction->get_arglist());
+ if (! tfunction->is_oneway()) {
+ if (arguments != "") {
+ arguments += ", ";
+ }
+ arguments += on_error_success; //"onError : Function, onSuccess : Function";
+ }
+
+ std::string result = "function " + tfunction->get_name() + "(" + arguments + ") : Void";
+ return result;
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_haxe_generator::function_signature_normal( t_function* tfunction) {
+ std::string arguments = argument_list(tfunction->get_arglist());
+
+ std::string resulttype;
+ if (tfunction->is_oneway() || tfunction->get_returntype()->is_void()) {
+ resulttype = "Void";
+ } else {
+ resulttype = type_name(tfunction->get_returntype());
+ }
+
+ std::string result = "function " + tfunction->get_name() + "(" + arguments + ") : "+resulttype;
+ return result;
+}
+
+/**
+ * Renders a comma separated field list, with type names
+ */
+string t_haxe_generator::argument_list(t_struct* tstruct) {
+ string result = "";
+
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+ bool first = true;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if (first) {
+ first = false;
+ } else {
+ result += ", ";
+ }
+ result += (*f_iter)->get_name() + " : " + type_name((*f_iter)->get_type());
+ }
+ return result;
+}
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ */
+string t_haxe_generator::type_to_enum(t_type* type) {
+ type = get_true_type(type);
+
+ if (type->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_VOID:
+ throw "NO T_VOID CONSTRUCT";
+ case t_base_type::TYPE_STRING:
+ return "TType.STRING";
+ case t_base_type::TYPE_BOOL:
+ return "TType.BOOL";
+ case t_base_type::TYPE_BYTE:
+ return "TType.BYTE";
+ case t_base_type::TYPE_I16:
+ return "TType.I16";
+ case t_base_type::TYPE_I32:
+ return "TType.I32";
+ case t_base_type::TYPE_I64:
+ return "TType.I64";
+ case t_base_type::TYPE_DOUBLE:
+ return "TType.DOUBLE";
+ }
+ } else if (type->is_enum()) {
+ return "TType.I32";
+ } else if (type->is_struct() || type->is_xception()) {
+ return "TType.STRUCT";
+ } else if (type->is_map()) {
+ return "TType.MAP";
+ } else if (type->is_set()) {
+ return "TType.SET";
+ } else if (type->is_list()) {
+ return "TType.LIST";
+ }
+
+ throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Applies the correct style to a string based on the value of nocamel_style_
+ */
+std::string t_haxe_generator::get_cap_name(std::string name){
+ name[0] = toupper(name[0]); // class name must start with uppercase letter
+ return name;
+}
+
+string t_haxe_generator::constant_name(string name) {
+ string constant_name;
+
+ bool is_first = true;
+ bool was_previous_char_upper = false;
+ for (string::iterator iter = name.begin(); iter != name.end(); ++iter) {
+ string::value_type character = (*iter);
+
+ bool is_upper = isupper(character);
+
+ if (is_upper && !is_first && !was_previous_char_upper) {
+ constant_name += '_';
+ }
+ constant_name += toupper(character);
+
+ is_first = false;
+ was_previous_char_upper = is_upper;
+ }
+
+ return constant_name;
+}
+
+/**
+ * Emits a haxeDoc comment if the provided object has a doc in Thrift
+ */
+void t_haxe_generator::generate_haxe_doc(ofstream &out,
+ t_doc* tdoc) {
+ if (tdoc->has_doc()) {
+ generate_docstring_comment(out,
+ "/**\n",
+ " * ", tdoc->get_doc(),
+ " */\n");
+ }
+}
+
+/**
+ * Emits a haxeDoc comment if the provided function object has a doc in Thrift
+ */
+void t_haxe_generator::generate_haxe_doc(ofstream &out,
+ t_function* tfunction) {
+ if (tfunction->has_doc()) {
+ stringstream ss;
+ ss << tfunction->get_doc();
+ const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+ vector<t_field*>::const_iterator p_iter;
+ for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
+ t_field* p = *p_iter;
+ ss << "\n@param " << p->get_name();
+ if (p->has_doc()) {
+ ss << " " << p->get_doc();
+ }
+ }
+ generate_docstring_comment(out,
+ "/**\n",
+ " * ", ss.str(),
+ " */\n");
+ }
+}
+
+std::string t_haxe_generator::generate_isset_check(t_field* field) {
+ return generate_isset_check(field->get_name());
+}
+
+std::string t_haxe_generator::generate_isset_check(std::string field_name) {
+ return "is" + get_cap_name("set") + get_cap_name(field_name) + "()";
+}
+
+void t_haxe_generator::generate_isset_set(ofstream& out, t_field* field) {
+ if (!type_can_be_null(field->get_type())) {
+ indent(out) << "this.__isset_" << field->get_name() << " = true;" << endl;
+ }
+}
+
+std::string t_haxe_generator::get_enum_class_name(t_type* type) {
+ string package = "";
+ t_program* program = type->get_program();
+ if (program != NULL && program != program_) {
+ package = program->get_namespace("haxe") + ".";
+ }
+ return package + type->get_name();
+}
+
+THRIFT_REGISTER_GENERATOR(haxe, "Haxe",
+" callbacks: Use onError()/onSuccess() callbacks for service methods (like AS3)\n"
+)
+
diff --git a/configure.ac b/configure.ac
index c49cb60..9f104fa 100755
--- a/configure.ac
+++ b/configure.ac
@@ -114,6 +114,7 @@
with_python="no"
with_ruby="no"
with_haskell="no"
+ with_haxe="no"
with_perl="no"
with_php="no"
with_php_extension="no"
@@ -318,6 +319,16 @@
AM_CONDITIONAL(WITH_GO, [test "$have_go" = "yes"])
+AX_THRIFT_LIB(haxe, [Haxe], yes)
+if test "$with_haxe" = "yes"; then
+ AC_PATH_PROG([HAXE], [haxe])
+ if [[ -x "$HAXE" ]] ; then
+ have_haxe="yes"
+ fi
+fi
+AM_CONDITIONAL(WITH_HAXE, [test "$have_haxe" = "yes"])
+
+
AX_THRIFT_LIB(d, [D], yes)
if test "$with_d" = "yes"; then
AX_DMD
@@ -657,6 +668,7 @@
test/cpp/Makefile
test/erl/Makefile
test/go/Makefile
+ test/haxe/Makefile
test/hs/Makefile
test/php/Makefile
test/perl/Makefile
@@ -668,6 +680,7 @@
tutorial/c_glib/Makefile
tutorial/cpp/Makefile
tutorial/go/Makefile
+ tutorial/haxe/Makefile
tutorial/hs/Makefile
tutorial/java/Makefile
tutorial/js/Makefile
@@ -690,6 +703,7 @@
echo "Building C# Library .......... : $have_csharp"
echo "Building Python Library ...... : $have_python"
echo "Building Ruby Library ........ : $have_ruby"
+echo "Building Haxe Library ........ : $have_haxe"
echo "Building Haskell Library ..... : $have_haskell"
echo "Building Perl Library ........ : $have_perl"
echo "Building PHP Library ......... : $have_php"
@@ -739,6 +753,11 @@
echo " Using Haskell ............. : $RUNHASKELL"
echo " Using Cabal ............... : $CABAL"
fi
+if test "$have_haxe" = "yes" ; then
+ echo
+ echo "Haxe Library:"
+ echo " Using Haxe ................ : $HAXE"
+fi
if test "$have_perl" = "yes" ; then
echo
echo "Perl Library:"
diff --git a/lib/haxe/README.md b/lib/haxe/README.md
new file mode 100644
index 0000000..3335b43
--- /dev/null
+++ b/lib/haxe/README.md
@@ -0,0 +1,75 @@
+Thrift Haxe Software Library
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+
+Using Thrift with Haxe
+========================
+
+Thrift requires Haxe 3.1.3.
+
+To get started, visit the /tutorial/haxe and /test/haxe dirs for examples.
+If you are using HIDE, you'll find the HIDE project files in these folders.
+
+
+Current status
+========================
+- tested with Haxe C++ target
+- transports: socket
+- protocols: binary, JSON
+- tutorial client and server available
+- cross-test client and server available
+
+
+Further developments
+========================
+- add HTTP transport, update tutorial and tests accordingly
+- improve to work with C#, Java and JavaScript Haxe/OpenFL targets
+- improve to work with more (ideally all) Haxe/OpenFL targets
+
+
+Dependencies
+========================
+
+Haxe Targets:
+Depending on the desired targets, you may have to install the appropriate HaxeLibs
+after installing Haxe itself. For example, if you plan to target C#, Java and C++,
+enter the following commands after installing Haxe:
+
+ haxelib install hxcpp
+ haxelib install hxjava
+ haxelib install hxcs
+
+For other targets, please consult the Haxe documentation whether or not any additional
+target libraries need to be installed and how to achieve this.
+
+Haxe Libraries:
+- None (at the time of writing)
+
+
+Known restrictions
+========================
+
+Although designed with maximum portability in mind, for technical reasons some platforms
+may only support parts of the library, or not be compatible at all.
+
+Javascript:
+- tutorial fails to build because of unsupported Sys.args
+
diff --git a/lib/haxe/src/org/apache/thrift/AbstractMethodError.hx b/lib/haxe/src/org/apache/thrift/AbstractMethodError.hx
new file mode 100644
index 0000000..9fb9bbb
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/AbstractMethodError.hx
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift;
+
+#if flash
+import flash.errors.IllegalOperationError;
+#else
+import org.apache.thrift.TException;
+#end
+
+class AbstractMethodError
+#if flash
+extends IllegalOperationError
+#else
+extends TException
+#end
+{
+
+ public function new(message : String="") {
+ super("Attempt to call an abstract method");
+ }
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/ArgumentError.hx b/lib/haxe/src/org/apache/thrift/ArgumentError.hx
new file mode 100644
index 0000000..8a5df6f
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/ArgumentError.hx
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift;
+
+#if ! flash
+// predefined for flash only
+class ArgumentError extends TException {
+ public function new(msg : String = "") {
+ super(msg);
+ }
+}
+#end
diff --git a/lib/haxe/src/org/apache/thrift/Limits.hx b/lib/haxe/src/org/apache/thrift/Limits.hx
new file mode 100644
index 0000000..7d2aa5d
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/Limits.hx
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift;
+
+class Limits {
+
+ // Haxe limits are not fixed values, they depend on the target platform
+ // For example, neko limits an int to 31 bits instead of 32. So we detect
+ // the values once during intialisation in order to
+ // (a) get the right values for the current platform, and
+ // (b) prevent us from dependecies to a bunch of defines
+
+ public static var I32_MAX = {
+ var last : Int = 0;
+ var next : Int = 0;
+ for(bit in 0 ... 32) {
+ last = next;
+ next = last | (1 << bit);
+ if(next < 0) {
+ break;
+ }
+ }
+ last; // final value
+ }
+
+ // add whatever you need
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/TApplicationException.hx b/lib/haxe/src/org/apache/thrift/TApplicationException.hx
new file mode 100644
index 0000000..012a802
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/TApplicationException.hx
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift;
+
+import org.apache.thrift.protocol.TField;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolUtil;
+import org.apache.thrift.protocol.TStruct;
+import org.apache.thrift.protocol.TType;
+
+ /**
+ * Application level exception
+ */
+class TApplicationException extends TException {
+
+ private static var TAPPLICATION_EXCEPTION_STRUCT = { new TStruct("TApplicationException"); };
+ private static var MESSAGE_FIELD = { new TField("message", TType.STRING, 1); };
+ private static var TYPE_FIELD = { new TField("type", TType.I32, 2); };
+
+ public static inline var UNKNOWN : Int = 0;
+ public static inline var UNKNOWN_METHOD : Int = 1;
+ public static inline var INVALID_MESSAGE_TYPE : Int = 2;
+ public static inline var WRONG_METHOD_NAME : Int = 3;
+ public static inline var BAD_SEQUENCE_ID : Int = 4;
+ public static inline var MISSING_RESULT : Int = 5;
+ public static inline var INTERNAL_ERROR : Int = 6;
+ public static inline var PROTOCOL_ERROR : Int = 7;
+ public static inline var INVALID_TRANSFORM : Int = 8;
+ public static inline var INVALID_PROTOCOL : Int = 9;
+ public static inline var UNSUPPORTED_CLIENT_TYPE : Int = 10;
+
+ public function new(type : Int = UNKNOWN, message : String = "") {
+ super(message, type);
+ }
+
+ public static function read(iprot:TProtocol) : TApplicationException {
+ var field:TField;
+ iprot.readStructBegin();
+
+ var message : String = null;
+ var type : Int = UNKNOWN;
+
+ while (true) {
+ field = iprot.readFieldBegin();
+ if (field.type == TType.STOP) {
+ break;
+ }
+ switch (field.id) {
+ case 1:
+ if (field.type == TType.STRING) {
+ message = iprot.readString();
+ }
+ else {
+ TProtocolUtil.skip(iprot, field.type);
+ }
+ case 2:
+ if (field.type == TType.I32) {
+ type = iprot.readI32();
+ }
+ else {
+ TProtocolUtil.skip(iprot, field.type);
+ }
+ default:
+ TProtocolUtil.skip(iprot, field.type);
+ }
+ iprot.readFieldEnd();
+ }
+ iprot.readStructEnd();
+ return new TApplicationException(type, message);
+ }
+
+ public function write(oprot:TProtocol) : Void {
+ oprot.writeStructBegin(TAPPLICATION_EXCEPTION_STRUCT);
+ if (errorMsg != null) {
+ oprot.writeFieldBegin(MESSAGE_FIELD);
+ oprot.writeString(errorMsg);
+ oprot.writeFieldEnd();
+ }
+ oprot.writeFieldBegin(TYPE_FIELD);
+ oprot.writeI32(errorID);
+ oprot.writeFieldEnd();
+ oprot.writeFieldStop();
+ oprot.writeStructEnd();
+ }
+}
diff --git a/lib/haxe/src/org/apache/thrift/TBase.hx b/lib/haxe/src/org/apache/thrift/TBase.hx
new file mode 100644
index 0000000..5d8bfc1
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/TBase.hx
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift;
+
+import org.apache.thrift.protocol.TProtocol;
+
+ /**
+ * Generic base interface for generated Thrift objects.
+ *
+ */
+interface TBase {
+
+ /**
+ * Reads the TObject from the given input protocol.
+ *
+ * @param iprot Input protocol
+ */
+ function read(iprot:TProtocol) : Void;
+
+ /**
+ * Writes the objects out to the protocol
+ *
+ * @param oprot Output protocol
+ */
+ function write(oprot:TProtocol) : Void;
+
+ /**
+ * Check if a field is currently set or unset.
+ *
+ * @param fieldId The field's id tag as found in the IDL.
+ */
+ function isSet(fieldId : Int) : Bool;
+
+ /**
+ * Get a field's value by id. Primitive types will be wrapped in the
+ * appropriate "boxed" types.
+ *
+ * @param fieldId The field's id tag as found in the IDL.
+ */
+ function getFieldValue(fieldId : Int) : Dynamic;
+
+ /**
+ * Set a field's value by id. Primitive types must be "boxed" in the
+ * appropriate object wrapper type.
+ *
+ * @param fieldId The field's id tag as found in the IDL.
+ */
+ function setFieldValue(fieldId : Int, value : Dynamic) : Void;
+}
diff --git a/lib/haxe/src/org/apache/thrift/TException.hx b/lib/haxe/src/org/apache/thrift/TException.hx
new file mode 100644
index 0000000..ed630ba
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/TException.hx
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift;
+
+class TException {
+
+ @:isVar
+ public var errorID(default,null) : Int;
+ @:isVar
+ public var errorMsg(default,null) : String;
+
+
+ public function new(msg : String = "", id : Int = 0) {
+ errorID = id;
+ errorMsg = msg;
+ }
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/TFieldRequirementType.hx b/lib/haxe/src/org/apache/thrift/TFieldRequirementType.hx
new file mode 100644
index 0000000..70f698f
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/TFieldRequirementType.hx
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift;
+
+ /**
+ * Requirement type constants.
+ *
+ */
+class TFieldRequirementType {
+ public static inline var REQUIRED : Int = 1;
+ public static inline var OPTIONAL : Int = 2;
+ public static inline var DEFAULT : Int = 3;
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/TProcessor.hx b/lib/haxe/src/org/apache/thrift/TProcessor.hx
new file mode 100644
index 0000000..78ce5a7
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/TProcessor.hx
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift;
+
+import org.apache.thrift.protocol.TProtocol;
+
+/**
+ * A processor is a generic object which operates upon an input stream and
+ * writes to some output stream.
+ */
+interface TProcessor {
+ function process(input:TProtocol, output:TProtocol) : Bool;
+}
diff --git a/lib/haxe/src/org/apache/thrift/helper/Int64Map.hx b/lib/haxe/src/org/apache/thrift/helper/Int64Map.hx
new file mode 100644
index 0000000..8d9e4e1
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/Int64Map.hx
@@ -0,0 +1,265 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.helper;
+
+import Map;
+import haxe.Int64;
+import haxe.ds.IntMap;
+
+
+// Int64Map allows mapping of Int64 keys to arbitrary values.
+// ObjectMap<> cannot be used, since we want to compare by value, not address
+
+class Int64Map<T> implements IMap< Int64, T> {
+
+ private var SubMaps : IntMap< IntMap< T>>; // Hi -> Lo -> Value
+
+ public function new() : Void {
+ SubMaps = new IntMap< IntMap< T>>();
+ };
+
+ private function GetSubMap( hi : haxe.Int32, canCreate : Bool) : IntMap< T> {
+ if( SubMaps.exists(hi)) {
+ return SubMaps.get(hi);
+ }
+
+ if( ! canCreate) {
+ return null;
+ }
+
+ var lomap = new IntMap< T>();
+ SubMaps.set( hi, lomap);
+ return lomap;
+ }
+
+ /**
+ Maps `key` to `value`.
+ If `key` already has a mapping, the previous value disappears.
+ If `key` is null, the result is unspecified.
+ **/
+ public function set( key : Int64, value : T ) : Void {
+ if( key == null) {
+ return;
+ }
+
+ var lomap = GetSubMap( Int64.getHigh(key), true);
+ lomap.set( Int64.getLow(key), value);
+ }
+
+
+ /**
+ Returns the current mapping of `key`.
+ If no such mapping exists, null is returned.
+ If `key` is null, the result is unspecified.
+
+ Note that a check like `map.get(key) == null` can hold for two reasons:
+
+ 1. the map has no mapping for `key`
+ 2. the map has a mapping with a value of `null`
+
+ If it is important to distinguish these cases, `exists()` should be
+ used.
+
+ **/
+ public function get( key : Int64) : Null<T> {
+ if( key == null) {
+ return null;
+ }
+
+ var lomap = GetSubMap( Int64.getHigh(key), false);
+ if( lomap == null) {
+ return null;
+ }
+
+ return lomap.get( Int64.getLow(key));
+ }
+
+ /**
+ Returns true if `key` has a mapping, false otherwise.
+ If `key` is null, the result is unspecified.
+ **/
+ public function exists( key : Int64) : Bool {
+ if( key == null) {
+ return false;
+ }
+
+ var lomap = GetSubMap( Int64.getHigh(key), false);
+ if( lomap == null) {
+ return false;
+ }
+
+ return lomap.exists( Int64.getLow(key));
+ }
+
+ /**
+ Removes the mapping of `key` and returns true if such a mapping existed,
+ false otherwise. If `key` is null, the result is unspecified.
+ **/
+ public function remove( key : Int64) : Bool {
+ if( key == null) {
+ return false;
+ }
+
+ var lomap = GetSubMap( Int64.getHigh(key), false);
+ if( lomap == null) {
+ return false;
+ }
+
+ return lomap.remove( Int64.getLow(key));
+ }
+
+
+ /**
+ Returns an Iterator over the keys of `this` Map.
+ The order of keys is undefined.
+ **/
+ public function keys() : Iterator<Int64> {
+ return new Int64KeyIterator<T>(SubMaps);
+ }
+
+ /**
+ Returns an Iterator over the values of `this` Map.
+ The order of values is undefined.
+ **/
+ public function iterator() : Iterator<T> {
+ return new Int64ValueIterator<T>(SubMaps);
+ }
+
+ /**
+ Returns a String representation of `this` Map.
+ The exact representation depends on the platform and key-type.
+ **/
+ public function toString() : String {
+ var result : String = "{";
+
+ var first = true;
+ for( key in this.keys()) {
+ if( first) {
+ first = false;
+ } else {
+ result += ", ";
+ }
+
+ var value = this.get(key);
+ result += Int64.toStr(key) + ' => $value';
+ }
+
+ return result + "}";
+ }
+
+}
+
+
+// internal helper class for Int64Map<T>
+// all class with matching methods can be used as iterator (duck typing)
+private class Int64MapIteratorBase<T> {
+
+ private var SubMaps : IntMap< IntMap< T>>; // Hi -> Lo -> Value
+
+ private var HiIterator : Iterator< Int> = null;
+ private var LoIterator : Iterator< Int> = null;
+ private var CurrentHi : Int = 0;
+
+ public function new( data : IntMap< IntMap< T>>) : Void {
+ SubMaps = data;
+ HiIterator = SubMaps.keys();
+ LoIterator = null;
+ CurrentHi = 0;
+ };
+
+ /**
+ Returns false if the iteration is complete, true otherwise.
+
+ Usually iteration is considered to be complete if all elements of the
+ underlying data structure were handled through calls to next(). However,
+ in custom iterators any logic may be used to determine the completion
+ state.
+ **/
+ public function hasNext() : Bool {
+
+ if( (LoIterator != null) && LoIterator.hasNext()) {
+ return true;
+ }
+
+ while( (HiIterator != null) && HiIterator.hasNext()) {
+ CurrentHi = HiIterator.next();
+ LoIterator = SubMaps.get(CurrentHi).keys();
+ if( (LoIterator != null) && LoIterator.hasNext()) {
+ return true;
+ }
+ }
+
+ HiIterator = null;
+ LoIterator = null;
+ return false;
+ }
+
+}
+
+
+// internal helper class for Int64Map<T>
+// all class with matching methods can be used as iterator (duck typing)
+private class Int64KeyIterator<T>extends Int64MapIteratorBase<T> {
+
+ public function new( data : IntMap< IntMap< T>>) : Void {
+ super(data);
+ };
+
+ /**
+ Returns the current item of the Iterator and advances to the next one.
+
+ This method is not required to check hasNext() first. A call to this
+ method while hasNext() is false yields unspecified behavior.
+ **/
+ public function next() : Int64 {
+ if( hasNext()) {
+ return Int64.make( CurrentHi, LoIterator.next());
+ } else {
+ throw "no more elements";
+ }
+ }
+}
+
+
+// internal helper class for Int64Map<T>
+// all class with matching methods can be used as iterator (duck typing)
+private class Int64ValueIterator<T> extends Int64MapIteratorBase<T> {
+
+ public function new( data : IntMap< IntMap< T>>) : Void {
+ super(data);
+ };
+
+ /**
+ Returns the current item of the Iterator and advances to the next one.
+
+ This method is not required to check hasNext() first. A call to this
+ method while hasNext() is false yields unspecified behavior.
+ **/
+ public function next() : T {
+ if( hasNext()) {
+ return SubMaps.get(CurrentHi).get(LoIterator.next());
+ } else {
+ throw "no more elements";
+ }
+ }
+}
+
+
+// EOF
diff --git a/lib/haxe/src/org/apache/thrift/helper/IntSet.hx b/lib/haxe/src/org/apache/thrift/helper/IntSet.hx
new file mode 100644
index 0000000..214f3bd
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/IntSet.hx
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.helper;
+
+import Map;
+
+
+class IntSet {
+
+ private var _elements = new haxe.ds.IntMap<Int>();
+ private var _size : Int = 0;
+ public var size(get,never) : Int;
+
+ public function new( values : Array<Int> = null) {
+ if ( values != null) {
+ for ( value in values) {
+ add(value);
+ }
+ }
+ }
+
+ public function iterator():Iterator<Int> {
+ return _elements.keys();
+ }
+
+ public function traceAll() : Void {
+ trace('$_size entries');
+ for(entry in this) {
+ var yes = contains(entry);
+ trace('- $entry, contains() = $yes');
+ }
+ }
+
+ public function add(o : Int) : Bool {
+ if( _elements.exists(o)) {
+ return false;
+ }
+ _size++;
+ _elements.set(o,_size);
+ return true;
+ }
+
+ public function clear() : Void {
+ while( _size > 0) {
+ remove( _elements.keys().next());
+ }
+ }
+
+ public function contains(o : Int) : Bool {
+ return _elements.exists(o);
+ }
+
+ public function isEmpty() : Bool {
+ return _size == 0;
+ }
+
+ public function remove(o : Int) : Bool {
+ if (contains(o)) {
+ _elements.remove(o);
+ _size--;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public function toArray() : Array<Int> {
+ var ret : Array<Int> = new Array<Int>();
+ for (key in _elements.keys()) {
+ ret.push(key);
+ }
+ return ret;
+ }
+
+ public function get_size() : Int {
+ return _size;
+ }
+}
+
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx b/lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx
new file mode 100644
index 0000000..c590c75
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.helper;
+
+import Map;
+
+
+class ObjectSet<K> {
+
+ private var _elements = new haxe.ds.ObjectMap<K,Int>();
+ private var _size : Int = 0;
+ public var size(get,never) : Int;
+
+ public function new( values : Array<K> = null) {
+ if ( values != null) {
+ for ( value in values) {
+ add(value);
+ }
+ }
+ }
+
+ public function iterator():Iterator<K> {
+ return _elements.keys();
+ }
+
+ public function traceAll() : Void {
+ trace('$_size entries');
+ for(entry in this) {
+ var yes = contains(entry);
+ trace('- $entry, contains() = $yes');
+ }
+ }
+
+ public function add(o : K) : Bool {
+ if( _elements.exists(o)) {
+ return false;
+ }
+ _size++;
+ _elements.set(o,_size);
+ return true;
+ }
+
+ public function clear() : Void {
+ while( _size > 0) {
+ remove( _elements.keys().next());
+ }
+ }
+
+ public function contains(o : K) : Bool {
+ return _elements.exists(o);
+ }
+
+ public function isEmpty() : Bool {
+ return _size == 0;
+ }
+
+ public function remove(o : K) : Bool {
+ if (contains(o)) {
+ _elements.remove(o);
+ _size--;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public function toArray() : Array<K> {
+ var ret : Array<K> = new Array<K>();
+ for (key in _elements.keys()) {
+ ret.push(key);
+ }
+ return ret;
+ }
+
+ public function get_size() : Int {
+ return _size;
+ }
+}
+
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/helper/StringSet.hx b/lib/haxe/src/org/apache/thrift/helper/StringSet.hx
new file mode 100644
index 0000000..ee772c7
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/StringSet.hx
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.helper;
+
+import Map;
+
+
+class StringSet {
+
+ private var _elements = new haxe.ds.StringMap<Int>();
+ private var _size : Int = 0;
+ public var size(get,never) : Int;
+
+ public function new( values : Array<String> = null) {
+ if ( values != null) {
+ for ( value in values) {
+ add(value);
+ }
+ }
+ }
+
+ public function iterator():Iterator<String> {
+ return _elements.keys();
+ }
+
+ public function traceAll() : Void {
+ trace('$_size entries');
+ for(entry in this) {
+ var yes = contains(entry);
+ trace('- $entry, contains() = $yes');
+ }
+ }
+
+ public function add(o : String) : Bool {
+ if( _elements.exists(o)) {
+ return false;
+ }
+ _size++;
+ _elements.set(o,_size);
+ return true;
+ }
+
+ public function clear() : Void {
+ while( _size > 0) {
+ remove( _elements.keys().next());
+ }
+ }
+
+ public function contains(o : String) : Bool {
+ return _elements.exists(o);
+ }
+
+ public function isEmpty() : Bool {
+ return _size == 0;
+ }
+
+ public function remove(o : String) : Bool {
+ if (contains(o)) {
+ _elements.remove(o);
+ _size--;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public function toArray() : Array<String> {
+ var ret : Array<String> = new Array<String>();
+ for (key in _elements.keys()) {
+ ret.push(key);
+ }
+ return ret;
+ }
+
+ public function get_size() : String {
+ return _size;
+ }
+}
+
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/meta_data/FieldMetaData.hx b/lib/haxe/src/org/apache/thrift/meta_data/FieldMetaData.hx
new file mode 100644
index 0000000..147eed9
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/meta_data/FieldMetaData.hx
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.meta_data;
+
+import flash.utils.Dictionary;
+
+/**
+* This class is used to store meta data about thrift fields. Every field in a
+* a struct should have a corresponding instance of this class describing it.
+*
+*/
+class FieldMetaData {
+
+ public var fieldName : String;
+ public var requirementType : Int;
+ public var valueMetaData:FieldValueMetaData;
+
+ private static var structMap:Dictionary = new Dictionary();
+
+ public function FieldMetaData(name : String, req : Int, vMetaData:FieldValueMetaData) {
+ this.fieldName = name;
+ this.requirementType = req;
+ this.valueMetaData = vMetaData;
+ }
+
+ public static function addStructMetaDataMap(sClass:Class, map:Dictionary) : Void{
+ structMap[sClass] = map;
+ }
+
+ /**
+ * Returns a map with metadata (i.e. instances of FieldMetaData) that
+ * describe the fields of the given class.
+ *
+ * @param sClass The TBase class for which the metadata map is requested
+ */
+ public static function getStructMetaDataMap(sClass:Class):Dictionary {
+ return structMap[sClass];
+ }
+}
diff --git a/lib/haxe/src/org/apache/thrift/meta_data/FieldValueMetaData.hx b/lib/haxe/src/org/apache/thrift/meta_data/FieldValueMetaData.hx
new file mode 100644
index 0000000..06c7f48
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/meta_data/FieldValueMetaData.hx
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.meta_data;
+
+import org.apache.thrift.protocol.TType;
+
+/**
+ * FieldValueMetaData and collection of subclasses to store metadata about
+ * the value(s) of a field
+ */
+class FieldValueMetaData {
+
+ public var type : Int;
+
+ public function FieldValueMetaData(type : Int) {
+ this.type = type;
+ }
+
+ public function isStruct() : Bool {
+ return type == TType.STRUCT;
+ }
+
+ public function isContainer() : Bool {
+ return type == TType.LIST || type == TType.MAP || type == TType.SET;
+ }
+}
diff --git a/lib/haxe/src/org/apache/thrift/meta_data/ListMetaData.hx b/lib/haxe/src/org/apache/thrift/meta_data/ListMetaData.hx
new file mode 100644
index 0000000..36bb2d1
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/meta_data/ListMetaData.hx
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.meta_data;
+
+class ListMetaData extends FieldValueMetaData {
+
+ public var elemMetaData:FieldValueMetaData;
+
+ public function ListMetaData(type : Int, eMetaData:FieldValueMetaData) {
+ super(type);
+ this.elemMetaData = eMetaData;
+ }
+}
diff --git a/lib/haxe/src/org/apache/thrift/meta_data/MapMetaData.hx b/lib/haxe/src/org/apache/thrift/meta_data/MapMetaData.hx
new file mode 100644
index 0000000..bf0502a
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/meta_data/MapMetaData.hx
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.meta_data;
+
+class MapMetaData extends FieldValueMetaData {
+
+ public var keyMetaData:FieldValueMetaData;
+ public var valueMetaData:FieldValueMetaData;
+
+ public function MapMetaData(type : Int, kMetaData:FieldValueMetaData, vMetaData:FieldValueMetaData) {
+ super(type);
+ this.keyMetaData = kMetaData;
+ this.valueMetaData = vMetaData;
+ }
+}
diff --git a/lib/haxe/src/org/apache/thrift/meta_data/SetMetaData.hx b/lib/haxe/src/org/apache/thrift/meta_data/SetMetaData.hx
new file mode 100644
index 0000000..0ee6c93
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/meta_data/SetMetaData.hx
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.meta_data;
+
+class SetMetaData extends FieldValueMetaData {
+
+ public var elemMetaData:FieldValueMetaData;
+
+ public function SetMetaData(type : Int, eMetaData:FieldValueMetaData) {
+ super(type);
+ this.elemMetaData = eMetaData;
+ }
+}
diff --git a/lib/haxe/src/org/apache/thrift/meta_data/StructMetaData.hx b/lib/haxe/src/org/apache/thrift/meta_data/StructMetaData.hx
new file mode 100644
index 0000000..bbf11e7
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/meta_data/StructMetaData.hx
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.meta_data;
+
+class StructMetaData extends FieldValueMetaData {
+
+ public var structClass:Class;
+
+ public function StructMetaData(type : Int, sClass:Class) {
+ super(type);
+ this.structClass = sClass;
+ }
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx
new file mode 100644
index 0000000..9693b35
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx
@@ -0,0 +1,296 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+import haxe.io.Bytes;
+import haxe.io.BytesInput;
+import haxe.io.BytesOutput;
+import haxe.io.BytesBuffer;
+import haxe.Int64;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransport;
+
+/**
+* Binary protocol implementation for thrift.
+*/
+class TBinaryProtocol implements TProtocol {
+
+ private static var ANONYMOUS_STRUCT:TStruct = new TStruct();
+
+ private static inline var VERSION_MASK : haxe.Int32 = 0xffff0000;
+ private static inline var VERSION_1 : haxe.Int32 = 0x80010000;
+
+ private var strictRead_ : Bool = false;
+ private var strictWrite_ : Bool = true;
+ private var trans_ : TTransport;
+
+ /**
+ * Constructor
+ */
+ public function new(trans:TTransport, strictRead : Bool=false, strictWrite : Bool=true) {
+ trans_ = trans;
+ strictRead_ = strictRead;
+ strictWrite_ = strictWrite;
+ }
+
+ public function getTransport():TTransport {
+ return trans_;
+ }
+
+ public function writeMessageBegin(message:TMessage) : Void {
+ if (strictWrite_) {
+ var version : Int = VERSION_1 | message.type;
+ writeI32(version);
+ writeString(message.name);
+ writeI32(message.seqid);
+ } else {
+ writeString(message.name);
+ writeByte(message.type);
+ writeI32(message.seqid);
+ }
+ }
+
+ public function writeMessageEnd() : Void {}
+
+ public function writeStructBegin(struct:TStruct) : Void {}
+
+ public function writeStructEnd() : Void {}
+
+ public function writeFieldBegin(field:TField) : Void {
+ writeByte(field.type);
+ writeI16(field.id);
+ }
+
+ public function writeFieldEnd() : Void {}
+
+ public function writeFieldStop() : Void {
+ writeByte(TType.STOP);
+ }
+
+ public function writeMapBegin(map:TMap) : Void {
+ writeByte(map.keyType);
+ writeByte(map.valueType);
+ writeI32(map.size);
+ }
+
+ public function writeMapEnd() : Void {}
+
+ public function writeListBegin(list:TList) : Void {
+ writeByte(list.elemType);
+ writeI32(list.size);
+ }
+
+ public function writeListEnd() : Void {}
+
+ public function writeSetBegin(set:TSet) : Void {
+ writeByte(set.elemType);
+ writeI32(set.size);
+ }
+
+ public function writeSetEnd() : Void {}
+
+ public function writeBool(b : Bool) : Void {
+ writeByte(b ? 1 : 0);
+ }
+
+
+ public function writeByte(b : Int) : Void {
+ var out = new BytesOutput();
+ out.bigEndian = true;
+ out.writeByte(b);
+ trans_.write(out.getBytes(), 0, 1);
+ }
+
+ public function writeI16(i16 : Int) : Void {
+ var out = new BytesOutput();
+ out.bigEndian = true;
+ out.writeInt16(i16);
+ trans_.write(out.getBytes(), 0, 2);
+ }
+
+ public function writeI32(i32 : Int) : Void {
+ var out = new BytesOutput();
+ out.bigEndian = true;
+ out.writeInt32(i32);
+ trans_.write(out.getBytes(), 0, 4);
+ }
+
+ public function writeI64(i64 : haxe.Int64) : Void {
+ var out = new BytesOutput();
+ out.bigEndian = true;
+ var hi = Int64.getHigh(i64);
+ var lo = Int64.getLow(i64);
+ out.writeInt32(hi);
+ out.writeInt32(lo);
+ trans_.write(out.getBytes(), 0, 8);
+ }
+
+ public function writeDouble(dub:Float) : Void {
+ var out = new BytesOutput();
+ out.bigEndian = true;
+ out.writeDouble(dub);
+ trans_.write(out.getBytes(), 0, 8);
+ }
+
+ public function writeString(str : String) : Void {
+ var out = new BytesOutput();
+ out.bigEndian = true;
+ out.writeString(str);
+ var bytes = out.getBytes();
+ writeI32( bytes.length);
+ trans_.write( bytes, 0, bytes.length);
+ }
+
+ public function writeBinary(bin:Bytes) : Void {
+ writeI32(bin.length);
+ trans_.write(bin, 0, bin.length);
+ }
+
+ /**
+ * Reading methods.
+ */
+
+ public function readMessageBegin():TMessage {
+ var size : Int = readI32();
+ if (size < 0) {
+ var version : Int = size & VERSION_MASK;
+ if (version != VERSION_1) {
+ throw new TProtocolException(TProtocolException.BAD_VERSION, "Bad version in readMessageBegin");
+ }
+ return new TMessage(readString(), size & 0x000000ff, readI32());
+ } else {
+ if (strictRead_) {
+ throw new TProtocolException(TProtocolException.BAD_VERSION, "Missing version in readMessageBegin, old client?");
+ }
+ return new TMessage(readStringBody(size), readByte(), readI32());
+ }
+ }
+
+ public function readMessageEnd() : Void {}
+
+ public function readStructBegin():TStruct {
+ return ANONYMOUS_STRUCT;
+ }
+
+ public function readStructEnd() : Void {}
+
+ public function readFieldBegin() : TField {
+ var type : Int = readByte();
+ var id : Int = 0;
+ if (type != TType.STOP)
+ {
+ id = readI16();
+ }
+ return new TField("", type, id);
+ }
+
+ public function readFieldEnd() : Void {}
+
+ public function readMapBegin() : TMap {
+ return new TMap(readByte(), readByte(), readI32());
+ }
+
+ public function readMapEnd() : Void {}
+
+ public function readListBegin():TList {
+ return new TList(readByte(), readI32());
+ }
+
+ public function readListEnd() : Void {}
+
+ public function readSetBegin() : TSet {
+ return new TSet(readByte(), readI32());
+ }
+
+ public function readSetEnd() : Void {}
+
+ public function readBool() : Bool {
+ return (readByte() == 1);
+ }
+
+
+ public function readByte() : Int {
+ var buffer = new BytesBuffer();
+ var len = trans_.readAll( buffer, 0, 1);
+ var inp = new BytesInput( buffer.getBytes(), 0, 1);
+ inp.bigEndian = true;
+ return inp.readByte();
+ }
+
+ public function readI16() : Int {
+ var buffer = new BytesBuffer();
+ var len = trans_.readAll( buffer, 0, 2);
+ var inp = new BytesInput( buffer.getBytes(), 0, 2);
+ inp.bigEndian = true;
+ return inp.readInt16();
+ }
+
+ public function readI32() : Int {
+ var buffer = new BytesBuffer();
+ var len = trans_.readAll( buffer, 0, 4);
+ var inp = new BytesInput( buffer.getBytes(), 0, 4);
+ inp.bigEndian = true;
+ return inp.readInt32();
+ }
+
+ public function readI64() : haxe.Int64 {
+ var buffer = new BytesBuffer();
+ var len = trans_.readAll( buffer, 0, 8);
+ var inp = new BytesInput( buffer.getBytes(), 0, 8);
+ inp.bigEndian = true;
+ var hi = inp.readInt32();
+ var lo = inp.readInt32();
+ return Int64.make(hi,lo);
+ }
+
+ public function readDouble():Float {
+ var buffer = new BytesBuffer();
+ var len = trans_.readAll( buffer, 0, 8);
+ var inp = new BytesInput( buffer.getBytes(), 0, 8);
+ inp.bigEndian = true;
+ return inp.readDouble();
+ }
+
+ public function readString() : String {
+ return readStringBody( readI32());
+ }
+
+ public function readStringBody(len : Int) : String {
+ if( len > 0) {
+ var buffer = new BytesBuffer();
+ trans_.readAll( buffer, 0, len);
+ var inp = new BytesInput( buffer.getBytes(), 0, len);
+ inp.bigEndian = true;
+ return inp.readString(len);
+ } else {
+ return "";
+ }
+ }
+
+ public function readBinary() : Bytes {
+ var len : Int = readI32();
+ var buffer = new BytesBuffer();
+ trans_.readAll( buffer, 0, len);
+ return buffer.getBytes();
+ }
+
+}
+
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocolFactory.hx b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocolFactory.hx
new file mode 100644
index 0000000..0d7c7c5
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocolFactory.hx
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+import org.apache.thrift.transport.TTransport;
+
+
+/**
+* Binary Protocol Factory
+*/
+class TBinaryProtocolFactory implements TProtocolFactory {
+
+ private var strictRead_ : Bool = false;
+ private var strictWrite_ : Bool = true;
+
+ public function new( strictRead : Bool = false, strictWrite : Bool = true) {
+ strictRead_ = strictRead;
+ strictWrite_ = strictWrite;
+ }
+
+ public function getProtocol( trans : TTransport) : TProtocol {
+ return new TBinaryProtocol( trans, strictRead_, strictWrite_);
+ }
+}
+
+
+
+
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TField.hx b/lib/haxe/src/org/apache/thrift/protocol/TField.hx
new file mode 100644
index 0000000..20f3fb9
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TField.hx
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+class TField {
+
+ public var name : String;
+ public var type : Int;
+ public var id : Int;
+
+ public function new(n : String = "", t : Int = 0, i : Int = 0) {
+ name = n;
+ type = t;
+ id = i;
+ }
+
+ public function toString() : String {
+ return '<TField name:"$name" type:"$type" field-id:"$id">';
+ }
+
+ public function equals( otherField : TField) : Bool {
+ return (type == otherField.type)
+ && (id == otherField.id);
+ }
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx
new file mode 100644
index 0000000..edd5e12
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx
@@ -0,0 +1,1074 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+import haxe.io.Bytes;
+import haxe.io.BytesInput;
+import haxe.io.BytesOutput;
+import haxe.io.BytesBuffer;
+import haxe.ds.GenericStack;
+import haxe.Utf8;
+import haxe.crypto.Base64;
+import haxe.Int64;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TMessage;
+import org.apache.thrift.protocol.TField;
+import org.apache.thrift.protocol.TMap;
+import org.apache.thrift.protocol.TSet;
+import org.apache.thrift.protocol.TList;
+import org.apache.thrift.transport.TTransport;
+
+
+
+/* JSON protocol implementation for thrift.
+* This is a full-featured protocol supporting Write and Read.
+*
+* Please see the C++ class header for a detailed description of the wire format.
+*
+* Adapted from the Java version.
+*/
+class TJSONProtocol implements TProtocol {
+
+ public var trans(default,null) : TTransport;
+
+ // Stack of nested contexts that we may be in
+ private var contextStack : GenericStack<JSONBaseContext> = new GenericStack<JSONBaseContext>();
+
+ // Current context that we are in
+ private var context : JSONBaseContext;
+
+ // Reader that manages a 1-byte buffer
+ private var reader : LookaheadReader;
+
+
+ // TJSONProtocol Constructor
+ public function new( trans : TTransport)
+ {
+ this.trans = trans;
+ this.context = new JSONBaseContext(this);
+ this.reader = new LookaheadReader(this);
+ }
+
+ public function getTransport() : TTransport {
+ return trans;
+ }
+
+ public function writeMessageBegin(message:TMessage) : Void {
+ WriteJSONArrayStart();
+ WriteJSONInteger( JSONConstants.VERSION);
+ WriteJSONString( Utf8Encode(message.name));
+ WriteJSONInteger( message.type);
+ WriteJSONInteger( message.seqid);
+ }
+
+ public function writeMessageEnd() : Void {
+ WriteJSONArrayEnd();
+ }
+
+ public function writeStructBegin(struct:TStruct) : Void {
+ WriteJSONObjectStart();
+ }
+
+ public function writeStructEnd() : Void {
+ WriteJSONObjectEnd();
+ }
+
+ public function writeFieldBegin(field:TField) : Void {
+ WriteJSONInteger( field.id );
+ WriteJSONObjectStart();
+ WriteJSONString( Utf8Encode( JSONConstants.GetTypeNameForTypeID( field.type)));
+ }
+
+ public function writeFieldEnd() : Void {
+ WriteJSONObjectEnd();
+ }
+
+ public function writeFieldStop() : Void { }
+
+ public function writeMapBegin(map:TMap) : Void {
+ WriteJSONArrayStart();
+ WriteJSONString( Utf8Encode( JSONConstants.GetTypeNameForTypeID( map.keyType)));
+ WriteJSONString( Utf8Encode( JSONConstants.GetTypeNameForTypeID( map.valueType)));
+ WriteJSONInteger( map.size);
+ WriteJSONObjectStart();
+ }
+
+ public function writeMapEnd() : Void {
+ WriteJSONObjectEnd();
+ WriteJSONArrayEnd();
+ }
+
+ public function writeListBegin(list:TList) : Void {
+ WriteJSONArrayStart();
+ WriteJSONString( Utf8Encode( JSONConstants.GetTypeNameForTypeID( list.elemType )));
+ WriteJSONInteger( list.size);
+ }
+
+ public function writeListEnd() : Void {
+ WriteJSONArrayEnd();
+ }
+
+ public function writeSetBegin(set:TSet) : Void {
+ WriteJSONArrayStart();
+ WriteJSONString( Utf8Encode( JSONConstants.GetTypeNameForTypeID( set.elemType)));
+ WriteJSONInteger( set.size);
+ }
+
+ public function writeSetEnd() : Void {
+ WriteJSONArrayEnd();
+ }
+
+ public function writeBool(b : Bool) : Void {
+ if( b)
+ WriteJSONInteger( 1);
+ else
+ WriteJSONInteger( 0);
+ }
+
+ public function writeByte(b : Int) : Void {
+ WriteJSONInteger( b);
+ }
+
+ public function writeI16(i16 : Int) : Void {
+ WriteJSONInteger( i16);
+ }
+
+ public function writeI32(i32 : Int) : Void {
+ WriteJSONInteger( i32);
+ }
+
+ public function writeI64(i64 : haxe.Int64) : Void {
+ WriteJSONInt64( i64);
+ }
+
+ public function writeDouble(dub:Float) : Void {
+ WriteJSONDouble(dub);
+ }
+
+ public function writeString(str : String) : Void {
+ WriteJSONString( Utf8Encode(str));
+ }
+
+ public function writeBinary(bin:Bytes) : Void {
+ WriteJSONBase64(bin);
+ }
+
+ public function readMessageBegin():TMessage {
+ var message : TMessage = new TMessage();
+ ReadJSONArrayStart();
+ if (ReadJSONInteger() != JSONConstants.VERSION)
+ {
+ throw new TProtocolException(TProtocolException.BAD_VERSION,
+ "Message contained bad version.");
+ }
+
+ var buf = ReadJSONString(false);
+ message.name = Utf8Decode(buf);
+ message.type = ReadJSONInteger();
+ message.seqid = ReadJSONInteger();
+ return message;
+ }
+
+ public function readMessageEnd() : Void {
+ ReadJSONArrayEnd();
+ }
+
+ public function readStructBegin():TStruct {
+ ReadJSONObjectStart();
+ return new TStruct();
+ }
+
+ public function readStructEnd() : Void {
+ ReadJSONObjectEnd();
+ }
+
+ public function readFieldBegin() : TField {
+ var field : TField = new TField();
+ var ch = reader.Peek();
+ if (StringFromBytes(ch) == JSONConstants.RBRACE)
+ {
+ field.type = TType.STOP;
+ }
+ else
+ {
+ field.id = ReadJSONInteger();
+ ReadJSONObjectStart();
+ field.type = JSONConstants.GetTypeIDForTypeName( Utf8Decode( ReadJSONString(false)));
+ }
+ return field;
+ }
+
+ public function readFieldEnd() : Void {
+ ReadJSONObjectEnd();
+ }
+
+ public function readMapBegin() : TMap {
+ ReadJSONArrayStart();
+ var KeyType = JSONConstants.GetTypeIDForTypeName( Utf8Decode( ReadJSONString(false)));
+ var ValueType = JSONConstants.GetTypeIDForTypeName( Utf8Decode( ReadJSONString(false)));
+ var Count : Int = ReadJSONInteger();
+ ReadJSONObjectStart();
+
+ var map = new TMap( KeyType, ValueType, Count);
+ return map;
+ }
+
+ public function readMapEnd() : Void {
+ ReadJSONObjectEnd();
+ ReadJSONArrayEnd();
+ }
+
+ public function readListBegin():TList {
+ ReadJSONArrayStart();
+ var ElementType = JSONConstants.GetTypeIDForTypeName( Utf8Decode( ReadJSONString(false)));
+ var Count : Int = ReadJSONInteger();
+
+ var list = new TList( ElementType, Count);
+ return list;
+ }
+
+ public function readListEnd() : Void {
+ ReadJSONArrayEnd();
+ }
+
+ public function readSetBegin() : TSet {
+ ReadJSONArrayStart();
+ var ElementType = JSONConstants.GetTypeIDForTypeName( Utf8Decode( ReadJSONString(false)));
+ var Count : Int = ReadJSONInteger();
+
+ var set = new TSet( ElementType, Count);
+ return set;
+ }
+
+ public function readSetEnd() : Void {
+ ReadJSONArrayEnd();
+ }
+
+ public function readBool() : Bool {
+ return (ReadJSONInteger() == 0 ? false : true);
+ }
+
+ public function readByte() : Int {
+ return ReadJSONInteger();
+ }
+
+ public function readI16() : Int {
+ return ReadJSONInteger();
+ }
+
+ public function readI32() : Int {
+ return ReadJSONInteger();
+ }
+
+ public function readI64() : haxe.Int64 {
+ return ReadJSONInt64();
+ }
+
+ public function readDouble():Float {
+ return ReadJSONDouble();
+ }
+
+ public function readString() : String {
+ var buf = ReadJSONString(false);
+ return Utf8Decode(buf);
+ }
+
+ public function readBinary() : Bytes {
+ return ReadJSONBase64();
+ }
+
+ // Push a new JSON context onto the stack.
+ private function PushContext(c : JSONBaseContext) : Void {
+ contextStack.add(context);
+ context = c;
+ }
+
+ // Pop the last JSON context off the stack
+ private function PopContext() : Void {
+ context = contextStack.pop();
+ }
+
+
+ // Write the bytes in array buf as a JSON characters, escaping as needed
+ private function WriteJSONString( b : Bytes) : Void {
+ context.Write();
+
+ var tmp = BytesFromString( JSONConstants.QUOTE);
+ trans.write( tmp, 0, tmp.length);
+
+ for (i in 0 ... b.length) {
+ var value = b.get(i);
+
+ if ((value & 0x00FF) >= 0x30)
+ {
+ if (String.fromCharCode(value) == JSONConstants.BACKSLASH.charAt(0))
+ {
+ tmp = BytesFromString( JSONConstants.BACKSLASH + JSONConstants.BACKSLASH);
+ trans.write( tmp, 0, tmp.length);
+ }
+ else
+ {
+ trans.write( b, i, 1);
+ }
+ }
+ else
+ {
+ var num = JSONConstants.JSON_CHAR_TABLE[value];
+ if (num == 1)
+ {
+ trans.write( b, i, 1);
+ }
+ else if (num > 1)
+ {
+ var buf = new BytesBuffer();
+ buf.addString( JSONConstants.BACKSLASH);
+ buf.addByte( num);
+ tmp = buf.getBytes();
+ trans.write( tmp, 0, tmp.length);
+ }
+ else
+ {
+ var buf = new BytesBuffer();
+ buf.addString( JSONConstants.ESCSEQ);
+ buf.addString( HexChar( (value & 0xFF000000) >> 12));
+ buf.addString( HexChar( (value & 0x00FF0000) >> 8));
+ buf.addString( HexChar( (value & 0x0000FF00) >> 4));
+ buf.addString( HexChar( value & 0x000000FF));
+ tmp = buf.getBytes();
+ trans.write( tmp, 0, tmp.length);
+ }
+ }
+ }
+
+ tmp = BytesFromString( JSONConstants.QUOTE);
+ trans.write( tmp, 0, tmp.length);
+ }
+
+ // Write out number as a JSON value. If the context dictates so,
+ // it will be wrapped in quotes to output as a JSON string.
+ private function WriteJSONInteger( num : Int) : Void {
+ context.Write();
+
+ var str : String = "";
+ var escapeNum : Bool = context.EscapeNumbers();
+
+ if (escapeNum) {
+ str += JSONConstants.QUOTE;
+ }
+
+ str += Std.string(num);
+
+ if (escapeNum) {
+ str += JSONConstants.QUOTE;
+ }
+
+ var tmp = BytesFromString( str);
+ trans.write( tmp, 0, tmp.length);
+ }
+
+ // Write out number as a JSON value. If the context dictates so,
+ // it will be wrapped in quotes to output as a JSON string.
+ private function WriteJSONInt64( num : Int64) : Void {
+ context.Write();
+
+ var str : String = "";
+ var escapeNum : Bool = context.EscapeNumbers();
+
+ if (escapeNum) {
+ str += JSONConstants.QUOTE;
+ }
+
+ str += Std.string(num);
+
+ if (escapeNum) {
+ str += JSONConstants.QUOTE;
+ }
+
+trace('WriteJSONInt64($str)');
+ var tmp = BytesFromString( str);
+ trans.write( tmp, 0, tmp.length);
+ }
+
+ // Write out a double as a JSON value. If it is NaN or infinity or if the
+ // context dictates escaping, Write out as JSON string.
+ private function WriteJSONDouble(num : Float) : Void {
+ context.Write();
+
+
+ var special : Bool = false;
+ var rendered : String = "";
+ if( Math.isNaN(num)) {
+ special = true;
+ rendered = JSONConstants.FLOAT_IS_NAN;
+ } else if (! Math.isFinite(num)) {
+ special = true;
+ if( num > 0) {
+ rendered = JSONConstants.FLOAT_IS_POS_INF;
+ } else {
+ rendered = JSONConstants.FLOAT_IS_NEG_INF;
+ }
+ } else {
+ rendered = Std.string(num); // plain and simple float number
+ }
+
+ // compose output
+ var escapeNum : Bool = special || context.EscapeNumbers();
+ var str : String = "";
+ if (escapeNum) {
+ str += JSONConstants.QUOTE;
+ }
+ str += rendered;
+ if (escapeNum) {
+ str += JSONConstants.QUOTE;
+ }
+
+ var tmp = BytesFromString( str);
+ trans.write( tmp, 0, tmp.length);
+ }
+
+ // Write out contents of byte array b as a JSON string with base-64 encoded data
+ private function WriteJSONBase64( b : Bytes) : Void {
+ context.Write();
+
+ var buf = new BytesBuffer();
+ buf.addString( JSONConstants.QUOTE);
+ buf.addString( Base64.encode(b));
+ buf.addString( JSONConstants.QUOTE);
+
+ var tmp = buf.getBytes();
+ trans.write( tmp, 0, tmp.length);
+ }
+
+ private function WriteJSONObjectStart() : Void {
+ context.Write();
+ var tmp = BytesFromString( JSONConstants.LBRACE);
+ trans.write( tmp, 0, tmp.length);
+ PushContext( new JSONPairContext(this));
+ }
+
+ private function WriteJSONObjectEnd() : Void {
+ PopContext();
+ var tmp = BytesFromString( JSONConstants.RBRACE);
+ trans.write( tmp, 0, tmp.length);
+ }
+
+ private function WriteJSONArrayStart() : Void {
+ context.Write();
+ var tmp = BytesFromString( JSONConstants.LBRACKET);
+ trans.write( tmp, 0, tmp.length);
+ PushContext( new JSONListContext(this));
+ }
+
+ private function WriteJSONArrayEnd() : Void {
+ PopContext();
+ var tmp = BytesFromString( JSONConstants.RBRACKET);
+ trans.write( tmp, 0, tmp.length);
+ }
+
+
+ /**
+ * Reading methods.
+ */
+
+ // Read a byte that must match char, otherwise an exception is thrown.
+ public function ReadJSONSyntaxChar( char : String) : Void {
+ var b = BytesFromString( char);
+
+ var ch = reader.Read();
+ if (ch.get(0) != b.get(0))
+ {
+ throw new TProtocolException(TProtocolException.INVALID_DATA,
+ 'Unexpected character: $ch');
+ }
+ }
+
+ // Read in a JSON string, unescaping as appropriate.
+ // Skip Reading from the context if skipContext is true.
+ private function ReadJSONString(skipContext : Bool) : Bytes
+ {
+ if (!skipContext)
+ {
+ context.Read();
+ }
+
+ var buffer : BytesBuffer = new BytesBuffer();
+
+ ReadJSONSyntaxChar( JSONConstants.QUOTE);
+ while (true)
+ {
+ var ch = reader.Read();
+
+ // end of string?
+ if (StringFromBytes(ch) == JSONConstants.QUOTE)
+ {
+ break;
+ }
+
+ // escaped?
+ if (StringFromBytes(ch) != JSONConstants.ESCSEQ.charAt(0))
+ {
+ buffer.addByte( ch.get(0));
+ continue;
+ }
+
+ // distinguish between \uXXXX (hex unicode) and \X (control chars)
+ ch = reader.Read();
+ if (StringFromBytes(ch) != JSONConstants.ESCSEQ.charAt(1))
+ {
+ var value = JSONConstants.ESCAPE_CHARS_TO_VALUES[ch.get(0)];
+ if( value == null)
+ {
+ throw new TProtocolException( TProtocolException.INVALID_DATA, "Expected control char");
+ }
+ buffer.addByte( value);
+ continue;
+ }
+
+
+ // it's \uXXXX
+ var hexbuf = new BytesBuffer();
+ var hexlen = trans.readAll( hexbuf, 0, 4);
+ if( hexlen != 4)
+ {
+ throw new TProtocolException( TProtocolException.INVALID_DATA, "Not enough data for \\uNNNN sequence");
+ }
+
+ var hexdigits = hexbuf.getBytes();
+ var charcode = 0;
+ charcode = (charcode << 4) + HexVal( String.fromCharCode(hexdigits.get(0)));
+ charcode = (charcode << 4) + HexVal( String.fromCharCode(hexdigits.get(1)));
+ charcode = (charcode << 4) + HexVal( String.fromCharCode(hexdigits.get(2)));
+ charcode = (charcode << 4) + HexVal( String.fromCharCode(hexdigits.get(3)));
+ buffer.addString( String.fromCharCode(charcode));
+ }
+
+ return buffer.getBytes();
+ }
+
+ // Return true if the given byte could be a valid part of a JSON number.
+ private function IsJSONNumeric(b : Int) : Bool {
+ switch (b)
+ {
+ case "+".code: return true;
+ case "-".code: return true;
+ case ".".code: return true;
+ case "0".code: return true;
+ case "1".code: return true;
+ case "2".code: return true;
+ case "3".code: return true;
+ case "4".code: return true;
+ case "5".code: return true;
+ case "6".code: return true;
+ case "7".code: return true;
+ case "8".code: return true;
+ case "9".code: return true;
+ case "E".code: return true;
+ case "e".code: return true;
+ }
+ return false;
+ }
+
+ // Read in a sequence of characters that are all valid in JSON numbers. Does
+ // not do a complete regex check to validate that this is actually a number.
+ private function ReadJSONNumericChars() : String
+ {
+ var buffer : BytesBuffer = new BytesBuffer();
+ while (true)
+ {
+ var ch = reader.Peek();
+ if( ! IsJSONNumeric( ch.get(0)))
+ {
+ break;
+ }
+ buffer.addByte( reader.Read().get(0));
+ }
+ return StringFromBytes( buffer.getBytes());
+ }
+
+ // Read in a JSON number. If the context dictates, Read in enclosing quotes.
+ private function ReadJSONInteger() : Int {
+ context.Read();
+
+ if (context.EscapeNumbers()) {
+ ReadJSONSyntaxChar( JSONConstants.QUOTE);
+ }
+
+ var str : String = ReadJSONNumericChars();
+
+ if (context.EscapeNumbers()) {
+ ReadJSONSyntaxChar( JSONConstants.QUOTE);
+ }
+
+ var value = Std.parseInt(str);
+ if( value == null) {
+ throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
+ }
+
+ return value;
+ }
+
+ // Read in a JSON number. If the context dictates, Read in enclosing quotes.
+ private function ReadJSONInt64() : haxe.Int64 {
+ context.Read();
+
+ if (context.EscapeNumbers()) {
+ ReadJSONSyntaxChar( JSONConstants.QUOTE);
+ }
+
+ var str : String = ReadJSONNumericChars();
+ if( str.length == 0) {
+ throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
+ }
+
+ if (context.EscapeNumbers()) {
+ ReadJSONSyntaxChar( JSONConstants.QUOTE);
+ }
+
+trace('ReadJSONInt64() = $str');
+
+ // process sign
+ var bMinus = false;
+ var startAt = 0;
+ if( (str.charAt(0) == "+") || (str.charAt(0) == "-")) {
+ bMinus = (str.charAt(0) == "-");
+ startAt++;
+ }
+
+ // process digits
+ var value : Int64 = Int64.make(0,0);
+ var bGotDigits = false;
+ for( i in startAt ... str.length) {
+ var ch = str.charAt(i);
+ var digit = JSONConstants.DECIMAL_DIGITS[ch];
+ if( digit == null) {
+ throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
+ }
+ bGotDigits = true;
+
+ // these are decimal digits
+ value = Int64.mul( value, Int64.make(0,10));
+ value = Int64.add( value, Int64.make(0,digit));
+ }
+
+ // process pending minus sign, if applicable
+ // this should also handle the edge case MIN_INT64 correctly
+ if( bMinus && (Int64.compare(value,Int64.make(0,0)) > 0)) {
+ value = Int64.neg( value);
+ bMinus = false;
+ }
+
+ if( ! bGotDigits) {
+ throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
+ }
+
+ return value;
+ }
+
+ // Read in a JSON double value. Throw if the value is not wrapped in quotes
+ // when expected or if wrapped in quotes when not expected.
+ private function ReadJSONDouble() : Float {
+ context.Read();
+
+ var str : String = "";
+ if (StringFromBytes(reader.Peek()) == JSONConstants.QUOTE) {
+ str = StringFromBytes( ReadJSONString(true));
+
+ // special cases
+ if( str == JSONConstants.FLOAT_IS_NAN) {
+ return Math.NaN;
+ }
+ if( str == JSONConstants.FLOAT_IS_POS_INF) {
+ return Math.POSITIVE_INFINITY;
+ }
+ if( str == JSONConstants.FLOAT_IS_NEG_INF) {
+ return Math.NEGATIVE_INFINITY;
+ }
+
+ if( ! context.EscapeNumbers()) {
+ // throw - we should not be in a string in this case
+ throw new TProtocolException(TProtocolException.INVALID_DATA, "Numeric data unexpectedly quoted");
+ }
+ }
+ else
+ {
+ if( context.EscapeNumbers()) {
+ // This will throw - we should have had a quote if EscapeNumbers() == true
+ ReadJSONSyntaxChar( JSONConstants.QUOTE);
+ }
+
+ str = ReadJSONNumericChars();
+ }
+
+ // parse and check - we should have at least one valid digit
+ var dub = Std.parseFloat( str);
+ if( (str.length == 0) || Math.isNaN(dub)) {
+ throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
+ }
+
+ return dub;
+ }
+
+ // Read in a JSON string containing base-64 encoded data and decode it.
+ private function ReadJSONBase64() : Bytes
+ {
+ var str = StringFromBytes( ReadJSONString(false));
+ return Base64.decode( str);
+ }
+
+ private function ReadJSONObjectStart() : Void {
+ context.Read();
+ ReadJSONSyntaxChar( JSONConstants.LBRACE);
+ PushContext(new JSONPairContext(this));
+ }
+
+ private function ReadJSONObjectEnd() : Void {
+ ReadJSONSyntaxChar( JSONConstants.RBRACE);
+ PopContext();
+ }
+
+ private function ReadJSONArrayStart() : Void {
+ context.Read();
+ ReadJSONSyntaxChar( JSONConstants.LBRACKET);
+ PushContext(new JSONListContext(this));
+ }
+
+ private function ReadJSONArrayEnd() : Void {
+ ReadJSONSyntaxChar( JSONConstants.RBRACKET);
+ PopContext();
+ }
+
+
+ public static function BytesFromString( str : String) : Bytes {
+ var buf = new BytesBuffer();
+ buf.addString( str);
+ return buf.getBytes();
+ }
+
+ public static function StringFromBytes( buf : Bytes) : String {
+ var inp = new BytesInput( buf);
+ return inp.readString( buf.length);
+ }
+
+ public static function Utf8Encode(str : String) : Bytes {
+ return BytesFromString( Utf8.encode( str));
+ }
+
+ public static function Utf8Decode( buf : Bytes) : String {
+ return Utf8.decode( StringFromBytes( buf));
+ }
+
+ // Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its corresponding hex value
+ private static function HexVal(char : String) : Int {
+ var value = JSONConstants.HEX_DIGITS[char];
+ if( value == null) {
+ throw new TProtocolException(TProtocolException.INVALID_DATA, 'Expected hex character: $char');
+ }
+ return value;
+ }
+
+ // Convert a byte containing a hex nibble to its corresponding hex character
+ private static function HexChar(nibble : Int) : String
+ {
+ return "0123456789abcdef".charAt(nibble & 0x0F);
+ }
+
+
+}
+
+
+@:allow(TJSONProtocol)
+class JSONConstants {
+ public static var COMMA = ",";
+ public static var COLON = ":";
+ public static var LBRACE = "{";
+ public static var RBRACE = "}";
+ public static var LBRACKET = "[";
+ public static var RBRACKET = "]";
+ public static var QUOTE = "\"";
+ public static var BACKSLASH = "\\";
+
+ public static var ESCSEQ = "\\u";
+
+ public static var FLOAT_IS_NAN = "NaN";
+ public static var FLOAT_IS_POS_INF = "Infinity";
+ public static var FLOAT_IS_NEG_INF = "-Infinity";
+
+ public static var VERSION = 1;
+ public static var JSON_CHAR_TABLE = [
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ "b".code, "t".code, "n".code, 0, "f".code, "r".code, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, "\"".code, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ ];
+
+ public static var ESCAPE_CHARS = ['"','\\','/','b','f','n','r','t'];
+ public static var ESCAPE_CHARS_TO_VALUES = [
+ "\"".code => 0x22,
+ "\\".code => 0x5C,
+ "/".code => 0x2F,
+ "b".code => 0x08,
+ "f".code => 0x0C,
+ "n".code => 0x0A,
+ "r".code => 0x0D,
+ "t".code => 0x09
+ ];
+
+ public static var DECIMAL_DIGITS = [
+ "0" => 0,
+ "1" => 1,
+ "2" => 2,
+ "3" => 3,
+ "4" => 4,
+ "5" => 5,
+ "6" => 6,
+ "7" => 7,
+ "8" => 8,
+ "9" => 9
+ ];
+
+ public static var HEX_DIGITS = [
+ "0" => 0,
+ "1" => 1,
+ "2" => 2,
+ "3" => 3,
+ "4" => 4,
+ "5" => 5,
+ "6" => 6,
+ "7" => 7,
+ "8" => 8,
+ "9" => 9,
+ "A" => 10,
+ "a" => 10,
+ "B" => 11,
+ "b" => 11,
+ "C" => 12,
+ "c" => 12,
+ "D" => 13,
+ "d" => 13,
+ "E" => 14,
+ "e" => 14,
+ "F" => 15,
+ "f" => 15
+ ];
+
+
+ public static var DEF_STRING_SIZE = 16;
+
+ public static var NAME_BOOL = 'tf';
+ public static var NAME_BYTE = 'i8';
+ public static var NAME_I16 = 'i16';
+ public static var NAME_I32 = 'i32';
+ public static var NAME_I64 = 'i64';
+ public static var NAME_DOUBLE = 'dbl';
+ public static var NAME_STRUCT = 'rec';
+ public static var NAME_STRING = 'str';
+ public static var NAME_MAP = 'map';
+ public static var NAME_LIST = 'lst';
+ public static var NAME_SET = 'set';
+
+ public static function GetTypeNameForTypeID(typeID : Int) : String {
+ switch (typeID)
+ {
+ case TType.BOOL: return NAME_BOOL;
+ case TType.BYTE: return NAME_BYTE;
+ case TType.I16: return NAME_I16;
+ case TType.I32: return NAME_I32;
+ case TType.I64: return NAME_I64;
+ case TType.DOUBLE: return NAME_DOUBLE;
+ case TType.STRING: return NAME_STRING;
+ case TType.STRUCT: return NAME_STRUCT;
+ case TType.MAP: return NAME_MAP;
+ case TType.SET: return NAME_SET;
+ case TType.LIST: return NAME_LIST;
+ }
+ throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized type");
+ }
+
+ private static var NAMES_TO_TYPES = [
+ NAME_BOOL => TType.BOOL,
+ NAME_BYTE => TType.BYTE,
+ NAME_I16 => TType.I16,
+ NAME_I32 => TType.I32,
+ NAME_I64 => TType.I64,
+ NAME_DOUBLE => TType.DOUBLE,
+ NAME_STRING => TType.STRING,
+ NAME_STRUCT => TType.STRUCT,
+ NAME_MAP => TType.MAP,
+ NAME_SET => TType.SET,
+ NAME_LIST => TType.LIST
+ ];
+
+ public static function GetTypeIDForTypeName(name : String) : Int
+ {
+ var type = NAMES_TO_TYPES[name];
+ if( null != type) {
+ return type;
+ }
+ throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized type");
+ }
+
+}
+
+
+// Base class for tracking JSON contexts that may require inserting/Reading
+// additional JSON syntax characters. This base context does nothing.
+@:allow(TJSONProtocol)
+class JSONBaseContext
+{
+ private var proto : TJSONProtocol;
+
+ public function new(proto : TJSONProtocol )
+ {
+ this.proto = proto;
+ }
+
+ public function Write() : Void { }
+ public function Read() : Void { }
+
+ public function EscapeNumbers() : Bool {
+ return false;
+ }
+}
+
+
+// Context for JSON lists.
+// Will insert/Read commas before each item except for the first one
+@:allow(TJSONProtocol)
+class JSONListContext extends JSONBaseContext
+{
+ public function new( proto : TJSONProtocol) {
+ super(proto);
+ }
+
+ private var first : Bool = true;
+
+ public override function Write() : Void {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ var buf = new BytesBuffer();
+ buf.addString( JSONConstants.COMMA);
+ var tmp = buf.getBytes();
+ proto.trans.write( tmp, 0, tmp.length);
+ }
+ }
+
+ public override function Read() : Void {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ proto.ReadJSONSyntaxChar( JSONConstants.COMMA);
+ }
+ }
+}
+
+
+// Context for JSON records.
+// Will insert/Read colons before the value portion of each record
+// pair, and commas before each key except the first. In addition,
+// will indicate that numbers in the key position need to be escaped
+// in quotes (since JSON keys must be strings).
+@:allow(TJSONProtocol)
+class JSONPairContext extends JSONBaseContext
+{
+ public function new( proto : TJSONProtocol ) {
+ super( proto);
+ }
+
+ private var first : Bool = true;
+ private var colon : Bool = true;
+
+ public override function Write() : Void {
+ if (first)
+ {
+ first = false;
+ colon = true;
+ }
+ else
+ {
+ var buf = new BytesBuffer();
+ buf.addString( colon ? JSONConstants.COLON : JSONConstants.COMMA);
+ var tmp = buf.getBytes();
+ proto.trans.write( tmp, 0, tmp.length);
+ colon = !colon;
+ }
+ }
+
+ public override function Read() : Void {
+ if (first)
+ {
+ first = false;
+ colon = true;
+ }
+ else
+ {
+ proto.ReadJSONSyntaxChar( colon ? JSONConstants.COLON : JSONConstants.COMMA);
+ colon = !colon;
+ }
+ }
+
+ public override function EscapeNumbers() : Bool
+ {
+ return colon;
+ }
+}
+
+// Holds up to one byte from the transport
+@:allow(TJSONProtocol)
+class LookaheadReader {
+
+ private var proto : TJSONProtocol;
+ private var data : Bytes;
+
+ public function new( proto : TJSONProtocol ) {
+ this.proto = proto;
+ data = null;
+ }
+
+
+ // Return and consume the next byte to be Read, either taking it from the
+ // data buffer if present or getting it from the transport otherwise.
+ public function Read() : Bytes {
+ var retval = Peek();
+ data = null;
+ return retval;
+ }
+
+ // Return the next byte to be Read without consuming, filling the data
+ // buffer if it has not been filled alReady.
+ public function Peek() : Bytes {
+ if (data == null) {
+ var buf = new BytesBuffer();
+ proto.trans.readAll(buf, 0, 1);
+ data = buf.getBytes();
+ }
+ return data;
+ }
+}
+
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocolFactory.hx b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocolFactory.hx
new file mode 100644
index 0000000..169629a
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocolFactory.hx
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+import org.apache.thrift.transport.TTransport;
+
+
+/**
+* JSON Protocol Factory
+*/
+class TJSONProtocolFactory implements TProtocolFactory {
+
+ public function new() {
+ }
+
+ public function getProtocol( trans : TTransport) : TProtocol {
+ return new TJSONProtocol( trans);
+ }
+}
+
+
+
+
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TList.hx b/lib/haxe/src/org/apache/thrift/protocol/TList.hx
new file mode 100644
index 0000000..d6c15c1
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TList.hx
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+class TList {
+
+ public var elemType : Int;
+ public var size : Int;
+
+ public function new(t : Int = 0, s : Int = 0) {
+ elemType = t;
+ size = s;
+ }
+
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TMap.hx b/lib/haxe/src/org/apache/thrift/protocol/TMap.hx
new file mode 100644
index 0000000..5af8c4e
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TMap.hx
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+class TMap {
+
+ public var keyType : Int;
+ public var valueType : Int;
+ public var size : Int;
+
+ public function new(k : Int = 0, v : Int = 0, s : Int = 0) {
+ keyType = k;
+ valueType = v;
+ size = s;
+ }
+
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TMessage.hx b/lib/haxe/src/org/apache/thrift/protocol/TMessage.hx
new file mode 100644
index 0000000..98c883b
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TMessage.hx
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+class TMessage {
+
+ public var name : String;
+ public var type : Int;
+ public var seqid : Int;
+
+ public function new(n : String = "", t : Int = 0, s : Int = 0) {
+ name = n;
+ type = t;
+ seqid = s;
+ }
+
+ public function toString() : String {
+ return "<TMessage name:'" + name + "' type: " + type + " seqid:" + seqid + ">";
+ }
+
+ public function equals(other:TMessage) : Bool {
+ return name == other.name && type == other.type && seqid == other.seqid;
+ }
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TMessageType.hx b/lib/haxe/src/org/apache/thrift/protocol/TMessageType.hx
new file mode 100644
index 0000000..b141940
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TMessageType.hx
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+class TMessageType {
+ public static inline var CALL : Int = 1;
+ public static inline var REPLY : Int = 2;
+ public static inline var EXCEPTION : Int = 3;
+ public static inline var ONEWAY : Int = 4;
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx
new file mode 100644
index 0000000..58873da
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+import haxe.io.Bytes;
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransport;
+
+/**
+* Protocol interface definition
+*/
+interface TProtocol {
+
+ function getTransport() : TTransport;
+
+ /**
+ * Writing methods.
+ */
+ function writeMessageBegin(message:TMessage) : Void;
+ function writeMessageEnd() : Void;
+ function writeStructBegin(struct:TStruct) : Void;
+ function writeStructEnd() : Void;
+ function writeFieldBegin(field:TField) : Void;
+ function writeFieldEnd() : Void;
+ function writeFieldStop() : Void;
+ function writeMapBegin(map:TMap) : Void;
+ function writeMapEnd() : Void;
+ function writeListBegin(list:TList) : Void;
+ function writeListEnd() : Void;
+ function writeSetBegin(set:TSet) : Void;
+ function writeSetEnd() : Void;
+ function writeBool(b : Bool) : Void;
+ function writeByte(b : Int) : Void;
+ function writeI16(i16 : Int) : Void;
+ function writeI32(i32 : Int) : Void;
+ function writeI64(i64 : haxe.Int64) : Void;
+ function writeDouble(dub : Float) : Void;
+ function writeString(str : String) : Void;
+ function writeBinary(bin : Bytes) : Void;
+
+ /**
+ * Reading methods.
+ */
+ function readMessageBegin():TMessage;
+ function readMessageEnd() : Void;
+ function readStructBegin():TStruct;
+ function readStructEnd() : Void;
+ function readFieldBegin():TField;
+ function readFieldEnd() : Void;
+ function readMapBegin():TMap;
+ function readMapEnd() : Void;
+ function readListBegin():TList;
+ function readListEnd() : Void;
+ function readSetBegin():TSet;
+ function readSetEnd() : Void;
+ function readBool() : Bool;
+ function readByte() : Int;
+ function readI16() : Int;
+ function readI32() : Int;
+ function readI64() : haxe.Int64;
+ function readDouble() : Float;
+ function readString() : String;
+ function readBinary() : Bytes;
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocolException.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocolException.hx
new file mode 100644
index 0000000..dbbcb8c
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocolException.hx
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+import org.apache.thrift.TException;
+
+class TProtocolException extends TException {
+
+ public static inline var UNKNOWN : Int = 0;
+ public static inline var INVALID_DATA : Int = 1;
+ public static inline var NEGATIVE_SIZE : Int = 2;
+ public static inline var SIZE_LIMIT : Int = 3;
+ public static inline var BAD_VERSION : Int = 4;
+ public static inline var NOT_IMPLEMENTED : Int = 5;
+ public static inline var DEPTH_LIMIT : Int = 6;
+
+ public function new(error : Int = UNKNOWN, message : String = "") {
+ super(message, error);
+ }
+
+
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocolFactory.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocolFactory.hx
new file mode 100644
index 0000000..d231dbe
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocolFactory.hx
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+import org.apache.thrift.transport.TTransport;
+
+interface TProtocolFactory {
+ function getProtocol(trans:TTransport):TProtocol;
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocolUtil.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocolUtil.hx
new file mode 100644
index 0000000..794e397
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocolUtil.hx
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+import org.apache.thrift.*;
+
+ /**
+ * Utility class with static methods for interacting with protocol data
+ * streams.
+ *
+ */
+class TProtocolUtil {
+
+ /**
+ * The maximum recursive depth the skip() function will traverse before
+ * throwing a TException.
+ */
+ private static var maxSkipDepth : Int = Limits.I32_MAX;
+
+ /**
+ * Specifies the maximum recursive depth that the skip function will
+ * traverse before throwing a TException. This is a global setting, so
+ * any call to skip in this JVM will enforce this value.
+ *
+ * @param depth the maximum recursive depth. A value of 2 would allow
+ * the skip function to skip a structure or collection with basic children,
+ * but it would not permit skipping a struct that had a field containing
+ * a child struct. A value of 1 would only allow skipping of simple
+ * types and empty structs/collections.
+ */
+ public function setMaxSkipDepth(depth : Int) : Void {
+ maxSkipDepth = depth;
+ }
+
+ /**
+ * Skips over the next data element from the provided input TProtocol object.
+ *
+ * @param prot the protocol object to read from
+ * @param type the next value will be intepreted as this TType value.
+ */
+ public static function skip(prot:TProtocol, type : Int) : Void {
+ skipMaxDepth(prot, type, maxSkipDepth);
+ }
+
+ /**
+ * Skips over the next data element from the provided input TProtocol object.
+ *
+ * @param prot the protocol object to read from
+ * @param type the next value will be intepreted as this TType value.
+ * @param maxDepth this function will only skip complex objects to this
+ * recursive depth, to prevent Java stack overflow.
+ */
+ public static function skipMaxDepth(prot:TProtocol, type : Int, maxDepth : Int) : Void {
+ if (maxDepth <= 0) {
+ throw new TException("Maximum skip depth exceeded");
+ }
+ switch (type) {
+ case TType.BOOL: {
+ prot.readBool();
+ }
+ case TType.BYTE: {
+ prot.readByte();
+ }
+ case TType.I16: {
+ prot.readI16();
+ }
+ case TType.I32: {
+ prot.readI32();
+ }
+ case TType.I64: {
+ prot.readI64();
+ }
+ case TType.DOUBLE: {
+ prot.readDouble();
+ }
+ case TType.STRING: {
+ prot.readBinary();
+ }
+ case TType.STRUCT: {
+ prot.readStructBegin();
+ while (true) {
+ var field:TField = prot.readFieldBegin();
+ if (field.type == TType.STOP) {
+ break;
+ }
+ skipMaxDepth(prot, field.type, maxDepth - 1);
+ prot.readFieldEnd();
+ }
+ prot.readStructEnd();
+ }
+ case TType.MAP: {
+ var map:TMap = prot.readMapBegin();
+ for (i in 0 ... map.size) {
+ skipMaxDepth(prot, map.keyType, maxDepth - 1);
+ skipMaxDepth(prot, map.valueType, maxDepth - 1);
+ }
+ prot.readMapEnd();
+ }
+ case TType.SET: {
+ var set:TSet = prot.readSetBegin();
+ for (j in 0 ... set.size) {
+ skipMaxDepth(prot, set.elemType, maxDepth - 1);
+ }
+ prot.readSetEnd();
+ }
+ case TType.LIST: {
+ var list:TList = prot.readListBegin();
+ for (k in 0 ... list.size) {
+ skipMaxDepth(prot, list.elemType, maxDepth - 1);
+ }
+ prot.readListEnd();
+ }
+ default:
+ trace("Unknown field type ",type," in skipMaxDepth()");
+ }
+ }
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TSet.hx b/lib/haxe/src/org/apache/thrift/protocol/TSet.hx
new file mode 100644
index 0000000..77806e6
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TSet.hx
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+class TSet {
+
+ public var elemType : Int;
+ public var size : Int;
+
+ public function new(t : Int = 0, s : Int = 0) {
+ elemType = t;
+ size = s;
+ }
+
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TStruct.hx b/lib/haxe/src/org/apache/thrift/protocol/TStruct.hx
new file mode 100644
index 0000000..faeef40
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TStruct.hx
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+class TStruct {
+
+ public var name : String;
+
+ public function new(n : String = "") {
+ name = n;
+ }
+
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TType.hx b/lib/haxe/src/org/apache/thrift/protocol/TType.hx
new file mode 100644
index 0000000..0534399
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TType.hx
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+class TType {
+
+ public static inline var STOP : Int = 0;
+ public static inline var VOID : Int = 1;
+ public static inline var BOOL : Int = 2;
+ public static inline var BYTE : Int = 3;
+ public static inline var DOUBLE : Int = 4;
+ public static inline var I16 : Int = 6;
+ public static inline var I32 : Int = 8;
+ public static inline var I64 : Int = 10;
+ public static inline var STRING : Int = 11;
+ public static inline var STRUCT : Int = 12;
+ public static inline var MAP : Int = 13;
+ public static inline var SET : Int = 14;
+ public static inline var LIST : Int = 15;
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/server/TServer.hx b/lib/haxe/src/org/apache/thrift/server/TServer.hx
new file mode 100644
index 0000000..9b235f69
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/server/TServer.hx
@@ -0,0 +1,105 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.server;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.meta_data.*;
+
+class TServer
+{
+ private var processor : TProcessor = null;
+ private var serverTransport : TServerTransport = null;
+ private var inputTransportFactory : TTransportFactory = null;
+ private var outputTransportFactory : TTransportFactory = null;
+ private var inputProtocolFactory : TProtocolFactory = null;
+ private var outputProtocolFactory : TProtocolFactory = null;
+
+ // server events
+ public var serverEventHandler : TServerEventHandler = null;
+
+ // Log delegation
+ private var _logDelegate : Dynamic->Void = null;
+ public var logDelegate(default,set) : Dynamic->Void;
+
+ public function new( processor : TProcessor,
+ serverTransport : TServerTransport,
+ inputTransportFactory : TTransportFactory = null,
+ outputTransportFactory : TTransportFactory = null,
+ inputProtocolFactory : TProtocolFactory = null,
+ outputProtocolFactory : TProtocolFactory = null,
+ logDelegate : Dynamic->Void = null)
+ {
+ this.processor = processor;
+ this.serverTransport = serverTransport;
+ this.inputTransportFactory = inputTransportFactory;
+ this.outputTransportFactory = outputTransportFactory;
+ this.inputProtocolFactory = inputProtocolFactory;
+ this.outputProtocolFactory = outputProtocolFactory;
+ this.logDelegate = logDelegate;
+
+ ApplyMissingDefaults();
+ }
+
+ private function ApplyMissingDefaults() {
+ if( processor == null)
+ throw "Invalid server configuration: processor missing";
+ if( serverTransport == null)
+ throw "Invalid server configuration: serverTransport missing";
+ if( inputTransportFactory == null)
+ inputTransportFactory = new TTransportFactory();
+ if( outputTransportFactory == null)
+ outputTransportFactory = new TTransportFactory();
+ if( inputProtocolFactory == null)
+ inputProtocolFactory = new TBinaryProtocolFactory();
+ if( outputProtocolFactory == null)
+ outputProtocolFactory= new TBinaryProtocolFactory();
+ if( logDelegate == null)
+ logDelegate = DefaultLogDelegate;
+ }
+
+
+ private function set_logDelegate(value : Dynamic->Void) : Dynamic->Void {
+ if(value != null) {
+ _logDelegate = value;
+ } else {
+ _logDelegate = DefaultLogDelegate;
+ }
+ return _logDelegate;
+ }
+
+
+ private function DefaultLogDelegate(value : Dynamic) : Void {
+ trace( value);
+ }
+
+
+
+ public function Serve() : Void {
+ throw new AbstractMethodError();
+ }
+
+
+ public function Stop() : Void {
+ throw new AbstractMethodError();
+ }
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx b/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx
new file mode 100644
index 0000000..08f48b2
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.server;
+
+import org.apache.thrift.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.protocol.*;
+
+
+// Interface implemented by server users to handle events from the server
+interface TServerEventHandler {
+
+ // Called before the server begins
+ function preServe() : Void;
+
+ // Called when a new client has connected and is about to being processing
+ function createContext( input : TProtocol, output : TProtocol) : Dynamic;
+
+ // Called when a client has finished request-handling to delete server context
+ function deleteContext( serverContext : Dynamic, input : TProtocol, output : TProtocol) : Void;
+
+ // Called when a client is about to call the processor
+ function processContext( serverContext : Dynamic, transport : TTransport) : Void;
+}
diff --git a/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx b/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx
new file mode 100644
index 0000000..20a7195
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx
@@ -0,0 +1,125 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.server;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.meta_data.*;
+
+// Simple single-threaded server for testing
+class TSimpleServer extends TServer {
+
+ private var stop : Bool = false;
+
+ public function new( processor : TProcessor,
+ serverTransport : TServerTransport,
+ transportFactory : TTransportFactory = null,
+ protocolFactory : TProtocolFactory = null,
+ logDelegate : Dynamic->Void = null) {
+ super( processor, serverTransport,
+ transportFactory, transportFactory,
+ protocolFactory, protocolFactory,
+ logDelegate);
+ }
+
+
+
+ public override function Serve() : Void
+ {
+ try
+ {
+ serverTransport.Listen();
+ }
+ catch (ttx : TTransportException)
+ {
+ logDelegate(ttx);
+ return;
+ }
+
+ // Fire the preServe server event when server is up,
+ // but before any client connections
+ if (serverEventHandler != null) {
+ serverEventHandler.preServe();
+ }
+
+ while( ! stop)
+ {
+ var client : TTransport = null;
+ var inputTransport : TTransport = null;
+ var outputTransport : TTransport = null;
+ var inputProtocol : TProtocol = null;
+ var outputProtocol : TProtocol = null;
+ var connectionContext : Dynamic = null;
+ try
+ {
+ client = serverTransport.Accept();
+ if (client != null) {
+ inputTransport = inputTransportFactory.getTransport( client);
+ outputTransport = outputTransportFactory.getTransport( client);
+ inputProtocol = inputProtocolFactory.getProtocol( inputTransport);
+ outputProtocol = outputProtocolFactory.getProtocol( outputTransport);
+
+ // Recover event handler (if any) and fire createContext
+ // server event when a client connects
+ if (serverEventHandler != null) {
+ connectionContext = serverEventHandler.createContext(inputProtocol, outputProtocol);
+ }
+
+ // Process client requests until client disconnects
+ while( true) {
+ // Fire processContext server event
+ // N.B. This is the pattern implemented in C++ and the event fires provisionally.
+ // That is to say it may be many minutes between the event firing and the client request
+ // actually arriving or the client may hang up without ever makeing a request.
+ if (serverEventHandler != null) {
+ serverEventHandler.processContext(connectionContext, inputTransport);
+ }
+
+ //Process client request (blocks until transport is readable)
+ if( ! processor.process( inputProtocol, outputProtocol)) {
+ break;
+ }
+ }
+ }
+ }
+ catch( ttx : TTransportException)
+ {
+ // Usually a client disconnect, expected
+ }
+ catch( e : Dynamic)
+ {
+ // Unexpected
+ logDelegate(e);
+ }
+
+ // Fire deleteContext server event after client disconnects
+ if (serverEventHandler != null) {
+ serverEventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
+ }
+ }
+ }
+
+ public override function Stop() : Void
+ {
+ stop = true;
+ serverTransport.Close();
+ }
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx
new file mode 100644
index 0000000..5d77140
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http : //www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.transport;
+
+import org.apache.thrift.transport.*;
+
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+import haxe.io.BytesOutput;
+import haxe.io.BytesInput;
+
+
+/**
+ * TFramedTransport is a buffered TTransport that ensures a fully read message
+ * every time by preceding messages with a 4-byte frame size.
+ */
+class TFramedTransport extends TTransport
+{
+ public static inline var DEFAULT_MAX_LENGTH = 16384000;
+
+ var maxLength_ : Int;
+
+ /**
+ * Underlying transport
+ */
+ var transport_ : TTransport = null;
+
+ /**
+ * Buffer for output
+ */
+ var writeBuffer_ : BytesOutput = new BytesOutput();
+
+ /**
+ * Buffer for input
+ */
+ var readBuffer_ : BytesInput = null;
+
+ /**
+ * Constructor wraps around another transport
+ */
+ public function new( transport : TTransport, maxLength : Int = DEFAULT_MAX_LENGTH) {
+ transport_ = transport;
+ maxLength_ = maxLength;
+ }
+
+ public override function open() : Void {
+ transport_.open();
+ }
+
+ public override function isOpen() : Bool {
+ return transport_.isOpen();
+ }
+
+ public override function close() : Void {
+ transport_.close();
+ }
+
+ public override function read(buf : BytesBuffer, off : Int, len : Int) : Int {
+ var data = Bytes.alloc(len);
+
+ if (readBuffer_ != null) {
+ var got : Int = readBuffer_.readBytes(data, off, len);
+ if (got > 0) {
+ buf.addBytes(data,0,got);
+ return got;
+ };
+ };
+
+ // Read another frame of data
+ readFrame();
+
+ var got = readBuffer_.readBytes(data, off, len);
+ buf.addBytes(data,0,got);
+ return got;
+ }
+
+
+ function readFrameSize() : Int {
+ var buffer = new BytesBuffer();
+ var len = transport_.readAll( buffer, 0, 4);
+ var inp = new BytesInput( buffer.getBytes(), 0, 4);
+ inp.bigEndian = true;
+ return inp.readInt32();
+ }
+
+
+ function readFrame() : Void {
+ var size : Int = readFrameSize();
+
+ if (size < 0) {
+ throw new TTransportException(TTransportException.UNKNOWN, 'Read a negative frame size ($size)!');
+ };
+ if (size > maxLength_) {
+ throw new TTransportException(TTransportException.UNKNOWN, 'Frame size ($size) larger than max length ($maxLength_)!');
+ };
+
+ var buffer = new BytesBuffer();
+ size = transport_.readAll( buffer, 0, size);
+ readBuffer_ = new BytesInput( buffer.getBytes(), 0, size);
+ readBuffer_.bigEndian = true;
+ }
+
+ public override function write(buf : Bytes, off : Int, len : Int) : Void {
+ writeBuffer_.writeBytes(buf, off, len);
+ }
+
+ function writeFrameSize(len : Int) : Void {
+ var out = new BytesOutput();
+ out.bigEndian = true;
+ out.writeInt32(len);
+ transport_.write(out.getBytes(), 0, 4);
+ }
+
+ public override function flush( callback : Dynamic->Void =null) : Void {
+ var buf : Bytes = writeBuffer_.getBytes();
+ var len : Int = buf.length;
+ writeBuffer_ = new BytesOutput();
+
+ writeFrameSize(len);
+ transport_.write(buf, 0, len);
+ transport_.flush();
+ }
+}
+
+
diff --git a/lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx b/lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx
new file mode 100644
index 0000000..00127bf
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http : //www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.transport;
+
+import org.apache.thrift.transport.*;
+
+
+class TFramedTransportFactory extends TTransportFactory {
+
+ var maxLength_ : Int;
+
+ public function new(maxLength : Int = TFramedTransport.DEFAULT_MAX_LENGTH) {
+ super();
+ maxLength_ = maxLength;
+ }
+
+ public override function getTransport(base : TTransport) : TTransport {
+ return new TFramedTransport(base, maxLength_);
+ }
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx
new file mode 100644
index 0000000..4e898f8
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx
@@ -0,0 +1,247 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.transport;
+
+import flash.errors.EOFError;
+import flash.events.Event;
+import flash.events.IOErrorEvent;
+import flash.events.ProgressEvent;
+import flash.events.SecurityErrorEvent;
+import flash.net.URLLoader;
+import flash.net.URLLoaderDataFormat;
+import flash.net.URLRequest;
+import flash.net.URLRequestMethod;
+import flash.utils.IDataInput;
+import flash.utils.IDataOutput;
+import haxe.io.Bytes;
+import flash.net.Socket;
+import flash.events.EventDispatcher;
+
+
+ /**
+ * HTTP implementation of the TTransport interface. Used for working with a
+ * Thrift web services implementation.
+ * Unlike Http Client, it uses a single POST, and chunk-encoding to transfer all messages.
+ */
+
+ public class TFullDuplexHttpClient extends TTransport
+ {
+ private var socket : Socket = null;
+ private var host : String;
+ private var port : Int;
+ private var resource : String;
+ private var stripped : Bool = false;
+ private var obuffer : Bytes = new Bytes();
+ private var input : IDataInput;
+ private var output : IDataOutput;
+ private var bytesInChunk : Int = 0;
+ private var CRLF : Bytes = new Bytes();
+ private var ioCallback : TException->Void = null;
+ private var eventDispatcher : EventDispatcher = new EventDispatcher();
+
+ public function new(host : String, port : Int, resource : String) : Void
+ {
+ CRLF.writeByte(13);
+ CRLF.writeByte(10);
+ this.host = host;
+ this.port = port;
+ this.resource = resource;
+ }
+
+ public override function close() : Void
+ {
+ this.input = null;
+ this.output = null;
+ this.stripped = false;
+ socket.close()
+ }
+
+ public override function peek() : Bool
+ {
+ if(socket.connected)
+ {
+ trace("Bytes remained:" + socket.bytesAvailable);
+ return socket.bytesAvailable>0;
+ }
+ return false;
+ }
+
+ public override function read(buf : Bytes, off : Int, len : Int) : Int
+ {
+ var n1 : Int = 0, n2 : Int = 0, n3 : Int = 0, n4 : Int = 0, cidx : Int = 2;
+ var chunkSize : Bytes = new Bytes();
+
+ try
+ {
+ while (!stripped)
+ {
+ n1 = n2;
+ n2 = n3;
+ n3 = n4;
+ n4 = input.readByte();
+ if ((n1 == 13) && (n2 == 10) && (n3 == 13) && (n4 == 10))
+ {
+ stripped = true;
+ }
+ }
+
+ // read chunk size
+ if (bytesInChunk == 0)
+ {
+ n1 = input.readByte();
+ n2 = input.readByte();
+
+ chunkSize.writeByte(n1);
+ chunkSize.writeByte(n2);
+
+ while (!((n1 == 13) && (n2 == 10)))
+ {
+ n1 = n2;
+ n2 = input.readByte();
+ chunkSize.writeByte(n2);
+ }
+
+ bytesInChunk = parseInt(chunkSize.toString(), 16);
+ }
+
+ input.readBytes(buf, off, len);
+ debugBuffer(buf);
+ bytesInChunk -= len;
+
+ if (bytesInChunk == 0)
+ {
+ // advance the : "\r\n"
+ input.readUTFBytes(2);
+ }
+ return len;
+ }
+ catch (e : EOFError)
+ {
+ trace(e);
+ throw new TTransportException(TTransportException.UNKNOWN, "No more data available.");
+ }
+ catch (e : TException)
+ {
+ trace('TException $e');
+ throw e;
+ }
+ catch (e : Error)
+ {
+ trace(e);
+ throw new TTransportException(TTransportException.UNKNOWN, 'Bad IO error: $e');
+ }
+ catch (e : Dynamic)
+ {
+ trace(e);
+ throw new TTransportException(TTransportException.UNKNOWN, 'Bad IO error: $e');
+ }
+ return 0;
+ }
+
+ public function debugBuffer(buf : Bytes) : Void
+ {
+ var debug : String = "BUFFER >>";
+ var i : Int;
+ for (i = 0; i < buf.length; i++)
+ {
+ debug += buf[i] as int;
+ debug += " ";
+ }
+
+ trace(debug + "<<");
+ }
+
+ public override function write(buf : Bytes, off : Int, len : Int) : Void
+ {
+ obuffer.writeBytes(buf, off, len);
+ }
+
+ public function addEventListener(type : String, listener : Function, useCapture : Bool = false, priority : Int = 0, useWeakReference : Bool = false) : Void
+ {
+ this.eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
+ }
+
+ public override function open() : Void
+ {
+ this.socket = new Socket();
+ this.socket.addEventListener(Event.CONNECT, socketConnected);
+ this.socket.addEventListener(IOErrorEvent.IO_ERROR, socketError);
+ this.socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, socketSecurityError);
+ this.socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
+ this.socket.connect(host, port);
+ }
+
+ public function socketConnected(event : Event) : Void
+ {
+ this.output = this.socket;
+ this.input = this.socket;
+ this.output.writeUTF("CONNECT " + resource + " HTTP/1.1\n" + "Host : " + host + ":" + port + "\r\n" + "User-Agent : BattleNet\r\n" + "Transfer-Encoding : chunked\r\n" + "content-type : application/x-thrift\r\n" + "Accept : */*\r\n\r\n");
+ this.eventDispatcher.dispatchEvent(event);
+ }
+
+ public function socketError(event : IOErrorEvent) : Void
+ {
+ trace("Error Connecting:" + event);
+ this.close();
+ if (ioCallback == null)
+ {
+ return;
+ }
+ ioCallback(new TTransportException(TTransportException.UNKNOWN, "IOError : " + event.text));
+ this.eventDispatcher.dispatchEvent(event);
+ }
+
+ public function socketSecurityError(event : SecurityErrorEvent) : Void
+ {
+ trace("Security Error Connecting:" + event);
+ this.close();
+ this.eventDispatcher.dispatchEvent(event);
+ }
+
+ public function socketDataHandler(event : ProgressEvent) : Void
+ {
+ trace("Got Data call:" +ioCallback);
+ if (ioCallback != null)
+ {
+ ioCallback(null);
+ };
+ this.eventDispatcher.dispatchEvent(event);
+ }
+
+ public override function flush(callback : Error->Void = null) : Void
+ {
+ trace("set callback:" + callback);
+ this.ioCallback = callback;
+ this.output.writeUTF(this.obuffer.length.toString(16));
+ this.output.writeBytes(CRLF);
+ this.output.writeBytes(this.obuffer);
+ this.output.writeBytes(CRLF);
+ this.socket.flush();
+ // waiting for new Flex sdk 3.5
+ //this.obuffer.clear();
+ this.obuffer = new Bytes();
+ }
+
+ public override function isOpen() : Bool
+ {
+ return (this.socket == null ? false : this.socket.connected);
+ }
+
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx
new file mode 100644
index 0000000..d2fda79
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.transport;
+
+
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+import haxe.io.BytesOutput;
+import haxe.io.BytesInput;
+
+#if openfl
+// OpenFL all targets
+import openfl.errors.EOFError;
+import openfl.events.Event;
+import openfl.events.IOErrorEvent;
+import openfl.events.SecurityErrorEvent;
+import openfl.net.URLLoader;
+import openfl.net.URLLoaderDataFormat;
+import openfl.net.URLRequest;
+import openfl.net.URLRequestMethod;
+#elseif flash
+// Haxe flash, no OpenFL
+import flash.errors.EOFError;
+import flash.events.Event;
+import flash.events.IOErrorEvent;
+import flash.events.SecurityErrorEvent;
+import flash.net.URLLoader;
+import flash.net.URLLoaderDataFormat;
+import flash.net.URLRequest;
+import flash.net.URLRequestMethod;
+#else
+// bare Haxe
+import haxe.Http;
+#end
+
+
+
+/**
+* HTTP implementation of the TTransport interface. Used for working with a
+* Thrift web services implementation.
+*/
+
+class THttpClient extends TTransport {
+
+ private var requestBuffer_ : BytesOutput = new BytesOutput();
+ private var responseBuffer_ : BytesInput = null;
+
+ #if (flash || openfl)
+ private var request_ : URLRequest = null;
+ #else
+ private var request_ : Http = null;
+ #end
+
+
+ #if (flash || openfl)
+
+ public function new( request : URLRequest) : Void {
+ request.contentType = "application/x-thrift";
+ request_ = request;
+ }
+
+ #else
+
+ public function new( requestUrl : String) : Void {
+ request_ = new Http(requestUrl);
+ request_.addHeader( "contentType", "application/x-thrift");
+ }
+
+ #end
+
+ public override function open() : Void {
+ }
+
+ public override function close() : Void {
+ }
+
+ public override function isOpen() : Bool {
+ return true;
+ }
+
+ public override function read(buf:BytesBuffer, off : Int, len : Int) : Int {
+ if (responseBuffer_ == null) {
+ throw new TTransportException(TTransportException.UNKNOWN, "Response buffer is empty, no request.");
+ }
+
+ #if flash
+ try {
+ var data = Bytes.alloc(len);
+ responseBuffer_.readBytes(data, off, len);
+ buf.addBytes(data,0,len);
+ return len;
+ } catch (e : EOFError) {
+ throw new TTransportException(TTransportException.UNKNOWN, "No more data available.");
+ }
+
+ #else
+
+ var data =Bytes.alloc(len);
+ len = responseBuffer_.readBytes(data, off, len);
+ buf.addBytes(data,0,len);
+ return len;
+
+ #end
+ }
+
+ public override function write(buf:Bytes, off : Int, len : Int) : Void {
+ requestBuffer_.writeBytes(buf, off, len);
+ }
+
+
+ #if (flash || openfl)
+
+ public override function flush(callback:Error->Void = null) : Void {
+ var loader : URLLoader = new URLLoader();
+
+ if (callback != null) {
+ loader.addEventListener(Event.COMPLETE, function(event:Event) : Void {
+ responseBuffer_ = new URLLoader(event.target).data;
+ callback(null);
+ });
+ loader.addEventListener(IOErrorEvent.IO_ERROR, function(event:IOErrorEvent) : Void {
+ callback(new TTransportException(TTransportException.UNKNOWN, "IOError: " + event.text));
+ responseBuffer_ = null;
+ });
+ loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(event:SecurityErrorEvent) : Void {
+ callback(new TTransportException(TTransportException.UNKNOWN, "SecurityError: " + event.text));
+ responseBuffer_ = null;
+ });
+ }
+
+ request_.method = URLRequestMethod.POST;
+ loader.dataFormat = URLLoaderDataFormat.BINARY;
+ //requestBuffer_.position = 0;
+ request_.data = requestBuffer_;
+ loader.load(request_);
+ }
+
+ #else
+
+ public override function flush(callback:Dynamic->Void = null) : Void {
+
+ var buffer = requestBuffer_;
+ requestBuffer_ = new BytesOutput();
+ responseBuffer_ = null;
+
+ request_.onData = function(data : String) {
+ responseBuffer_ = new BytesInput(buffer.getBytes());
+ callback(null);
+ };
+ request_.onError = function(msg : String) {
+ callback(new TTransportException(TTransportException.UNKNOWN, "IOError: " + msg));
+ };
+
+ #if js
+ request_.setPostData(buffer.getBytes().toString());
+ request_.request(true/*POST*/);
+ #else
+ request_.customRequest( true/*POST*/, buffer);
+ #end
+ }
+
+ #end
+
+}
+
+
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx
new file mode 100644
index 0000000..1953244
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx
@@ -0,0 +1,132 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.transport;
+
+import haxe.remoting.SocketProtocol;
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+import haxe.io.BytesInput;
+import haxe.io.BytesOutput;
+import haxe.io.Input;
+import haxe.io.Output;
+import haxe.io.Eof;
+
+//import flash.net.ServerSocket; - not yet available on Haxe 3.1.3
+#if ! (flash || html5)
+
+import sys.net.Host;
+
+
+class TServerSocket extends TServerTransport {
+
+ // Underlying server with socket
+ private var _socket : Socket= null;
+
+ // Port to listen on
+ private var _port : Int = 0;
+
+ // Timeout for client sockets from accept
+ private var _clientTimeout : Int = 0;
+
+ // Whether or not to wrap new TSocket connections in buffers
+ private var _useBufferedSockets : Bool = false;
+
+
+ public function new( port : Int, clientTimeout : Int = 0, useBufferedSockets : Bool = false)
+ {
+ _port = port;
+ _clientTimeout = clientTimeout;
+ _useBufferedSockets = useBufferedSockets;
+
+ try
+ {
+ _socket = new Socket();
+ _socket.bind( new Host('localhost'), port);
+ }
+ catch (e : Dynamic)
+ {
+ _socket = null;
+ throw new TTransportException( TTransportException.UNKNOWN, 'Could not create ServerSocket on port $port: $e');
+ }
+ }
+
+
+ public override function Listen() : Void
+ {
+ // Make sure not to block on accept
+ if (_socket != null) {
+ try
+ {
+ _socket.listen(1);
+ }
+ catch (e : Dynamic)
+ {
+ trace('Error $e');
+ throw new TTransportException( TTransportException.UNKNOWN, 'Could not accept on listening socket: $e');
+ }
+ }
+ }
+
+ private override function AcceptImpl() : TTransport
+ {
+ if (_socket == null) {
+ throw new TTransportException( TTransportException.NOT_OPEN, "No underlying server socket.");
+ }
+
+ try
+ {
+ var accepted = _socket.accept();
+ var result = TSocket.fromSocket(accepted);
+ accepted.setTimeout( _clientTimeout);
+
+ if( _useBufferedSockets)
+ {
+ throw "buffered transport not yet supported"; // TODO
+ //result = new TBufferedTransport(result);
+ }
+
+ return result;
+ }
+ catch (e : Dynamic)
+ {
+ trace('Error $e');
+ throw new TTransportException( TTransportException.UNKNOWN, '$e');
+ }
+ }
+
+ public override function Close() : Void
+ {
+ if (_socket != null)
+ {
+ try
+ {
+ _socket.close();
+ }
+ catch (e : Dynamic)
+ {
+ trace('Error $e');
+ throw new TTransportException( TTransportException.UNKNOWN, 'WARNING: Could not close server socket: $e');
+ }
+ _socket = null;
+ }
+ }
+}
+
+#end
diff --git a/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx
new file mode 100644
index 0000000..e0ce697
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.transport;
+
+class TServerTransport {
+
+ public function Accept() : TTransport {
+ var transport = AcceptImpl();
+ if (transport == null) {
+ throw new TTransportException( TTransportException.UNKNOWN, "accept() may not return NULL");
+ }
+ return transport;
+ }
+
+ public function Listen() : Void {
+ throw new AbstractMethodError();
+ }
+
+ public function Close() : Void {
+ throw new AbstractMethodError();
+ }
+
+ private function AcceptImpl() : TTransport {
+ throw new AbstractMethodError();
+ }
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx
new file mode 100644
index 0000000..306730d
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx
@@ -0,0 +1,296 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.transport;
+
+#if flash
+import flash.net.Socket;
+#elseif js
+import js.html.WebSocket;
+#else
+import haxe.remoting.SocketProtocol;
+#end
+
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+import haxe.io.BytesInput;
+import haxe.io.BytesOutput;
+import haxe.io.Input;
+import haxe.io.Output;
+import haxe.io.Eof;
+
+
+#if ! (flash || js)
+import sys.net.Host;
+#end
+
+
+ /**
+ * Socket implementation of the TTransport interface. Used for working with a
+ * Thrift Socket Server based implementations.
+ */
+
+class TSocket extends TTransport {
+
+ #if (flash || js)
+ private var host : String;
+ #else
+ private var host : Host;
+ #end
+
+ private var port : Int;
+
+ #if js
+ private var socket : WebSocket = null;
+ #else
+ private var socket : Socket = null;
+ #end
+
+ #if js
+ private var input : Dynamic = null;
+ private var output : WebSocket = null;
+ #elseif flash
+ private var input : Socket = null;
+ private var output : Socket = null;
+ #else
+ private var input : Input = null;
+ private var output : Output = null;
+ #end
+
+ private var obuffer : BytesOutput = new BytesOutput();
+ private var ioCallback : TException->Void = null;
+ private var readCount : Int = 0;
+
+ public function new(host : String, port : Int) : Void {
+ #if (flash || js)
+ this.host = host;
+ #else
+ this.host = new Host(host);
+ #end
+ this.port = port;
+ }
+
+ #if ! (flash || js)
+ // used by TSocketServer
+ public static function fromSocket( socket : Socket) : TSocket {
+ var result = new TSocket("",0);
+ result.assignSocket(socket);
+ return result;
+ }
+ #end
+
+ public override function close() : Void {
+ input = null;
+ output = null;
+ socket.close();
+ }
+
+ public override function peek() : Bool {
+ if( (input == null) || (socket == null)) {
+ return false;
+ } else {
+ #if flash
+ return (input.bytesAvailable > 0);
+ #elseif js
+ return true;
+ #else
+ var ready = Socket.select( [socket], null, null, 0);
+ return (ready.read.length > 0);
+ #end
+ }
+ }
+
+
+ public override function read( buf : BytesBuffer, off : Int, len : Int) : Int {
+ try
+ {
+ #if flash
+
+ var remaining = len;
+ while( remaining > 0) {
+ buf.addByte( input.readByte());
+ --remaining;
+ }
+ return len;
+
+ #elseif js
+
+ if( input == null) {
+ throw new TTransportException(TTransportException.UNKNOWN, "Still no data "); // don't block
+ }
+ var nr = len;
+ while( nr < len) {
+ buf.addByte( input.get(off+nr));
+ ++nr;
+ }
+ return len;
+
+ #else
+
+ socket.waitForRead();
+ if(readCount < off) {
+ input.read(off-readCount);
+ readCount = off;
+ }
+ var data = input.read(len);
+ readCount += data.length;
+ buf.add(data);
+ return data.length;
+
+ #end
+ }
+ catch (e : Eof)
+ {
+ trace('Eof $e');
+ throw new TTransportException(TTransportException.END_OF_FILE, "No more data available.");
+ }
+ catch (e : TException)
+ {
+ trace('TException $e');
+ throw e;
+ }
+ catch (e : Dynamic)
+ {
+ trace('Error $e');
+ throw new TTransportException(TTransportException.UNKNOWN, 'Bad IO error : $e');
+ }
+ }
+
+
+ public override function write(buf : Bytes, off : Int, len : Int) : Void
+ {
+ obuffer.writeBytes(buf, off, len);
+ }
+
+
+
+ public override function flush(callback : Dynamic->Void = null) : Void
+ {
+ if( ! isOpen())
+ {
+ throw new TTransportException(TTransportException.NOT_OPEN, "Transport not open");
+ }
+
+ #if flash
+
+ var bytes = new flash.utils.ByteArray();
+ var data = obuffer.getBytes();
+ var len = 0;
+ while( len < data.length) {
+ bytes.writeByte(data.get(len));
+ ++len;
+ }
+
+ #elseif js
+
+ var data = obuffer.getBytes();
+ var outbuf = new js.html.Int8Array(data.length);
+ var len = 0;
+ while( len < data.length) {
+ outbuf.set( [data.get(len)], len);
+ ++len;
+ }
+ var bytes = outbuf.buffer;
+
+
+ #else
+
+ var bytes = obuffer.getBytes();
+ var len = bytes.length;
+
+ #end
+
+ obuffer = new BytesOutput();
+
+
+ ioCallback = callback;
+ try {
+ readCount = 0;
+ #if js
+ output.send( bytes);
+ #else
+ output.writeBytes( bytes, 0, bytes.length);
+ #end
+ if(ioCallback != null) {
+ ioCallback(null); // success call
+ }
+ }
+ catch (e : TException)
+ {
+ trace('TException $e');
+ if(ioCallback != null) {
+ ioCallback(e);
+ }
+ }
+ catch (e : Dynamic) {
+ trace(e);
+ if(ioCallback != null) {
+ ioCallback(new TTransportException(TTransportException.UNKNOWN, 'Bad IO error : $e'));
+ }
+ }
+ }
+
+ public override function isOpen() : Bool
+ {
+ return (socket != null);
+ }
+
+ public override function open() : Void
+ {
+ #if js
+ var socket = new WebSocket();
+ socket.onmessage = function( event : js.html.MessageEvent) {
+ this.input = event.data;
+ }
+
+ #elseif flash
+
+ var socket = new Socket();
+ socket.connect(host, port);
+
+ #else
+
+ var socket = new Socket();
+ socket.setBlocking(true);
+ socket.setFastSend(true);
+ socket.connect(host, port);
+
+ #end
+
+ assignSocket( socket);
+ }
+
+ #if js
+ private function assignSocket( socket : WebSocket) : Void
+ #else
+ private function assignSocket( socket : Socket) : Void
+ #end
+ {
+ this.socket = socket;
+
+ #if (flash || js)
+ output = socket;
+ input = socket;
+ #else
+ output = socket.output;
+ input = socket.input;
+ #end
+ }
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TTransport.hx
new file mode 100644
index 0000000..35303d5
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TTransport.hx
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.transport;
+
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+import org.apache.thrift.AbstractMethodError;
+
+class TTransport {
+
+ /**
+ * Queries whether the transport is open.
+ *
+ * @return True if the transport is open.
+ */
+ public function isOpen() : Bool {
+ throw new AbstractMethodError();
+ }
+
+ /**
+ * Is there more data to be read?
+ *
+ * @return True if the remote side is still alive and feeding us
+ */
+ public function peek() : Bool {
+ return isOpen();
+ }
+
+ /**
+ * Opens the transport for reading/writing.
+ *
+ * @throws TTransportException if the transport could not be opened
+ */
+ public function open() : Void {
+ throw new AbstractMethodError();
+ }
+
+ /**
+ * Closes the transport.
+ */
+ public function close() : Void {
+ throw new AbstractMethodError();
+ };
+
+ /**
+ * Reads up to len bytes into buffer buf, starting att offset off.
+ *
+ * @param buf Array to read into
+ * @param off Index to start reading at
+ * @param len Maximum number of bytes to read
+ * @return The bytes count actually read
+ * @throws TTransportException if there was an error reading data
+ */
+ public function read( buf : BytesBuffer, off : Int, len : Int) : Int {
+ throw new AbstractMethodError();
+ }
+
+ /**
+ * Guarantees that all of len bytes are actually read off the transport.
+ *
+ * @param buf Array to read into
+ * @param off Index to start reading at
+ * @param len Maximum number of bytes to read
+ * @return The number of bytes actually read, which must be equal to len
+ * @throws TTransportException if there was an error reading data
+ */
+ public function readAll(buf : BytesBuffer, off : Int, len : Int) : Int {
+ var got : Int = 0;
+ var ret : Int = 0;
+ while (got < len) {
+ ret = read(buf, off+got, len-got);
+ if (ret <= 0) {
+ throw new TTransportException(TTransportException.UNKNOWN,
+ "Cannot read. Remote side has closed. Tried to read "
+ + len + " bytes, but only got " + got + " bytes.");
+ }
+ got += ret;
+ }
+ return got;
+ }
+
+ /**
+ * Writes the buffer to the output
+ *
+ * @param buf The output data buffer
+ * @throws TTransportException if an error occurs writing data
+ */
+ public function writeAll(buf:Bytes) : Void {
+ write(buf, 0, buf.length);
+ }
+
+ /**
+ * Writes up to len bytes from the buffer.
+ *
+ * @param buf The output data buffer
+ * @param off The offset to start writing from
+ * @param len The number of bytes to write
+ * @throws TTransportException if there was an error writing data
+ */
+ public function write(buf:Bytes, off : Int, len : Int) : Void {
+ throw new AbstractMethodError();
+ }
+
+ /**
+ * Flush any pending data out of a transport buffer.
+ *
+ * @throws TTransportException if there was an error writing out data.
+ */
+ public function flush(callback:Dynamic->Void =null) : Void {
+ if(callback != null)
+ callback(new AbstractMethodError());
+ else
+ throw new AbstractMethodError();
+ }
+
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/transport/TTransportException.hx b/lib/haxe/src/org/apache/thrift/transport/TTransportException.hx
new file mode 100644
index 0000000..3db6456
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TTransportException.hx
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.transport;
+
+import org.apache.thrift.TException;
+
+class TTransportException extends TException {
+
+ public static inline var UNKNOWN : Int = 0;
+ public static inline var NOT_OPEN : Int = 1;
+ public static inline var ALREADY_OPEN : Int = 2;
+ public static inline var TIMED_OUT : Int = 3;
+ public static inline var END_OF_FILE : Int = 4;
+
+ public function new(error : Int = UNKNOWN, message : String = "") {
+ super(message, error);
+ }
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TTransportFactory.hx b/lib/haxe/src/org/apache/thrift/transport/TTransportFactory.hx
new file mode 100644
index 0000000..f20321f
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TTransportFactory.hx
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.transport;
+
+/**
+ * Factory class used to create wrapped instance of Transports.
+ * This is used primarily in servers, which get Transports from
+ * a ServerTransport and then may want to mutate them (i.e. create
+ * a BufferedTransport from the underlying base transport)
+ *
+ */
+class TTransportFactory {
+
+ public function new() {
+ }
+
+ /**
+ * Return a wrapped instance of the base Transport.
+ *
+ * @param trans The base transport
+ * @return Wrapped Transport
+ */
+ public function getTransport( trans : TTransport) : TTransport {
+ return trans;
+ }
+
+}
diff --git a/test/Makefile.am b/test/Makefile.am
index cc1f43d..23ec498 100755
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -49,6 +49,10 @@
SUBDIRS += hs
endif
+if WITH_HAXE
+SUBDIRS += haxe
+endif
+
if WITH_GO
SUBDIRS += go
endif
diff --git a/test/haxe/Makefile.am b/test/haxe/Makefile.am
new file mode 100644
index 0000000..08c0369
--- /dev/null
+++ b/test/haxe/Makefile.am
@@ -0,0 +1,52 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+THRIFT = $(top_srcdir)/compiler/cpp/thrift
+THRIFTCMD = $(THRIFT) --gen haxe -r
+THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift
+
+BIN_CPP = bin/Main-debug
+
+gen-haxe/ThriftTest/ThriftTest.hx: $(THRIFTTEST)
+ $(THRIFTCMD) $(THRIFTTEST)
+
+all-local: $(BIN_CPP)
+
+$(BIN_CPP): gen-haxe/ThriftTest/ThriftTest.hx
+ $(HAXE) --cwd . cpp.hxml
+
+
+#TODO: other haxe targets
+# $(HAXE) --cwd . csharp
+# $(HAXE) --cwd . flash
+# $(HAXE) --cwd . java
+# $(HAXE) --cwd . javascript
+# $(HAXE) --cwd . neko
+# $(HAXE) --cwd . php
+# $(HAXE) --cwd . python # needs Haxe 3.1.4
+
+
+clean-local:
+ $(RM) -r gen-haxe bin
+
+check: $(BIN_CPP)
+ timeout 120 $(BIN_CPP) server &
+ sleep 1
+ $(BIN_CPP) client
+
diff --git a/test/haxe/cpp.hxml b/test/haxe/cpp.hxml
new file mode 100644
index 0000000..6adb52d
--- /dev/null
+++ b/test/haxe/cpp.hxml
@@ -0,0 +1,41 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#CPP target
+-cpp bin
+
+#To produce 64 bit binaries the file should define the HXCPP_M64 compile variable:
+#-D HXCPP_M64
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/csharp.hxml b/test/haxe/csharp.hxml
new file mode 100644
index 0000000..295c017
--- /dev/null
+++ b/test/haxe/csharp.hxml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#CSHARP target
+-cs bin/Tutorial.exe
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/flash.hxml b/test/haxe/flash.hxml
new file mode 100644
index 0000000..a1f0568
--- /dev/null
+++ b/test/haxe/flash.hxml
@@ -0,0 +1,41 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Flash target
+-swf bin/Tutorial.swf
+
+#Add debug information
+-debug
+
+# we need some goodies from sys.net
+# --macro allowPackage("sys")
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/java.hxml b/test/haxe/java.hxml
new file mode 100644
index 0000000..c615565
--- /dev/null
+++ b/test/haxe/java.hxml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Java target
+-java bin/Tutorial.jar
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/javascript.hxml b/test/haxe/javascript.hxml
new file mode 100644
index 0000000..b2b3876
--- /dev/null
+++ b/test/haxe/javascript.hxml
@@ -0,0 +1,44 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#JavaScript target
+-js bin/Tutorial.js
+
+#You can use -D source-map-content (requires Haxe 3.1+) to have the .hx
+#files directly embedded into the map file, this way you only have to
+#upload it, and it will be always in sync with the compiled .js even if
+#you modify your .hx files.
+-D source-map-content
+
+#Generate source map and add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/make_all.bat b/test/haxe/make_all.bat
new file mode 100644
index 0000000..eaeba89
--- /dev/null
+++ b/test/haxe/make_all.bat
@@ -0,0 +1,68 @@
+@echo off
+rem /*
+rem * Licensed to the Apache Software Foundation (ASF) under one
+rem * or more contributor license agreements. See the NOTICE file
+rem * distributed with this work for additional information
+rem * regarding copyright ownership. The ASF licenses this file
+rem * to you under the Apache License, Version 2.0 (the
+rem * "License"); you may not use this file except in compliance
+rem * with the License. You may obtain a copy of the License at
+rem *
+rem * http://www.apache.org/licenses/LICENSE-2.0
+rem *
+rem * Unless required by applicable law or agreed to in writing,
+rem * software distributed under the License is distributed on an
+rem * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem * KIND, either express or implied. See the License for the
+rem * specific language governing permissions and limitations
+rem * under the License.
+rem */
+
+setlocal
+if "%HOMEDRIVE%"=="" goto MISSINGVARS
+if "%HOMEPATH%"=="" goto MISSINGVARS
+if "%HAXEPATH%"=="" goto NOTINSTALLED
+
+set path=%HAXEPATH%;%HAXEPATH%\..\neko;%path%
+
+rem # invoke Thrift comnpiler
+thrift -r -gen haxe ..\ThriftTest.thrift
+if errorlevel 1 goto STOP
+
+rem # invoke Haxe compiler for all targets
+for %%a in (*.hxml) do (
+ rem * filter Python, as it is not supported by Haxe 3.1.3 (but will be in 3.1.4)
+ if not "%%a"=="python.hxml" (
+ echo --------------------------
+ echo Building %%a ...
+ echo --------------------------
+ haxe --cwd . %%a
+ )
+)
+
+
+echo.
+echo done.
+pause
+goto eof
+
+:NOTINSTALLED
+echo FATAL: Either Haxe is not installed, or the HAXEPATH variable is not set.
+pause
+goto eof
+
+:MISSINGVARS
+echo FATAL: Unable to locate home folder.
+echo.
+echo Both HOMEDRIVE and HOMEPATH need to be set to point to your Home folder.
+echo The current values are:
+echo HOMEDRIVE=%HOMEDRIVE%
+echo HOMEPATH=%HOMEPATH%
+pause
+goto eof
+
+:STOP
+pause
+goto eof
+
+:eof
diff --git a/test/haxe/make_all.sh b/test/haxe/make_all.sh
new file mode 100644
index 0000000..2621258
--- /dev/null
+++ b/test/haxe/make_all.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# invoke Thrift comnpiler
+thrift -r -gen haxe ../ThriftTest.thrift
+
+# output folder
+if [ ! -d bin ]; then
+ mkdir bin
+fi
+
+# invoke Haxe compiler
+for target in *.hxml; do
+ echo --------------------------
+ echo Building ${target} ...
+ echo --------------------------
+ if [ ! -d bin/${target} ]; then
+ mkdir bin/${target}
+ fi
+ haxe --cwd . ${target}
+done
+
+
+#eof
diff --git a/test/haxe/neko.hxml b/test/haxe/neko.hxml
new file mode 100644
index 0000000..6161f69
--- /dev/null
+++ b/test/haxe/neko.hxml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#neko target
+-neko bin/Tutorial.n
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/php.hxml b/test/haxe/php.hxml
new file mode 100644
index 0000000..1eaac8b
--- /dev/null
+++ b/test/haxe/php.hxml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#PHP target
+-php bin/Tutorial.php
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/project.hide b/test/haxe/project.hide
new file mode 100644
index 0000000..f09030b
--- /dev/null
+++ b/test/haxe/project.hide
@@ -0,0 +1,85 @@
+{
+ "type" : 0
+ ,"target" : 4
+ ,"name" : "Apache Thrift cross-platform test client/server"
+ ,"main" : null
+ ,"projectPackage" : ""
+ ,"company" : "Apache Software Foundation (ASF)"
+ ,"license" : "Apache License, Version 2.0"
+ ,"url" : "http://www.apache.org/licenses/LICENSE-2.0"
+ ,"targetData" : [
+ {
+ "pathToHxml" : "flash.hxml"
+ ,"runActionType" : 1
+ ,"runActionText" : "bin/Tutorial.swf"
+ }
+ ,{
+ "pathToHxml" : "javascript.hxml"
+ ,"runActionType" : 1
+ ,"runActionText" : "bin\\index.html"
+ }
+ ,{
+ "pathToHxml" : "neko.hxml"
+ ,"runActionType" : 2
+ ,"runActionText" : "neko bin/Tutorial.n"
+ }
+ ,{
+ "pathToHxml" : "php.hxml"
+ }
+ ,{
+ "pathToHxml" : "cpp.hxml"
+ ,"runActionType" : 2
+ ,"runActionText" : "bin/Main-debug.exe client --json"
+ }
+ ,{
+ "pathToHxml" : "java.hxml"
+ }
+ ,{
+ "pathToHxml" : "csharp.hxml"
+ }
+ ,{
+ "pathToHxml" : "python.hxml"
+ ,"runActionType" : 2
+ ,"runActionText" : "python bin/Tutorial.py"
+ }
+ ]
+ ,"files" : [
+ {
+ "path" : "src\\Arguments.hx"
+ ,"useTabs" : true
+ ,"indentSize" : 4
+ ,"foldedRegions" : [
+
+ ]
+ ,"activeLine" : 159
+ }
+ ,{
+ "path" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\protocol\\TJSONProtocol.hx"
+ ,"useTabs" : true
+ ,"indentSize" : 4
+ ,"foldedRegions" : [
+
+ ]
+ ,"activeLine" : 665
+ }
+ ,{
+ "path" : "src\\TestClient.hx"
+ ,"useTabs" : true
+ ,"indentSize" : 4
+ ,"foldedRegions" : [
+
+ ]
+ ,"activeLine" : 325
+ }
+ ]
+ ,"activeFile" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\protocol\\TJSONProtocol.hx"
+ ,"openFLTarget" : null
+ ,"openFLBuildMode" : "Debug"
+ ,"runActionType" : null
+ ,"runActionText" : null
+ ,"buildActionCommand" : null
+ ,"hiddenItems" : [
+
+ ]
+ ,"showHiddenItems" : false
+}
\ No newline at end of file
diff --git a/test/haxe/python.hxml b/test/haxe/python.hxml
new file mode 100644
index 0000000..f2c19fa
--- /dev/null
+++ b/test/haxe/python.hxml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Python target
+-python bin/Tutorial.py
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/src/Arguments.hx b/test/haxe/src/Arguments.hx
new file mode 100644
index 0000000..bcf3793
--- /dev/null
+++ b/test/haxe/src/Arguments.hx
@@ -0,0 +1,181 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+using StringTools;
+
+
+enum Prot {
+ binary;
+ json;
+}
+
+enum Trns {
+ socket;
+ http;
+}
+
+
+class Arguments
+{
+ public var server(default,null) : Bool = false;
+ public var framed(default,null) : Bool = false;
+ public var buffered(default,null) : Bool = false;
+ public var protocol(default,null) : Prot = binary;
+ public var transport(default,null) : Trns = socket;
+
+ public var host(default,null) : String = "localhost";
+ public var port(default,null) : Int = 9090;
+
+ public var numIterations(default,null) : Int = 1;
+ public var numThreads(default,null) : Int = 1;
+
+
+ public function new() {
+ #if sys
+ try {
+ ParseArgs();
+ } catch (e : String) {
+ trace(GetHelp());
+ throw e;
+ }
+ #else
+ trace("WN: Platform does not support program arguments, using defaults.");
+ #end
+ }
+
+ #if sys
+
+ private static function GetHelp() : String {
+ return "\n"
+ +Sys.executablePath()+" [client|server] [options]\n"
+ +"Modus: Either client or server, the default is client.\n"
+ +"\n"
+ +"Options:\n"
+ +" -f, --framed framed transport (supersedes buffered)\n"
+ +" -b, --buffered buffered transport\n"
+ +" --json JSON protocol\n"
+ +" --protocol=<prot> Choose protocol: json, binary (default binary).\n"
+ +" --port=<port> Port number for socket transport, default 9090\n"
+ +"\n"
+ +"Client only options:\n"
+ +" --host=<host> Host name, IP or URL, default localhost\n"
+ +" -n=<iterations> Number of test iterations\n"
+ +" -t=<threads> Number of test threads\n"
+ +" -u=<url> Target Host/URL (same as --host)\n"
+ +"\n"
+ +"All arguments are optional.\n";
+ }
+
+
+ private function ParseArgs() : Void {
+ var step = 0;
+ for (arg in Sys.args()) {
+
+ // server|client
+ switch(step) {
+ case 0:
+ ++step;
+ if ( arg == "client")
+ server = false;
+ else if ( arg == "server")
+ server = true;
+ else
+ throw "First argument must be 'server' or 'client'";
+
+ case 1:
+ if ( (arg == "-f") || (arg == "--framed")) {
+ framed = true;
+ } else if (( arg == "-b") || ( arg == "--buffered")) {
+ buffered = true;
+ } else if (( arg == "--json") || (arg == "--protocol=json")){
+ protocol = json;
+ } else if (( arg == "--protocol=binary")){
+ protocol = binary;
+ } else if (arg.startsWith("--host=")) {
+ ClientOnlyOption(arg);
+ host = arg.substr(arg.indexOf("=") + 1);
+ } else if (arg.startsWith("--port=")) {
+ var tmp = Std.parseInt(arg.substr(arg.indexOf("=")+1));
+ if( tmp != null)
+ port = tmp;
+ else
+ throw "Invalid port number "+arg;
+ } else if (arg == "-n") {
+ ClientOnlyOption(arg);
+ step = 2;
+ } else if (arg == "-t") {
+ ClientOnlyOption(arg);
+ step = 3;
+ } else if (arg == "-u") {
+ ClientOnlyOption(arg);
+ step = 4;
+ } else {
+ throw "Unexpected argument "+arg;
+ }
+
+ case 2: // num iterations
+ step = 1;
+ var tmp = Std.parseInt(arg);
+ if( tmp != null)
+ numIterations = tmp;
+ else
+ throw "Invalid numeric value "+arg;
+
+ case 3: // num threads
+ step = 1;
+ var tmp = Std.parseInt(arg);
+ if( tmp != null)
+ numThreads = tmp;
+ else
+ throw "Invalid numeric value "+arg;
+
+ case 4: // url
+ step = 1;
+ host = arg;
+
+ default:
+ throw "Unexpected state";
+ }
+
+
+ if ( framed && buffered)
+ {
+ trace("WN: framed supersedes buffered transport");
+ }
+
+ }
+ }
+
+ #end
+
+
+ private function ClientOnlyOption( arg : String) {
+ if( server) {
+ throw "Unexpected argument in client mode: "+arg;
+ }
+ }
+}
diff --git a/test/haxe/src/Main.hx b/test/haxe/src/Main.hx
new file mode 100644
index 0000000..a8ad147
--- /dev/null
+++ b/test/haxe/src/Main.hx
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import thrift.test.*; // generated code
+
+class Main
+{
+ static function main() {
+ try {
+ var args = new Arguments();
+
+ if (args.server)
+ TestServer.Execute(args);
+ else
+ TestClient.Execute(args);
+
+ trace("Completed.");
+ } catch (e : String) {
+ trace(e);
+ }
+ }
+
+}
diff --git a/test/haxe/src/TestClient.hx b/test/haxe/src/TestClient.hx
new file mode 100644
index 0000000..8698220
--- /dev/null
+++ b/test/haxe/src/TestClient.hx
@@ -0,0 +1,696 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package;
+
+import haxe.Int32;
+import haxe.Int64;
+import haxe.Timer;
+import haxe.ds.IntMap;
+import haxe.ds.StringMap;
+import haxe.ds.ObjectMap;
+
+import org.apache.thrift.*;
+import org.apache.thrift.helper.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+#if cpp
+import cpp.vm.Thread;
+#else
+// no thread support (yet)
+#end
+
+import thrift.test.*; // generated code
+
+
+class TestResults {
+ private var successCnt : Int = 0;
+ private var errorCnt : Int = 0;
+ private var failedTests : String = "";
+ private var print_direct : Bool = false;
+
+ public function new(direct : Bool) {
+ print_direct = direct;
+ }
+
+ public function Expect( expr : Bool, msg : String) : Void {
+ if ( expr) {
+ ++successCnt;
+ } else {
+ ++errorCnt;
+ failedTests += "\n " + msg;
+ if( print_direct) {
+ trace('FAIL: $msg');
+ }
+ }
+ }
+
+
+ public function PrintSummary() : Void {
+ var total = successCnt + errorCnt;
+ var sp = (100 * successCnt) / total;
+ var ep = (100 * errorCnt) / total;
+
+ trace('===========================');
+ trace('Tests executed $total');
+ trace('Tests succeeded $successCnt ($sp%)');
+ trace('Tests failed $errorCnt ($ep%)');
+ if ( errorCnt > 0)
+ {
+ trace('===========================');
+ trace('FAILED TESTS: $failedTests');
+ }
+ trace('===========================');
+ }
+}
+
+
+class TestClient {
+
+ public static function Execute(args : Arguments) : Void
+ {
+ try
+ {
+ var difft = Timer.stamp();
+
+ if( args.numThreads > 1) {
+ var threads = new List<Thread>();
+ for( test in 0 ... args.numThreads) {
+ threads.add( StartThread( args));
+ }
+ for( thread in threads) {
+ Thread.readMessage(true);
+ }
+ } else {
+ var rslt = new TestResults(true);
+ RunClient(args,rslt);
+ rslt.PrintSummary();
+ }
+
+ difft = Timer.stamp() - difft;
+ trace('total test time: $difft seconds');
+ }
+ catch (e : TException)
+ {
+ trace('$e');
+ }
+ catch (e : Dynamic)
+ {
+ trace('$e');
+ }
+ }
+
+
+ private static function StartThread(args : Arguments) : Thread {
+ var thread = Thread.create(
+ function() : Void {
+ var main : Thread = Thread.readMessage(true);
+ try
+ {
+ var rslt = new TestResults(false);
+ RunClient(args,rslt);
+ // TODO: promote rslt values to main thread
+ }
+ catch (e : TException)
+ {
+ trace('$e');
+ }
+ catch (e : Dynamic)
+ {
+ trace('$e');
+ }
+ main.sendMessage("done");
+ });
+
+ thread.sendMessage(Thread.current());
+ return thread;
+ }
+
+
+ public static function RunClient(args : Arguments, rslt : TestResults)
+ {
+ var transport : TTransport = null;
+ switch (args.transport)
+ {
+ case socket:
+ transport = new TSocket(args.host, args.port);
+ case http:
+ throw "http transport not supported yet";
+ //transport = new THttpClient(args.host);
+ default:
+ throw "Unhandled transport";
+ }
+
+ // optional: layered transport
+ if ( args.framed) {
+ trace("- framed transport");
+ transport = new TFramedTransport(transport);
+ } else if ( args.buffered) {
+ trace("- buffered transport");
+ throw "TBufferedTransport not implemented yet";
+ //transport = new TBufferedTransport(transport);
+ }
+
+ // protocol
+ var protocol : TProtocol = null;
+ switch( args.protocol)
+ {
+ case binary:
+ trace("- binary protocol");
+ protocol = new TBinaryProtocol(transport);
+ case json:
+ trace("- json protocol");
+ protocol = new TJSONProtocol(transport);
+ default:
+ throw "Unhandled protocol";
+ }
+
+
+ // run the test code
+ HaxeBasicsTest( rslt);
+ ClientTest( transport, protocol, rslt);
+
+ }
+
+
+ public static function HaxeBasicsTest( rslt : TestResults) : Void
+ {
+ // We need to test a few basic things used in the ClientTest
+ // Anything else beyond this scope should go into /lib/haxe/ instead
+
+ var map32 = new IntMap<Int32>();
+ var map64 = new Int64Map<Int32>();
+
+ rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map<Int32> Test #1");
+ rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #2");
+ rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map<Int32> Test #3");
+ rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #4");
+
+ map32.set( 42, 815);
+ map64.set( Int64.make(0,42), 815);
+ map32.set( -517, 23);
+ map64.set( Int64.make(-5,17), 23);
+ map32.set( 0, -123);
+ map64.set( Int64.make(0,0), -123);
+
+ rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map<Int32> Test #10");
+ rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #11");
+ rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map<Int32> Test #12");
+ rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #13");
+ rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #14");
+ rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #15");
+ rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map<Int32> Test #16");
+ rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #Int64.make(-5,17)");
+ rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map<Int32> Test #18");
+ rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map<Int32> Test #19");
+ rslt.Expect( map32.remove( -517) == map64.remove( Int64.make(-5,17)), "Int64Map<Int32> Test #20");
+ rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #21");
+ rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map<Int32> Test #22");
+ rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #23");
+ rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #24");
+ rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #25");
+ rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map<Int32> Test #26");
+ rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #27");
+ rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map<Int32> Test #28");
+
+ map32.set( 42, 1);
+ map64.set( Int64.make(0,42), 1);
+ map32.set( -517, -2);
+ map64.set( Int64.make(-5,17), -2);
+ map32.set( 0, 3);
+ map64.set( Int64.make(0,0), 3);
+
+ var c32 = 0;
+ for (key in map32.keys()) {
+ ++c32;
+ }
+ var c64 = 0;
+ for (key in map64.keys()) {
+ ++c64;
+ }
+ rslt.Expect( c32 == c64, "Int64Map<Int32> Test #30");
+
+ var s32 = map32.toString();
+ var s64 = map64.toString();
+ trace("Int64Map<Int32>.toString(): " + ' ("$s32" == "$s64")');
+
+ map32.remove( 42);
+ map64.remove( Int64.make(0,42));
+ map32.remove( -517);
+ map64.remove( Int64.make(-5,17));
+ map32.remove( 0);
+ map64.remove( Int64.make(0,0));
+
+ rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map<Int32> Test #90");
+ rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #91");
+ rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map<Int32> Test #92");
+ rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #93");
+ rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #94");
+ rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #95");
+ rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map<Int32> Test #96");
+ rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #97");
+ rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map<Int32> Test #98");
+ }
+
+
+ public static function ClientTest( transport : TTransport, protocol : TProtocol, rslt : TestResults) : Void
+ {
+ var client = new ThriftTestImpl(protocol,protocol);
+ try
+ {
+ if (!transport.isOpen())
+ {
+ transport.open();
+ }
+ }
+ catch (e : TException)
+ {
+ trace('$e');
+ return;
+ }
+ catch (e : Dynamic)
+ {
+ trace('$e');
+ return;
+ }
+
+ var start = Date.now();
+
+ trace('testVoid()');
+ client.testVoid();
+ trace(' = void');
+ rslt.Expect(true,"testVoid()"); // bump counter
+
+ trace('testString("Test")');
+ var s = client.testString("Test");
+ trace(' = "$s"');
+ rslt.Expect(s == "Test", '$s == "Test"');
+
+ trace('testByte(1)');
+ var i8 = client.testByte(1);
+ trace(' = $i8');
+ rslt.Expect(i8 == 1, '$i8 == 1');
+
+ trace('testI32(-1)');
+ var i32 = client.testI32(-1);
+ trace(' = $i32');
+ rslt.Expect(i32 == -1, '$i32 == -1');
+
+ trace('testI64(-34359738368)');
+ var i64 = client.testI64( Int64.make( 0xFFFFFFF8, 0x00000000)); // -34359738368
+ trace(' = $i64');
+ rslt.Expect( Int64.compare( i64, Int64.make( 0xFFFFFFF8, 0x00000000)) == 0,
+ Int64.toStr(i64) +" == "+Int64.toStr(Int64.make( 0xFFFFFFF8, 0x00000000)));
+
+ // edge case: the largest negative Int64 has no positive Int64 equivalent
+ trace('testI64(-9223372036854775808)');
+ i64 = client.testI64( Int64.make( 0x80000000, 0x00000000)); // -9223372036854775808
+ trace(' = $i64');
+ rslt.Expect( Int64.compare( i64, Int64.make( 0x80000000, 0x00000000)) == 0,
+ Int64.toStr(i64) +" == "+Int64.toStr(Int64.make( 0x80000000, 0x00000000)));
+
+ trace('testDouble(5.325098235)');
+ var dub = client.testDouble(5.325098235);
+ trace(' = $dub');
+ rslt.Expect(dub == 5.325098235, '$dub == 5.325098235');
+
+ trace('testStruct({"Zero", 1, -3, -5})');
+ var o = new Xtruct();
+ o.string_thing = "Zero";
+ o.byte_thing = 1;
+ o.i32_thing = -3;
+ o.i64_thing = Int64.make(0,-5);
+ var i = client.testStruct(o);
+ trace(' = {"' + i.string_thing + '", ' + i.byte_thing +', '
+ + i.i32_thing +', '+ Int64.toStr(i.i64_thing) + '}');
+ rslt.Expect( i.string_thing == o.string_thing, "i.string_thing == o.string_thing");
+ rslt.Expect( i.byte_thing == o.byte_thing, "i.byte_thing == o.byte_thing");
+ rslt.Expect( i.i32_thing == o.i32_thing, "i.i64_thing == o.i64_thing");
+ rslt.Expect( i.i32_thing == o.i32_thing, "i.i64_thing == o.i64_thing");
+
+ trace('testNest({1, {\"Zero\", 1, -3, -5}, 5})');
+ var o2 = new Xtruct2();
+ o2.byte_thing = 1;
+ o2.struct_thing = o;
+ o2.i32_thing = 5;
+ var i2 = client.testNest(o2);
+ i = i2.struct_thing;
+ trace(" = {" + i2.byte_thing + ", {\"" + i.string_thing + "\", "
+ + i.byte_thing + ", " + i.i32_thing + ", " + Int64.toStr(i.i64_thing) + "}, "
+ + i2.i32_thing + "}");
+ rslt.Expect( i2.byte_thing == o2.byte_thing, "i2.byte_thing == o2.byte_thing");
+ rslt.Expect( i2.i32_thing == o2.i32_thing, "i2.i32_thing == o2.i32_thing");
+ rslt.Expect( i.string_thing == o.string_thing, "i.string_thing == o.string_thing");
+ rslt.Expect( i.byte_thing == o.byte_thing, "i.byte_thing == o.byte_thing");
+ rslt.Expect( i.i32_thing == o.i32_thing, "i.i32_thing == o.i32_thing");
+ rslt.Expect( Int64.compare( i.i64_thing, o.i64_thing) == 0, "i.i64_thing == o.i64_thing");
+
+ var mapout = new IntMap< haxe.Int32>();
+ for ( j in 0 ... 5)
+ {
+ mapout.set(j, j - 10);
+ }
+ trace("testMap({");
+ var first : Bool = true;
+ for( key in mapout.keys())
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ trace(", ");
+ }
+ trace(key + " => " + mapout.get(key));
+ }
+ trace("})");
+
+ var mapin = client.testMap(mapout);
+
+ trace(" = {");
+ first = true;
+ for( key in mapin.keys())
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ trace(", ");
+ }
+ trace(key + " => " + mapin.get(key));
+ rslt.Expect( mapin.get(key) == mapout.get(key), ' mapin.get($key) == mapout.get($key)');
+ }
+ trace("}");
+ for( key in mapout.keys())
+ {
+ rslt.Expect(mapin.exists(key), 'mapin.exists($key)');
+ }
+
+ var listout = new List<Int>();
+ for (j in -2 ... 3)
+ {
+ listout.add(j);
+ }
+ trace("testList({");
+ first = true;
+ for( j in listout)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ trace(", ");
+ }
+ trace(j);
+ }
+ trace("})");
+
+ var listin = client.testList(listout);
+
+ trace(" = {");
+ first = true;
+ for( j in listin)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ trace(", ");
+ }
+ trace(j);
+ }
+ trace("}");
+
+ rslt.Expect(listin.length == listout.length, "listin.length == listout.length");
+ var literout = listout.iterator();
+ var literin = listin.iterator();
+ while( literin.hasNext()) {
+ rslt.Expect(literin.next() == literout.next(), "literin[i] == literout[i]");
+ }
+
+ //set
+ var setout = new IntSet();
+ for (j in -2 ... 3)
+ {
+ setout.add(j);
+ }
+ trace("testSet({");
+ first = true;
+ for( j in setout)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ trace(", ");
+ }
+ trace(j);
+ }
+ trace("})");
+
+ var setin = client.testSet(setout);
+
+ trace(" = {");
+ first = true;
+ for( j in setin)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ trace(", ");
+ }
+ trace(j);
+ rslt.Expect(setout.contains(j), 'setout.contains($j)');
+ }
+ trace("}");
+ rslt.Expect(setin.size == setout.size, "setin.length == setout.length");
+
+
+ trace("testEnum(ONE)");
+ var ret = client.testEnum(Numberz.ONE);
+ trace(" = " + ret);
+ rslt.Expect(ret == Numberz.ONE, '$ret == Numberz.ONE');
+
+ trace("testEnum(TWO)");
+ ret = client.testEnum(Numberz.TWO);
+ trace(" = " + ret);
+ rslt.Expect(ret == Numberz.TWO, '$ret == Numberz.TWO');
+
+ trace("testEnum(THREE)");
+ ret = client.testEnum(Numberz.THREE);
+ trace(" = " + ret);
+ rslt.Expect(ret == Numberz.THREE, '$ret == Numberz.THREE');
+
+ trace("testEnum(FIVE)");
+ ret = client.testEnum(Numberz.FIVE);
+ trace(" = " + ret);
+ rslt.Expect(ret == Numberz.FIVE, '$ret == Numberz.FIVE');
+
+ trace("testEnum(EIGHT)");
+ ret = client.testEnum(Numberz.EIGHT);
+ trace(" = " + ret);
+ rslt.Expect(ret == Numberz.EIGHT, '$ret == Numberz.EIGHT');
+
+ trace("testTypedef(309858235082523)");
+ var uid = client.testTypedef( Int64.make( 0x119D0, 0x7E08671B)); // 309858235082523
+ trace(" = " + uid);
+ rslt.Expect( Int64.compare( uid, Int64.make( 0x119D0, 0x7E08671B)) == 0,
+ Int64.toStr(uid)+" == "+Int64.toStr(Int64.make( 0x119D0, 0x7E08671B)));
+
+ trace("testMapMap(1)");
+ var mm = client.testMapMap(1);
+ trace(" = {");
+ for( key in mm.keys())
+ {
+ trace(key + " => {");
+ var m2 = mm.get(key);
+ for( k2 in m2.keys())
+ {
+ trace(k2 + " => " + m2.get(k2) + ", ");
+ }
+ trace("}, ");
+ }
+ trace("}");
+
+ var pos = mm.get(4);
+ var neg = mm.get(-4);
+ rslt.Expect( (pos != null) && (neg != null), "(pos != null) && (neg != null)");
+ for (i in 0 ... 5) {
+ rslt.Expect( pos.get(i) == i, 'pos.get($i) == $i');
+ rslt.Expect( neg.get(-i) == -i, 'neg.get(-$i) == -$i');
+ }
+
+ var insane = new Insanity();
+ insane.userMap = new IntMap< Int64>();
+ insane.userMap.set( Numberz.FIVE, Int64.make(0,5000));
+ var truck = new Xtruct();
+ truck.string_thing = "Truck";
+ truck.byte_thing = 8;
+ truck.i32_thing = 8;
+ truck.i64_thing = Int64.make(0,8);
+ insane.xtructs = new List<Xtruct>();
+ insane.xtructs.add(truck);
+ trace("testInsanity()");
+ var whoa = client.testInsanity(insane);
+ trace(" = {");
+ for( key in whoa.keys())
+ {
+ var val = whoa.get(key);
+ trace(key + " => {");
+
+ for( k2 in val.keys())
+ {
+ var v2 = val.get(k2);
+
+ trace(k2 + " => {");
+ var userMap = v2.userMap;
+
+ trace("{");
+ if (userMap != null)
+ {
+ for( k3 in userMap.keys())
+ {
+ trace(k3 + " => " + userMap.get(k3) + ", ");
+ }
+ }
+ else
+ {
+ trace("null");
+ }
+ trace("}, ");
+
+ var xtructs = v2.xtructs;
+
+ trace("{");
+ if (xtructs != null)
+ {
+ for( x in xtructs)
+ {
+ trace("{\"" + x.string_thing + "\", "
+ + x.byte_thing + ", " + x.i32_thing + ", "
+ + x.i32_thing + "}, ");
+ }
+ }
+ else
+ {
+ trace("null");
+ }
+ trace("}");
+
+ trace("}, ");
+ }
+ trace("}, ");
+ }
+ trace("}");
+
+ var first_map = whoa.get(Int64.make(0,1));
+ var second_map = whoa.get(Int64.make(0,2));
+ rslt.Expect( (first_map != null) && (second_map != null), "(first_map != null) && (second_map != null)");
+ if ((first_map != null) && (second_map != null))
+ {
+ var crazy2 = first_map.get(Numberz.TWO);
+ var crazy3 = first_map.get(Numberz.THREE);
+ var looney = second_map.get(Numberz.SIX);
+ rslt.Expect( (crazy2 != null) && (crazy3 != null) && (looney != null),
+ "(crazy2 != null) && (crazy3 != null) && (looney != null)");
+
+ rslt.Expect( Int64.compare( crazy2.userMap.get(Numberz.EIGHT), Int64.make(0,8)) == 0,
+ "crazy2.UserMap.get(Numberz.EIGHT) == 8");
+ rslt.Expect( Int64.compare( crazy3.userMap.get(Numberz.EIGHT), Int64.make(0,8)) == 0,
+ "crazy3.UserMap.get(Numberz.EIGHT) == 8");
+ rslt.Expect( Int64.compare( crazy2.userMap.get(Numberz.FIVE), Int64.make(0,5)) == 0,
+ "crazy2.UserMap.get(Numberz.FIVE) == 5");
+ rslt.Expect( Int64.compare( crazy3.userMap.get(Numberz.FIVE), Int64.make(0,5)) == 0,
+ "crazy3.UserMap.get(Numberz.FIVE) == 5");
+
+ var crz2iter = crazy2.xtructs.iterator();
+ var crz3iter = crazy3.xtructs.iterator();
+ rslt.Expect( crz2iter.hasNext() && crz3iter.hasNext(), "crz2iter.hasNext() && crz3iter.hasNext()");
+ var goodbye2 = crz2iter.next();
+ var goodbye3 = crz3iter.next();
+ rslt.Expect( crz2iter.hasNext() && crz3iter.hasNext(), "crz2iter.hasNext() && crz3iter.hasNext()");
+ var hello2 = crz2iter.next();
+ var hello3 = crz3iter.next();
+ rslt.Expect( ! (crz2iter.hasNext() || crz3iter.hasNext()), "! (crz2iter.hasNext() || crz3iter.hasNext())");
+
+ rslt.Expect( hello2.string_thing == "Hello2", 'hello2.String_thing == "Hello2"');
+ rslt.Expect( hello2.byte_thing == 2, 'hello2.Byte_thing == 2');
+ rslt.Expect( hello2.i32_thing == 2, 'hello2.I32_thing == 2');
+ rslt.Expect( Int64.compare( hello2.i64_thing, Int64.make(0,2)) == 0, 'hello2.I64_thing == 2');
+ rslt.Expect( hello3.string_thing == "Hello2", 'hello3.String_thing == "Hello2"');
+ rslt.Expect( hello3.byte_thing == 2, 'hello3.Byte_thing == 2');
+ rslt.Expect( hello3.i32_thing == 2, 'hello3.I32_thing == 2');
+ rslt.Expect( Int64.compare( hello3.i64_thing, Int64.make(0,2)) == 0, 'hello3.I64_thing == 2');
+
+ rslt.Expect( goodbye2.string_thing == "Goodbye4", 'goodbye2.String_thing == "Goodbye4"');
+ rslt.Expect( goodbye2.byte_thing == 4, 'goodbye2.Byte_thing == 4');
+ rslt.Expect( goodbye2.i32_thing == 4, 'goodbye2.I32_thing == 4');
+ rslt.Expect( Int64.compare( goodbye2.i64_thing, Int64.make(0,4)) == 0, 'goodbye2.I64_thing == 4');
+ rslt.Expect( goodbye3.string_thing == "Goodbye4", 'goodbye3.String_thing == "Goodbye4"');
+ rslt.Expect( goodbye3.byte_thing == 4, 'goodbye3.Byte_thing == 4');
+ rslt.Expect( goodbye3.i32_thing == 4, 'goodbye3.I32_thing == 4');
+ rslt.Expect( Int64.compare( goodbye3.i64_thing, Int64.make(0,4)) == 0, 'goodbye3.I64_thing == 4');
+ }
+
+ var arg0 = 1;
+ var arg1 = 2;
+ var arg2 = Int64.make( 0x7FFFFFFF,0xFFFFFFFF);
+ var multiDict = new IntMap< String>();
+ multiDict.set(1, "one");
+ var arg4 = Numberz.FIVE;
+ var arg5 = Int64.make(0,5000000);
+ trace("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + "," + multiDict + "," + arg4 + "," + arg5 + ")");
+ var multiResponse = client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5);
+ trace(" = Xtruct(byte_thing:" + multiResponse.byte_thing + ",string_thing:" + multiResponse.string_thing
+ + ",i32_thing:" + multiResponse.i32_thing
+ + ",i64_thing:" + Int64.toStr(multiResponse.i64_thing) + ")");
+
+ rslt.Expect( multiResponse.string_thing == "Hello2", 'multiResponse.String_thing == "Hello2"');
+ rslt.Expect( multiResponse.byte_thing == arg0, 'multiResponse.Byte_thing == arg0');
+ rslt.Expect( multiResponse.i32_thing == arg1, 'multiResponse.I32_thing == arg1');
+ rslt.Expect( Int64.compare( multiResponse.i64_thing, arg2) == 0, 'multiResponse.I64_thing == arg2');
+
+
+ trace("Test Oneway(1)");
+ client.testOneway(1);
+
+ trace("Test Calltime()");
+ var difft = Timer.stamp();
+ for ( k in 0 ... 1000) {
+ client.testVoid();
+ }
+ difft = Timer.stamp() - difft;
+ trace('$difft ms per testVoid() call');
+ }
+}
diff --git a/test/haxe/src/TestServer.hx b/test/haxe/src/TestServer.hx
new file mode 100644
index 0000000..66b06e0
--- /dev/null
+++ b/test/haxe/src/TestServer.hx
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import thrift.test.*; // generated code
+
+
+class TestServer
+{
+ public static function Execute(args : Arguments) : Void
+ {
+ try
+ {
+ // Transport
+ var transport : TServerTransport = null;
+ switch( args.transport) {
+ case socket:
+ trace("- socket port "+args.port);
+ transport = new TServerSocket( args.port);
+ case http:
+ trace("- http");
+ throw "HTTP server not implemented yet";
+ //transport = new THttpServer( targetHost);
+ default:
+ throw "Unhandled transport";
+ }
+
+ // optional: layered transport
+ var transfactory : TTransportFactory = null;
+ if ( args.framed) {
+ trace("- framed transport");
+ transfactory = new TFramedTransportFactory();
+ } else if ( args.buffered) {
+ trace("- buffered transport");
+ throw "TBufferedTransport not implemented yet";
+ //transfactory = new TBufferedTransportFactory();
+ }
+
+ // protocol
+ var protfactory : TProtocolFactory = null;
+ switch( args.protocol)
+ {
+ case binary:
+ trace("- binary protocol");
+ protfactory = new TBinaryProtocolFactory();
+ case json:
+ trace("- json protocol");
+ protfactory = new TJSONProtocolFactory();
+ default:
+ throw "Unhandled protocol";
+ }
+
+
+ // Processor
+ var handler = new TestServerHandler();
+ var processor = new ThriftTestProcessor(handler);
+
+ // Simple Server
+ var server = new TSimpleServer( processor, transport, transfactory, protfactory);
+
+
+ /*
+ // Server event handler
+ var events = new TestServerEventHandler();
+ server.setEventHandler(serverEvents);
+ handler.server = serverEngine;
+ */
+
+ // Run it
+ server.Serve();
+ trace("done.");
+
+ }
+ catch (x : TException)
+ {
+ trace('$x');
+ }
+ catch (x : Dynamic)
+ {
+ trace('$x');
+ }
+ }
+}
diff --git a/test/haxe/src/TestServerEventHandler.hx b/test/haxe/src/TestServerEventHandler.hx
new file mode 100644
index 0000000..b52943a
--- /dev/null
+++ b/test/haxe/src/TestServerEventHandler.hx
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import thrift.test.*; // generated code
+
+
+class TestServerEventHandler : TServerEventHandler
+{
+ public int callCount = 0;
+ public void preServe()
+ {
+ callCount++;
+ }
+ public Object createContext(Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output)
+ {
+ callCount++;
+ return null;
+ }
+ public void deleteContext(Object serverContext, Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output)
+ {
+ callCount++;
+ }
+ public void processContext(Object serverContext, Thrift.Transport.TTransport transport)
+ {
+ callCount++;
+ }
+}
+
+
\ No newline at end of file
diff --git a/test/haxe/src/TestServerHandler.hx b/test/haxe/src/TestServerHandler.hx
new file mode 100644
index 0000000..e988adb
--- /dev/null
+++ b/test/haxe/src/TestServerHandler.hx
@@ -0,0 +1,470 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+import org.apache.thrift.helper.*;
+
+import haxe.Int32;
+import haxe.Int64;
+import haxe.io.Bytes;
+import haxe.ds.IntMap;
+import haxe.ds.StringMap;
+import haxe.ds.ObjectMap;
+
+import thrift.test.*; // generated code
+
+
+class TestServerHandler implements ThriftTest {
+
+ public var server:TServer;
+
+ public function new() {
+ }
+
+ /**
+ * Prints "testVoid()" and returns nothing.
+ */
+ public function testVoid():Void
+ {
+ trace("testVoid()");
+ }
+
+ /**
+ * Prints 'testString("%s")' with thing as '%s'
+ * @param string thing - the string to print
+ * @return string - returns the string 'thing'
+ *
+ * @param thing
+ */
+ public function testString(thing:String):String
+ {
+ trace("teststring(\"" + thing + "\")");
+ return thing;
+ }
+
+ /**
+ * Prints 'testByte("%d")' with thing as '%d'
+ * @param byte thing - the byte to print
+ * @return byte - returns the byte 'thing'
+ *
+ * @param thing
+ */
+ public function testByte(thing:haxe.Int32):haxe.Int32
+ {
+ trace("testByte(" + thing + ")");
+ return thing;
+ }
+
+ /**
+ * Prints 'testI32("%d")' with thing as '%d'
+ * @param i32 thing - the i32 to print
+ * @return i32 - returns the i32 'thing'
+ *
+ * @param thing
+ */
+ public function testI32(thing:haxe.Int32):haxe.Int32
+ {
+ trace("testI32(" + thing + ")");
+ return thing;
+ }
+
+ /**
+ * Prints 'testI64("%d")' with thing as '%d'
+ * @param i64 thing - the i64 to print
+ * @return i64 - returns the i64 'thing'
+ *
+ * @param thing
+ */
+ public function testI64(thing:haxe.Int64):haxe.Int64
+ {
+ trace("testI64(" + thing + ")");
+ return thing;
+ }
+
+ /**
+ * Prints 'testDouble("%f")' with thing as '%f'
+ * @param double thing - the double to print
+ * @return double - returns the double 'thing'
+ *
+ * @param thing
+ */
+ public function testDouble(thing:Float):Float
+ {
+ trace("testDouble(" + thing + ")");
+ return thing;
+ }
+
+ /**
+ * Prints 'testStruct("{%s}")' where thing has been formatted
+ * into a string of comma seperated values
+ * @param Xtruct thing - the Xtruct to print
+ * @return Xtruct - returns the Xtruct 'thing'
+ *
+ * @param thing
+ */
+ public function testStruct(thing:Xtruct):Xtruct
+ {
+ trace("testStruct({" +
+ "\"" + thing.string_thing + "\", " +
+ thing.byte_thing + ", " +
+ thing.i32_thing + ", " +
+ Int64.toStr(thing.i64_thing) + "})");
+ return thing;
+ }
+
+ /**
+ * Prints 'testNest("{%s}")' where thing has been formatted
+ * into a string of the nested struct
+ * @param Xtruct2 thing - the Xtruct2 to print
+ * @return Xtruct2 - returns the Xtruct2 'thing'
+ *
+ * @param thing
+ */
+ public function testNest(nest:Xtruct2):Xtruct2
+ {
+ var thing:Xtruct = nest.struct_thing;
+ trace("testNest({" +
+ nest.byte_thing + ", {" +
+ "\"" + thing.string_thing + "\", " +
+ thing.byte_thing + ", " +
+ thing.i32_thing + ", " +
+ Int64.toStr(thing.i64_thing) + "}, " +
+ nest.i32_thing + "})");
+ return nest;
+ }
+
+ /**
+ * Prints 'testMap("{%s")' where thing has been formatted
+ * into a string of 'key => value' pairs
+ * seperated by commas and new lines
+ * @param map<i32,i32> thing - the map<i32,i32> to print
+ * @return map<i32,i32> - returns the map<i32,i32> 'thing'
+ *
+ * @param thing
+ */
+ public function testMap(thing:IntMap<haxe.Int32>):IntMap<haxe.Int32>
+ {
+ trace("testMap({");
+ var first:Bool = true;
+ for (key in thing.keys()) {
+ if (first) {
+ first = false;
+ } else {
+ trace(", ");
+ };
+ trace(key + " => " + thing.get(key));
+ };
+ trace("})");
+ return thing;
+ }
+
+ /**
+ * Prints 'testStringMap("{%s}")' where thing has been formatted
+ * into a string of 'key => value' pairs
+ * seperated by commas and new lines
+ * @param map<string,string> thing - the map<string,string> to print
+ * @return map<string,string> - returns the map<string,string> 'thing'
+ *
+ * @param thing
+ */
+ public function testStringMap(thing:StringMap<String>):StringMap<String>
+ {
+ trace("testStringMap({");
+ var first:Bool = true;
+ for (key in thing.keys()) {
+ if (first) {
+ first = false;
+ } else {
+ trace(", ");
+ };
+ trace(key + " => " + thing.get(key));
+ };
+ trace("})");
+ return thing;
+ }
+
+ /**
+ * Prints 'testSet("{%s}")' where thing has been formatted
+ * into a string of values
+ * seperated by commas and new lines
+ * @param set<i32> thing - the set<i32> to print
+ * @return set<i32> - returns the set<i32> 'thing'
+ *
+ * @param thing
+ */
+ public function testSet(thing:IntSet):IntSet
+ {
+ trace("testSet({");
+ var first:Bool = true;
+ for (elem in thing) {
+ if (first) {
+ first = false;
+ } else {
+ trace(", ");
+ };
+ trace(elem);
+ };
+ trace("})");
+ return thing;
+ }
+
+ /**
+ * Prints 'testList("{%s}")' where thing has been formatted
+ * into a string of values
+ * seperated by commas and new lines
+ * @param list<i32> thing - the list<i32> to print
+ * @return list<i32> - returns the list<i32> 'thing'
+ *
+ * @param thing
+ */
+ public function testList(thing:List<haxe.Int32>):List<haxe.Int32>
+ {
+ trace("testList({");
+ var first:Bool = true;
+ for (elem in thing) {
+ if (first) {
+ first = false;
+ } else {
+ trace(", ");
+ };
+ trace(elem);
+ };
+ trace("})");
+ return thing;
+ }
+
+ /**
+ * Prints 'testEnum("%d")' where thing has been formatted into it's numeric value
+ * @param Numberz thing - the Numberz to print
+ * @return Numberz - returns the Numberz 'thing'
+ *
+ * @param thing
+ */
+ public function testEnum(thing:Int):Int
+ {
+ trace("testEnum(" + thing + ")");
+ return thing;
+ }
+
+ /**
+ * Prints 'testTypedef("%d")' with thing as '%d'
+ * @param UserId thing - the UserId to print
+ * @return UserId - returns the UserId 'thing'
+ *
+ * @param thing
+ */
+ public function testTypedef(thing:haxe.Int64):haxe.Int64
+ {
+ trace("testTypedef(" + thing + ")");
+ return thing;
+ }
+
+ /**
+ * Prints 'testMapMap("%d")' with hello as '%d'
+ * @param i32 hello - the i32 to print
+ * @return map<i32,map<i32,i32>> - returns a dictionary with these values:
+ * {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, },
+ * 4 => {1 => 1, 2 => 2, 3 => 3, 4 => 4, }, }
+ *
+ * @param hello
+ */
+ public function testMapMap(hello:haxe.Int32):IntMap<IntMap<haxe.Int32>>
+ {
+ trace("testMapMap(" + hello + ")");
+ var mapmap = new IntMap<IntMap<Int>>();
+ var pos = new IntMap<Int>();
+ var neg = new IntMap<Int>();
+ for (i in 1 ... 5) {
+ pos.set(i, i);
+ neg.set(-i, -i);
+ };
+ mapmap.set(4, pos);
+ mapmap.set(-4, neg);
+ return mapmap;
+ }
+
+ /**
+ * So you think you've got this all worked, out eh?
+ *
+ * Creates a the returned map with these values and prints it out:
+ * { 1 => { 2 => argument,
+ * 3 => argument,
+ * },
+ * 2 => { 6 => <empty Insanity struct>, },
+ * }
+ * @return map<UserId, map<Numberz,Insanity>> - a map with the above values
+ *
+ * @param argument
+ */
+ public function testInsanity(argument : Insanity) : Int64Map< IntMap< Insanity>>
+ {
+ trace("testInsanity()");
+
+ var hello = new Xtruct();
+ hello.string_thing = "Hello2";
+ hello.byte_thing = 2;
+ hello.i32_thing = 2;
+ hello.i64_thing = Int64.make(0, 2);
+
+ var goodbye = new Xtruct();
+ goodbye.string_thing = "Goodbye4";
+ goodbye.byte_thing = 4;
+ goodbye.i32_thing = 4;
+ goodbye.i64_thing = Int64.make(0, 4);
+
+ var crazy = new Insanity();
+ crazy.userMap = new IntMap< haxe.Int64>();
+ crazy.userMap.set(Numberz.EIGHT, Int64.make(0,8));
+ crazy.xtructs = new List<Xtruct>();
+ crazy.xtructs.add(goodbye);
+
+ var looney = new Insanity();
+ crazy.userMap.set(Numberz.FIVE, Int64.make(0,5));
+ crazy.xtructs.add(hello);
+
+ var first_map = new IntMap< Insanity>();
+ first_map.set(Numberz.TWO, crazy);
+ first_map.set(Numberz.THREE, crazy);
+
+ var second_map = new IntMap< Insanity>();
+ second_map.set(Numberz.SIX, looney);
+
+ var insane = new Int64Map< IntMap< Insanity>>();
+ insane.set( Int64.make(0,1), first_map);
+ insane.set( Int64.make(0,2), second_map);
+
+ return insane;
+ }
+
+ /**
+ * Prints 'testMulti()'
+ * @param byte arg0 -
+ * @param i32 arg1 -
+ * @param i64 arg2 -
+ * @param map<i16, string> arg3 -
+ * @param Numberz arg4 -
+ * @param UserId arg5 -
+ * @return Xtruct - returns an Xtruct
+ * with string_thing = "Hello2, byte_thing = arg0, i32_thing = arg1
+ * and i64_thing = arg2
+ *
+ * @param arg0
+ * @param arg1
+ * @param arg2
+ * @param arg3
+ * @param arg4
+ * @param arg5
+ */
+ public function testMulti(arg0:haxe.Int32, arg1:haxe.Int32, arg2:haxe.Int64,
+ arg3:IntMap<String>, arg4:Int, arg5:haxe.Int64):Xtruct
+ {
+ trace("testMulti()");
+ var hello = new Xtruct();
+ hello.string_thing = "Hello2";
+ hello.byte_thing = arg0;
+ hello.i32_thing = arg1;
+ hello.i64_thing = arg2;
+ return hello;
+ }
+
+ /**
+ * Print 'testException(%s)' with arg as '%s'
+ * @param string arg - a string indication what type of exception to throw
+ * if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
+ * elsen if arg == "TException" throw TException
+ * else do not throw anything
+ *
+ * @param arg
+ */
+ public function testException(arg:String):Void
+ {
+ trace("testException(" + arg + ")");
+ if (arg == "Xception") {
+ var x = new Xception();
+ x.errorCode = 1001;
+ x.message = arg;
+ throw x;
+ };
+ if (arg == "TException") {
+ throw new TException();
+ };
+ return;
+ }
+
+ /**
+ * Print 'testMultiException(%s, %s)' with arg0 as '%s' and arg1 as '%s'
+ * @param string arg - a string indication what type of exception to throw
+ * if arg0 == "Xception"
+ * throw Xception with errorCode = 1001 and message = "This is an Xception"
+ * else if arg0 == "Xception2"
+ * throw Xception2 with errorCode = 2002 and message = "This is an Xception2"
+ * else do not throw anything
+ * @return Xtruct - an Xtruct with string_thing = arg1
+ *
+ * @param arg0
+ * @param arg1
+ */
+ public function testMultiException(arg0:String, arg1:String):Xtruct
+ {
+ trace("testMultiException(" + arg0 + ", " + arg1 + ")");
+ if (arg0 == "Xception") {
+ var x = new Xception();
+ x.errorCode = 1001;
+ x.message = "This is an Xception";
+ throw x;
+ } else if (arg0 == "Xception2") {
+ var x = new Xception2();
+ x.errorCode = 2002;
+ x.struct_thing = new Xtruct();
+ x.struct_thing.string_thing = "This is an Xception2";
+ throw x;
+ };
+ var result = new Xtruct();
+ result.string_thing = arg1;
+ return result;
+ }
+
+ /**
+ * Print 'testOneway(%d): Sleeping...' with secondsToSleep as '%d'
+ * sleep 'secondsToSleep'
+ * Print 'testOneway(%d): done sleeping!' with secondsToSleep as '%d'
+ * @param i32 secondsToSleep - the number of seconds to sleep
+ *
+ * @param secondsToSleep
+ */
+ public function testOneway(secondsToSleep:haxe.Int32):Void
+ {
+ trace("testOneway(" + secondsToSleep + "), sleeping...");
+ Sys.sleep(secondsToSleep);
+ trace("testOneway finished");
+ }
+
+ public function testStop():Void
+ {
+ if (server != null) {
+ server.Stop();
+ };
+ }
+}
diff --git a/tutorial/Makefile.am b/tutorial/Makefile.am
index 2b9be52..79fd8fd 100755
--- a/tutorial/Makefile.am
+++ b/tutorial/Makefile.am
@@ -50,6 +50,10 @@
SUBDIRS += hs
endif
+if WITH_HAXE
+SUBDIRS += haxe
+endif
+
if WITH_GO
SUBDIRS += go
endif
diff --git a/tutorial/haxe/Makefile.am b/tutorial/haxe/Makefile.am
new file mode 100644
index 0000000..d98be0a
--- /dev/null
+++ b/tutorial/haxe/Makefile.am
@@ -0,0 +1,50 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+gen-haxe/tutorial/calculator.hx gen-haxe/shared/shared_service.hx: $(top_srcdir)/tutorial/tutorial.thrift
+ $(THRIFT) --gen haxe -r $<
+
+all-local: bin/Main-debug
+
+check: gen-haxe/tutorial/calculator.hx
+
+bin/Main-debug: gen-haxe/tutorial/calculator.hx
+ $(HAXE) --cwd . cpp.hxml
+
+tutorialserver: all
+ bin/Main-debug server
+
+tutorialclient: all
+ bin/Main-debug
+
+tutorialsecureserver: all
+ bin/Main-debug server secure
+
+tutorialsecureclient: all
+ bin/Main-debug secure
+
+clean-local:
+ $(RM) -r gen-haxe bin
+
+EXTRA_DIST = \
+ src/Main.hx \
+ src/CalculatorHandler.hx
+
diff --git a/tutorial/haxe/cpp.hxml b/tutorial/haxe/cpp.hxml
new file mode 100644
index 0000000..6adb52d
--- /dev/null
+++ b/tutorial/haxe/cpp.hxml
@@ -0,0 +1,41 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#CPP target
+-cpp bin
+
+#To produce 64 bit binaries the file should define the HXCPP_M64 compile variable:
+#-D HXCPP_M64
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/csharp.hxml b/tutorial/haxe/csharp.hxml
new file mode 100644
index 0000000..295c017
--- /dev/null
+++ b/tutorial/haxe/csharp.hxml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#CSHARP target
+-cs bin/Tutorial.exe
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/flash.hxml b/tutorial/haxe/flash.hxml
new file mode 100644
index 0000000..a1f0568
--- /dev/null
+++ b/tutorial/haxe/flash.hxml
@@ -0,0 +1,41 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Flash target
+-swf bin/Tutorial.swf
+
+#Add debug information
+-debug
+
+# we need some goodies from sys.net
+# --macro allowPackage("sys")
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/java.hxml b/tutorial/haxe/java.hxml
new file mode 100644
index 0000000..c615565
--- /dev/null
+++ b/tutorial/haxe/java.hxml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Java target
+-java bin/Tutorial.jar
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/javascript.hxml b/tutorial/haxe/javascript.hxml
new file mode 100644
index 0000000..b2b3876
--- /dev/null
+++ b/tutorial/haxe/javascript.hxml
@@ -0,0 +1,44 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#JavaScript target
+-js bin/Tutorial.js
+
+#You can use -D source-map-content (requires Haxe 3.1+) to have the .hx
+#files directly embedded into the map file, this way you only have to
+#upload it, and it will be always in sync with the compiled .js even if
+#you modify your .hx files.
+-D source-map-content
+
+#Generate source map and add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/make_all.bat b/tutorial/haxe/make_all.bat
new file mode 100644
index 0000000..656dd15
--- /dev/null
+++ b/tutorial/haxe/make_all.bat
@@ -0,0 +1,68 @@
+@echo off
+rem /*
+rem * Licensed to the Apache Software Foundation (ASF) under one
+rem * or more contributor license agreements. See the NOTICE file
+rem * distributed with this work for additional information
+rem * regarding copyright ownership. The ASF licenses this file
+rem * to you under the Apache License, Version 2.0 (the
+rem * "License"); you may not use this file except in compliance
+rem * with the License. You may obtain a copy of the License at
+rem *
+rem * http://www.apache.org/licenses/LICENSE-2.0
+rem *
+rem * Unless required by applicable law or agreed to in writing,
+rem * software distributed under the License is distributed on an
+rem * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem * KIND, either express or implied. See the License for the
+rem * specific language governing permissions and limitations
+rem * under the License.
+rem */
+
+setlocal
+if "%HOMEDRIVE%"=="" goto MISSINGVARS
+if "%HOMEPATH%"=="" goto MISSINGVARS
+if "%HAXEPATH%"=="" goto NOTINSTALLED
+
+set path=%HAXEPATH%;%HAXEPATH%\..\neko;%path%
+
+rem # invoke Thrift comnpiler
+thrift -r -gen haxe ..\tutorial.thrift
+if errorlevel 1 goto STOP
+
+rem # invoke Haxe compiler for all targets
+for %%a in (*.hxml) do (
+ rem * filter Python, as it is not supported by Haxe 3.1.3 (but will be in 3.1.4)
+ if not "%%a"=="python.hxml" (
+ echo --------------------------
+ echo Building %%a ...
+ echo --------------------------
+ haxe --cwd . %%a
+ )
+)
+
+
+echo.
+echo done.
+pause
+goto eof
+
+:NOTINSTALLED
+echo FATAL: Either Haxe is not installed, or the HAXEPATH variable is not set.
+pause
+goto eof
+
+:MISSINGVARS
+echo FATAL: Unable to locate home folder.
+echo.
+echo Both HOMEDRIVE and HOMEPATH need to be set to point to your Home folder.
+echo The current values are:
+echo HOMEDRIVE=%HOMEDRIVE%
+echo HOMEPATH=%HOMEPATH%
+pause
+goto eof
+
+:STOP
+pause
+goto eof
+
+:eof
diff --git a/tutorial/haxe/make_all.sh b/tutorial/haxe/make_all.sh
new file mode 100644
index 0000000..2ee650d
--- /dev/null
+++ b/tutorial/haxe/make_all.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# invoke Thrift comnpiler
+thrift -r -gen haxe ../tutorial.thrift
+
+# output folder
+if [ ! -d bin ]; then
+ mkdir bin
+fi
+
+# invoke Haxe compoiler
+for target in *.hxml; do
+ echo --------------------------
+ echo Building ${target} ...
+ echo --------------------------
+ if [ ! -d bin/${target} ]; then
+ mkdir bin/${target}
+ fi
+ haxe --cwd . ${target}
+done
+
+
+#eof
diff --git a/tutorial/haxe/neko.hxml b/tutorial/haxe/neko.hxml
new file mode 100644
index 0000000..6161f69
--- /dev/null
+++ b/tutorial/haxe/neko.hxml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#neko target
+-neko bin/Tutorial.n
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/php.hxml b/tutorial/haxe/php.hxml
new file mode 100644
index 0000000..1eaac8b
--- /dev/null
+++ b/tutorial/haxe/php.hxml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#PHP target
+-php bin/Tutorial.php
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/project.hide b/tutorial/haxe/project.hide
new file mode 100644
index 0000000..46c0a50
--- /dev/null
+++ b/tutorial/haxe/project.hide
@@ -0,0 +1,105 @@
+{
+ "type" : 0
+ ,"target" : 4
+ ,"name" : "Apache Thrift Tutorial"
+ ,"main" : null
+ ,"projectPackage" : ""
+ ,"company" : "Apache Software Foundation (ASF)"
+ ,"license" : "Apache License, Version 2.0"
+ ,"url" : "http://www.apache.org/licenses/LICENSE-2.0"
+ ,"targetData" : [
+ {
+ "pathToHxml" : "flash.hxml"
+ ,"runActionType" : 1
+ ,"runActionText" : "bin/Tutorial.swf"
+ }
+ ,{
+ "pathToHxml" : "javascript.hxml"
+ ,"runActionType" : 1
+ ,"runActionText" : "bin\\index.html"
+ }
+ ,{
+ "pathToHxml" : "neko.hxml"
+ ,"runActionType" : 2
+ ,"runActionText" : "neko bin/Tutorial.n"
+ }
+ ,{
+ "pathToHxml" : "php.hxml"
+ }
+ ,{
+ "pathToHxml" : "cpp.hxml"
+ ,"runActionType" : 2
+ ,"runActionText" : "bin/Main-debug.exe"
+ }
+ ,{
+ "pathToHxml" : "java.hxml"
+ }
+ ,{
+ "pathToHxml" : "csharp.hxml"
+ ,"runActionType" : 2
+ ,"runActionText" : "bin\\Tutorial.exe\\bin\\Main-Debug.exe"
+ }
+ ,{
+ "pathToHxml" : "python.hxml"
+ ,"runActionType" : 2
+ ,"runActionText" : "python bin/Tutorial.py"
+ }
+ ]
+ ,"files" : [
+ {
+ "path" : "src\\org\\apache\\thrift\\server\\TServer.hx"
+ ,"useTabs" : true
+ ,"indentSize" : 4
+ ,"foldedRegions" : [
+
+ ]
+ ,"activeLine" : 76
+ }
+ ,{
+ "path" : "src\\org\\apache\\thrift\\server\\TSimpleServer.hx"
+ ,"useTabs" : true
+ ,"indentSize" : 4
+ ,"foldedRegions" : [
+
+ ]
+ ,"activeLine" : 100
+ }
+ ,{
+ "path" : "src\\shared\\SharedServiceProcessor.hx"
+ ,"useTabs" : true
+ ,"indentSize" : 4
+ ,"foldedRegions" : [
+
+ ]
+ ,"activeLine" : 20
+ }
+ ,{
+ "path" : "src\\tutorial\\CalculatorProcessor.hx"
+ ,"useTabs" : true
+ ,"indentSize" : 4
+ ,"foldedRegions" : [
+
+ ]
+ ,"activeLine" : 79
+ }
+ ,{
+ "path" : "src\\Main.hx"
+ ,"useTabs" : true
+ ,"indentSize" : 4
+ ,"foldedRegions" : [
+
+ ]
+ ,"activeLine" : 276
+ }
+ ]
+ ,"activeFile" : "src\\Main.hx"
+ ,"openFLTarget" : null
+ ,"openFLBuildMode" : "Debug"
+ ,"runActionType" : null
+ ,"runActionText" : null
+ ,"buildActionCommand" : null
+ ,"hiddenItems" : [
+
+ ]
+ ,"showHiddenItems" : false
+}
\ No newline at end of file
diff --git a/tutorial/haxe/python.hxml b/tutorial/haxe/python.hxml
new file mode 100644
index 0000000..f2c19fa
--- /dev/null
+++ b/tutorial/haxe/python.hxml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Python target
+-python bin/Tutorial.py
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/src/CalculatorHandler.hx b/tutorial/haxe/src/CalculatorHandler.hx
new file mode 100644
index 0000000..ee75edd
--- /dev/null
+++ b/tutorial/haxe/src/CalculatorHandler.hx
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package;
+
+import haxe.ds.IntMap;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import tutorial.*;
+import shared.*;
+
+
+class CalculatorHandler implements Calculator {
+
+ private var log = new IntMap<SharedStruct>();
+
+ public function new() {
+ }
+
+ public function ping() : Void {
+ trace("ping()");
+ }
+
+
+ public function add( num1 : haxe.Int32, num2 : haxe.Int32) : haxe.Int32 {
+ trace('add( $num1, $num2)');
+ return num1 + num2;
+ }
+
+ public function calculate( logid : haxe.Int32, work : Work) : haxe.Int32 {
+ trace('calculate( $logid, '+work.op+","+work.num1+","+work.num2+")");
+
+ var val : haxe.Int32 = 0;
+ switch (work.op)
+ {
+ case Operation.ADD:
+ val = work.num1 + work.num2;
+
+ case Operation.SUBTRACT:
+ val = work.num1 - work.num2;
+
+ case Operation.MULTIPLY:
+ val = work.num1 * work.num2;
+
+ case Operation.DIVIDE:
+ if (work.num2 == 0)
+ {
+ var io = new InvalidOperation();
+ io.what = work.op;
+ io.why = "Cannot divide by 0";
+ throw io;
+ }
+ val = Std.int( work.num1 / work.num2);
+
+ default:
+ var io = new InvalidOperation();
+ io.what = work.op;
+ io.why = "Unknown operation";
+ throw io;
+ }
+
+ var entry = new SharedStruct();
+ entry.key = logid;
+ entry.value = '$val';
+ log.set(logid, entry);
+
+ return val;
+ }
+
+ public function getStruct( key : haxe.Int32) : SharedStruct {
+ trace('getStruct($key)');
+ return log.get(key);
+ }
+
+ // oneway method, no args
+ public function zip() : Void {
+ trace("zip()");
+ }
+
+}
diff --git a/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx
new file mode 100644
index 0000000..5c9345e
--- /dev/null
+++ b/tutorial/haxe/src/Main.hx
@@ -0,0 +1,329 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import tutorial.*;
+import shared.*;
+
+
+enum Prot {
+ binary;
+ json;
+}
+
+enum Trns {
+ socket;
+ http;
+}
+
+class Main {
+
+ private static var server : Bool = false;
+ private static var framed : Bool = false;
+ private static var buffered : Bool = false;
+ private static var prot : Prot = binary;
+ private static var trns : Trns = socket;
+
+ private static var targetHost : String = "localhost";
+ private static var targetPort : Int = 9090;
+
+ static function main() {
+ #if ! (flash || js)
+ try {
+ ParseArgs();
+ } catch (e : String) {
+ trace(e);
+ trace(GetHelp());
+ return;
+ }
+ #end
+
+ try {
+ if (server)
+ RunServer();
+ else
+ RunClient();
+ } catch (e : String) {
+ trace(e);
+ }
+
+ trace("Completed.");
+ }
+
+
+ #if ! (flash || js)
+
+ private static function GetHelp() : String {
+ return Sys.executablePath()+" modus trnsOption transport protocol\n"
+ +"Options:\n"
+ +" modus: client, server (default: client)\n"
+ +" trnsOption: framed, buffered (default: none)\n"
+ +" transport: socket, http (default: socket)\n"
+ +" protocol: binary, json (default: binary)\n"
+ +"\n"
+ +"All arguments are optional.\n";
+ }
+
+
+ private static function ParseArgs() : Void {
+ var step = 0;
+ for (arg in Sys.args()) {
+
+ // server|client
+ switch(step) {
+ case 0:
+ ++step;
+ if ( arg == "client")
+ server = false;
+ else if ( arg == "server")
+ server = true;
+ else
+ throw "First argument must be 'server' or 'client'";
+
+ case 1:
+ if ( arg == "framed") {
+ framed = true;
+ } else if ( arg == "buffered") {
+ buffered = true;
+ } else if ( arg == "socket") {
+ trns = socket;
+ ++step;
+ } else if ( arg == "http") {
+ trns = http;
+ ++step;
+ } else {
+ throw "Unknown transport "+arg;
+ }
+
+ case 2:
+ if ( arg == "binary") {
+ prot = binary;
+ ++step;
+ } else if ( arg == "json") {
+ prot = json;
+ ++step;
+ } else {
+ throw "Unknown protocol "+arg;
+ }
+
+ default:
+ throw "Unexpected argument "+arg;
+ }
+
+ if ( framed && buffered)
+ {
+ trace("WN: framed supersedes buffered");
+ }
+
+ }
+ }
+
+ #end
+
+ private static function ClientSetup() : Calculator {
+ trace("Client configuration:");
+
+ // endpoint transport
+ var transport : TTransport;
+ switch(trns)
+ {
+ case socket:
+ trace('- socket transport $targetHost:$targetPort');
+ transport = new TSocket( targetHost, targetPort);
+ case http:
+ trace("- http transport $targetHost");
+ #if flash
+ transport = new THttpClient( new flash.net.URLRequest(targetHost));
+ #else
+ transport = new THttpClient( targetHost);
+ #end
+ default:
+ throw "Unhandled transport";
+ }
+
+
+ // optinal layered transport
+ if ( framed) {
+ trace("- framed transport");
+ transport = new TFramedTransport(transport);
+ } else if ( buffered) {
+ trace("- buffered transport");
+ throw "TBufferedTransport not implemented yet";
+ //transport = new TBufferedTransport(transport);
+ }
+
+
+ // protocol
+ var protocol : TProtocol;
+ switch(prot)
+ {
+ case binary:
+ trace("- binary protocol");
+ protocol = new TBinaryProtocol( transport);
+ case json:
+ trace("- JSON protocol");
+ protocol = new TJSONProtocol( transport);
+ default:
+ throw "Unhandled protocol";
+ }
+
+
+ // put everything together
+ transport.open();
+ return new CalculatorImpl(protocol,protocol);
+ }
+
+
+ private static function RunClient() : Void {
+ var client = ClientSetup();
+
+ try {
+ client.ping();
+ trace("ping() successful");
+ } catch(error : TException) {
+ trace('ping() failed: $error');
+ } catch(error : Dynamic) {
+ trace('ping() failed: $error');
+ }
+
+ try {
+ var sum = client.add( 1, 1);
+ trace('1+1=$sum');
+ } catch(error : TException) {
+ trace('add() failed: $error');
+ } catch(error : Dynamic) {
+ trace('add() failed: $error');
+ }
+
+
+ var work = new tutorial.Work();
+ work.op = tutorial.Operation.DIVIDE;
+ work.num1 = 1;
+ work.num2 = 0;
+ try {
+ var quotient = client.calculate( 1, work);
+ trace('Whoa we can divide by 0! Result = $quotient');
+ } catch(error : TException) {
+ trace('calculate() failed: $error');
+ } catch(error : Dynamic) {
+ trace('calculate() failed: $error');
+ }
+
+ work.op = tutorial.Operation.SUBTRACT;
+ work.num1 = 15;
+ work.num2 = 10;
+ try {
+ var diff = client.calculate( 1, work);
+ trace('15-10=$diff');
+ } catch(error : TException) {
+ trace('calculate() failed: $error');
+ } catch(error : Dynamic) {
+ trace('calculate() failed: $error');
+ }
+
+
+ try {
+ var log : SharedStruct = client.getStruct( 1);
+ var logval = log.value;
+ trace('Check log: $logval');
+ } catch(error : TException) {
+ trace('getStruct() failed: $error');
+ } catch(error : Dynamic) {
+ trace('getStruct() failed: $error');
+ }
+ }
+
+
+ private static function ServerSetup() : TServer {
+ trace("Server configuration:");
+
+ // endpoint transport
+ var transport : TServerTransport = null;
+ switch(trns)
+ {
+ case socket:
+ #if (flash || js)
+ throw 'current platform does not support socket servers';
+ #else
+ trace('- socket transport port $targetPort');
+ transport = new TServerSocket( targetPort);
+ #end
+ case http:
+ throw "HTTP server not implemented yet";
+ //trace("- http transport");
+ //transport = new THttpClient( targetHost);
+ default:
+ throw "Unhandled transport";
+ }
+
+ // optional: layered transport
+ var transfactory : TTransportFactory = null;
+ if ( framed) {
+ trace("- framed transport");
+ transfactory = new TFramedTransportFactory();
+ } else if ( buffered) {
+ trace("- buffered transport");
+ throw "TBufferedTransport not implemented yet";
+ //transfactory = new TBufferedTransportFactory();
+ }
+
+ // protocol
+ var protfactory : TProtocolFactory = null;
+ switch(prot)
+ {
+ case binary:
+ trace("- binary protocol");
+ protfactory = new TBinaryProtocolFactory();
+ case json:
+ trace("- JSON protocol");
+ protfactory = new TJSONProtocolFactory();
+ default:
+ throw "Unhandled protocol";
+ }
+
+ var handler = new CalculatorHandler();
+ var processor = new CalculatorProcessor(handler);
+ var server = new TSimpleServer( processor, transport, transfactory, protfactory);
+ return server;
+ }
+
+
+ private static function RunServer() : Void {
+ try
+ {
+ var server = ServerSetup();
+
+ trace("\nStarting the server...");
+ server.Serve();
+ }
+ catch( e : Dynamic)
+ {
+ trace('RunServer() failed: $e');
+ }
+ trace("done.");
+ }
+
+}
diff --git a/tutorial/shared.thrift b/tutorial/shared.thrift
index db4b694..60e8e7a 100644
--- a/tutorial/shared.thrift
+++ b/tutorial/shared.thrift
@@ -27,6 +27,7 @@
namespace java shared
namespace perl shared
namespace php shared
+namespace haxe shared
struct SharedStruct {
1: i32 key
diff --git a/tutorial/tutorial.thrift b/tutorial/tutorial.thrift
index 3150151..c8710d4 100644
--- a/tutorial/tutorial.thrift
+++ b/tutorial/tutorial.thrift
@@ -67,6 +67,7 @@
namespace java tutorial
namespace php tutorial
namespace perl tutorial
+namespace haxe tutorial
/**
* Thrift lets you do typedefs to get pretty names for your types. Standard