From 17e419f563052a7da84e5d7e45f4c8a53cb99675 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Mon, 28 Jul 2014 01:25:30 +0200 Subject: [PATCH 01/24] Haxe: Compiler, Library, Tutorial --- compiler/cpp/CMakeLists.txt | 1 + compiler/cpp/Makefile.am | 1 + compiler/cpp/src/generate/t_haxe_generator.cc | 2709 +++++++++++++++++ .../org/apache/thrift/AbstractMethodError.hx | 40 + .../src/org/apache/thrift/ArgumentError.hx | 29 + lib/haxe/src/org/apache/thrift/Error.hx | 55 + lib/haxe/src/org/apache/thrift/Limits.hx | 44 + lib/haxe/src/org/apache/thrift/Set.hx | 83 + .../org/apache/thrift/TApplicationError.hx | 102 + lib/haxe/src/org/apache/thrift/TBase.hx | 66 + lib/haxe/src/org/apache/thrift/TError.hx | 30 + .../apache/thrift/TFieldRequirementType.hx | 31 + lib/haxe/src/org/apache/thrift/TProcessor.hx | 30 + .../apache/thrift/meta_data/FieldMetaData.hx | 56 + .../thrift/meta_data/FieldValueMetaData.hx | 43 + .../apache/thrift/meta_data/ListMetaData.hx | 30 + .../apache/thrift/meta_data/MapMetaData.hx | 32 + .../apache/thrift/meta_data/SetMetaData.hx | 30 + .../apache/thrift/meta_data/StructMetaData.hx | 30 + .../apache/thrift/protocol/TBinaryProtocol.hx | 333 ++ .../src/org/apache/thrift/protocol/TField.hx | 42 + .../src/org/apache/thrift/protocol/TList.hx | 32 + .../src/org/apache/thrift/protocol/TMap.hx | 34 + .../org/apache/thrift/protocol/TMessage.hx | 41 + .../apache/thrift/protocol/TMessageType.hx | 27 + .../org/apache/thrift/protocol/TProtocol.hx | 82 + .../apache/thrift/protocol/TProtocolError.hx | 39 + .../thrift/protocol/TProtocolFactory.hx | 26 + .../apache/thrift/protocol/TProtocolUtil.hx | 135 + .../src/org/apache/thrift/protocol/TSet.hx | 32 + .../src/org/apache/thrift/protocol/TStruct.hx | 30 + .../src/org/apache/thrift/protocol/TType.hx | 38 + .../thrift/transport/TFramedTransport.hx | 149 + .../thrift/transport/TFullDuplexHttpClient.hx | 238 ++ .../apache/thrift/transport/THttpClient.hx | 171 ++ .../org/apache/thrift/transport/TSocket.hx | 200 ++ .../org/apache/thrift/transport/TTransport.hx | 129 + .../thrift/transport/TTransportError.hx | 36 + .../thrift/transport/TTransportFactory.hx | 41 + tutorial/haxe/src/Main.hx | 251 ++ tutorial/shared.thrift | 1 + tutorial/tutorial.thrift | 1 + 42 files changed, 5550 insertions(+) create mode 100644 compiler/cpp/src/generate/t_haxe_generator.cc create mode 100644 lib/haxe/src/org/apache/thrift/AbstractMethodError.hx create mode 100644 lib/haxe/src/org/apache/thrift/ArgumentError.hx create mode 100644 lib/haxe/src/org/apache/thrift/Error.hx create mode 100644 lib/haxe/src/org/apache/thrift/Limits.hx create mode 100644 lib/haxe/src/org/apache/thrift/Set.hx create mode 100644 lib/haxe/src/org/apache/thrift/TApplicationError.hx create mode 100644 lib/haxe/src/org/apache/thrift/TBase.hx create mode 100644 lib/haxe/src/org/apache/thrift/TError.hx create mode 100644 lib/haxe/src/org/apache/thrift/TFieldRequirementType.hx create mode 100644 lib/haxe/src/org/apache/thrift/TProcessor.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/FieldMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/FieldValueMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/ListMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/MapMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/SetMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/StructMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TField.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TList.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TMap.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TMessage.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TMessageType.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TProtocolError.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TProtocolFactory.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TProtocolUtil.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TSet.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TStruct.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TType.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/THttpClient.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TSocket.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TTransport.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TTransportError.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TTransportFactory.hx create mode 100644 tutorial/haxe/src/Main.hx diff --git a/compiler/cpp/CMakeLists.txt b/compiler/cpp/CMakeLists.txt index 152e5db450e..3bac05a6891 100644 --- a/compiler/cpp/CMakeLists.txt +++ b/compiler/cpp/CMakeLists.txt @@ -120,6 +120,7 @@ THRIFT_ADD_COMPILER(c_glib "Enable compiler for C with Glib" ON) 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 601fd3263ef..4a09b2d7716 100644 --- a/compiler/cpp/Makefile.am +++ b/compiler/cpp/Makefile.am @@ -71,6 +71,7 @@ thrift_SOURCES += src/generate/t_c_glib_generator.cc \ src/generate/t_cpp_generator.cc \ src/generate/t_java_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/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc new file mode 100644 index 00000000000..5b9403ec12e --- /dev/null +++ b/compiler/cpp/src/generate/t_haxe_generator.cc @@ -0,0 +1,2709 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include +#include + +#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& parsed_options, + const std::string& option_string) + : t_oop_generator(program) + { + (void) option_string; + std::map::const_iterator iter; + + out_dir_base_ = "gen-haxe"; + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + void generate_consts(std::vector 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_haxe_bean_boilerplate(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); + + /** + * 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(t_function* tfunction, std::string on_error_success, std::string prefix=""); + std::string argument_list(t_struct* tstruct); + std::string type_to_enum(t_type* ttype); + std::string get_enum_class_name(t_type* type); + + bool type_can_be_null(t_type* ttype) { + ttype = get_true_type(ttype); + + return + ttype->is_container() || + ttype->is_struct() || + ttype->is_xception() || + ttype->is_string(); + } + + std::string constant_name(std::string name); + + private: + + /** + * 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.Set;\n" + + "import haxe.io.Bytes;\n" + + //flash only: "import flash.utils.ByteArray;\n" + + //flash only: "import flash.utils.Dictionary;\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& members = tstruct->get_members(); + vector::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& functions = tservice->get_functions(); + vector::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.Set;" << endl << + //flash only: "import flash.utils.Dictionary;" << endl << + endl; + + indent(f_enum) << + "class " << tenum->get_name() << " "; + scope_up(f_enum); + + vector constants = tenum->get_constants(); + vector::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 Set( ["; + 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 = { [" << endl; + 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 << + "]; };" << endl; + indent_down(); + + 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 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; + + scope_up(f_consts); + f_consts << endl; + + f_consts << haxe_type_imports(); + + + + indent(f_consts) << + "class " << program_name_ << + "Constants {" << endl << endl; + indent_up(); + vector::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; + scope_down(f_consts); + 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& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::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& val = value->get_map(); + map::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& val = value->get_list(); + vector::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 Error "; + } + out << "implements TBase "; + + scope_up(out); + indent(out) << endl; + + indent(out) << + "static var STRUCT_DESC = { new TStruct(\"" << tstruct->get_name() << "\"); };" << endl; + + const vector& members = tstruct->get_members(); + vector::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) << "public var " << (*m_iter)->get_name() + "(default,default) : " + type_name((*m_iter)->get_type()) << ";" << endl; + + 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_haxe_bean_boilerplate(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& fields = tstruct->get_members(); + vector::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 TProtocolError(TProtocolError.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& fields = tstruct->get_members(); + vector::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 TProtocolError(TProtocolError.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 TProtocolError(TProtocolError.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& fields = tstruct->get_sorted_members(); + vector::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& fields = tstruct->get_sorted_members(); + vector::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& fields = tstruct->get_members(); + vector::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& fields = tstruct->get_members(); + vector::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 haxe Bean boilerplate functions (setters, getters, etc.) + * for the given struct. + * + * @param tstruct The struct definition + */ +void t_haxe_generator::generate_haxe_bean_boilerplate(ofstream& out, + t_struct* tstruct) { + const vector& fields = tstruct->get_members(); + vector::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); + std::string propName = tmp("thriftPropertyChange"); + indent(out) << "public function set_" << field_name << "(" << field_name + << ":" << type_name(type) << ") : Void {" << endl; + indent_up(); + indent(out) << "this._" << field_name << " = " << field_name << ";" << + endl; + generate_isset_set(out, field); + + 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 = new String(\"" << tstruct->get_name() << "(\");" << endl; + out << indent() << "var first : Bool = true;" << endl << endl; + + const vector& fields = tstruct->get_members(); + vector::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& fields = tstruct->get_members(); + vector::const_iterator f_iter; + + // Static Map with fieldID -> FieldMetaData mappings + indent(out) << "inline static var metaDataMap : Dictionary = new Dictionary();" << 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_ << ".*\n;" << endl; + } + + generate_service_server(tservice); + generate_service_helpers(tservice); + + f_service_.close(); + +} + +/** + * 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 functions = tservice->get_functions(); + vector::iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_haxe_doc(f_service_, *f_iter); + string on_error_success; + if (!(*f_iter)->is_oneway()) { + if ((*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << "//function onError(Error) : Void;" << endl; + indent(f_service_) << "//function onSuccess() : Void;" << endl; + on_error_success = "onError : Error->Void = null, onSuccess : Void->Void = null"; + } + else { + indent(f_service_) << "//function onError(Error) : Void;" << endl; + indent(f_service_) << "//function onSuccess(" << type_name((*f_iter)->get_returntype()) << ") : Void;" << endl; + on_error_success = "onError : Error->Void = null, onSuccess : "+type_name((*f_iter)->get_returntype())+"->Void = null"; + } + } + indent(f_service_) << function_signature(*f_iter,on_error_success) << ";" << + endl << endl; + } + 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 functions = tservice->get_functions(); + vector::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 functions = tservice->get_functions(); + vector::const_iterator f_iter; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + string funname = (*f_iter)->get_name(); + + // Open function + std::string on_error_success; + if (!(*f_iter)->is_oneway()) { + if ((*f_iter)->get_returntype()->is_void()) { + indent(f_service_) << "//function onError(Error) : Void;" << endl; + indent(f_service_) << "//function onSuccess() : Void;" << endl; + on_error_success = "onError : Error->Void = null, onSuccess : Void->Void = null"; + } + else { + indent(f_service_) << "//function onError(Error) : Void;" << endl; + indent(f_service_) << "//function onSuccess(" << type_name((*f_iter)->get_returntype()) << ") : Void;" << endl; + on_error_success = "onError : Error->Void = null, onSuccess : "+type_name((*f_iter)->get_returntype())+"->Void = null"; + } + } + indent(f_service_) << + "public " << function_signature(*f_iter,on_error_success) << endl; + scope_up(f_service_); + + + // 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::const_iterator fld_iter; + const vector& fields = arg_struct->get_members(); + + // Serialize the request + f_service_ << + indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", TMessageType.CALL, 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_service_ << indent() << "oprot_.getTransport().flush();" << endl; + } + else { + f_service_ << indent() << "oprot_.getTransport().flush(function(error:Error) : Void {" << endl; + indent_up(); + f_service_ << indent() << "try {" << endl; + indent_up(); + string resultname = get_cap_name( (*f_iter)->get_name() + "_result"); + f_service_ << + indent() << "if (error != null) {" << endl << + indent() << " if (onError != null) onError(error);" << endl << + indent() << " return;" << endl << + indent() << "}" << endl << + indent() << "var msg : TMessage = iprot_.readMessageBegin();" << endl << + indent() << "if (msg.type == TMessageType.EXCEPTION) {" << endl << + indent() << " var x:TApplicationError = TApplicationError.read(iprot_);" << endl << + indent() << " iprot_.readMessageEnd();" << endl << + indent() << " if (onError != null) onError(x);" << endl << + indent() << " return;" << endl << + indent() << "}" << endl << + indent() << "var result : " << resultname << " = new " << resultname << "();" << endl << + indent() << "result.read(iprot_);" << endl << + indent() << "iprot_.readMessageEnd();" << endl; + + // Careful, only return _result if not a void function + if (!(*f_iter)->get_returntype()->is_void()) { + f_service_ << + indent() << "if (result." << generate_isset_check("success") << ") {" << endl << + indent() << " if (onSuccess != null) onSuccess(result.success);" << endl << + indent() << " return;" << endl << + indent() << "}" << endl; + } + + t_struct* xs = (*f_iter)->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { + f_service_ << + indent() << "if (result." << (*x_iter)->get_name() << " != null) {" << endl << + indent() << " if (onError != null) onError(result." << (*x_iter)->get_name() << ");" << endl << + indent() << " return;" << endl << + indent() << "}" << endl; + } + + // If you get here it's an exception, unless a void function + if ((*f_iter)->get_returntype()->is_void()) { + f_service_ << + indent() << "if (onSuccess != null) onSuccess();" << endl << + indent() << "return;" << endl; + } else { + + f_service_ << + indent() << "if (onError != null)" << endl; + indent_up(); + f_service_ << + indent() << "onError( new TApplicationError(TApplicationError.MISSING_RESULT," << endl << + indent() << " \"" << (*f_iter)->get_name() << " failed: unknown result\"));" << endl; + indent_down(); + } + indent_down(); + f_service_ << indent() << "} catch (e:TError) {" << endl << + indent() << " if (onError != null) onError(e);" << endl << + indent() << "}" << endl; + + + indent_down(); + indent(f_service_) << + "});" << 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 functions = tservice->get_functions(); + vector::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(); + + indent(f_service_) << + "public function " << service_name_ << "Processor(iface:" << service_name_ << ")" << endl; + scope_up(f_service_); + if (!extends.empty()) { + f_service_ << + indent() << "super(iface);" << endl; + } + f_service_ << + indent() << "iface_ = iface;" << endl; + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_service_ << + indent() << "PROCESS_MAP[\"" << (*f_iter)->get_name() << "\"] = " << (*f_iter)->get_name() << "();" << endl; + } + + scope_down(f_service_); + f_service_ << endl; + + f_service_ << + indent() << "private var iface_:" << service_name_ << ";" << endl; + + if (extends.empty()) { + f_service_ << + indent() << "inline static var PROCESS_MAP : Dictionary = new Dictionary();" << endl; + } + + 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 : Function = PROCESS_MAP[msg.name];" << endl << + indent() << "if (fn == null) {" << endl << + indent() << " TProtocolUtil.skip(iprot, TType.STRUCT);" << endl << + indent() << " iprot.readMessageEnd();" << endl << + indent() << " var x : TApplicationError = new TApplicationError(TApplicationError.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.call(this,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& fields = xs->get_members(); + vector::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() << "() : Function {" << 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& xceptions = xs->get_members(); + vector::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 a function with exceptions + if (xceptions.size() > 0) { + f_service_ << + indent() << "try {" << endl; + indent_up(); + } + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + f_service_ << indent(); + if (tfunction->is_oneway()){ + f_service_ << + "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; + } else { + f_service_ << "// sorry this operation is not supported yet" << endl; + f_service_ << indent() << "throw new Error(\"This is not yet supported\");" << endl; + } + + // Set isset on success field + if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void() && !type_can_be_null(tfunction->get_returntype())) { + f_service_ << + indent() << "result.set" << get_cap_name("success") << get_cap_name("isSet") << "(true);" << endl; + } + + if (!tfunction->is_oneway() && xceptions.size() > 0) { + indent_down(); + f_service_ << indent() << "}"; + 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_ << "}"; + } + } + f_service_ << " catch (th:Error) {" << endl; + indent_up(); + f_service_ << + indent() << "trace(\"Internal error processing " << tfunction->get_name() << "\", th);" << endl << + indent() << "var x : TApplicationError = new TApplicationError(TApplicationError.INTERNAL_ERROR, \"Internal error processing " << tfunction->get_name() << "\");" << endl << + indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl << + indent() << "x.write(oprot);" << endl << + indent() << "oprot.writeMessageEnd();" << endl << + indent() << "oprot.getTransport().flush();" << endl << + indent() << "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 << " : TMap = iprot.readMapBegin();" << endl; + } else if (ttype->is_set()) { + indent(out) << "var " << obj << " : TSet = iprot.readSetBegin();" << endl; + } else if (ttype->is_list()) { + indent(out) << "var " << obj << " : TList = 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 (var " << i << " : Int = 0; " << + i << " < " << obj << ".size" << "; " << + "++" << i << ")" << 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 << "[" << 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 << ".push(" << 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 (var " << iter << " : Dynamic 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 (var " << iter << " : Dynamic in " << prefix << ")"; + } else if (ttype->is_set()) { + indent(out) << + "for each (var " << iter << " : Dynamic in " << prefix << ".toArray())"; + } else if (ttype->is_list()) { + indent(out) << + "for each (var " << iter << " : Dynamic in " << prefix << ")"; + } + + 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 + "[" + 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 + */ +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); + } else if (ttype->is_enum()) { + return "Int"; + } else if (ttype->is_map()) { + return "Dictionary"; + } else if (ttype->is_set()) { + return "Set"; + } else if (ttype->is_list()) { + return "Array"; + } + + // 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 "hyxe.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(t_function* tfunction, + string on_error_success, + string prefix) { + 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 " + + prefix + tfunction->get_name() + "(" + arguments + ") : Void"; + return result; +} + +/** + * Renders a comma separated field list, with type names + */ +string t_haxe_generator::argument_list(t_struct* tstruct) { + string result = ""; + + const vector& fields = tstruct->get_members(); + vector::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& fields = tfunction->get_arglist()->get_members(); + vector::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", +"" +/* sample option +" bindable: Add [bindable] metadata to all the struct classes.\n" +*/ +) + 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 00000000000..bc1a3b4f4e6 --- /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.TError; +#end + +class AbstractMethodError +#if flash +extends IllegalOperationError +#else +extends TError +#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 00000000000..14482f45e87 --- /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 Error { + public function new(msg : String = "") { + super(msg); + } +} +#end diff --git a/lib/haxe/src/org/apache/thrift/Error.hx b/lib/haxe/src/org/apache/thrift/Error.hx new file mode 100644 index 00000000000..08189f9f904 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/Error.hx @@ -0,0 +1,55 @@ +/* + * 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; + +// there seems no built-in equivalent for the Error object in Haxe (or it is very well hidden) +// http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Error.html +class Error { + + private var _id : Int; + private var _msg : String; + + public var errorID(default,never) : Int; + public var message(default,never) : String; + private var name(default,never) : String; // NOT IMPLEMENTED + + + function new(message : String = "", id : Int = 0) { + //super(); + _id = id; + _msg = message; + } + + function get_errorID() : Int { + return _id; + } + + function get_message() : String { + return _msg; + } + + + // NOT IMPLEMENTED + // see http://haxe.org/manual/cr-rtti-structure.html + private function get_name() : String { + throw "not implemented"; + } + +} 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 00000000000..08637c14618 --- /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 ... 31) { + 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/Set.hx b/lib/haxe/src/org/apache/thrift/Set.hx new file mode 100644 index 00000000000..b38926fcf49 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/Set.hx @@ -0,0 +1,83 @@ +/* + * 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 Map; + + +class Set { + + private var _elements : haxe.ds.ObjectMap = new haxe.ds.ObjectMap(); + private var _size : Int = 0; + public var size(default,never) : Int = 0; + + public function new( values : Array) { + for ( value in values) { + add(value); + } + } + + public function add(o : K) : Bool { + if( _elements.exists(o)) { + return false; + } + _size++; + _elements.set(o,0); + 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 { + var ret : Array = new Array(); + 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/TApplicationError.hx b/lib/haxe/src/org/apache/thrift/TApplicationError.hx new file mode 100644 index 00000000000..1bbb095eea9 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/TApplicationError.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 TApplicationError extends TError { + + 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):TApplicationError { + 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 TApplicationError(type, message); + } + + public function write(oprot:TProtocol) : Void { + oprot.writeStructBegin(TAPPLICATION_EXCEPTION_STRUCT); + if (message != null) { + oprot.writeFieldBegin(MESSAGE_FIELD); + oprot.writeString(message); + 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 00000000000..5d8bfc10cf2 --- /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/TError.hx b/lib/haxe/src/org/apache/thrift/TError.hx new file mode 100644 index 00000000000..b154038ce1f --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/TError.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.Error; + +class TError extends Error { + + public function new(msg : String = "", err : Int = 0) { + super( msg, err); + } + +} \ No newline at end of file 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 00000000000..70f698f9c1c --- /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 00000000000..78ce5a7320c --- /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/meta_data/FieldMetaData.hx b/lib/haxe/src/org/apache/thrift/meta_data/FieldMetaData.hx new file mode 100644 index 00000000000..147eed944d4 --- /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 00000000000..06c7f48af18 --- /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 00000000000..36bb2d1fb01 --- /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 00000000000..bf0502a0173 --- /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 00000000000..0ee6c93b0fd --- /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 00000000000..bbf11e72b7a --- /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 00000000000..ce9ab996a94 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx @@ -0,0 +1,333 @@ +/* + * 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.TError; +import org.apache.thrift.transport.THttpClient; +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 = false; + out.writeByte(b); + trans_.write(out.getBytes(), 0, 1); + } + + public function writeI16(i16 : Int) : Void { + var out = new BytesOutput(); + out.bigEndian = false; + out.writeInt16(i16); + trans_.write(out.getBytes(), 0, 2); + } + + public function writeI32(i32 : Int) : Void { + var out = new BytesOutput(); + out.bigEndian = false; + out.writeInt32(i32); + trans_.write(out.getBytes(), 0, 4); + } + + public function writeI64(i64 : haxe.Int64) : Void { + var out = new BytesOutput(); + out.bigEndian = false; + + var oneByte = Int64.make(0,0xFF); + for(i in 0 ... 7) { + out.writeByte( Int64.toInt( Int64.and(oneByte,i64))); + i64 = Int64.shr(i64,8); + } + + trans_.write(out.getBytes(), 0, 8); + } + + public function writeDouble(dub:Float) : Void { + var out = new BytesOutput(); + out.bigEndian = false; + out.writeDouble(dub); + trans_.write(out.getBytes(), 0, 8); + } + + public function writeString(str : String) : Void { + var out = new BytesOutput(); + out.bigEndian = false; + 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 TProtocolError(TProtocolError.BAD_VERSION, "Bad version in readMessageBegin"); + } + return new TMessage(readString(), size & 0x000000ff, readI32()); + } else { + if (strictRead_) { + throw new TProtocolError(TProtocolError.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 bytes : Bytes = (new BytesBuffer()).getBytes(); + var len = trans_.readAll(bytes, 0, 1); + var inp = new BytesInput(bytes, 0, 1); + inp.bigEndian = false; + return inp.readByte(); + } + + public function readI16() : Int { + var bytes : Bytes = (new BytesBuffer()).getBytes(); + var len = trans_.readAll(bytes, 0, 2); + var inp = new BytesInput(bytes, 0, 2); + inp.bigEndian = false; + return inp.readInt16(); + } + + public function readI32() : Int { + var bytes : Bytes = (new BytesBuffer()).getBytes(); + var len = trans_.readAll(bytes, 0, 4); + var inp = new BytesInput(bytes, 0, 4); + inp.bigEndian = false; + return inp.readInt32(); + } + + public function readI64() : haxe.Int64 { + var bytes : Bytes = (new BytesBuffer()).getBytes(); + var len = trans_.readAll(bytes, 0, 8); + var inp = new BytesInput(bytes, 0, 8); + inp.bigEndian = false; + + var mask = Int64.make(0xFFFFFFFF,0xFFFFFF00); + var result = Int64.make(0,0); + for(i in 0 ... 7) { + var nextByte = Int64.make(0,inp.readByte()); + result = Int64.shl( result, 8); + result = Int64.and( result, mask); + result = Int64.or( result, nextByte); + } + + return result; + } + + public function readDouble():Float { + var bytes : Bytes = (new BytesBuffer()).getBytes(); + var len = trans_.readAll(bytes, 0, 8); + var inp = new BytesInput(bytes, 0, 8); + inp.bigEndian = false; + return inp.readDouble(); + } + + public function readString() : String { + return readStringBody( readI32()); + } + + public function readStringBody(len : Int) : String { + if( len > 0) { + var bytes : Bytes = (new BytesBuffer()).getBytes(); + trans_.readAll(bytes, 0, len); + var inp = new BytesInput(bytes, 0, len); + inp.bigEndian = false; + return inp.readString(len); + } else { + return ""; + } + } + + public function readBinary() : Bytes { + var len : Int = readI32(); + var bytes : Bytes = (new BytesBuffer()).getBytes(); + trans_.readAll(bytes, 0, len); + return bytes; + } + +} + +/** +* Factory +*/ +/* +public static class Factory implements TProtocolFactory { + protected boolean strictRead_ = false; + protected boolean strictWrite_ = true; + + public Factory() { + this(false, true); + } + + public Factory(boolean strictRead, boolean strictWrite) { + strictRead_ = strictRead; + strictWrite_ = strictWrite; + } + + public TProtocol getProtocol(TTransport trans) { + 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 00000000000..9f3db62dfd3 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/protocol/TField.hx @@ -0,0 +1,42 @@ +/* + * 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 ""; + } + + public function equals(otherField:TField) : Bool { + return type == otherField.type && id == otherField.id; + } + +} 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 00000000000..d6c15c181bf --- /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 00000000000..5af8c4ec7ce --- /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 00000000000..98c883bfd27 --- /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 ""; + } + + 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 00000000000..b1419402d92 --- /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 00000000000..c3977222492 --- /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.TError; +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; + +} \ No newline at end of file diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocolError.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocolError.hx new file mode 100644 index 00000000000..0befa53b2c0 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocolError.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.TError; + +class TProtocolError extends TError { + + 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 00000000000..d231dbed1f6 --- /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 00000000000..ec93a74a5f8 --- /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 TError("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 00000000000..77806e674e8 --- /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 00000000000..faeef404e84 --- /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 00000000000..3c952f21baa --- /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; + +} \ No newline at end of file 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 00000000000..1e2870dfb23 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx @@ -0,0 +1,149 @@ +/* + * 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 : Bytes, off : Int, len : Int) : Int { + if (readBuffer_ != null) { + var got : Int = readBuffer_.readBytes(buf, off, len); + if (got > 0) { + return got; + }; + }; + + // Read another frame of data + readFrame(); + + return readBuffer_.readBytes(buf, off, len); + } + + + function readFrameSize() : Int { + var bytes : Bytes = (new BytesBuffer()).getBytes(); + var len = transport_.readAll(bytes, 0, 4); + var inp = new BytesInput(bytes, 0, 4); + inp.bigEndian = false; + return inp.readInt32(); + } + + + function readFrame() : Void { + var size : Int = readFrameSize(); + + if (size < 0) { + throw new TTransportError('Read a negative frame size ($size)!'); + }; + if (size > maxLength_) { + throw new TTransportError('Frame size ($size) larger than max length ($maxLength_)!'); + }; + + var bytes : Bytes = (new BytesBuffer()).getBytes(); + size = transport_.readAll(bytes, 0, size); + readBuffer_ = new BytesInput(bytes, 0, size); + readBuffer_.bigEndian = false; + } + + 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 = false; + out.writeInt32(len); + transport_.write(out.getBytes(), 0, 4); + } + + public override function flush( callback : Error->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(); + } +} + + +class TFramedTransportFactory extends TTransportFactory { + + var maxLength_ : Int; + + public function new(maxLength : Int = TFramedTransport.DEFAULT_MAX_LENGTH) { + 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 00000000000..944e9a55fad --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx @@ -0,0 +1,238 @@ +/* + * 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 : Function = 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 TTransportError(TTransportError.UNKNOWN, "No more data available."); + } + catch (e : Error) + { + trace(e); + // WTF?? + throw new TTransportError(TTransportError.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 TTransportError(TTransportError.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 00000000000..0fc7f3f4741 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx @@ -0,0 +1,171 @@ +/* + * 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.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:Bytes, off : Int, len : Int) : Int { + if (responseBuffer_ == null) { + throw new TTransportError(TTransportError.UNKNOWN, "Response buffer is empty, no request."); + } + + #if flash + try { + responseBuffer_.readBytes(buf, off, len); + return len; + } catch (e : EOFError) { + throw new TTransportError(TTransportError.UNKNOWN, "No more data available."); + } + + #else + responseBuffer_.readBytes(buf, off, 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_ = URLLoader(event.target).data; + callback(null); + }); + loader.addEventListener(IOErrorEvent.IO_ERROR, function(event:IOErrorEvent) : Void { + callback(new TTransportError(TTransportError.UNKNOWN, "IOError: " + event.text)); + responseBuffer_ = null; + }); + loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(event:SecurityErrorEvent) : Void { + callback(new TTransportError(TTransportError.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:Error->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 TTransportError(TTransportError.UNKNOWN, "IOError: " + msg)); + }; + request_.customRequest( true/*POST*/, buffer); + } + + #end + +} + + \ No newline at end of file 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 00000000000..cdd5d06ec5e --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx @@ -0,0 +1,200 @@ +/* + * 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 || openfl) +import flash.events.EventDispatcher; +import flash.events.Event; +import flash.events.IOErrorEvent; +import flash.events.ProgressEvent; +import flash.events.SecurityErrorEvent; +import flash.errors.EOFError; +import flash.errors.IOError; +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 flash.net.Socket; +#else +import haxe.remoting.SocketProtocol; +#end + +import haxe.io.Bytes; +import haxe.io.BytesInput; +import haxe.io.BytesOutput; +import sys.net.Host; + + + /** + * Socket implementation of the TTransport interface. Used for working with a + * Thrift Socket Server based implementations. + */ + +class TSocket extends TTransport { + + private var socket : Socket = null; + private var host : Host; + private var port : Int; + private var obuffer : BytesOutput = new BytesOutput(); + private var input : BytesInput; + private var output : BytesOutput; + private var ioCallback : TTransportError->Void = null; + + #if flash + private var eventDispatcher : EventDispatcher = new EventDispatcher(); + #end + + public function new(host : String, port : Int) : Void { + this.host = new Host(host); + this.port = port; + } + + public override function close() : Void { + this.input = null; + this.output = null; + socket.close(); + } + + public override function peek() : Bool { + #if (flash || openfl) + return socket.connected && (socket.bytesAvailable > 0); + #else + return true; // method missing + #end + } + + public override function read(buf : Bytes, off : Int, len : Int) : Int { + try + { + input.readBytes(buf, off, len); + return len; + } + #if (flash || openfl) + catch (e : EOFError) + { + trace(e); + throw new TTransportError(TTransportError.END_OF_FILE, "No more data available."); + } + catch (e : IOError) + { + trace(e); + if(isOpen()) + { + throw new TTransportError(TTransportError.UNKNOWN, "IO error while reading : " + e); + } + else + { + throw new TTransportError(TTransportError.NOT_OPEN, "Socket seem not to be opened : " + e); + } + } + #end + catch (e : Error) + { + trace(e); + throw new TTransportError(TTransportError.UNKNOWN, "Bad IO error : " + e); + } + + return 0; + } + + public override function write(buf : Bytes, off : Int, len : Int) : Void + { + obuffer.writeBytes(buf, off, len); + } + + public override function open() : Void + { + socket = new Socket(); + #if (flash || openfl) + socket.addEventListener(Event.CONNECT, socketConnected); + socket.addEventListener(IOErrorEvent.IO_ERROR, socketError); + socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, socketSecurityError); + socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler); + #end + socket.connect(host, port); + socket.setFastSend(true); + } + + /* + + public function addEventListener( type : String, listener : Dynamic ->Void, ?useCapture : Bool, + ?priority : Int, ?useWeakReference : Bool):Void + { + this.eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference); + } + + public function socketConnected(event : Event) : Void + { + this.output = this.socket; + this.input = this.socket; + this.eventDispatcher.dispatchEvent(event); + } + + public function socketError(event : IOErrorEvent) : Void + { + trace("Error Connecting:" + event); + this.close(); + if (ioCallback == null) + { + return; + } + ioCallback(new TTransportError(TTransportError.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 + { + if (ioCallback != null) + { + ioCallback(null); + } + this.eventDispatcher.dispatchEvent(event); + } + + */ + + public override function flush(callback : Error->Void = null) : Void + { + var bytes = obuffer.getBytes(); + obuffer = new BytesOutput(); + + ioCallback = callback; + output.writeBytes( bytes, 0, bytes.length); + } + + public override function isOpen() : Bool + { + #if (flash || openfl) + return (socket != null) && socket.connected; + #else + return (socket != null); + #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 00000000000..80407c03180 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/transport/TTransport.hx @@ -0,0 +1,129 @@ +/* + * 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 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 number of bytes actually read + * @throws TTransportException if there was an error reading data + */ + public function read(buf:Bytes, 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:Bytes, 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 TTransportError(TTransportError.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:Error->Void =null) : Void { + throw new AbstractMethodError(); + } + +} \ No newline at end of file diff --git a/lib/haxe/src/org/apache/thrift/transport/TTransportError.hx b/lib/haxe/src/org/apache/thrift/transport/TTransportError.hx new file mode 100644 index 00000000000..64a16fd4539 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/transport/TTransportError.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.TError; + +class TTransportError extends TError { + + 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); + } + +} \ No newline at end of file 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 00000000000..498ac3d6047 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/transport/TTransportFactory.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.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 { + + /** + * 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/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx new file mode 100644 index 00000000000..d3fe2f9be53 --- /dev/null +++ b/tutorial/haxe/src/Main.hx @@ -0,0 +1,251 @@ +/* + * 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.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 = 80; + + static function main() { + try { + ParseArgs(); + } catch (e : String) { + println(e); + println(GetHelp()); + return; + } + + + try { + if (server) + RunServer(); + else + RunClient(); + } catch (e : String) { + println(e); + } + + println("Completed."); + } + + + private static function println(txt : String) { + Sys.println(txt); + } + + + 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) + { + println("WN: framed supersedes buffered"); + } + + } + } + + + private static function ClientSetup() : Calculator { + + // endpoint transport + var transport : TTransport; + switch(trns) + { + case socket: + transport = new TSocket( targetHost, targetPort); + case http: + transport = new THttpClient( targetHost); + default: + throw "Unhandled transport"; + } + + + // optinal layered transport + if ( framed) { + transport = new TFramedTransport(transport); + } else if ( buffered) { + throw "TBufferedTransport not implemented yet"; + //transport = new TBufferedTransport(transport); + } + + + // protocol + var protocol : TProtocol; + switch(prot) + { + case binary: + protocol = new TBinaryProtocol( transport); + /* + case json: + protocol = new TJsonProtocol( transport); + */ + default: + throw "Unhandled protocol"; + } + + + // put everything together + return new CalculatorImpl(protocol,protocol); + } + + + private static function RunClient() : Void { + var client = ClientSetup(); + + client.ping(); + println("ping()"); + + client.add( 1, 1, + null, + function( sum : haxe.Int32) : Void { + println('1+1= $sum'); + }); + + + var work = new tutorial.Work(); + work.op = tutorial.Operation.DIVIDE; + work.num1 = 1; + work.num2 = 0; + try { + client.calculate( 1, work, + function(error : Error) : Void { + println("Error: "+error.message); + }, + function(quotient : haxe.Int32) : Void { + println('Whoa we can divide by 0! Result = $quotient'); + }); + + } + catch(e : Error) { + println("TODO: exception"); + /* + switch v := err.(type) { + case *tutorial.InvalidOperation:; + println("Invalid operation:", v); + default:; + println("Error during operation:", err); + } + */ + } + + work.op = tutorial.Operation.SUBTRACT; + work.num1 = 15; + work.num2 = 10; + client.calculate( 1, work, + null, + function( diff : haxe.Int32) : Void { + println('15-10=$diff\n'); + }); + + + client.getStruct( 1, + null, + function( log : SharedStruct) : Void { + println('Check log: $(log.Value)'); + }); + } + + + private static function RunServer() : Void { + throw "Not implemented"; + } + +} diff --git a/tutorial/shared.thrift b/tutorial/shared.thrift index db4b69443be..60e8e7adbd2 100644 --- a/tutorial/shared.thrift +++ b/tutorial/shared.thrift @@ -27,6 +27,7 @@ namespace d share // "shared" would collide with the eponymous D keyword. 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 3150151dece..c8710d418ca 100644 --- a/tutorial/tutorial.thrift +++ b/tutorial/tutorial.thrift @@ -67,6 +67,7 @@ namespace d tutorial 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 From cff089794170cb60b4aa532cdbdc85820e94f538 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Thu, 31 Jul 2014 23:17:36 +0200 Subject: [PATCH 02/24] multiple fixes - endianess (network byte order) - property getter/setter - socket transport - class Set --- compiler/cpp/src/generate/t_haxe_generator.cc | 28 +-- lib/haxe/src/org/apache/thrift/Error.hx | 6 +- lib/haxe/src/org/apache/thrift/TError.hx | 2 +- .../src/org/apache/thrift/helper/IntSet.hx | 94 +++++++++ .../thrift/{Set.hx => helper/ObjectSet.hx} | 51 +++-- .../src/org/apache/thrift/helper/StringSet.hx | 94 +++++++++ .../apache/thrift/protocol/TBinaryProtocol.hx | 66 +++---- .../thrift/transport/TFramedTransport.hx | 29 +-- .../apache/thrift/transport/THttpClient.hx | 8 +- .../org/apache/thrift/transport/TSocket.hx | 181 ++++++------------ .../org/apache/thrift/transport/TTransport.hx | 7 +- .../thrift/transport/TTransportError.hx | 2 +- tutorial/haxe/src/Main.hx | 57 ++++-- 13 files changed, 398 insertions(+), 227 deletions(-) create mode 100644 lib/haxe/src/org/apache/thrift/helper/IntSet.hx rename lib/haxe/src/org/apache/thrift/{Set.hx => helper/ObjectSet.hx} (68%) create mode 100644 lib/haxe/src/org/apache/thrift/helper/StringSet.hx diff --git a/compiler/cpp/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc index 5b9403ec12e..d858f52ec26 100644 --- a/compiler/cpp/src/generate/t_haxe_generator.cc +++ b/compiler/cpp/src/generate/t_haxe_generator.cc @@ -262,7 +262,7 @@ string t_haxe_generator::haxe_package() { string t_haxe_generator::haxe_type_imports() { return string() + - "import org.apache.thrift.Set;\n" + + "import org.apache.thrift.helper.*;\n" + "import haxe.io.Bytes;\n" + //flash only: "import flash.utils.ByteArray;\n" + //flash only: "import flash.utils.Dictionary;\n" + @@ -374,7 +374,7 @@ void t_haxe_generator::generate_enum(t_enum* tenum) { // Add haxe imports f_enum << string() + - "import org.apache.thrift.Set;" << endl << + "import org.apache.thrift.helper.*;" << endl << //flash only: "import flash.utils.Dictionary;" << endl << endl; @@ -394,7 +394,7 @@ void t_haxe_generator::generate_enum(t_enum* tenum) { // Create a static Set with all valid values for this enum f_enum << endl; - indent(f_enum) << "public static var VALID_VALUES = { new Set( ["; + 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) { @@ -405,7 +405,7 @@ void t_haxe_generator::generate_enum(t_enum* tenum) { indent_down(); f_enum << "]); };" << endl; - indent(f_enum) << "public static var VALUES_TO_NAMES = { [" << 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) { @@ -413,9 +413,9 @@ void t_haxe_generator::generate_enum(t_enum* tenum) { indent(f_enum) << (*c_iter)->get_name() << " => \"" << (*c_iter)->get_name() << "\""; firstValue = false; } - f_enum << endl << - "]; };" << endl; + f_enum << endl; indent_down(); + indent(f_enum) << "]; };" << endl; scope_down(f_enum); // end class @@ -438,7 +438,6 @@ void t_haxe_generator::generate_consts(std::vector consts) { f_consts << autogen_comment() << haxe_package() << ";" << endl; - scope_up(f_consts); f_consts << endl; f_consts << haxe_type_imports(); @@ -460,7 +459,6 @@ void t_haxe_generator::generate_consts(std::vector consts) { indent_down(); indent(f_consts) << "}" << endl; - scope_down(f_consts); f_consts.close(); } @@ -730,7 +728,7 @@ void t_haxe_generator::generate_haxe_struct_definition(ofstream &out, 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) << "public var " << (*m_iter)->get_name() + "(default,default) : " + type_name((*m_iter)->get_type()) << ";" << endl; + indent(out) << "public var " << (*m_iter)->get_name() + "(get,set) : " + type_name((*m_iter)->get_type()) << ";" << endl; indent(out) << "inline static var " << upcase_string((*m_iter)->get_name()) << " : Int = " << (*m_iter)->get_key() << ";" << endl; } @@ -1188,12 +1186,16 @@ void t_haxe_generator::generate_haxe_bean_boilerplate(ofstream& out, // Simple setter generate_haxe_doc(out, field); std::string propName = tmp("thriftPropertyChange"); - indent(out) << "public function set_" << field_name << "(" << field_name - << ":" << type_name(type) << ") : Void {" << endl; + 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; + 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; diff --git a/lib/haxe/src/org/apache/thrift/Error.hx b/lib/haxe/src/org/apache/thrift/Error.hx index 08189f9f904..9925c447232 100644 --- a/lib/haxe/src/org/apache/thrift/Error.hx +++ b/lib/haxe/src/org/apache/thrift/Error.hx @@ -26,9 +26,9 @@ class Error { private var _id : Int; private var _msg : String; - public var errorID(default,never) : Int; - public var message(default,never) : String; - private var name(default,never) : String; // NOT IMPLEMENTED + public var errorID(get,never) : Int; + public var message(get,never) : String; + private var name(default,null) : String; // NOT IMPLEMENTED function new(message : String = "", id : Int = 0) { diff --git a/lib/haxe/src/org/apache/thrift/TError.hx b/lib/haxe/src/org/apache/thrift/TError.hx index b154038ce1f..e452415d74a 100644 --- a/lib/haxe/src/org/apache/thrift/TError.hx +++ b/lib/haxe/src/org/apache/thrift/TError.hx @@ -27,4 +27,4 @@ class TError extends Error { super( msg, err); } -} \ No newline at end of file +} 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 00000000000..ed37c88e054 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/helper/IntSet.hx @@ -0,0 +1,94 @@ +/* + * 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(); + private var _size : Int = 0; + public var size(get,never) : Int; + + public function new( values : Array) { + for ( value in values) { + add(value); + } + } + + public function iterator():Iterator { + 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 { + var ret : Array = new Array(); + 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/Set.hx b/lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx similarity index 68% rename from lib/haxe/src/org/apache/thrift/Set.hx rename to lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx index b38926fcf49..1064ae96b5a 100644 --- a/lib/haxe/src/org/apache/thrift/Set.hx +++ b/lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx @@ -17,16 +17,16 @@ * under the License. */ -package org.apache.thrift; +package org.apache.thrift.helper; import Map; -class Set { +class ObjectSet { - private var _elements : haxe.ds.ObjectMap = new haxe.ds.ObjectMap(); + private var _elements = new haxe.ds.ObjectMap(); private var _size : Int = 0; - public var size(default,never) : Int = 0; + public var size(get,never) : Int; public function new( values : Array) { for ( value in values) { @@ -34,12 +34,24 @@ class Set { } } + public function iterator():Iterator { + 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,0); + _elements.set(o,_size); return true; } @@ -50,30 +62,29 @@ class Set { } public function contains(o : K) : Bool { - return _elements.exists(o); + return _elements.exists(o); } public function isEmpty() : Bool { - return _size == 0; + return _size == 0; } public function remove(o : K) : Bool { - if (contains(o)) { - _elements.remove(o); - _size--; - return true; - } - else { - return false; - } + if (contains(o)) { + _elements.remove(o); + _size--; + return true; + } else { + return false; + } } public function toArray() : Array { - var ret : Array = new Array(); - for (key in _elements.keys()) { - ret.push(key); - } - return ret; + var ret : Array = new Array(); + for (key in _elements.keys()) { + ret.push(key); + } + return ret; } public function get_size() : Int { 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 00000000000..b2b31b9ec07 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/helper/StringSet.hx @@ -0,0 +1,94 @@ +/* + * 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(); + private var _size : Int = 0; + public var size(get,never) : Int; + + public function new( values : Array) { + for ( value in values) { + add(value); + } + } + + public function iterator():Iterator { + 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 { + var ret : Array = new Array(); + 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/protocol/TBinaryProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx index ce9ab996a94..9b62cc6e7d7 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx @@ -115,28 +115,28 @@ class TBinaryProtocol implements TProtocol { public function writeByte(b : Int) : Void { var out = new BytesOutput(); - out.bigEndian = false; + out.bigEndian = true; out.writeByte(b); trans_.write(out.getBytes(), 0, 1); } public function writeI16(i16 : Int) : Void { var out = new BytesOutput(); - out.bigEndian = false; + out.bigEndian = true; out.writeInt16(i16); trans_.write(out.getBytes(), 0, 2); } public function writeI32(i32 : Int) : Void { var out = new BytesOutput(); - out.bigEndian = false; + 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 = false; + out.bigEndian = true; var oneByte = Int64.make(0,0xFF); for(i in 0 ... 7) { @@ -149,14 +149,14 @@ class TBinaryProtocol implements TProtocol { public function writeDouble(dub:Float) : Void { var out = new BytesOutput(); - out.bigEndian = false; + out.bigEndian = true; out.writeDouble(dub); trans_.write(out.getBytes(), 0, 8); } public function writeString(str : String) : Void { var out = new BytesOutput(); - out.bigEndian = false; + out.bigEndian = true; out.writeString(str); var bytes = out.getBytes(); writeI32( bytes.length); @@ -232,34 +232,34 @@ class TBinaryProtocol implements TProtocol { public function readByte() : Int { - var bytes : Bytes = (new BytesBuffer()).getBytes(); - var len = trans_.readAll(bytes, 0, 1); - var inp = new BytesInput(bytes, 0, 1); - inp.bigEndian = false; + 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 bytes : Bytes = (new BytesBuffer()).getBytes(); - var len = trans_.readAll(bytes, 0, 2); - var inp = new BytesInput(bytes, 0, 2); - inp.bigEndian = false; + 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 bytes : Bytes = (new BytesBuffer()).getBytes(); - var len = trans_.readAll(bytes, 0, 4); - var inp = new BytesInput(bytes, 0, 4); - inp.bigEndian = false; + 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 bytes : Bytes = (new BytesBuffer()).getBytes(); - var len = trans_.readAll(bytes, 0, 8); - var inp = new BytesInput(bytes, 0, 8); - inp.bigEndian = false; + var buffer = new BytesBuffer(); + var len = trans_.readAll( buffer, 0, 8); + var inp = new BytesInput( buffer.getBytes(), 0, 8); + inp.bigEndian = true; var mask = Int64.make(0xFFFFFFFF,0xFFFFFF00); var result = Int64.make(0,0); @@ -274,10 +274,10 @@ class TBinaryProtocol implements TProtocol { } public function readDouble():Float { - var bytes : Bytes = (new BytesBuffer()).getBytes(); - var len = trans_.readAll(bytes, 0, 8); - var inp = new BytesInput(bytes, 0, 8); - inp.bigEndian = false; + 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(); } @@ -287,10 +287,10 @@ class TBinaryProtocol implements TProtocol { public function readStringBody(len : Int) : String { if( len > 0) { - var bytes : Bytes = (new BytesBuffer()).getBytes(); - trans_.readAll(bytes, 0, len); - var inp = new BytesInput(bytes, 0, len); - inp.bigEndian = false; + 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 ""; @@ -299,9 +299,9 @@ class TBinaryProtocol implements TProtocol { public function readBinary() : Bytes { var len : Int = readI32(); - var bytes : Bytes = (new BytesBuffer()).getBytes(); - trans_.readAll(bytes, 0, len); - return bytes; + var buffer = new BytesBuffer(); + trans_.readAll( buffer, 0, len); + return buffer.getBytes(); } } diff --git a/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx index 1e2870dfb23..f61ec7fa928 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx @@ -72,10 +72,13 @@ class TFramedTransport extends TTransport transport_.close(); } - public override function read(buf : Bytes, off : Int, len : Int) : Int { + public override function read(buf : BytesBuffer, off : Int, len : Int) : Int { + var data = Bytes.alloc(len); + if (readBuffer_ != null) { - var got : Int = readBuffer_.readBytes(buf, off, len); + var got : Int = readBuffer_.readBytes(data, off, len); if (got > 0) { + buf.addBytes(data,0,got); return got; }; }; @@ -83,15 +86,17 @@ class TFramedTransport extends TTransport // Read another frame of data readFrame(); - return readBuffer_.readBytes(buf, off, len); + var got = readBuffer_.readBytes(data, off, len); + buf.addBytes(data,0,got); + return got; } function readFrameSize() : Int { - var bytes : Bytes = (new BytesBuffer()).getBytes(); - var len = transport_.readAll(bytes, 0, 4); - var inp = new BytesInput(bytes, 0, 4); - inp.bigEndian = false; + 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(); } @@ -106,10 +111,10 @@ class TFramedTransport extends TTransport throw new TTransportError('Frame size ($size) larger than max length ($maxLength_)!'); }; - var bytes : Bytes = (new BytesBuffer()).getBytes(); - size = transport_.readAll(bytes, 0, size); - readBuffer_ = new BytesInput(bytes, 0, size); - readBuffer_.bigEndian = false; + 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 { @@ -118,7 +123,7 @@ class TFramedTransport extends TTransport function writeFrameSize(len : Int) : Void { var out = new BytesOutput(); - out.bigEndian = false; + out.bigEndian = true; out.writeInt32(len); transport_.write(out.getBytes(), 0, 4); } diff --git a/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx index 0fc7f3f4741..e0cab2d9b22 100644 --- a/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx +++ b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx @@ -21,6 +21,7 @@ package org.apache.thrift.transport; import haxe.io.Bytes; +import haxe.io.BytesBuffer; import haxe.io.BytesOutput; import haxe.io.BytesInput; @@ -94,7 +95,7 @@ class THttpClient extends TTransport { return true; } - public override function read(buf:Bytes, off : Int, len : Int) : Int { + public override function read(buf:BytesBuffer, off : Int, len : Int) : Int { if (responseBuffer_ == null) { throw new TTransportError(TTransportError.UNKNOWN, "Response buffer is empty, no request."); } @@ -108,7 +109,10 @@ class THttpClient extends TTransport { } #else - responseBuffer_.readBytes(buf, off, len); + + var data =Bytes.alloc(len); + len = responseBuffer_.readBytes(data, off, len); + buf.addBytes(data,0,len); return len; #end diff --git a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx index cdd5d06ec5e..160beda0ae3 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx @@ -19,28 +19,14 @@ package org.apache.thrift.transport; -#if (flash || openfl) -import flash.events.EventDispatcher; -import flash.events.Event; -import flash.events.IOErrorEvent; -import flash.events.ProgressEvent; -import flash.events.SecurityErrorEvent; -import flash.errors.EOFError; -import flash.errors.IOError; -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 flash.net.Socket; -#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; import sys.net.Host; @@ -51,150 +37,109 @@ import sys.net.Host; class TSocket extends TTransport { - private var socket : Socket = null; private var host : Host; private var port : Int; - private var obuffer : BytesOutput = new BytesOutput(); - private var input : BytesInput; - private var output : BytesOutput; - private var ioCallback : TTransportError->Void = null; + private var socket : Socket = null; - #if flash - private var eventDispatcher : EventDispatcher = new EventDispatcher(); - #end + private var input : Input = null; + private var output : Output = null; + private var obuffer : BytesOutput = new BytesOutput(); + private var ioCallback : TTransportError->Void = null; + private var readCount : Int = 0; + public function new(host : String, port : Int) : Void { this.host = new Host(host); this.port = port; } public override function close() : Void { - this.input = null; - this.output = null; + input = null; + output = null; socket.close(); } public override function peek() : Bool { - #if (flash || openfl) - return socket.connected && (socket.bytesAvailable > 0); - #else - return true; // method missing - #end + if( (input == null) || (socket == null)) { + return false; + } else { + var ready = Socket.select( [socket], null, null, 0); + return (ready.read.length > 0); + } } - public override function read(buf : Bytes, off : Int, len : Int) : Int { + + public override function read( buf : BytesBuffer, off : Int, len : Int) : Int { try { - input.readBytes(buf, off, len); - return len; + 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; } - #if (flash || openfl) - catch (e : EOFError) + catch (e : Eof) { - trace(e); + trace('Eof $e'); throw new TTransportError(TTransportError.END_OF_FILE, "No more data available."); } - catch (e : IOError) - { - trace(e); - if(isOpen()) - { - throw new TTransportError(TTransportError.UNKNOWN, "IO error while reading : " + e); - } - else - { - throw new TTransportError(TTransportError.NOT_OPEN, "Socket seem not to be opened : " + e); - } - } - #end catch (e : Error) { - trace(e); + trace('Error $e'); throw new TTransportError(TTransportError.UNKNOWN, "Bad IO error : " + e); } - - return 0; } - + + public override function write(buf : Bytes, off : Int, len : Int) : Void { obuffer.writeBytes(buf, off, len); } - public override function open() : Void - { - socket = new Socket(); - #if (flash || openfl) - socket.addEventListener(Event.CONNECT, socketConnected); - socket.addEventListener(IOErrorEvent.IO_ERROR, socketError); - socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, socketSecurityError); - socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler); - #end - socket.connect(host, port); - socket.setFastSend(true); - } - - /* - - public function addEventListener( type : String, listener : Dynamic ->Void, ?useCapture : Bool, - ?priority : Int, ?useWeakReference : Bool):Void - { - this.eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference); - } - - public function socketConnected(event : Event) : Void - { - this.output = this.socket; - this.input = this.socket; - this.eventDispatcher.dispatchEvent(event); - } - - public function socketError(event : IOErrorEvent) : Void - { - trace("Error Connecting:" + event); - this.close(); - if (ioCallback == null) - { - return; - } - ioCallback(new TTransportError(TTransportError.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 - { - if (ioCallback != null) - { - ioCallback(null); - } - this.eventDispatcher.dispatchEvent(event); - } - - */ + public override function flush(callback : Error->Void = null) : Void { + if( ! isOpen()) + { + throw new TTransportError(TTransportError.NOT_OPEN, "Transport not open"); + } + var bytes = obuffer.getBytes(); obuffer = new BytesOutput(); + var len = bytes.length; + ioCallback = callback; - output.writeBytes( bytes, 0, bytes.length); + try { + readCount = 0; + output.writeBytes( bytes, 0, bytes.length); + ioCallback(null); // success call + } + catch (e : Error) { + trace(e); + ioCallback(new TTransportError(TTransportError.UNKNOWN, "Bad IO error : " + e)); + } } public override function isOpen() : Bool { - #if (flash || openfl) - return (socket != null) && socket.connected; - #else return (socket != null); - #end + } + + public override function open() : Void + { + socket = new Socket(); + socket.setBlocking(true); + socket.connect(host, port); + socket.setFastSend(true); + + output = socket.output; + input = socket.input; } } diff --git a/lib/haxe/src/org/apache/thrift/transport/TTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TTransport.hx index 80407c03180..c4994022498 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TTransport.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TTransport.hx @@ -20,6 +20,7 @@ package org.apache.thrift.transport; import haxe.io.Bytes; +import haxe.io.BytesBuffer; import org.apache.thrift.AbstractMethodError; class TTransport { @@ -64,10 +65,10 @@ class TTransport { * @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 + * @return The bytes count actually read * @throws TTransportException if there was an error reading data */ - public function read(buf:Bytes, off : Int, len : Int) : Int { + public function read( buf : BytesBuffer, off : Int, len : Int) : Int { throw new AbstractMethodError(); } @@ -80,7 +81,7 @@ class TTransport { * @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:Bytes, off : Int, len : Int) : Int { + public function readAll(buf : BytesBuffer, off : Int, len : Int) : Int { var got : Int = 0; var ret : Int = 0; while (got < len) { diff --git a/lib/haxe/src/org/apache/thrift/transport/TTransportError.hx b/lib/haxe/src/org/apache/thrift/transport/TTransportError.hx index 64a16fd4539..638449e7dd4 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TTransportError.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TTransportError.hx @@ -33,4 +33,4 @@ class TTransportError extends TError { super(message, error); } -} \ No newline at end of file +} diff --git a/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx index d3fe2f9be53..d7b753ed482 100644 --- a/tutorial/haxe/src/Main.hx +++ b/tutorial/haxe/src/Main.hx @@ -47,7 +47,7 @@ class Main { private static var trns : Trns = socket; private static var targetHost : String = "localhost"; - private static var targetPort : Int = 80; + private static var targetPort : Int = 9090; static function main() { try { @@ -144,14 +144,17 @@ class Main { private static function ClientSetup() : Calculator { + println("Client configuration:"); // endpoint transport var transport : TTransport; switch(trns) { case socket: - transport = new TSocket( targetHost, targetPort); + println("- socket transport"); + transport = new TSocket( targetHost, targetPort); case http: + println("- http transport"); transport = new THttpClient( targetHost); default: throw "Unhandled transport"; @@ -160,8 +163,10 @@ class Main { // optinal layered transport if ( framed) { + println("- framed transport"); transport = new TFramedTransport(transport); } else if ( buffered) { + println("- buffered transport"); throw "TBufferedTransport not implemented yet"; //transport = new TBufferedTransport(transport); } @@ -172,9 +177,11 @@ class Main { switch(prot) { case binary: + println("- binary protocol"); protocol = new TBinaryProtocol( transport); /* case json: + println("- json protocol"); protocol = new TJsonProtocol( transport); */ default: @@ -183,31 +190,41 @@ class Main { // put everything together + transport.open(); return new CalculatorImpl(protocol,protocol); } private static function RunClient() : Void { var client = ClientSetup(); - - client.ping(); - println("ping()"); + + client.ping( + function(error : Error) : Void { + println("ping() failed: "+error.message); + }, + function() : Void { + println("ping()"); + }); + client.add( 1, 1, - null, + function(error : Error) : Void { + println("add() failed: "+error.message); + }, function( sum : haxe.Int32) : Void { println('1+1= $sum'); }); - + var work = new tutorial.Work(); work.op = tutorial.Operation.DIVIDE; work.num1 = 1; work.num2 = 0; +trace( work.toString()); try { client.calculate( 1, work, function(error : Error) : Void { - println("Error: "+error.message); + println("calculate() failed: "+error.message); }, function(quotient : haxe.Int32) : Void { println('Whoa we can divide by 0! Result = $quotient'); @@ -215,32 +232,30 @@ class Main { } catch(e : Error) { - println("TODO: exception"); - /* - switch v := err.(type) { - case *tutorial.InvalidOperation:; - println("Invalid operation:", v); - default:; - println("Error during operation:", err); - } - */ + println("Exception "+e.message); } work.op = tutorial.Operation.SUBTRACT; work.num1 = 15; work.num2 = 10; client.calculate( 1, work, - null, + function(error : Error) : Void { + println("calculate() failed: "+error.message); + }, function( diff : haxe.Int32) : Void { println('15-10=$diff\n'); }); - + client.getStruct( 1, - null, + function(error : Error) : Void { + println("getStruct() failed: "+error.message); + }, function( log : SharedStruct) : Void { - println('Check log: $(log.Value)'); + var logval = log.value; + println('Check log: $logval'); }); + } From ba4db27c6aaac28640c002a4b3dfa5f733791efe Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Sun, 3 Aug 2014 00:55:26 +0200 Subject: [PATCH 03/24] completed server-side, refactoring --- compiler/cpp/src/generate/t_haxe_generator.cc | 233 +++++++++++------- .../apache/thrift/protocol/TBinaryProtocol.hx | 26 -- .../thrift/protocol/TBinaryProtocolFactory.hx | 45 ++++ .../src/org/apache/thrift/server/TServer.hx | 109 ++++++++ .../thrift/server/TServerEventHandler.hx | 45 ++++ .../org/apache/thrift/server/TSimpleServer.hx | 129 ++++++++++ .../thrift/transport/TFramedTransport.hx | 16 +- .../transport/TFramedTransportFactory.hx | 37 +++ .../apache/thrift/transport/TServerSocket.hx | 130 ++++++++++ .../thrift/transport/TServerTransport.hx | 47 ++++ .../org/apache/thrift/transport/TSocket.hx | 23 +- .../thrift/transport/TTransportError.hx | 2 +- .../thrift/transport/TTransportFactory.hx | 21 +- tutorial/haxe/src/CalculatorHandler.hx | 112 +++++++++ tutorial/haxe/src/Main.hx | 87 ++++++- 15 files changed, 906 insertions(+), 156 deletions(-) create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocolFactory.hx create mode 100644 lib/haxe/src/org/apache/thrift/server/TServer.hx create mode 100644 lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx create mode 100644 lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx create mode 100644 tutorial/haxe/src/CalculatorHandler.hx diff --git a/compiler/cpp/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc index d858f52ec26..1a4cb4f527e 100644 --- a/compiler/cpp/src/generate/t_haxe_generator.cc +++ b/compiler/cpp/src/generate/t_haxe_generator.cc @@ -113,6 +113,8 @@ class t_haxe_generator : public t_oop_generator { 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); + string generate_service_method_onsuccess(t_function* tfunction, bool as_type, bool omit_name); /** * Serialization constructs @@ -264,8 +266,9 @@ string t_haxe_generator::haxe_type_imports() { string() + "import org.apache.thrift.helper.*;\n" + "import haxe.io.Bytes;\n" + - //flash only: "import flash.utils.ByteArray;\n" + - //flash only: "import flash.utils.Dictionary;\n" + + "import haxe.ds.IntMap;\n" + + "import haxe.ds.StringMap;\n" + + "import haxe.ds.ObjectMap;\n" + "\n"; } @@ -277,7 +280,7 @@ string t_haxe_generator::haxe_type_imports() { string t_haxe_generator::haxe_thrift_imports() { return string() + - "import org.apache.thrift.*;\n" + + "import org.apache.thrift.*;\n" + "import org.apache.thrift.meta_data.*;\n" + "import org.apache.thrift.protocol.*;\n" + "\n"; @@ -331,8 +334,8 @@ string t_haxe_generator::haxe_thrift_gen_imports(t_service* tservice) { } } - haxe_thrift_gen_imports((*f_iter)->get_arglist(), imports); - haxe_thrift_gen_imports((*f_iter)->get_xceptions(), imports); + haxe_thrift_gen_imports((*f_iter)->get_arglist(), imports); + haxe_thrift_gen_imports((*f_iter)->get_xceptions(), imports); } @@ -375,7 +378,6 @@ void t_haxe_generator::generate_enum(t_enum* tenum) { // Add haxe imports f_enum << string() + "import org.apache.thrift.helper.*;" << endl << - //flash only: "import flash.utils.Dictionary;" << endl << endl; indent(f_enum) << @@ -446,7 +448,7 @@ void t_haxe_generator::generate_consts(std::vector consts) { indent(f_consts) << "class " << program_name_ << - "Constants {" << endl << endl; + "Constants {" << endl << endl; indent_up(); vector::iterator c_iter; for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { @@ -1312,7 +1314,7 @@ void t_haxe_generator::generate_haxe_meta_data_map(ofstream& out, vector::const_iterator f_iter; // Static Map with fieldID -> FieldMetaData mappings - indent(out) << "inline static var metaDataMap : Dictionary = new Dictionary();" << endl; + indent(out) << "inline static var metaDataMap : IntMap = new IntMap();" << endl; if (fields.size() > 0) { // Populate map @@ -1479,16 +1481,76 @@ void t_haxe_generator::generate_service(t_service* tservice) { haxe_thrift_gen_imports(tservice) << endl; if(!package_name_.empty()) { - f_service_ << "import " << package_name_ << ".*\n;" << endl; + 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); + //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 (!tfunction->is_oneway()) { + std::string on_success_impl = generate_service_method_onsuccess(tfunction, false, false); + indent(f_service_) << "// function onError(Error) : Void;" << endl; + indent(f_service_) << "// function " << on_success_impl.c_str() << ";" << endl; + } + + std::string on_error_success = "onError : Error->Void = null, " + + generate_service_method_onsuccess(tfunction, true, false); + + if( is_interface) { + indent(f_service_) << function_signature(tfunction,on_error_success) << ";" << + endl << endl; + } else { + indent(f_service_) << + "public " << function_signature(tfunction,on_error_success) << " {" << endl; + } +} + /** * Generates a service interface definition. * @@ -1508,21 +1570,7 @@ void t_haxe_generator::generate_service_interface(t_service* tservice) { vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_haxe_doc(f_service_, *f_iter); - string on_error_success; - if (!(*f_iter)->is_oneway()) { - if ((*f_iter)->get_returntype()->is_void()) { - indent(f_service_) << "//function onError(Error) : Void;" << endl; - indent(f_service_) << "//function onSuccess() : Void;" << endl; - on_error_success = "onError : Error->Void = null, onSuccess : Void->Void = null"; - } - else { - indent(f_service_) << "//function onError(Error) : Void;" << endl; - indent(f_service_) << "//function onSuccess(" << type_name((*f_iter)->get_returntype()) << ") : Void;" << endl; - on_error_success = "onError : Error->Void = null, onSuccess : "+type_name((*f_iter)->get_returntype())+"->Void = null"; - } - } - indent(f_service_) << function_signature(*f_iter,on_error_success) << ";" << - endl << endl; + generate_service_method_signature(*f_iter,true); } indent_down(); f_service_ << @@ -1546,6 +1594,7 @@ void t_haxe_generator::generate_service_helpers(t_service* tservice) { } } + /** * Generates a service client definition. * @@ -1561,9 +1610,9 @@ void t_haxe_generator::generate_service_client(t_service* tservice) { indent(f_service_) << "class " << service_name_ << - "Impl" << extends_client << - " implements " << service_name_ << - " {" << endl << endl; + "Impl" << extends_client << + " implements " << service_name_ << + " {" << endl << endl; indent_up(); indent(f_service_) << @@ -1620,22 +1669,9 @@ void t_haxe_generator::generate_service_client(t_service* tservice) { string funname = (*f_iter)->get_name(); // Open function - std::string on_error_success; - if (!(*f_iter)->is_oneway()) { - if ((*f_iter)->get_returntype()->is_void()) { - indent(f_service_) << "//function onError(Error) : Void;" << endl; - indent(f_service_) << "//function onSuccess() : Void;" << endl; - on_error_success = "onError : Error->Void = null, onSuccess : Void->Void = null"; - } - else { - indent(f_service_) << "//function onError(Error) : Void;" << endl; - indent(f_service_) << "//function onSuccess(" << type_name((*f_iter)->get_returntype()) << ") : Void;" << endl; - on_error_success = "onError : Error->Void = null, onSuccess : "+type_name((*f_iter)->get_returntype())+"->Void = null"; - } - } - indent(f_service_) << - "public " << function_signature(*f_iter,on_error_success) << endl; - scope_up(f_service_); + generate_service_method_signature(*f_iter,false); + + indent_up(); // Get the struct of function call params @@ -1675,7 +1711,7 @@ void t_haxe_generator::generate_service_client(t_service* tservice) { indent() << "}" << endl << indent() << "var msg : TMessage = iprot_.readMessageBegin();" << endl << indent() << "if (msg.type == TMessageType.EXCEPTION) {" << endl << - indent() << " var x:TApplicationError = TApplicationError.read(iprot_);" << endl << + indent() << " var x = TApplicationError.read(iprot_);" << endl << indent() << " iprot_.readMessageEnd();" << endl << indent() << " if (onError != null) onError(x);" << endl << indent() << " return;" << endl << @@ -1760,39 +1796,39 @@ void t_haxe_generator::generate_service_server(t_service* tservice) { // Generate the header portion indent(f_service_) << "class " << service_name_ << - "Processor" << extends_processor << - " implements TProcessor {" << - endl << endl; + "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 " << service_name_ << "Processor(iface:" << service_name_ << ")" << endl; + "public function new( iface : " << service_name_ << ")" << endl; scope_up(f_service_); if (!extends.empty()) { f_service_ << indent() << "super(iface);" << endl; } f_service_ << - indent() << "iface_ = iface;" << endl; + indent() << service_name_ << "_iface_ = iface;" << endl; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { f_service_ << - indent() << "PROCESS_MAP[\"" << (*f_iter)->get_name() << "\"] = " << (*f_iter)->get_name() << "();" << endl; + indent() << "PROCESS_MAP.set(\"" << (*f_iter)->get_name() << "\", " << (*f_iter)->get_name() << "());" << endl; } scope_down(f_service_); f_service_ << endl; - f_service_ << - indent() << "private var iface_:" << service_name_ << ";" << endl; - - if (extends.empty()) { - f_service_ << - indent() << "inline static var PROCESS_MAP : Dictionary = new Dictionary();" << endl; - } - - f_service_ << endl; - // Generate the server implementation string override = ""; if (tservice->get_extends() != NULL) { @@ -1809,18 +1845,18 @@ void t_haxe_generator::generate_service_server(t_service* tservice) { // do you have an oprot? // do you you need nullcheck? f_service_ << - indent() << "var fn : Function = PROCESS_MAP[msg.name];" << endl << + 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 : TApplicationError = new TApplicationError(TApplicationError.UNKNOWN_METHOD, \"Invalid method name: '\"+msg.name+\"'\");" << endl << + indent() << " var x = new TApplicationError(TApplicationError.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.call(this,msg.seqid, iprot, oprot);" << endl; + indent() << "fn( msg.seqid, iprot, oprot);" << endl; f_service_ << indent() << "return true;" << endl; @@ -1876,7 +1912,7 @@ void t_haxe_generator::generate_process_function(t_service* tservice, (void) tservice; // Open class indent(f_service_) << - "private function " << tfunction->get_name() << "() : Function {" << endl; + "private function " << tfunction->get_name() << "() : Int->TProtocol->TProtocol->Void {" << endl; indent_up(); // Open function @@ -1903,8 +1939,8 @@ void t_haxe_generator::generate_process_function(t_service* tservice, indent() << "var result : " << resultname << " = new " << resultname << "();" << endl; } - // Try block for a function with exceptions - if (xceptions.size() > 0) { + // Try block for any non-oneway function to catch (defined or undefined) exceptions + if (!tfunction->is_oneway()) { f_service_ << indent() << "try {" << endl; indent_up(); @@ -1916,33 +1952,47 @@ void t_haxe_generator::generate_process_function(t_service* tservice, vector::const_iterator f_iter; f_service_ << indent(); - if (tfunction->is_oneway()){ - f_service_ << - "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_ << + 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 { - f_service_ << "// sorry this operation is not supported yet" << endl; - f_service_ << indent() << "throw new Error(\"This is not yet supported\");" << endl; - } - - // Set isset on success field - if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void() && !type_can_be_null(tfunction->get_returntype())) { - f_service_ << - indent() << "result.set" << get_cap_name("success") << get_cap_name("isSet") << "(true);" << endl; + 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(); } - if (!tfunction->is_oneway() && xceptions.size() > 0) { + if (!tfunction->is_oneway()) { indent_down(); f_service_ << indent() << "}"; + // 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()) { @@ -1955,11 +2005,12 @@ void t_haxe_generator::generate_process_function(t_service* tservice, f_service_ << "}"; } } - f_service_ << " catch (th:Error) {" << endl; + // always catch all exceptions + f_service_ << " catch (th : Dynamic) {" << endl; indent_up(); f_service_ << indent() << "trace(\"Internal error processing " << tfunction->get_name() << "\", th);" << endl << - indent() << "var x : TApplicationError = new TApplicationError(TApplicationError.INTERNAL_ERROR, \"Internal error processing " << tfunction->get_name() << "\");" << endl << + indent() << "var x = new TApplicationError(TApplicationError.INTERNAL_ERROR, \"Internal error processing " << tfunction->get_name() << "\");" << endl << indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl << indent() << "x.write(oprot);" << endl << indent() << "oprot.writeMessageEnd();" << endl << @@ -2537,7 +2588,7 @@ string t_haxe_generator::declare_field(t_field* tfield, bool init) { */ string t_haxe_generator::function_signature(t_function* tfunction, string on_error_success, - string prefix) { + string prefix) { std::string arguments = argument_list(tfunction->get_arglist()); if (! tfunction->is_oneway()) { if (arguments != "") { diff --git a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx index 9b62cc6e7d7..b30ee02afbd 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx @@ -26,7 +26,6 @@ import haxe.io.BytesBuffer; import haxe.Int64; import org.apache.thrift.TError; -import org.apache.thrift.transport.THttpClient; import org.apache.thrift.transport.TTransport; /** @@ -306,28 +305,3 @@ class TBinaryProtocol implements TProtocol { } -/** -* Factory -*/ -/* -public static class Factory implements TProtocolFactory { - protected boolean strictRead_ = false; - protected boolean strictWrite_ = true; - - public Factory() { - this(false, true); - } - - public Factory(boolean strictRead, boolean strictWrite) { - strictRead_ = strictRead; - strictWrite_ = strictWrite; - } - - public TProtocol getProtocol(TTransport trans) { - return new TBinaryProtocol(trans, strictRead_, strictWrite_); - } -} -*/ - - - \ No newline at end of file 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 00000000000..0d7c7c57efd --- /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/server/TServer.hx b/lib/haxe/src/org/apache/thrift/server/TServer.hx new file mode 100644 index 00000000000..03b62e4cd6c --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/server/TServer.hx @@ -0,0 +1,109 @@ +/** + * 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. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +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 00000000000..1b9479e35b8 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.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. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +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 00000000000..1e9216cc06e --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx @@ -0,0 +1,129 @@ +/** + * 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. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +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 : TTransportError) + { + 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 : TTransportError) + { + // Usually a client disconnect, expected + } + catch( e : Error) + { + // 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 index f61ec7fa928..68a5c09da1d 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx @@ -105,10 +105,10 @@ class TFramedTransport extends TTransport var size : Int = readFrameSize(); if (size < 0) { - throw new TTransportError('Read a negative frame size ($size)!'); + throw new TTransportError(TTransportError.UNKNOWN, 'Read a negative frame size ($size)!'); }; if (size > maxLength_) { - throw new TTransportError('Frame size ($size) larger than max length ($maxLength_)!'); + throw new TTransportError(TTransportError.UNKNOWN, 'Frame size ($size) larger than max length ($maxLength_)!'); }; var buffer = new BytesBuffer(); @@ -140,15 +140,3 @@ class TFramedTransport extends TTransport } -class TFramedTransportFactory extends TTransportFactory { - - var maxLength_ : Int; - - public function new(maxLength : Int = TFramedTransport.DEFAULT_MAX_LENGTH) { - maxLength_ = maxLength; - } - - public override function getTransport(base : TTransport) : TTransport { - return new TFramedTransport(base, maxLength_); - } -} 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 00000000000..00127bf0498 --- /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/TServerSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx new file mode 100644 index 00000000000..fe78810a595 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx @@ -0,0 +1,130 @@ +/** + * 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. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +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 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 : Error) + { + _socket = null; + throw new TTransportError( TTransportError.UNKNOWN, 'Could not create ServerSocket on port $port.'); + } + } + + + public override function Listen() : Void + { + // Make sure not to block on accept + if (_socket != null) { + try + { + _socket.listen(1); + } + catch (e : Error) + { + trace('Error $e'); + throw new TTransportError( TTransportError.UNKNOWN, 'Could not accept on listening socket: $e'); + } + } + } + + private override function AcceptImpl() : TTransport + { + if (_socket == null) { + throw new TTransportError( TTransportError.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 : Error) + { + trace('Error $e'); + throw new TTransportError( TTransportError.UNKNOWN, '$e'); + } + } + + public override function Close() : Void + { + if (_socket != null) + { + try + { + _socket.close(); + } + catch (e : Error) + { + trace('Error $e'); + throw new TTransportError( TTransportError.UNKNOWN, 'WARNING: Could not close server socket: $e'); + } + _socket = null; + } + } +} 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 00000000000..bd1b5dc8985 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx @@ -0,0 +1,47 @@ +/** + * 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. + * + * Contains some contributions under the Thrift Software License. + * Please see doc/old-thrift-license.txt in the Thrift distribution for + * details. + */ + +package org.apache.thrift.transport; + +class TServerTransport { + + public function Accept() : TTransport { + var transport = AcceptImpl(); + if (transport == null) { + throw new TTransportError( TTransportError.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 index 160beda0ae3..7cc4f1092b5 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx @@ -53,6 +53,13 @@ class TSocket extends TTransport { this.port = port; } + // used by TSocketServer + public static function fromSocket( socket : Socket) : TSocket { + var result = new TSocket("",0); + result.assignSocket(socket); + return result; + } + public override function close() : Void { input = null; output = null; @@ -118,11 +125,15 @@ class TSocket extends TTransport { try { readCount = 0; output.writeBytes( bytes, 0, bytes.length); - ioCallback(null); // success call + if(ioCallback != null) { + ioCallback(null); // success call + } } catch (e : Error) { trace(e); - ioCallback(new TTransportError(TTransportError.UNKNOWN, "Bad IO error : " + e)); + if(ioCallback != null) { + ioCallback(new TTransportError(TTransportError.UNKNOWN, "Bad IO error : " + e)); + } } } @@ -142,4 +153,12 @@ class TSocket extends TTransport { input = socket.input; } + private function assignSocket( socket : Socket) : Void + { + this.socket = socket; + + output = socket.output; + input = socket.input; + } + } diff --git a/lib/haxe/src/org/apache/thrift/transport/TTransportError.hx b/lib/haxe/src/org/apache/thrift/transport/TTransportError.hx index 638449e7dd4..c4e49548557 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TTransportError.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TTransportError.hx @@ -30,7 +30,7 @@ class TTransportError extends TError { public static inline var END_OF_FILE : Int = 4; public function new(error : Int = UNKNOWN, message : String = "") { - super(message, error); + 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 index 498ac3d6047..f20321f47d9 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TTransportFactory.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TTransportFactory.hx @@ -28,14 +28,17 @@ package org.apache.thrift.transport; */ class TTransportFactory { - /** - * Return a wrapped instance of the base Transport. - * - * @param trans The base transport - * @return Wrapped Transport - */ - public function getTransport( trans : TTransport) : TTransport { - return trans; - } + 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/tutorial/haxe/src/CalculatorHandler.hx b/tutorial/haxe/src/CalculatorHandler.hx new file mode 100644 index 00000000000..3a493ed20a7 --- /dev/null +++ b/tutorial/haxe/src/CalculatorHandler.hx @@ -0,0 +1,112 @@ +/* + * 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(); + + public function new() { + } + + // function onError(Error) : Void; + // function onSuccess() : Void; + public function ping(onError : Error->Void = null, onSuccess : Void->Void = null) : Void { + trace("ping()"); + } + + + // function onError(Error) : Void; + // function onSuccess(haxe.Int32) : Void; + public function add( num1 : haxe.Int32, num2 : haxe.Int32, + onError : Error->Void = null, onSuccess : haxe.Int32->Void = null) : Void { + trace('add( $num1, $num2)'); + onSuccess( num1 + num2); + } + + // function onError(Error) : Void; + // function onSuccess(haxe.Int32) : Void; + public function calculate( logid : haxe.Int32, work : Work, + onError : Error->Void = null, onSuccess : haxe.Int32->Void = null) : Void { + 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); + + onSuccess( val); + } + + // function onError(Error) : Void; + // function onSuccess( retval : SharedStruct); + public function getStruct( key : haxe.Int32, + onError : Error->Void = null, onSuccess : SharedStruct->Void = null) : Void { + trace('getStruct($key)'); + onSuccess( 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 index d7b753ed482..5a555831383 100644 --- a/tutorial/haxe/src/Main.hx +++ b/tutorial/haxe/src/Main.hx @@ -22,6 +22,7 @@ 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.*; @@ -151,10 +152,10 @@ class Main { switch(trns) { case socket: - println("- socket transport"); + println('- socket transport $targetHost:$targetPort'); transport = new TSocket( targetHost, targetPort); case http: - println("- http transport"); + println("- http transport $targetHost"); transport = new THttpClient( targetHost); default: throw "Unhandled transport"; @@ -179,11 +180,10 @@ class Main { case binary: println("- binary protocol"); protocol = new TBinaryProtocol( transport); - /* case json: - println("- json protocol"); - protocol = new TJsonProtocol( transport); - */ + throw "JSON protocol not implemented yet"; + //println("- json protocol"); + //protocol = new TJsonProtocol( transport); default: throw "Unhandled protocol"; } @@ -200,7 +200,7 @@ class Main { client.ping( function(error : Error) : Void { - println("ping() failed: "+error.message); + println('ping() failed: $error'); }, function() : Void { println("ping()"); @@ -209,7 +209,7 @@ class Main { client.add( 1, 1, function(error : Error) : Void { - println("add() failed: "+error.message); + println('add() failed: $error'); }, function( sum : haxe.Int32) : Void { println('1+1= $sum'); @@ -220,11 +220,10 @@ class Main { work.op = tutorial.Operation.DIVIDE; work.num1 = 1; work.num2 = 0; -trace( work.toString()); try { client.calculate( 1, work, function(error : Error) : Void { - println("calculate() failed: "+error.message); + println('calculate() failed: $error'); }, function(quotient : haxe.Int32) : Void { println('Whoa we can divide by 0! Result = $quotient'); @@ -240,7 +239,7 @@ trace( work.toString()); work.num2 = 10; client.calculate( 1, work, function(error : Error) : Void { - println("calculate() failed: "+error.message); + println('calculate() failed: $error'); }, function( diff : haxe.Int32) : Void { println('15-10=$diff\n'); @@ -249,7 +248,7 @@ trace( work.toString()); client.getStruct( 1, function(error : Error) : Void { - println("getStruct() failed: "+error.message); + println('getStruct() failed: $error'); }, function( log : SharedStruct) : Void { var logval = log.value; @@ -259,8 +258,70 @@ trace( work.toString()); } + private static function ServerSetup() : TServer { + println("Server configuration:"); + + // endpoint transport + var transport : TServerTransport = null; + switch(trns) + { + case socket: + println('- socket transport port $targetPort'); + transport = new TServerSocket( targetPort); + case http: + throw "HTTP server not implemented yet"; + //println("- http transport"); + //transport = new THttpClient( targetHost); + default: + throw "Unhandled transport"; + } + + // optinal layered transport + var transfactory : TTransportFactory = null; + if ( framed) { + println("- framed transport"); + transfactory = new TFramedTransportFactory(); + } else if ( buffered) { + println("- buffered transport"); + throw "TBufferedTransport not implemented yet"; + //transfactory = new TBufferedTransportFactory(); + } + + // protocol + var protfactory : TProtocolFactory = null; + switch(prot) + { + case binary: + println("- binary protocol"); + protfactory = new TBinaryProtocolFactory(); + case json: + throw "JSON protocol not implemented yet"; + //println("- 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 { - throw "Not implemented"; + try + { + var server = ServerSetup(); + + println("\nStarting the server..."); + server.Serve(); + } + catch( e : Error) + { + println('RunServer() failed: $e'); + } + println("done."); } } From ad80a8137b95913a6972d5e6f07747e2bc820f52 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Sun, 3 Aug 2014 01:48:13 +0200 Subject: [PATCH 04/24] added HIDE project files --- tutorial/haxe/cpp.hxml | 39 ++++++++++++ tutorial/haxe/csharp.hxml | 36 +++++++++++ tutorial/haxe/flash.hxml | 36 +++++++++++ tutorial/haxe/java.hxml | 36 +++++++++++ tutorial/haxe/javascript.hxml | 42 +++++++++++++ tutorial/haxe/neko.hxml | 36 +++++++++++ tutorial/haxe/php.hxml | 36 +++++++++++ tutorial/haxe/project.hide | 112 ++++++++++++++++++++++++++++++++++ tutorial/haxe/python.hxml | 36 +++++++++++ 9 files changed, 409 insertions(+) create mode 100644 tutorial/haxe/cpp.hxml create mode 100644 tutorial/haxe/csharp.hxml create mode 100644 tutorial/haxe/flash.hxml create mode 100644 tutorial/haxe/java.hxml create mode 100644 tutorial/haxe/javascript.hxml create mode 100644 tutorial/haxe/neko.hxml create mode 100644 tutorial/haxe/php.hxml create mode 100644 tutorial/haxe/project.hide create mode 100644 tutorial/haxe/python.hxml diff --git a/tutorial/haxe/cpp.hxml b/tutorial/haxe/cpp.hxml new file mode 100644 index 00000000000..c86320bab29 --- /dev/null +++ b/tutorial/haxe/cpp.hxml @@ -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. +# + +#integrate files to classpath +-cp 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 00000000000..4ddf4dd15c7 --- /dev/null +++ b/tutorial/haxe/csharp.hxml @@ -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. +# + +#integrate files to classpath +-cp 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 00000000000..2cbb500c34d --- /dev/null +++ b/tutorial/haxe/flash.hxml @@ -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. +# + +#integrate files to classpath +-cp src + +#this class wil be used as entry point for your app. +-main Main + +#Flash target +-swf bin/Tutorial.swf + +#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/java.hxml b/tutorial/haxe/java.hxml new file mode 100644 index 00000000000..72824a2dbac --- /dev/null +++ b/tutorial/haxe/java.hxml @@ -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. +# + +#integrate files to classpath +-cp 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 00000000000..d982051bd1c --- /dev/null +++ b/tutorial/haxe/javascript.hxml @@ -0,0 +1,42 @@ +# +# 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 + +#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/neko.hxml b/tutorial/haxe/neko.hxml new file mode 100644 index 00000000000..1f20ac704d5 --- /dev/null +++ b/tutorial/haxe/neko.hxml @@ -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. +# + +#integrate files to classpath +-cp 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 00000000000..23ad7bf7a7b --- /dev/null +++ b/tutorial/haxe/php.hxml @@ -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. +# + +#integrate files to classpath +-cp 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 00000000000..e515603f53a --- /dev/null +++ b/tutorial/haxe/project.hide @@ -0,0 +1,112 @@ +{ + "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" + } + ,{ + "pathToHxml" : "python.hxml" + ,"runActionType" : 2 + ,"runActionText" : "python bin/Tutorial.py" + } + ] + ,"files" : [ + { + "path" : "src\\Main.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 316 + } + ,{ + "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\\CalculatorHandler.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 65 + } + ,{ + "path" : "src\\tutorial\\CalculatorProcessor.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 79 + } + ] + ,"activeFile" : "src\\CalculatorHandler.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 00000000000..0bef80805bc --- /dev/null +++ b/tutorial/haxe/python.hxml @@ -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. +# + +#integrate files to classpath +-cp 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 From 3b402afee85438b0c55a192d328f3cbe0220c49c Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Tue, 5 Aug 2014 22:18:51 +0200 Subject: [PATCH 05/24] Build enhancements - added README file - added some rudimentary shell/batch script files, - revised *.hxml project files --- .gitignore | 1 + lib/haxe/README.md | 76 +++++++++++++++++++++++++++++++++++ tutorial/haxe/cpp.hxml | 2 + tutorial/haxe/csharp.hxml | 2 + tutorial/haxe/flash.hxml | 2 + tutorial/haxe/java.hxml | 2 + tutorial/haxe/javascript.hxml | 2 + tutorial/haxe/make_all.bat | 41 +++++++++++++++++++ tutorial/haxe/make_all.sh | 41 +++++++++++++++++++ tutorial/haxe/neko.hxml | 2 + tutorial/haxe/php.hxml | 2 + tutorial/haxe/project.hide | 11 ++++- tutorial/haxe/python.hxml | 2 + 13 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 lib/haxe/README.md create mode 100644 tutorial/haxe/make_all.bat create mode 100644 tutorial/haxe/make_all.sh diff --git a/.gitignore b/.gitignore index a2501657d21..d118290d07f 100644 --- a/.gitignore +++ b/.gitignore @@ -242,3 +242,4 @@ test-driver /tutorial/js/build/ /ylwrap +/tutorial/haxe/bin diff --git a/lib/haxe/README.md b/lib/haxe/README.md new file mode 100644 index 00000000000..2fa76f648c9 --- /dev/null +++ b/lib/haxe/README.md @@ -0,0 +1,76 @@ +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. + + +Work in progress +======================== + +WHAT WORKS: +- tutorial works with sockets, both client and server +- tested with Haxe C++ target +- designed to work with all other Haxe and OpenFL targets (not tested!) + +TODO: +- build scripts and makefiles for tutorial and test +- cross-test client and server (currently working on this part) +- JSON protocol, update tutorial and test accordingly +- HTTP transport, update tutorial and test accordingly +- Tests of all components against as much as possible Haxe and/or OpenFL targets +- Try to minimze or eliminate known restrictions (see below) + + +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 hxcs + haxelib install hxjava + haxelib install hxcpp + +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 Sys.args + diff --git a/tutorial/haxe/cpp.hxml b/tutorial/haxe/cpp.hxml index c86320bab29..6adb52d7e33 100644 --- a/tutorial/haxe/cpp.hxml +++ b/tutorial/haxe/cpp.hxml @@ -19,6 +19,8 @@ #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 diff --git a/tutorial/haxe/csharp.hxml b/tutorial/haxe/csharp.hxml index 4ddf4dd15c7..295c017e739 100644 --- a/tutorial/haxe/csharp.hxml +++ b/tutorial/haxe/csharp.hxml @@ -19,6 +19,8 @@ #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 diff --git a/tutorial/haxe/flash.hxml b/tutorial/haxe/flash.hxml index 2cbb500c34d..ee0f43d3ed9 100644 --- a/tutorial/haxe/flash.hxml +++ b/tutorial/haxe/flash.hxml @@ -19,6 +19,8 @@ #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 diff --git a/tutorial/haxe/java.hxml b/tutorial/haxe/java.hxml index 72824a2dbac..c615565a9a6 100644 --- a/tutorial/haxe/java.hxml +++ b/tutorial/haxe/java.hxml @@ -19,6 +19,8 @@ #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 diff --git a/tutorial/haxe/javascript.hxml b/tutorial/haxe/javascript.hxml index d982051bd1c..b2b3876cf15 100644 --- a/tutorial/haxe/javascript.hxml +++ b/tutorial/haxe/javascript.hxml @@ -19,6 +19,8 @@ #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 diff --git a/tutorial/haxe/make_all.bat b/tutorial/haxe/make_all.bat new file mode 100644 index 00000000000..89cd4ef9a7a --- /dev/null +++ b/tutorial/haxe/make_all.bat @@ -0,0 +1,41 @@ +@echo off +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 + +rem # invoke Haxe compiler for all targets +for %%a in (*.hxml) do ( + 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 + +:eof diff --git a/tutorial/haxe/make_all.sh b/tutorial/haxe/make_all.sh new file mode 100644 index 00000000000..2ee650dce26 --- /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 index 1f20ac704d5..6161f69773c 100644 --- a/tutorial/haxe/neko.hxml +++ b/tutorial/haxe/neko.hxml @@ -19,6 +19,8 @@ #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 diff --git a/tutorial/haxe/php.hxml b/tutorial/haxe/php.hxml index 23ad7bf7a7b..1eaac8b2b94 100644 --- a/tutorial/haxe/php.hxml +++ b/tutorial/haxe/php.hxml @@ -19,6 +19,8 @@ #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 diff --git a/tutorial/haxe/project.hide b/tutorial/haxe/project.hide index e515603f53a..bf7db8d5f79 100644 --- a/tutorial/haxe/project.hide +++ b/tutorial/haxe/project.hide @@ -87,7 +87,7 @@ ,"foldedRegions" : [ ] - ,"activeLine" : 65 + ,"activeLine" : 76 } ,{ "path" : "src\\tutorial\\CalculatorProcessor.hx" @@ -98,6 +98,15 @@ ] ,"activeLine" : 79 } + ,{ + "path" : "cpp.hxml" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 5 + } ] ,"activeFile" : "src\\CalculatorHandler.hx" ,"openFLTarget" : null diff --git a/tutorial/haxe/python.hxml b/tutorial/haxe/python.hxml index 0bef80805bc..f2c19fa93e1 100644 --- a/tutorial/haxe/python.hxml +++ b/tutorial/haxe/python.hxml @@ -19,6 +19,8 @@ #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 From 6b6ca94f666e76a3e3836171cd9bff6ca15af079 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Wed, 6 Aug 2014 00:24:54 +0200 Subject: [PATCH 06/24] improved error handling --- lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx | 2 +- .../apache/thrift/transport/TFullDuplexHttpClient.hx | 5 ++--- .../src/org/apache/thrift/transport/TServerSocket.hx | 10 +++++----- lib/haxe/src/org/apache/thrift/transport/TSocket.hx | 4 ++-- tutorial/haxe/src/Main.hx | 6 +++--- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx b/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx index 1e9216cc06e..5e2b1f17197 100644 --- a/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx +++ b/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx @@ -108,7 +108,7 @@ class TSimpleServer extends TServer { { // Usually a client disconnect, expected } - catch( e : Error) + catch( e : Dynamic) { // Unexpected logDelegate(e); diff --git a/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx index 944e9a55fad..160d973ef51 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx @@ -137,11 +137,10 @@ import flash.events.EventDispatcher; trace(e); throw new TTransportError(TTransportError.UNKNOWN, "No more data available."); } - catch (e : Error) + catch (e : Dynamic) { trace(e); - // WTF?? - throw new TTransportError(TTransportError.UNKNOWN, "Bad IO error:" + e); + throw new TTransportError(TTransportError.UNKNOWN, 'Bad IO error: $e'); } return 0; } diff --git a/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx index fe78810a595..7dec79d1e5c 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx @@ -60,10 +60,10 @@ class TServerSocket extends TServerTransport { _socket = new Socket(); _socket.bind( new Host('localhost'), port); } - catch (e : Error) + catch (e : Dynamic) { _socket = null; - throw new TTransportError( TTransportError.UNKNOWN, 'Could not create ServerSocket on port $port.'); + throw new TTransportError( TTransportError.UNKNOWN, 'Could not create ServerSocket on port $port: $e'); } } @@ -76,7 +76,7 @@ class TServerSocket extends TServerTransport { { _socket.listen(1); } - catch (e : Error) + catch (e : Dynamic) { trace('Error $e'); throw new TTransportError( TTransportError.UNKNOWN, 'Could not accept on listening socket: $e'); @@ -104,7 +104,7 @@ class TServerSocket extends TServerTransport { return result; } - catch (e : Error) + catch (e : Dynamic) { trace('Error $e'); throw new TTransportError( TTransportError.UNKNOWN, '$e'); @@ -119,7 +119,7 @@ class TServerSocket extends TServerTransport { { _socket.close(); } - catch (e : Error) + catch (e : Dynamic) { trace('Error $e'); throw new TTransportError( TTransportError.UNKNOWN, 'WARNING: Could not close server socket: $e'); diff --git a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx index 7cc4f1092b5..c4607a192c4 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx @@ -94,7 +94,7 @@ class TSocket extends TTransport { trace('Eof $e'); throw new TTransportError(TTransportError.END_OF_FILE, "No more data available."); } - catch (e : Error) + catch (e : Dynamic) { trace('Error $e'); throw new TTransportError(TTransportError.UNKNOWN, "Bad IO error : " + e); @@ -129,7 +129,7 @@ class TSocket extends TTransport { ioCallback(null); // success call } } - catch (e : Error) { + catch (e : Dynamic) { trace(e); if(ioCallback != null) { ioCallback(new TTransportError(TTransportError.UNKNOWN, "Bad IO error : " + e)); diff --git a/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx index 5a555831383..e25ab7aaabd 100644 --- a/tutorial/haxe/src/Main.hx +++ b/tutorial/haxe/src/Main.hx @@ -230,8 +230,8 @@ class Main { }); } - catch(e : Error) { - println("Exception "+e.message); + catch(e : Dynamic) { + println('Exception $e'); } work.op = tutorial.Operation.SUBTRACT; @@ -317,7 +317,7 @@ class Main { println("\nStarting the server..."); server.Serve(); } - catch( e : Error) + catch( e : Dynamic) { println('RunServer() failed: $e'); } From 7f6f196633a8689ba4dddf1b553a1ac95585f8f9 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Fri, 8 Aug 2014 23:54:00 +0200 Subject: [PATCH 07/24] improvements for flash and js targets --- compiler/cpp/src/generate/t_haxe_generator.cc | 6 +- .../apache/thrift/transport/THttpClient.hx | 16 +- .../apache/thrift/transport/TServerSocket.hx | 6 + .../org/apache/thrift/transport/TSocket.hx | 140 ++++++++++++++++-- tutorial/haxe/flash.hxml | 3 + tutorial/haxe/make_all.bat | 11 +- tutorial/haxe/project.hide | 22 +-- tutorial/haxe/src/Main.hx | 97 ++++++------ 8 files changed, 217 insertions(+), 84 deletions(-) diff --git a/compiler/cpp/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc index 1a4cb4f527e..210a395fb66 100644 --- a/compiler/cpp/src/generate/t_haxe_generator.cc +++ b/compiler/cpp/src/generate/t_haxe_generator.cc @@ -269,6 +269,10 @@ string t_haxe_generator::haxe_type_imports() { "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"; } @@ -280,7 +284,7 @@ string t_haxe_generator::haxe_type_imports() { string t_haxe_generator::haxe_thrift_imports() { return string() + - "import org.apache.thrift.*;\n" + + "import org.apache.thrift.*;\n" + "import org.apache.thrift.meta_data.*;\n" + "import org.apache.thrift.protocol.*;\n" + "\n"; diff --git a/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx index e0cab2d9b22..aafb6ef0ca4 100644 --- a/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx +++ b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx @@ -102,8 +102,10 @@ class THttpClient extends TTransport { #if flash try { - responseBuffer_.readBytes(buf, off, len); - return len; + var data = Bytes.alloc(len); + responseBuffer_.readBytes(data, off, len); + buf.addBytes(data,0,len); + return len; } catch (e : EOFError) { throw new TTransportError(TTransportError.UNKNOWN, "No more data available."); } @@ -130,7 +132,7 @@ class THttpClient extends TTransport { if (callback != null) { loader.addEventListener(Event.COMPLETE, function(event:Event) : Void { - responseBuffer_ = URLLoader(event.target).data; + responseBuffer_ = new URLLoader(event.target).data; callback(null); }); loader.addEventListener(IOErrorEvent.IO_ERROR, function(event:IOErrorEvent) : Void { @@ -145,7 +147,7 @@ class THttpClient extends TTransport { request_.method = URLRequestMethod.POST; loader.dataFormat = URLLoaderDataFormat.BINARY; - requestBuffer_.position = 0; + //requestBuffer_.position = 0; request_.data = requestBuffer_; loader.load(request_); } @@ -165,7 +167,13 @@ class THttpClient extends TTransport { request_.onError = function(msg : String) { callback(new TTransportError(TTransportError.UNKNOWN, "IOError: " + msg)); }; + + #if js + request_.setPostData(buffer.getBytes().toString()); + request_.request(true/*POST*/); + #else request_.customRequest( true/*POST*/, buffer); + #end } #end diff --git a/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx index 7dec79d1e5c..8ebb724aaed 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx @@ -31,6 +31,10 @@ 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) + import sys.net.Host; @@ -128,3 +132,5 @@ class TServerSocket extends TServerTransport { } } } + +#end diff --git a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx index c4607a192c4..56b2a7d5ad0 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx @@ -19,7 +19,14 @@ 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; @@ -27,7 +34,11 @@ import haxe.io.BytesOutput; import haxe.io.Input; import haxe.io.Output; import haxe.io.Eof; + + +#if ! (flash || js) import sys.net.Host; +#end /** @@ -37,28 +48,52 @@ import sys.net.Host; class TSocket extends TTransport { - private var host : Host; + #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; - - private var input : Input = 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 : TTransportError->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; @@ -70,8 +105,14 @@ class TSocket extends TTransport { 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 } } @@ -79,6 +120,29 @@ class TSocket extends TTransport { 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 TTransportError(TTransportError.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); @@ -88,6 +152,8 @@ class TSocket extends TTransport { readCount += data.length; buf.add(data); return data.length; + + #end } catch (e : Eof) { @@ -116,15 +182,46 @@ class TSocket extends TTransport { throw new TTransportError(TTransportError.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(); - var len = bytes.length; 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 } @@ -144,21 +241,44 @@ class TSocket extends TTransport { public override function open() : Void { - socket = new Socket(); - socket.setBlocking(true); + #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); - - output = socket.output; - input = socket.input; + socket.connect(host, port); + + #end + + assignSocket( socket); } - private function assignSocket( socket : Socket) : Void + #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/tutorial/haxe/flash.hxml b/tutorial/haxe/flash.hxml index ee0f43d3ed9..a1f0568ad4a 100644 --- a/tutorial/haxe/flash.hxml +++ b/tutorial/haxe/flash.hxml @@ -31,6 +31,9 @@ #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) diff --git a/tutorial/haxe/make_all.bat b/tutorial/haxe/make_all.bat index 89cd4ef9a7a..1ea1c0a7272 100644 --- a/tutorial/haxe/make_all.bat +++ b/tutorial/haxe/make_all.bat @@ -11,10 +11,13 @@ thrift -r -gen haxe ..\tutorial.thrift rem # invoke Haxe compiler for all targets for %%a in (*.hxml) do ( - echo -------------------------- - echo Building %%a ... - echo -------------------------- - haxe --cwd . %%a + 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 + ) ) diff --git a/tutorial/haxe/project.hide b/tutorial/haxe/project.hide index bf7db8d5f79..8106e5244a9 100644 --- a/tutorial/haxe/project.hide +++ b/tutorial/haxe/project.hide @@ -51,7 +51,7 @@ ,"foldedRegions" : [ ] - ,"activeLine" : 316 + ,"activeLine" : 0 } ,{ "path" : "src\\org\\apache\\thrift\\server\\TServer.hx" @@ -80,15 +80,6 @@ ] ,"activeLine" : 20 } - ,{ - "path" : "src\\CalculatorHandler.hx" - ,"useTabs" : true - ,"indentSize" : 4 - ,"foldedRegions" : [ - - ] - ,"activeLine" : 76 - } ,{ "path" : "src\\tutorial\\CalculatorProcessor.hx" ,"useTabs" : true @@ -98,17 +89,8 @@ ] ,"activeLine" : 79 } - ,{ - "path" : "cpp.hxml" - ,"useTabs" : true - ,"indentSize" : 4 - ,"foldedRegions" : [ - - ] - ,"activeLine" : 5 - } ] - ,"activeFile" : "src\\CalculatorHandler.hx" + ,"activeFile" : "src\\Main.hx" ,"openFLTarget" : null ,"openFLBuildMode" : "Debug" ,"runActionType" : null diff --git a/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx index e25ab7aaabd..3d9687bb686 100644 --- a/tutorial/haxe/src/Main.hx +++ b/tutorial/haxe/src/Main.hx @@ -50,15 +50,16 @@ class Main { private static var targetHost : String = "localhost"; private static var targetPort : Int = 9090; - static function main() { + static function main() { + #if ! (flash || js) try { ParseArgs(); } catch (e : String) { - println(e); - println(GetHelp()); + trace(e); + trace(GetHelp()); return; } - + #end try { if (server) @@ -66,18 +67,15 @@ class Main { else RunClient(); } catch (e : String) { - println(e); + trace(e); } - println("Completed."); + trace("Completed."); } + - - private static function println(txt : String) { - Sys.println(txt); - } - - + #if ! (flash || js) + private static function GetHelp() : String { return Sys.executablePath()+" modus trnsOption transport protocol\n" +"Options:\n" @@ -89,7 +87,7 @@ class Main { +"All arguments are optional.\n"; } - + private static function ParseArgs() : Void { var step = 0; for (arg in Sys.args()) { @@ -137,26 +135,31 @@ class Main { if ( framed && buffered) { - println("WN: framed supersedes buffered"); + trace("WN: framed supersedes buffered"); } } } - + + #end private static function ClientSetup() : Calculator { - println("Client configuration:"); + trace("Client configuration:"); // endpoint transport var transport : TTransport; switch(trns) { case socket: - println('- socket transport $targetHost:$targetPort'); + trace('- socket transport $targetHost:$targetPort'); transport = new TSocket( targetHost, targetPort); case http: - println("- http transport $targetHost"); - transport = new THttpClient( targetHost); + trace("- http transport $targetHost"); + #if flash + transport = new THttpClient( new flash.net.URLRequest(targetHost)); + #else + transport = new THttpClient( targetHost); + #end default: throw "Unhandled transport"; } @@ -164,10 +167,10 @@ class Main { // optinal layered transport if ( framed) { - println("- framed transport"); + trace("- framed transport"); transport = new TFramedTransport(transport); } else if ( buffered) { - println("- buffered transport"); + trace("- buffered transport"); throw "TBufferedTransport not implemented yet"; //transport = new TBufferedTransport(transport); } @@ -178,11 +181,11 @@ class Main { switch(prot) { case binary: - println("- binary protocol"); + trace("- binary protocol"); protocol = new TBinaryProtocol( transport); case json: throw "JSON protocol not implemented yet"; - //println("- json protocol"); + //trace("- json protocol"); //protocol = new TJsonProtocol( transport); default: throw "Unhandled protocol"; @@ -200,19 +203,19 @@ class Main { client.ping( function(error : Error) : Void { - println('ping() failed: $error'); + trace('ping() failed: $error'); }, function() : Void { - println("ping()"); + trace("ping()"); }); client.add( 1, 1, function(error : Error) : Void { - println('add() failed: $error'); + trace('add() failed: $error'); }, function( sum : haxe.Int32) : Void { - println('1+1= $sum'); + trace('1+1= $sum'); }); @@ -223,15 +226,15 @@ class Main { try { client.calculate( 1, work, function(error : Error) : Void { - println('calculate() failed: $error'); + trace('calculate() failed: $error'); }, function(quotient : haxe.Int32) : Void { - println('Whoa we can divide by 0! Result = $quotient'); + trace('Whoa we can divide by 0! Result = $quotient'); }); } catch(e : Dynamic) { - println('Exception $e'); + trace('Exception $e'); } work.op = tutorial.Operation.SUBTRACT; @@ -239,38 +242,42 @@ class Main { work.num2 = 10; client.calculate( 1, work, function(error : Error) : Void { - println('calculate() failed: $error'); + trace('calculate() failed: $error'); }, function( diff : haxe.Int32) : Void { - println('15-10=$diff\n'); + trace('15-10=$diff\n'); }); client.getStruct( 1, function(error : Error) : Void { - println('getStruct() failed: $error'); + trace('getStruct() failed: $error'); }, function( log : SharedStruct) : Void { var logval = log.value; - println('Check log: $logval'); + trace('Check log: $logval'); }); } private static function ServerSetup() : TServer { - println("Server configuration:"); + trace("Server configuration:"); // endpoint transport var transport : TServerTransport = null; switch(trns) { case socket: - println('- socket transport port $targetPort'); + #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"; - //println("- http transport"); + //trace("- http transport"); //transport = new THttpClient( targetHost); default: throw "Unhandled transport"; @@ -279,10 +286,10 @@ class Main { // optinal layered transport var transfactory : TTransportFactory = null; if ( framed) { - println("- framed transport"); + trace("- framed transport"); transfactory = new TFramedTransportFactory(); } else if ( buffered) { - println("- buffered transport"); + trace("- buffered transport"); throw "TBufferedTransport not implemented yet"; //transfactory = new TBufferedTransportFactory(); } @@ -292,11 +299,11 @@ class Main { switch(prot) { case binary: - println("- binary protocol"); + trace("- binary protocol"); protfactory = new TBinaryProtocolFactory(); case json: throw "JSON protocol not implemented yet"; - //println("- json protocol"); + //trace("- json protocol"); //protfactory = new TJsonProtocolFactory(); default: throw "Unhandled protocol"; @@ -314,14 +321,14 @@ class Main { { var server = ServerSetup(); - println("\nStarting the server..."); + trace("\nStarting the server..."); server.Serve(); } catch( e : Dynamic) { - println('RunServer() failed: $e'); + trace('RunServer() failed: $e'); } - println("done."); + trace("done."); } - + } From 18a7556f7f3fbc44f5503b38e7187e145fb1efb1 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Mon, 11 Aug 2014 17:21:43 +0200 Subject: [PATCH 08/24] improved codegen for struct members --- compiler/cpp/src/generate/t_haxe_generator.cc | 27 ++++++++++--------- tutorial/haxe/project.hide | 4 ++- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/compiler/cpp/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc index 210a395fb66..d72d9a8e9cb 100644 --- a/compiler/cpp/src/generate/t_haxe_generator.cc +++ b/compiler/cpp/src/generate/t_haxe_generator.cc @@ -99,7 +99,7 @@ class t_haxe_generator : public t_oop_generator { 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_haxe_bean_boilerplate(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); @@ -733,9 +733,14 @@ void t_haxe_generator::generate_haxe_struct_definition(ofstream &out, 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) << "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; } @@ -776,14 +781,14 @@ void t_haxe_generator::generate_haxe_struct_definition(ofstream &out, } 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() << ";" << + indent(out) << "this." << (*m_iter)->get_name() << " = " << (*m_iter)->get_value()->get_integer() << ";" << endl; } } indent_down(); indent(out) << "}" << endl << endl; - generate_haxe_bean_boilerplate(out, tstruct); + generate_property_getters_setters(out, tstruct); generate_generic_field_getters_setters(out, tstruct); generate_generic_isset_method(out, tstruct); @@ -1165,12 +1170,11 @@ void t_haxe_generator::generate_generic_isset_method(std::ofstream& out, t_struc } /** - * Generates a set of haxe Bean boilerplate functions (setters, getters, etc.) - * for the given struct. + * Generates a set of property setters/getters for the given struct. * * @param tstruct The struct definition */ -void t_haxe_generator::generate_haxe_bean_boilerplate(ofstream& out, +void t_haxe_generator::generate_property_getters_setters(ofstream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; @@ -1185,23 +1189,22 @@ void t_haxe_generator::generate_haxe_bean_boilerplate(ofstream& out, indent(out) << "public function get_" << field_name << "():" << type_name(type) << " {" << endl; indent_up(); - indent(out) << "return this._" << field_name << ";" << endl; + indent(out) << "return this." << field_name << ";" << endl; indent_down(); indent(out) << "}" << endl << endl; // Simple setter generate_haxe_doc(out, field); - std::string propName = tmp("thriftPropertyChange"); 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; + "this." << field_name << " = " << field_name << ";" << endl; generate_isset_set(out, field); indent(out) << - "return this._" << field_name << ";" << endl; + "return this." << field_name << ";" << endl; indent_down(); indent(out) << "}" << endl << endl; @@ -1242,7 +1245,7 @@ void t_haxe_generator::generate_haxe_struct_tostring(ofstream& out, indent_up(); out << - indent() << "var ret : String = new String(\"" << tstruct->get_name() << "(\");" << endl; + indent() << "var ret : String = \"" << tstruct->get_name() << "(\";" << endl; out << indent() << "var first : Bool = true;" << endl << endl; const vector& fields = tstruct->get_members(); diff --git a/tutorial/haxe/project.hide b/tutorial/haxe/project.hide index 8106e5244a9..066a82e5bc0 100644 --- a/tutorial/haxe/project.hide +++ b/tutorial/haxe/project.hide @@ -1,6 +1,6 @@ { "type" : 0 - ,"target" : 4 + ,"target" : 6 ,"name" : "Apache Thrift Tutorial" ,"main" : null ,"projectPackage" : "" @@ -36,6 +36,8 @@ } ,{ "pathToHxml" : "csharp.hxml" + ,"runActionType" : 2 + ,"runActionText" : "bin\\Tutorial.exe\\bin\\Main-Debug.exe" } ,{ "pathToHxml" : "python.hxml" From 05ef10c5a104d2c2aef3e38d0c0f21ba858faeb5 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Tue, 12 Aug 2014 01:26:51 +0200 Subject: [PATCH 09/24] Server not available for HTML5 --- lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx index 8ebb724aaed..a0f29a217b5 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx @@ -33,7 +33,7 @@ import haxe.io.Output; import haxe.io.Eof; //import flash.net.ServerSocket; - not yet available on Haxe 3.1.3 -#if ! (flash) +#if ! (flash || html5) import sys.net.Host; From f51feaaabca5bbde2a07dbee2ff7c963fce3a781 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Tue, 12 Aug 2014 18:44:25 +0200 Subject: [PATCH 10/24] Replace AS3 onError/onSuccess callback style by "normal" function():result/exception style. The AS3 callback style is still available via option, --- compiler/cpp/src/generate/t_haxe_generator.cc | 382 ++++++++++++------ .../thrift/transport/TFullDuplexHttpClient.hx | 5 + .../org/apache/thrift/transport/TSocket.hx | 14 +- tutorial/haxe/project.hide | 56 ++- tutorial/haxe/src/CalculatorHandler.hx | 25 +- tutorial/haxe/src/Main.hx | 71 ++-- 6 files changed, 350 insertions(+), 203 deletions(-) diff --git a/compiler/cpp/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc index d72d9a8e9cb..0840fffcfc1 100644 --- a/compiler/cpp/src/generate/t_haxe_generator.cc +++ b/compiler/cpp/src/generate/t_haxe_generator.cc @@ -54,6 +54,9 @@ class t_haxe_generator : public t_oop_generator { (void) option_string; std::map::const_iterator iter; + iter = parsed_options.find("callbacks"); + callbacks_ = (iter != parsed_options.end()); + out_dir_base_ = "gen-haxe"; } @@ -114,7 +117,6 @@ class t_haxe_generator : public t_oop_generator { 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); - string generate_service_method_onsuccess(t_function* tfunction, bool as_type, bool omit_name); /** * Serialization constructs @@ -187,10 +189,14 @@ class t_haxe_generator : public t_oop_generator { 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(t_function* tfunction, std::string on_error_success, std::string prefix=""); + 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); @@ -205,7 +211,8 @@ class t_haxe_generator : public t_oop_generator { std::string constant_name(std::string name); private: - + bool callbacks_; + /** * File streams */ @@ -284,7 +291,7 @@ string t_haxe_generator::haxe_type_imports() { string t_haxe_generator::haxe_thrift_imports() { return string() + - "import org.apache.thrift.*;\n" + + "import org.apache.thrift.*;\n" + "import org.apache.thrift.meta_data.*;\n" + "import org.apache.thrift.protocol.*;\n" + "\n"; @@ -734,7 +741,7 @@ void t_haxe_generator::generate_haxe_struct_definition(ofstream &out, 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) << "@:isVar" << endl; indent(out) << "public var " << (*m_iter)->get_name() + "(get,set) : " + type_name((*m_iter)->get_type()) << ";" << endl; } @@ -1539,23 +1546,46 @@ string t_haxe_generator::generate_service_method_onsuccess(t_function* tfunction * @param tfunction The service function to generate code for. */ void t_haxe_generator::generate_service_method_signature(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(Error) : Void;" << endl; - indent(f_service_) << "// function " << on_success_impl.c_str() << ";" << endl; - } + if( callbacks_) { + generate_service_method_signature_callback( tfunction, is_interface); + } else { + generate_service_method_signature_normal( tfunction, is_interface); + } +} - std::string on_error_success = "onError : Error->Void = null, " - + generate_service_method_onsuccess(tfunction, true, false); - - if( is_interface) { - indent(f_service_) << function_signature(tfunction,on_error_success) << ";" << - endl << endl; - } else { - indent(f_service_) << - "public " << function_signature(tfunction,on_error_success) << " {" << endl; - } +/** + * 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(Error) : 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; + } } /** @@ -1702,76 +1732,116 @@ void t_haxe_generator::generate_service_client(t_service* tservice) { 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 { - f_service_ << indent() << "oprot_.getTransport().flush(function(error:Error) : Void {" << endl; - indent_up(); - f_service_ << indent() << "try {" << endl; + indent(f_service_) << "oprot_.getTransport().flush(function(error:Error) : Void {" << endl; indent_up(); + if( callbacks_) { + indent(f_service_) << "try {" << endl; + indent_up(); + } string resultname = get_cap_name( (*f_iter)->get_name() + "_result"); - f_service_ << - indent() << "if (error != null) {" << endl << - indent() << " if (onError != null) onError(error);" << endl << - indent() << " return;" << endl << - indent() << "}" << endl << - indent() << "var msg : TMessage = iprot_.readMessageBegin();" << endl << - indent() << "if (msg.type == TMessageType.EXCEPTION) {" << endl << - indent() << " var x = TApplicationError.read(iprot_);" << endl << - indent() << " iprot_.readMessageEnd();" << endl << - indent() << " if (onError != null) onError(x);" << endl << - indent() << " return;" << endl << - indent() << "}" << endl << - indent() << "var result : " << resultname << " = new " << resultname << "();" << endl << - indent() << "result.read(iprot_);" << endl << - indent() << "iprot_.readMessageEnd();" << endl; + 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 = TApplicationError.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()) { - f_service_ << - indent() << "if (result." << generate_isset_check("success") << ") {" << endl << - indent() << " if (onSuccess != null) onSuccess(result.success);" << endl << - indent() << " return;" << endl << - indent() << "}" << endl; + 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& xceptions = xs->get_members(); vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { - f_service_ << - indent() << "if (result." << (*x_iter)->get_name() << " != null) {" << endl << - indent() << " if (onError != null) onError(result." << (*x_iter)->get_name() << ");" << endl << - indent() << " return;" << endl << - indent() << "}" << endl; + 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()) { - f_service_ << - indent() << "if (onSuccess != null) onSuccess();" << endl << - indent() << "return;" << endl; + if( callbacks_) { + indent(f_service_) << "if (onSuccess != null) onSuccess();" << endl; + } + indent(f_service_) << "return;" << endl; } else { - - f_service_ << - indent() << "if (onError != null)" << endl; + if( callbacks_) { + indent(f_service_) << "if (onError != null)" << endl; + indent_up(); + indent(f_service_) << "onError( new TApplicationError(TApplicationError.MISSING_RESULT," << endl; + indent(f_service_) << " \"" << (*f_iter)->get_name() << " failed: unknown result\"));" << endl; + indent_down(); + } else { + indent(f_service_) << "throw new TApplicationError(TApplicationError.MISSING_RESULT," << endl; + indent(f_service_) << " \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl; + } + } + + if( callbacks_) { + indent_down(); + indent(f_service_) << "} catch (e:TError) {" << endl; indent_up(); - f_service_ << - indent() << "onError( new TApplicationError(TApplicationError.MISSING_RESULT," << endl << - indent() << " \"" << (*f_iter)->get_name() << " failed: unknown result\"));" << endl; + indent(f_service_) << "if (onError != null) onError(e);" << endl; indent_down(); - } - indent_down(); - f_service_ << indent() << "} catch (e:TError) {" << endl << - indent() << " if (onError != null) onError(e);" << endl << - indent() << "}" << endl; - + 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; @@ -1946,59 +2016,88 @@ void t_haxe_generator::generate_process_function(t_service* tservice, indent() << "var result : " << resultname << " = new " << resultname << "();" << endl; } - // Try block for any non-oneway function to catch (defined or undefined) exceptions - if (!tfunction->is_oneway()) { - f_service_ << - indent() << "try {" << endl; - indent_up(); - } + // Try block for any function to catch (defined or undefined) exceptions + f_service_ << + indent() << "try {" << endl; + indent_up(); - // Generate the function call - t_struct* arg_struct = tfunction->get_arglist(); - const std::vector& fields = arg_struct->get_members(); - vector::const_iterator f_iter; + if(callbacks_) { + // callback function style onError/onSuccess - 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; + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::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 { - 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(); + 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(f_service_) << "});" << endl; + indent_down(); } - indent_down(); + + } else { + // normal function():result style + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::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; + } - if (!tfunction->is_oneway()) { - indent_down(); - f_service_ << indent() << "}"; + 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; @@ -2012,20 +2111,22 @@ void t_haxe_generator::generate_process_function(t_service* tservice, f_service_ << "}"; } } - // always catch all exceptions - f_service_ << " catch (th : Dynamic) {" << endl; - indent_up(); - f_service_ << - indent() << "trace(\"Internal error processing " << tfunction->get_name() << "\", th);" << endl << - indent() << "var x = new TApplicationError(TApplicationError.INTERNAL_ERROR, \"Internal error processing " << tfunction->get_name() << "\");" << endl << - indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl << - indent() << "x.write(oprot);" << endl << - indent() << "oprot.writeMessageEnd();" << endl << - indent() << "oprot.getTransport().flush();" << endl << - indent() << "return;" << endl; - indent_down(); - f_service_ << indent() << "}" << endl; } + + // 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 TApplicationError(TApplicationError.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()) { @@ -2593,9 +2694,10 @@ string t_haxe_generator::declare_field(t_field* tfield, bool init) { * @param tfunction Function definition * @return String of rendered function definition */ -string t_haxe_generator::function_signature(t_function* tfunction, - string on_error_success, - string prefix) { +string t_haxe_generator::function_signature_callback( t_function* tfunction) { + std::string on_error_success = "onError : Error->Void = null, " + + generate_service_method_onsuccess(tfunction, true, false); + std::string arguments = argument_list(tfunction->get_arglist()); if (! tfunction->is_oneway()) { if (arguments != "") { @@ -2604,8 +2706,27 @@ string t_haxe_generator::function_signature(t_function* tfunction, arguments += on_error_success; //"onError : Function, onSuccess : Function"; } - std::string result = "function " + - prefix + tfunction->get_name() + "(" + arguments + ") : Void"; + 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; } @@ -2761,9 +2882,6 @@ std::string t_haxe_generator::get_enum_class_name(t_type* type) { } THRIFT_REGISTER_GENERATOR(haxe, "Haxe", -"" -/* sample option -" bindable: Add [bindable] metadata to all the struct classes.\n" -*/ +" callbacks: Use onError()/onSuccess() callbacks for service methods (like AS3)\n" ) diff --git a/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx index 160d973ef51..ce8c81a4295 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx @@ -137,6 +137,11 @@ import flash.events.EventDispatcher; trace(e); throw new TTransportError(TTransportError.UNKNOWN, "No more data available."); } + catch (e : Error) + { + trace('Error $e'); + throw new TTransportError(TTransportError.UNKNOWN, "Bad IO error : "+e.errorID+" "+e.message); + } catch (e : Dynamic) { trace(e); diff --git a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx index 56b2a7d5ad0..87765e6839d 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx @@ -160,10 +160,15 @@ class TSocket extends TTransport { trace('Eof $e'); throw new TTransportError(TTransportError.END_OF_FILE, "No more data available."); } + catch (e : Error) + { + trace('Error $e'); + throw new TTransportError(TTransportError.UNKNOWN, "Bad IO error : "+e.errorID+" "+e.message); + } catch (e : Dynamic) { trace('Error $e'); - throw new TTransportError(TTransportError.UNKNOWN, "Bad IO error : " + e); + throw new TTransportError(TTransportError.UNKNOWN, "Bad IO error : "); } } @@ -226,6 +231,13 @@ class TSocket extends TTransport { ioCallback(null); // success call } } + catch (e : Error) + { + trace('Error $e'); + if(ioCallback != null) { + ioCallback(new TTransportError(TTransportError.UNKNOWN, "Bad IO error : "+e.errorID+" "+e.message)); + } + } catch (e : Dynamic) { trace(e); if(ioCallback != null) { diff --git a/tutorial/haxe/project.hide b/tutorial/haxe/project.hide index 066a82e5bc0..6d23a0a1e8c 100644 --- a/tutorial/haxe/project.hide +++ b/tutorial/haxe/project.hide @@ -1,6 +1,6 @@ { "type" : 0 - ,"target" : 6 + ,"target" : 4 ,"name" : "Apache Thrift Tutorial" ,"main" : null ,"projectPackage" : "" @@ -47,15 +47,6 @@ ] ,"files" : [ { - "path" : "src\\Main.hx" - ,"useTabs" : true - ,"indentSize" : 4 - ,"foldedRegions" : [ - - ] - ,"activeLine" : 0 - } - ,{ "path" : "src\\org\\apache\\thrift\\server\\TServer.hx" ,"useTabs" : true ,"indentSize" : 4 @@ -91,6 +82,51 @@ ] ,"activeLine" : 79 } + ,{ + "path" : "gen-haxe\\tutorial\\CalculatorProcessor.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 136 + } + ,{ + "path" : "src\\Main.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 235 + } + ,{ + "path" : "gen-haxe\\tutorial\\CalculatorImpl.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 17 + } + ,{ + "path" : "gen-haxe\\shared\\SharedServiceImpl.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 0 + } + ,{ + "path" : "src\\CalculatorHandler.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 95 + } ] ,"activeFile" : "src\\Main.hx" ,"openFLTarget" : null diff --git a/tutorial/haxe/src/CalculatorHandler.hx b/tutorial/haxe/src/CalculatorHandler.hx index 3a493ed20a7..ee75edd9d45 100644 --- a/tutorial/haxe/src/CalculatorHandler.hx +++ b/tutorial/haxe/src/CalculatorHandler.hx @@ -38,25 +38,17 @@ class CalculatorHandler implements Calculator { public function new() { } - // function onError(Error) : Void; - // function onSuccess() : Void; - public function ping(onError : Error->Void = null, onSuccess : Void->Void = null) : Void { + public function ping() : Void { trace("ping()"); } - // function onError(Error) : Void; - // function onSuccess(haxe.Int32) : Void; - public function add( num1 : haxe.Int32, num2 : haxe.Int32, - onError : Error->Void = null, onSuccess : haxe.Int32->Void = null) : Void { + public function add( num1 : haxe.Int32, num2 : haxe.Int32) : haxe.Int32 { trace('add( $num1, $num2)'); - onSuccess( num1 + num2); + return num1 + num2; } - // function onError(Error) : Void; - // function onSuccess(haxe.Int32) : Void; - public function calculate( logid : haxe.Int32, work : Work, - onError : Error->Void = null, onSuccess : haxe.Int32->Void = null) : Void { + public function calculate( logid : haxe.Int32, work : Work) : haxe.Int32 { trace('calculate( $logid, '+work.op+","+work.num1+","+work.num2+")"); var val : haxe.Int32 = 0; @@ -93,15 +85,12 @@ class CalculatorHandler implements Calculator { entry.value = '$val'; log.set(logid, entry); - onSuccess( val); + return val; } - // function onError(Error) : Void; - // function onSuccess( retval : SharedStruct); - public function getStruct( key : haxe.Int32, - onError : Error->Void = null, onSuccess : SharedStruct->Void = null) : Void { + public function getStruct( key : haxe.Int32) : SharedStruct { trace('getStruct($key)'); - onSuccess( log.get(key)); + return log.get(key); } // oneway method, no args diff --git a/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx index 3d9687bb686..73e73b99ffc 100644 --- a/tutorial/haxe/src/Main.hx +++ b/tutorial/haxe/src/Main.hx @@ -201,22 +201,19 @@ class Main { private static function RunClient() : Void { var client = ClientSetup(); - client.ping( - function(error : Error) : Void { - trace('ping() failed: $error'); - }, - function() : Void { - trace("ping()"); - }); - + try { + client.ping(); + trace("ping() successful"); + } catch(error : Dynamic) { + trace('ping() failed: $error'); + } - client.add( 1, 1, - function(error : Error) : Void { - trace('add() failed: $error'); - }, - function( sum : haxe.Int32) : Void { - trace('1+1= $sum'); - }); + try { + var sum = client.add( 1, 1); + trace('1+1=$sum'); + } catch(error : Dynamic) { + trace('add() failed: $error'); + } var work = new tutorial.Work(); @@ -224,40 +221,30 @@ class Main { work.num1 = 1; work.num2 = 0; try { - client.calculate( 1, work, - function(error : Error) : Void { - trace('calculate() failed: $error'); - }, - function(quotient : haxe.Int32) : Void { - trace('Whoa we can divide by 0! Result = $quotient'); - }); - - } - catch(e : Dynamic) { - trace('Exception $e'); + var quotient = client.calculate( 1, work); + trace('Whoa we can divide by 0! Result = $quotient'); + } catch(error : Dynamic) { + trace('calculate() failed: $error'); } work.op = tutorial.Operation.SUBTRACT; work.num1 = 15; work.num2 = 10; - client.calculate( 1, work, - function(error : Error) : Void { - trace('calculate() failed: $error'); - }, - function( diff : haxe.Int32) : Void { - trace('15-10=$diff\n'); - }); + try { + var diff = client.calculate( 1, work); + trace('15-10=$diff'); + } catch(error : Dynamic) { + trace('calculate() failed: $error'); + } - client.getStruct( 1, - function(error : Error) : Void { - trace('getStruct() failed: $error'); - }, - function( log : SharedStruct) : Void { - var logval = log.value; - trace('Check log: $logval'); - }); - + try { + var log : SharedStruct = client.getStruct( 1); + var logval = log.value; + trace('Check log: $logval'); + } catch(error : Dynamic) { + trace('getStruct() failed: $error'); + } } From 21ce660e360e6b74b0ba2f2d54761c2cb9f0cc2c Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Tue, 12 Aug 2014 19:23:38 +0200 Subject: [PATCH 11/24] error improvements --- compiler/cpp/src/generate/t_haxe_generator.cc | 2 +- .../thrift/transport/TFullDuplexHttpClient.hx | 13 +++++++---- .../org/apache/thrift/transport/TSocket.hx | 22 ++++++++++++++----- tutorial/haxe/src/Main.hx | 10 +++++++++ 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/compiler/cpp/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc index 0840fffcfc1..81140ba709b 100644 --- a/compiler/cpp/src/generate/t_haxe_generator.cc +++ b/compiler/cpp/src/generate/t_haxe_generator.cc @@ -716,7 +716,7 @@ void t_haxe_generator::generate_haxe_struct_definition(ofstream &out, "class " << clsname << " "; if (is_exception) { - out << "extends Error "; + out << "extends TError "; } out << "implements TBase "; diff --git a/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx index ce8c81a4295..8953fd6a958 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx @@ -53,7 +53,7 @@ import flash.events.EventDispatcher; private var output : IDataOutput; private var bytesInChunk : Int = 0; private var CRLF : Bytes = new Bytes(); - private var ioCallback : Function = null; + private var ioCallback : TError->Void = null; private var eventDispatcher : EventDispatcher = new EventDispatcher(); public function new(host : String, port : Int, resource : String) : Void @@ -137,11 +137,16 @@ import flash.events.EventDispatcher; trace(e); throw new TTransportError(TTransportError.UNKNOWN, "No more data available."); } - catch (e : Error) + catch (e : TError) { - trace('Error $e'); - throw new TTransportError(TTransportError.UNKNOWN, "Bad IO error : "+e.errorID+" "+e.message); + trace('TError $e'); + throw e; } + catch (e : Error) + { + trace(e); + throw new TTransportError(TTransportError.UNKNOWN, 'Bad IO error: $e'); + } catch (e : Dynamic) { trace(e); diff --git a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx index 87765e6839d..185b0cc4cf0 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx @@ -74,7 +74,7 @@ class TSocket extends TTransport { #end private var obuffer : BytesOutput = new BytesOutput(); - private var ioCallback : TTransportError->Void = null; + private var ioCallback : TError->Void = null; private var readCount : Int = 0; public function new(host : String, port : Int) : Void { @@ -160,15 +160,20 @@ class TSocket extends TTransport { trace('Eof $e'); throw new TTransportError(TTransportError.END_OF_FILE, "No more data available."); } + catch (e : TError) + { + trace('TError $e'); + throw e; + } catch (e : Error) { trace('Error $e'); - throw new TTransportError(TTransportError.UNKNOWN, "Bad IO error : "+e.errorID+" "+e.message); + throw new TTransportError(TTransportError.UNKNOWN, 'Bad IO error : $e'); } catch (e : Dynamic) { trace('Error $e'); - throw new TTransportError(TTransportError.UNKNOWN, "Bad IO error : "); + throw new TTransportError(TTransportError.UNKNOWN, 'Bad IO error : $e'); } } @@ -231,17 +236,24 @@ class TSocket extends TTransport { ioCallback(null); // success call } } + catch (e : TError) + { + trace('TError $e'); + if(ioCallback != null) { + ioCallback(e); + } + } catch (e : Error) { trace('Error $e'); if(ioCallback != null) { - ioCallback(new TTransportError(TTransportError.UNKNOWN, "Bad IO error : "+e.errorID+" "+e.message)); + ioCallback(new TTransportError(TTransportError.UNKNOWN, 'Bad IO error : $e')); } } catch (e : Dynamic) { trace(e); if(ioCallback != null) { - ioCallback(new TTransportError(TTransportError.UNKNOWN, "Bad IO error : " + e)); + ioCallback(new TTransportError(TTransportError.UNKNOWN, 'Bad IO error : $e')); } } } diff --git a/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx index 73e73b99ffc..3a2803cff5e 100644 --- a/tutorial/haxe/src/Main.hx +++ b/tutorial/haxe/src/Main.hx @@ -204,6 +204,8 @@ class Main { try { client.ping(); trace("ping() successful"); + } catch(error : TError) { + trace('ping() failed: $error'); } catch(error : Dynamic) { trace('ping() failed: $error'); } @@ -211,6 +213,8 @@ class Main { try { var sum = client.add( 1, 1); trace('1+1=$sum'); + } catch(error : TError) { + trace('add() failed: $error'); } catch(error : Dynamic) { trace('add() failed: $error'); } @@ -223,6 +227,8 @@ class Main { try { var quotient = client.calculate( 1, work); trace('Whoa we can divide by 0! Result = $quotient'); + } catch(error : TError) { + trace('calculate() failed: $error'); } catch(error : Dynamic) { trace('calculate() failed: $error'); } @@ -233,6 +239,8 @@ class Main { try { var diff = client.calculate( 1, work); trace('15-10=$diff'); + } catch(error : TError) { + trace('calculate() failed: $error'); } catch(error : Dynamic) { trace('calculate() failed: $error'); } @@ -242,6 +250,8 @@ class Main { var log : SharedStruct = client.getStruct( 1); var logval = log.value; trace('Check log: $logval'); + } catch(error : TError) { + trace('getStruct() failed: $error'); } catch(error : Dynamic) { trace('getStruct() failed: $error'); } From d6440a588092307d410135f223037ec6c6bfa821 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Tue, 12 Aug 2014 21:34:42 +0200 Subject: [PATCH 12/24] - added test client/server (work in progress) - improved codegen for list/set/map - renamed T*Error to T*Exception - fixed license headers --- compiler/cpp/src/generate/t_haxe_generator.cc | 126 +++-- .../org/apache/thrift/AbstractMethodError.hx | 4 +- .../src/org/apache/thrift/ArgumentError.hx | 2 +- ...ationError.hx => TApplicationException.hx} | 10 +- .../thrift/{TError.hx => TException.hx} | 17 +- .../src/org/apache/thrift/helper/IntSet.hx | 8 +- .../src/org/apache/thrift/helper/ObjectSet.hx | 8 +- .../src/org/apache/thrift/helper/StringSet.hx | 8 +- .../apache/thrift/protocol/TBinaryProtocol.hx | 6 +- .../org/apache/thrift/protocol/TProtocol.hx | 2 +- ...ProtocolError.hx => TProtocolException.hx} | 4 +- .../apache/thrift/protocol/TProtocolUtil.hx | 2 +- .../src/org/apache/thrift/server/TServer.hx | 4 - .../thrift/server/TServerEventHandler.hx | 4 - .../org/apache/thrift/server/TSimpleServer.hx | 8 +- .../thrift/transport/TFramedTransport.hx | 6 +- .../thrift/transport/TFullDuplexHttpClient.hx | 14 +- .../apache/thrift/transport/THttpClient.hx | 12 +- .../apache/thrift/transport/TServerSocket.hx | 14 +- .../thrift/transport/TServerTransport.hx | 6 +- .../org/apache/thrift/transport/TSocket.hx | 34 +- .../org/apache/thrift/transport/TTransport.hx | 9 +- ...ansportError.hx => TTransportException.hx} | 4 +- test/haxe/cpp.hxml | 41 ++ test/haxe/csharp.hxml | 38 ++ test/haxe/flash.hxml | 41 ++ test/haxe/java.hxml | 38 ++ test/haxe/javascript.hxml | 44 ++ test/haxe/make_all.bat | 44 ++ test/haxe/make_all.sh | 41 ++ test/haxe/neko.hxml | 38 ++ test/haxe/php.hxml | 38 ++ test/haxe/project.hide | 121 +++++ test/haxe/python.hxml | 38 ++ test/haxe/src/Arguments.hx | 173 ++++++ test/haxe/src/Main.hx | 48 ++ test/haxe/src/TestClient.hx | 409 +++++++++++++++ test/haxe/src/TestServer.hx | 107 ++++ .../haxe/src/TestServerEventHandler.hx | 58 +- test/haxe/src/TestServerHandler.hx | 496 ++++++++++++++++++ tutorial/haxe/project.hide | 38 +- tutorial/haxe/src/Main.hx | 12 +- 42 files changed, 1957 insertions(+), 218 deletions(-) rename lib/haxe/src/org/apache/thrift/{TApplicationError.hx => TApplicationException.hx} (92%) rename lib/haxe/src/org/apache/thrift/{TError.hx => TException.hx} (79%) rename lib/haxe/src/org/apache/thrift/protocol/{TProtocolError.hx => TProtocolException.hx} (94%) rename lib/haxe/src/org/apache/thrift/transport/{TTransportError.hx => TTransportException.hx} (93%) create mode 100644 test/haxe/cpp.hxml create mode 100644 test/haxe/csharp.hxml create mode 100644 test/haxe/flash.hxml create mode 100644 test/haxe/java.hxml create mode 100644 test/haxe/javascript.hxml create mode 100644 test/haxe/make_all.bat create mode 100644 test/haxe/make_all.sh create mode 100644 test/haxe/neko.hxml create mode 100644 test/haxe/php.hxml create mode 100644 test/haxe/project.hide create mode 100644 test/haxe/python.hxml create mode 100644 test/haxe/src/Arguments.hx create mode 100644 test/haxe/src/Main.hx create mode 100644 test/haxe/src/TestClient.hx create mode 100644 test/haxe/src/TestServer.hx rename lib/haxe/src/org/apache/thrift/Error.hx => test/haxe/src/TestServerEventHandler.hx (51%) create mode 100644 test/haxe/src/TestServerHandler.hx diff --git a/compiler/cpp/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc index 81140ba709b..54d7558806b 100644 --- a/compiler/cpp/src/generate/t_haxe_generator.cc +++ b/compiler/cpp/src/generate/t_haxe_generator.cc @@ -716,7 +716,7 @@ void t_haxe_generator::generate_haxe_struct_definition(ofstream &out, "class " << clsname << " "; if (is_exception) { - out << "extends TError "; + out << "extends TException "; } out << "implements TBase "; @@ -897,7 +897,7 @@ void t_haxe_generator::generate_haxe_struct_reader(ofstream& out, 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 TProtocolError(TProtocolError.UNKNOWN, \"Required field '" << (*f_iter)->get_name() << "' was not found in serialized data! Struct: \" + toString());" << endl << + indent() << " throw new TProtocolException(TProtocolException.UNKNOWN, \"Required field '" << (*f_iter)->get_name() << "' was not found in serialized data! Struct: \" + toString());" << endl << indent() << "}" << endl; } } @@ -926,7 +926,7 @@ void t_haxe_generator::generate_haxe_validator(ofstream& out, 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 TProtocolError(TProtocolError.UNKNOWN, \"Required field '" << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());" << 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; @@ -943,7 +943,7 @@ void t_haxe_generator::generate_haxe_validator(ofstream& out, 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 TProtocolError(TProtocolError.UNKNOWN, \"The field '" << field->get_name() << "' has been assigned the invalid value \" + " << field->get_name() << ");" << endl; + 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; } @@ -1575,7 +1575,7 @@ void t_haxe_generator::generate_service_method_signature_normal(t_function* tfun 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(Error) : Void;" << endl; + indent(f_service_) << "// function onError(Dynamic) : Void;" << endl; indent(f_service_) << "// function " << on_success_impl.c_str() << ";" << endl; } @@ -1740,7 +1740,7 @@ void t_haxe_generator::generate_service_client(t_service* tservice) { f_service_ << indent() << "oprot_.getTransport().flush();" << endl; } else { - indent(f_service_) << "oprot_.getTransport().flush(function(error:Error) : Void {" << endl; + indent(f_service_) << "oprot_.getTransport().flush(function(error:Dynamic) : Void {" << endl; indent_up(); if( callbacks_) { indent(f_service_) << "try {" << endl; @@ -1760,7 +1760,7 @@ void t_haxe_generator::generate_service_client(t_service* tservice) { 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 = TApplicationError.read(iprot_);" << endl; + 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; @@ -1815,18 +1815,18 @@ void t_haxe_generator::generate_service_client(t_service* tservice) { if( callbacks_) { indent(f_service_) << "if (onError != null)" << endl; indent_up(); - indent(f_service_) << "onError( new TApplicationError(TApplicationError.MISSING_RESULT," << endl; + 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 TApplicationError(TApplicationError.MISSING_RESULT," << endl; + 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:TError) {" << endl; + indent(f_service_) << "} catch( e : TException) {" << endl; indent_up(); indent(f_service_) << "if (onError != null) onError(e);" << endl; indent_down(); @@ -1926,7 +1926,7 @@ void t_haxe_generator::generate_service_server(t_service* tservice) { indent() << "if (fn == null) {" << endl << indent() << " TProtocolUtil.skip(iprot, TType.STRUCT);" << endl << indent() << " iprot.readMessageEnd();" << endl << - indent() << " var x = new TApplicationError(TApplicationError.UNKNOWN_METHOD, \"Invalid method name: '\"+msg.name+\"'\");" << 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 << @@ -2118,7 +2118,7 @@ void t_haxe_generator::generate_process_function(t_service* tservice, indent_up(); indent(f_service_) << "trace(\"Internal error processing " << tfunction->get_name() << "\", th);" << endl; if( ! tfunction->is_oneway()) { - indent(f_service_) << "var x = new TApplicationError(TApplicationError.INTERNAL_ERROR, \"Internal error processing " << tfunction->get_name() << "\");" << endl; + 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; @@ -2265,11 +2265,11 @@ void t_haxe_generator::generate_deserialize_container(ofstream& out, // Declare variables, read header if (ttype->is_map()) { - indent(out) << "var " << obj << " : TMap = iprot.readMapBegin();" << endl; + indent(out) << "var " << obj << " = iprot.readMapBegin();" << endl; } else if (ttype->is_set()) { - indent(out) << "var " << obj << " : TSet = iprot.readSetBegin();" << endl; + indent(out) << "var " << obj << " = iprot.readSetBegin();" << endl; } else if (ttype->is_list()) { - indent(out) << "var " << obj << " : TList = iprot.readListBegin();" << endl; + indent(out) << "var " << obj << " = iprot.readListBegin();" << endl; } indent(out) @@ -2281,9 +2281,7 @@ void t_haxe_generator::generate_deserialize_container(ofstream& out, // For loop iterates over elements string i = tmp("_i"); indent(out) << - "for (var " << i << " : Int = 0; " << - i << " < " << obj << ".size" << "; " << - "++" << i << ")" << endl; + "for( " << i << " in 0 ... (" << obj << ".size-1))" << endl; scope_up(out); @@ -2330,7 +2328,7 @@ void t_haxe_generator::generate_deserialize_map_element(ofstream& out, generate_deserialize_field(out, &fval); indent(out) << - prefix << "[" << key << "] = " << val << ";" << endl; + prefix << ".set( " << key << ", " << val << ");" << endl; } /** @@ -2477,7 +2475,7 @@ void t_haxe_generator::generate_serialize_container(ofstream& out, string iter = tmp("_key"); string counter = tmp("_sizeCounter"); indent(out) << "var " << counter << " : Int = 0;" << endl; - indent(out) << "for (var " << iter << " : Dynamic in " << prefix << ") {" << endl; + indent(out) << "for( " << iter << " in " << prefix << ") {" << endl; indent(out) << " " << counter << +"++;" << endl; indent(out) << "}" << endl; @@ -2501,26 +2499,26 @@ void t_haxe_generator::generate_serialize_container(ofstream& out, string iter = tmp("elem"); if (ttype->is_map()) { indent(out) << - "for (var " << iter << " : Dynamic in " << prefix << ")"; + "for( " << iter << " in " << prefix << ".keys())" << endl; } else if (ttype->is_set()) { indent(out) << - "for each (var " << iter << " : Dynamic in " << prefix << ".toArray())"; + "for( " << iter << " in " << prefix << ".toArray())" << endl; } else if (ttype->is_list()) { indent(out) << - "for each (var " << iter << " : Dynamic in " << prefix << ")"; + "for( " << iter << " in " << prefix << ")" << endl; } - scope_up(out); + 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); - } + 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); + scope_down(out); if (ttype->is_map()) { indent(out) << @@ -2545,7 +2543,7 @@ void t_haxe_generator::generate_serialize_map_element(ofstream& out, string map) { t_field kfield(tmap->get_key_type(), iter); generate_serialize_field(out, &kfield, ""); - t_field vfield(tmap->get_val_type(), map + "[" + iter + "]"); + t_field vfield(tmap->get_val_type(), map + ".get(" + iter + ")"); generate_serialize_field(out, &vfield, ""); } @@ -2585,14 +2583,56 @@ string t_haxe_generator::type_name(t_type* ttype, bool in_container, bool in_ini if (ttype->is_base_type()) { return base_type_name((t_base_type*)ttype, in_container); - } else if (ttype->is_enum()) { + } + + if (ttype->is_enum()) { return "Int"; - } else if (ttype->is_map()) { - return "Dictionary"; - } else if (ttype->is_set()) { - return "Set"; - } else if (ttype->is_list()) { - return "Array"; + } + + if (ttype->is_map()) { + t_type* tkey = ((t_map*)ttype)->get_key_type(); + t_type* tval = ((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)+">"; + default: + break; // default to ObjectMap<> + } + } + return "ObjectMap< "+type_name(tkey)+", "+type_name(tval)+">"; + } + + if (ttype->is_set()) { + t_type* tkey = ((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"; + default: + break; // default to ObjectSet + } + } + 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 @@ -2623,7 +2663,7 @@ string t_haxe_generator::base_type_name(t_base_type* type, return "Void"; case t_base_type::TYPE_STRING: if (type->is_binary()) { - return "hyxe.io.Bytes"; + return "haxe.io.Bytes"; } else { return "String"; } @@ -2649,7 +2689,7 @@ string t_haxe_generator::base_type_name(t_base_type* 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()); + 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) { @@ -2695,7 +2735,7 @@ string t_haxe_generator::declare_field(t_field* tfield, bool init) { * @return String of rendered function definition */ string t_haxe_generator::function_signature_callback( t_function* tfunction) { - std::string on_error_success = "onError : Error->Void = null, " + std::string on_error_success = "onError : Dynamic->Void = null, " + generate_service_method_onsuccess(tfunction, true, false); std::string arguments = argument_list(tfunction->get_arglist()); diff --git a/lib/haxe/src/org/apache/thrift/AbstractMethodError.hx b/lib/haxe/src/org/apache/thrift/AbstractMethodError.hx index bc1a3b4f4e6..9fb9bbbaaf4 100644 --- a/lib/haxe/src/org/apache/thrift/AbstractMethodError.hx +++ b/lib/haxe/src/org/apache/thrift/AbstractMethodError.hx @@ -22,14 +22,14 @@ package org.apache.thrift; #if flash import flash.errors.IllegalOperationError; #else -import org.apache.thrift.TError; +import org.apache.thrift.TException; #end class AbstractMethodError #if flash extends IllegalOperationError #else -extends TError +extends TException #end { diff --git a/lib/haxe/src/org/apache/thrift/ArgumentError.hx b/lib/haxe/src/org/apache/thrift/ArgumentError.hx index 14482f45e87..8a5df6f234c 100644 --- a/lib/haxe/src/org/apache/thrift/ArgumentError.hx +++ b/lib/haxe/src/org/apache/thrift/ArgumentError.hx @@ -21,7 +21,7 @@ package org.apache.thrift; #if ! flash // predefined for flash only -class ArgumentError extends Error { +class ArgumentError extends TException { public function new(msg : String = "") { super(msg); } diff --git a/lib/haxe/src/org/apache/thrift/TApplicationError.hx b/lib/haxe/src/org/apache/thrift/TApplicationException.hx similarity index 92% rename from lib/haxe/src/org/apache/thrift/TApplicationError.hx rename to lib/haxe/src/org/apache/thrift/TApplicationException.hx index 1bbb095eea9..012a80280ab 100644 --- a/lib/haxe/src/org/apache/thrift/TApplicationError.hx +++ b/lib/haxe/src/org/apache/thrift/TApplicationException.hx @@ -28,7 +28,7 @@ import org.apache.thrift.protocol.TType; /** * Application level exception */ -class TApplicationError extends TError { +class TApplicationException extends TException { private static var TAPPLICATION_EXCEPTION_STRUCT = { new TStruct("TApplicationException"); }; private static var MESSAGE_FIELD = { new TField("message", TType.STRING, 1); }; @@ -50,7 +50,7 @@ class TApplicationError extends TError { super(message, type); } - public static function read(iprot:TProtocol):TApplicationError { + public static function read(iprot:TProtocol) : TApplicationException { var field:TField; iprot.readStructBegin(); @@ -83,14 +83,14 @@ class TApplicationError extends TError { iprot.readFieldEnd(); } iprot.readStructEnd(); - return new TApplicationError(type, message); + return new TApplicationException(type, message); } public function write(oprot:TProtocol) : Void { oprot.writeStructBegin(TAPPLICATION_EXCEPTION_STRUCT); - if (message != null) { + if (errorMsg != null) { oprot.writeFieldBegin(MESSAGE_FIELD); - oprot.writeString(message); + oprot.writeString(errorMsg); oprot.writeFieldEnd(); } oprot.writeFieldBegin(TYPE_FIELD); diff --git a/lib/haxe/src/org/apache/thrift/TError.hx b/lib/haxe/src/org/apache/thrift/TException.hx similarity index 79% rename from lib/haxe/src/org/apache/thrift/TError.hx rename to lib/haxe/src/org/apache/thrift/TException.hx index e452415d74a..ed630bac241 100644 --- a/lib/haxe/src/org/apache/thrift/TError.hx +++ b/lib/haxe/src/org/apache/thrift/TException.hx @@ -19,12 +19,17 @@ package org.apache.thrift; -import org.apache.thrift.Error; - -class TError extends Error { +class TException { - public function new(msg : String = "", err : Int = 0) { - super( msg, err); - } + @: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/helper/IntSet.hx b/lib/haxe/src/org/apache/thrift/helper/IntSet.hx index ed37c88e054..214f3bd72c6 100644 --- a/lib/haxe/src/org/apache/thrift/helper/IntSet.hx +++ b/lib/haxe/src/org/apache/thrift/helper/IntSet.hx @@ -28,9 +28,11 @@ class IntSet { private var _size : Int = 0; public var size(get,never) : Int; - public function new( values : Array) { - for ( value in values) { - add(value); + public function new( values : Array = null) { + if ( values != null) { + for ( value in values) { + add(value); + } } } diff --git a/lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx b/lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx index 1064ae96b5a..c590c759f93 100644 --- a/lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx +++ b/lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx @@ -28,9 +28,11 @@ class ObjectSet { private var _size : Int = 0; public var size(get,never) : Int; - public function new( values : Array) { - for ( value in values) { - add(value); + public function new( values : Array = null) { + if ( values != null) { + for ( value in values) { + add(value); + } } } diff --git a/lib/haxe/src/org/apache/thrift/helper/StringSet.hx b/lib/haxe/src/org/apache/thrift/helper/StringSet.hx index b2b31b9ec07..ee772c7197c 100644 --- a/lib/haxe/src/org/apache/thrift/helper/StringSet.hx +++ b/lib/haxe/src/org/apache/thrift/helper/StringSet.hx @@ -28,9 +28,11 @@ class StringSet { private var _size : Int = 0; public var size(get,never) : Int; - public function new( values : Array) { - for ( value in values) { - add(value); + public function new( values : Array = null) { + if ( values != null) { + for ( value in values) { + add(value); + } } } diff --git a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx index b30ee02afbd..6dd1bcc726f 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx @@ -25,7 +25,7 @@ import haxe.io.BytesOutput; import haxe.io.BytesBuffer; import haxe.Int64; -import org.apache.thrift.TError; +import org.apache.thrift.TException; import org.apache.thrift.transport.TTransport; /** @@ -176,12 +176,12 @@ class TBinaryProtocol implements TProtocol { if (size < 0) { var version : Int = size & VERSION_MASK; if (version != VERSION_1) { - throw new TProtocolError(TProtocolError.BAD_VERSION, "Bad version in readMessageBegin"); + throw new TProtocolException(TProtocolException.BAD_VERSION, "Bad version in readMessageBegin"); } return new TMessage(readString(), size & 0x000000ff, readI32()); } else { if (strictRead_) { - throw new TProtocolError(TProtocolError.BAD_VERSION, "Missing version in readMessageBegin, old client?"); + throw new TProtocolException(TProtocolException.BAD_VERSION, "Missing version in readMessageBegin, old client?"); } return new TMessage(readStringBody(size), readByte(), readI32()); } diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx index c3977222492..eeca4a364f6 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx @@ -20,7 +20,7 @@ package org.apache.thrift.protocol; import haxe.io.Bytes; -import org.apache.thrift.TError; +import org.apache.thrift.TException; import org.apache.thrift.transport.TTransport; /** diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocolError.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocolException.hx similarity index 94% rename from lib/haxe/src/org/apache/thrift/protocol/TProtocolError.hx rename to lib/haxe/src/org/apache/thrift/protocol/TProtocolException.hx index 0befa53b2c0..dbbcb8cb797 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TProtocolError.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocolException.hx @@ -19,9 +19,9 @@ package org.apache.thrift.protocol; -import org.apache.thrift.TError; +import org.apache.thrift.TException; -class TProtocolError extends TError { +class TProtocolException extends TException { public static inline var UNKNOWN : Int = 0; public static inline var INVALID_DATA : Int = 1; diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocolUtil.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocolUtil.hx index ec93a74a5f8..794e397fd58 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TProtocolUtil.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocolUtil.hx @@ -69,7 +69,7 @@ class TProtocolUtil { */ public static function skipMaxDepth(prot:TProtocol, type : Int, maxDepth : Int) : Void { if (maxDepth <= 0) { - throw new TError("Maximum skip depth exceeded"); + throw new TException("Maximum skip depth exceeded"); } switch (type) { case TType.BOOL: { diff --git a/lib/haxe/src/org/apache/thrift/server/TServer.hx b/lib/haxe/src/org/apache/thrift/server/TServer.hx index 03b62e4cd6c..9b235f69b09 100644 --- a/lib/haxe/src/org/apache/thrift/server/TServer.hx +++ b/lib/haxe/src/org/apache/thrift/server/TServer.hx @@ -15,10 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * - * Contains some contributions under the Thrift Software License. - * Please see doc/old-thrift-license.txt in the Thrift distribution for - * details. */ package org.apache.thrift.server; diff --git a/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx b/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx index 1b9479e35b8..08f48b2a69e 100644 --- a/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx +++ b/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx @@ -15,10 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * - * Contains some contributions under the Thrift Software License. - * Please see doc/old-thrift-license.txt in the Thrift distribution for - * details. */ package org.apache.thrift.server; diff --git a/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx b/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx index 5e2b1f17197..20a71950327 100644 --- a/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx +++ b/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx @@ -15,10 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * - * Contains some contributions under the Thrift Software License. - * Please see doc/old-thrift-license.txt in the Thrift distribution for - * details. */ package org.apache.thrift.server; @@ -52,7 +48,7 @@ class TSimpleServer extends TServer { { serverTransport.Listen(); } - catch (ttx : TTransportError) + catch (ttx : TTransportException) { logDelegate(ttx); return; @@ -104,7 +100,7 @@ class TSimpleServer extends TServer { } } } - catch( ttx : TTransportError) + catch( ttx : TTransportException) { // Usually a client disconnect, expected } diff --git a/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx index 68a5c09da1d..5d77140ba27 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx @@ -105,10 +105,10 @@ class TFramedTransport extends TTransport var size : Int = readFrameSize(); if (size < 0) { - throw new TTransportError(TTransportError.UNKNOWN, 'Read a negative frame size ($size)!'); + throw new TTransportException(TTransportException.UNKNOWN, 'Read a negative frame size ($size)!'); }; if (size > maxLength_) { - throw new TTransportError(TTransportError.UNKNOWN, 'Frame size ($size) larger than max length ($maxLength_)!'); + throw new TTransportException(TTransportException.UNKNOWN, 'Frame size ($size) larger than max length ($maxLength_)!'); }; var buffer = new BytesBuffer(); @@ -128,7 +128,7 @@ class TFramedTransport extends TTransport transport_.write(out.getBytes(), 0, 4); } - public override function flush( callback : Error->Void =null) : Void { + public override function flush( callback : Dynamic->Void =null) : Void { var buf : Bytes = writeBuffer_.getBytes(); var len : Int = buf.length; writeBuffer_ = new BytesOutput(); diff --git a/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx index 8953fd6a958..4e898f89b72 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx @@ -53,7 +53,7 @@ import flash.events.EventDispatcher; private var output : IDataOutput; private var bytesInChunk : Int = 0; private var CRLF : Bytes = new Bytes(); - private var ioCallback : TError->Void = null; + private var ioCallback : TException->Void = null; private var eventDispatcher : EventDispatcher = new EventDispatcher(); public function new(host : String, port : Int, resource : String) : Void @@ -135,22 +135,22 @@ import flash.events.EventDispatcher; catch (e : EOFError) { trace(e); - throw new TTransportError(TTransportError.UNKNOWN, "No more data available."); + throw new TTransportException(TTransportException.UNKNOWN, "No more data available."); } - catch (e : TError) + catch (e : TException) { - trace('TError $e'); + trace('TException $e'); throw e; } catch (e : Error) { trace(e); - throw new TTransportError(TTransportError.UNKNOWN, 'Bad IO error: $e'); + throw new TTransportException(TTransportException.UNKNOWN, 'Bad IO error: $e'); } catch (e : Dynamic) { trace(e); - throw new TTransportError(TTransportError.UNKNOWN, 'Bad IO error: $e'); + throw new TTransportException(TTransportException.UNKNOWN, 'Bad IO error: $e'); } return 0; } @@ -204,7 +204,7 @@ import flash.events.EventDispatcher; { return; } - ioCallback(new TTransportError(TTransportError.UNKNOWN, "IOError : " + event.text)); + ioCallback(new TTransportException(TTransportException.UNKNOWN, "IOError : " + event.text)); this.eventDispatcher.dispatchEvent(event); } diff --git a/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx index aafb6ef0ca4..d2fda79f72b 100644 --- a/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx +++ b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx @@ -97,7 +97,7 @@ class THttpClient extends TTransport { public override function read(buf:BytesBuffer, off : Int, len : Int) : Int { if (responseBuffer_ == null) { - throw new TTransportError(TTransportError.UNKNOWN, "Response buffer is empty, no request."); + throw new TTransportException(TTransportException.UNKNOWN, "Response buffer is empty, no request."); } #if flash @@ -107,7 +107,7 @@ class THttpClient extends TTransport { buf.addBytes(data,0,len); return len; } catch (e : EOFError) { - throw new TTransportError(TTransportError.UNKNOWN, "No more data available."); + throw new TTransportException(TTransportException.UNKNOWN, "No more data available."); } #else @@ -136,11 +136,11 @@ class THttpClient extends TTransport { callback(null); }); loader.addEventListener(IOErrorEvent.IO_ERROR, function(event:IOErrorEvent) : Void { - callback(new TTransportError(TTransportError.UNKNOWN, "IOError: " + event.text)); + callback(new TTransportException(TTransportException.UNKNOWN, "IOError: " + event.text)); responseBuffer_ = null; }); loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(event:SecurityErrorEvent) : Void { - callback(new TTransportError(TTransportError.UNKNOWN, "SecurityError: " + event.text)); + callback(new TTransportException(TTransportException.UNKNOWN, "SecurityError: " + event.text)); responseBuffer_ = null; }); } @@ -154,7 +154,7 @@ class THttpClient extends TTransport { #else - public override function flush(callback:Error->Void = null) : Void { + public override function flush(callback:Dynamic->Void = null) : Void { var buffer = requestBuffer_; requestBuffer_ = new BytesOutput(); @@ -165,7 +165,7 @@ class THttpClient extends TTransport { callback(null); }; request_.onError = function(msg : String) { - callback(new TTransportError(TTransportError.UNKNOWN, "IOError: " + msg)); + callback(new TTransportException(TTransportException.UNKNOWN, "IOError: " + msg)); }; #if js diff --git a/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx index a0f29a217b5..1953244a0f6 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx @@ -15,10 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * - * Contains some contributions under the Thrift Software License. - * Please see doc/old-thrift-license.txt in the Thrift distribution for - * details. */ package org.apache.thrift.transport; @@ -67,7 +63,7 @@ class TServerSocket extends TServerTransport { catch (e : Dynamic) { _socket = null; - throw new TTransportError( TTransportError.UNKNOWN, 'Could not create ServerSocket on port $port: $e'); + throw new TTransportException( TTransportException.UNKNOWN, 'Could not create ServerSocket on port $port: $e'); } } @@ -83,7 +79,7 @@ class TServerSocket extends TServerTransport { catch (e : Dynamic) { trace('Error $e'); - throw new TTransportError( TTransportError.UNKNOWN, 'Could not accept on listening socket: $e'); + throw new TTransportException( TTransportException.UNKNOWN, 'Could not accept on listening socket: $e'); } } } @@ -91,7 +87,7 @@ class TServerSocket extends TServerTransport { private override function AcceptImpl() : TTransport { if (_socket == null) { - throw new TTransportError( TTransportError.NOT_OPEN, "No underlying server socket."); + throw new TTransportException( TTransportException.NOT_OPEN, "No underlying server socket."); } try @@ -111,7 +107,7 @@ class TServerSocket extends TServerTransport { catch (e : Dynamic) { trace('Error $e'); - throw new TTransportError( TTransportError.UNKNOWN, '$e'); + throw new TTransportException( TTransportException.UNKNOWN, '$e'); } } @@ -126,7 +122,7 @@ class TServerSocket extends TServerTransport { catch (e : Dynamic) { trace('Error $e'); - throw new TTransportError( TTransportError.UNKNOWN, 'WARNING: Could not close server socket: $e'); + throw new TTransportException( TTransportException.UNKNOWN, 'WARNING: Could not close server socket: $e'); } _socket = null; } diff --git a/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx index bd1b5dc8985..e0ce6972093 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx @@ -15,10 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * - * Contains some contributions under the Thrift Software License. - * Please see doc/old-thrift-license.txt in the Thrift distribution for - * details. */ package org.apache.thrift.transport; @@ -28,7 +24,7 @@ class TServerTransport { public function Accept() : TTransport { var transport = AcceptImpl(); if (transport == null) { - throw new TTransportError( TTransportError.UNKNOWN, "accept() may not return NULL"); + throw new TTransportException( TTransportException.UNKNOWN, "accept() may not return NULL"); } return transport; } diff --git a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx index 185b0cc4cf0..306730d9542 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx @@ -74,7 +74,7 @@ class TSocket extends TTransport { #end private var obuffer : BytesOutput = new BytesOutput(); - private var ioCallback : TError->Void = null; + private var ioCallback : TException->Void = null; private var readCount : Int = 0; public function new(host : String, port : Int) : Void { @@ -132,7 +132,7 @@ class TSocket extends TTransport { #elseif js if( input == null) { - throw new TTransportError(TTransportError.UNKNOWN, "Still no data "); // don't block + throw new TTransportException(TTransportException.UNKNOWN, "Still no data "); // don't block } var nr = len; while( nr < len) { @@ -158,22 +158,17 @@ class TSocket extends TTransport { catch (e : Eof) { trace('Eof $e'); - throw new TTransportError(TTransportError.END_OF_FILE, "No more data available."); + throw new TTransportException(TTransportException.END_OF_FILE, "No more data available."); } - catch (e : TError) + catch (e : TException) { - trace('TError $e'); + trace('TException $e'); throw e; } - catch (e : Error) - { - trace('Error $e'); - throw new TTransportError(TTransportError.UNKNOWN, 'Bad IO error : $e'); - } catch (e : Dynamic) { trace('Error $e'); - throw new TTransportError(TTransportError.UNKNOWN, 'Bad IO error : $e'); + throw new TTransportException(TTransportException.UNKNOWN, 'Bad IO error : $e'); } } @@ -185,11 +180,11 @@ class TSocket extends TTransport { - public override function flush(callback : Error->Void = null) : Void + public override function flush(callback : Dynamic->Void = null) : Void { if( ! isOpen()) { - throw new TTransportError(TTransportError.NOT_OPEN, "Transport not open"); + throw new TTransportException(TTransportException.NOT_OPEN, "Transport not open"); } #if flash @@ -236,24 +231,17 @@ class TSocket extends TTransport { ioCallback(null); // success call } } - catch (e : TError) + catch (e : TException) { - trace('TError $e'); + trace('TException $e'); if(ioCallback != null) { ioCallback(e); } } - catch (e : Error) - { - trace('Error $e'); - if(ioCallback != null) { - ioCallback(new TTransportError(TTransportError.UNKNOWN, 'Bad IO error : $e')); - } - } catch (e : Dynamic) { trace(e); if(ioCallback != null) { - ioCallback(new TTransportError(TTransportError.UNKNOWN, 'Bad IO error : $e')); + ioCallback(new TTransportException(TTransportException.UNKNOWN, 'Bad IO error : $e')); } } } diff --git a/lib/haxe/src/org/apache/thrift/transport/TTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TTransport.hx index c4994022498..35303d5d414 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TTransport.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TTransport.hx @@ -87,7 +87,7 @@ class TTransport { while (got < len) { ret = read(buf, off+got, len-got); if (ret <= 0) { - throw new TTransportError(TTransportError.UNKNOWN, + throw new TTransportException(TTransportException.UNKNOWN, "Cannot read. Remote side has closed. Tried to read " + len + " bytes, but only got " + got + " bytes."); } @@ -123,8 +123,11 @@ class TTransport { * * @throws TTransportException if there was an error writing out data. */ - public function flush(callback:Error->Void =null) : Void { - throw new AbstractMethodError(); + 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/TTransportError.hx b/lib/haxe/src/org/apache/thrift/transport/TTransportException.hx similarity index 93% rename from lib/haxe/src/org/apache/thrift/transport/TTransportError.hx rename to lib/haxe/src/org/apache/thrift/transport/TTransportException.hx index c4e49548557..3db64569e98 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TTransportError.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TTransportException.hx @@ -19,9 +19,9 @@ package org.apache.thrift.transport; -import org.apache.thrift.TError; +import org.apache.thrift.TException; -class TTransportError extends TError { +class TTransportException extends TException { public static inline var UNKNOWN : Int = 0; public static inline var NOT_OPEN : Int = 1; diff --git a/test/haxe/cpp.hxml b/test/haxe/cpp.hxml new file mode 100644 index 00000000000..6adb52d7e33 --- /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 00000000000..295c017e739 --- /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 00000000000..a1f0568ad4a --- /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 00000000000..c615565a9a6 --- /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 00000000000..b2b3876cf15 --- /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 00000000000..c9e8f501048 --- /dev/null +++ b/test/haxe/make_all.bat @@ -0,0 +1,44 @@ +@echo off +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 + +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 + +:eof diff --git a/test/haxe/make_all.sh b/test/haxe/make_all.sh new file mode 100644 index 00000000000..27a1f1d9135 --- /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 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/test/haxe/neko.hxml b/test/haxe/neko.hxml new file mode 100644 index 00000000000..6161f69773c --- /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 00000000000..1eaac8b2b94 --- /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 00000000000..0a8fc6c60e9 --- /dev/null +++ b/test/haxe/project.hide @@ -0,0 +1,121 @@ +{ + "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" + } + ,{ + "pathToHxml" : "java.hxml" + } + ,{ + "pathToHxml" : "csharp.hxml" + } + ,{ + "pathToHxml" : "python.hxml" + ,"runActionType" : 2 + ,"runActionText" : "python bin/Tutorial.py" + } + ] + ,"files" : [ + { + "path" : "gen-haxe\\thrift\\test\\ThriftTestImpl.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 3879 + } + ,{ + "path" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\server\\TSimpleServer.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 102 + } + ,{ + "path" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\transport\\TServerTransport.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 26 + } + ,{ + "path" : "src\\TestClient.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 37 + } + ,{ + "path" : "src\\TestServer.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 33 + } + ,{ + "path" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\helper\\IntSet.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 31 + } + ,{ + "path" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\protocol\\TProtocolException.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 23 + } + ] + ,"activeFile" : "src\\TestClient.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 00000000000..f2c19fa93e1 --- /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 00000000000..ddb647a20cc --- /dev/null +++ b/test/haxe/src/Arguments.hx @@ -0,0 +1,173 @@ +/* + * 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(e); + trace(GetHelp()); + return; + } + #else + trace("WN: Platform does not support program arguments, using defaults."); + #end + } + + #if sys + + 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"; + */ + return "TODO: help screen"; + } + + + 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.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 00000000000..08591b81e4b --- /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 Program +{ + 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 00000000000..df837a64218 --- /dev/null +++ b/test/haxe/src/TestClient.hx @@ -0,0 +1,409 @@ +/* + * 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 TestClient { + + public static function Execute(args : Arguments) : Void + { + try + { + //issue tests on separate threads simultaneously + Thread[] threads = new Thread[numThreads]; + DateTime start = DateTime.Now; + for( test in 0 .. (numThreads-1)) + { + Thread t = new Thread(new ParameterizedThreadStart(ClientThread)); + threads[test] = t; + if (url == null) + { + // endpoint transport + TTransport trans = null; + if (pipe != null) + trans = new TNamedPipeClientTransport(pipe); + else + { + if (encrypted) + trans = new TTLSSocket(host, port, "../../../../../keys/client.pem"); + else + trans = new TSocket(host, port); + } + + // layered transport + if (buffered) + trans = new TBufferedTransport(trans as TStreamTransport); + if (framed) + trans = new TFramedTransport(trans); + + //ensure proper open/close of transport + trans.Open(); + trans.Close(); + t.Start(trans); + } + else + { + THttpClient http = new THttpClient(new Uri(url)); + t.Start(http); + } + } + + for (int test = 0; test < numThreads; test++) + { + threads[test].Join(); + } + Console.Write("Total time: " + (DateTime.Now - start)); + } + catch (Exception outerEx) + { + Console.WriteLine(outerEx.Message + " ST: " + outerEx.StackTrace); + } + + Console.WriteLine(); + Console.WriteLine(); + } + + public static void ClientThread(object obj) + { + TTransport transport = (TTransport)obj; + for (int i = 0; i < numIterations; i++) + { + ClientTest(transport); + } + transport.Close(); + } + + public static void ClientTest(TTransport transport) + { + TProtocol proto; + if (protocol == "compact") + proto = new TCompactProtocol(transport); + else if (protocol == "json") + proto = new TJSONProtocol(transport); + else + proto = new TBinaryProtocol(transport); + + ThriftTest.Client client = new ThriftTest.Client(proto); + try + { + if (!transport.IsOpen) + { + transport.Open(); + } + } + catch (TTransportException ttx) + { + Console.WriteLine("Connect failed: " + ttx.Message); + return; + } + + long start = DateTime.Now.ToFileTime(); + + Console.Write("testVoid()"); + client.testVoid(); + Console.WriteLine(" = void"); + + Console.Write("testString(\"Test\")"); + string s = client.testString("Test"); + Console.WriteLine(" = \"" + s + "\""); + + Console.Write("testByte(1)"); + sbyte i8 = client.testByte((sbyte)1); + Console.WriteLine(" = " + i8); + + Console.Write("testI32(-1)"); + int i32 = client.testI32(-1); + Console.WriteLine(" = " + i32); + + Console.Write("testI64(-34359738368)"); + long i64 = client.testI64(-34359738368); + Console.WriteLine(" = " + i64); + + Console.Write("testDouble(5.325098235)"); + double dub = client.testDouble(5.325098235); + Console.WriteLine(" = " + dub); + + Console.Write("testStruct({\"Zero\", 1, -3, -5})"); + Xtruct o = new Xtruct(); + o.String_thing = "Zero"; + o.Byte_thing = (sbyte)1; + o.I32_thing = -3; + o.I64_thing = -5; + Xtruct i = client.testStruct(o); + Console.WriteLine(" = {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}"); + + Console.Write("testNest({1, {\"Zero\", 1, -3, -5}, 5})"); + Xtruct2 o2 = new Xtruct2(); + o2.Byte_thing = (sbyte)1; + o2.Struct_thing = o; + o2.I32_thing = 5; + Xtruct2 i2 = client.testNest(o2); + i = i2.Struct_thing; + Console.WriteLine(" = {" + i2.Byte_thing + ", {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}, " + i2.I32_thing + "}"); + + Dictionary mapout = new Dictionary(); + for (int j = 0; j < 5; j++) + { + mapout[j] = j - 10; + } + Console.Write("testMap({"); + bool first = true; + foreach (int key in mapout.Keys) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(key + " => " + mapout[key]); + } + Console.Write("})"); + + Dictionary mapin = client.testMap(mapout); + + Console.Write(" = {"); + first = true; + foreach (int key in mapin.Keys) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(key + " => " + mapin[key]); + } + Console.WriteLine("}"); + + List listout = new List(); + for (int j = -2; j < 3; j++) + { + listout.Add(j); + } + Console.Write("testList({"); + first = true; + foreach (int j in listout) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(j); + } + Console.Write("})"); + + List listin = client.testList(listout); + + Console.Write(" = {"); + first = true; + foreach (int j in listin) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(j); + } + Console.WriteLine("}"); + + //set + THashSet setout = new THashSet(); + for (int j = -2; j < 3; j++) + { + setout.Add(j); + } + Console.Write("testSet({"); + first = true; + foreach (int j in setout) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(j); + } + Console.Write("})"); + + THashSet setin = client.testSet(setout); + + Console.Write(" = {"); + first = true; + foreach (int j in setin) + { + if (first) + { + first = false; + } + else + { + Console.Write(", "); + } + Console.Write(j); + } + Console.WriteLine("}"); + + + Console.Write("testEnum(ONE)"); + Numberz ret = client.testEnum(Numberz.ONE); + Console.WriteLine(" = " + ret); + + Console.Write("testEnum(TWO)"); + ret = client.testEnum(Numberz.TWO); + Console.WriteLine(" = " + ret); + + Console.Write("testEnum(THREE)"); + ret = client.testEnum(Numberz.THREE); + Console.WriteLine(" = " + ret); + + Console.Write("testEnum(FIVE)"); + ret = client.testEnum(Numberz.FIVE); + Console.WriteLine(" = " + ret); + + Console.Write("testEnum(EIGHT)"); + ret = client.testEnum(Numberz.EIGHT); + Console.WriteLine(" = " + ret); + + Console.Write("testTypedef(309858235082523)"); + long uid = client.testTypedef(309858235082523L); + Console.WriteLine(" = " + uid); + + Console.Write("testMapMap(1)"); + Dictionary> mm = client.testMapMap(1); + Console.Write(" = {"); + foreach (int key in mm.Keys) + { + Console.Write(key + " => {"); + Dictionary m2 = mm[key]; + foreach (int k2 in m2.Keys) + { + Console.Write(k2 + " => " + m2[k2] + ", "); + } + Console.Write("}, "); + } + Console.WriteLine("}"); + + Insanity insane = new Insanity(); + insane.UserMap = new Dictionary(); + insane.UserMap[Numberz.FIVE] = 5000L; + Xtruct truck = new Xtruct(); + truck.String_thing = "Truck"; + truck.Byte_thing = (sbyte)8; + truck.I32_thing = 8; + truck.I64_thing = 8; + insane.Xtructs = new List(); + insane.Xtructs.Add(truck); + Console.Write("testInsanity()"); + Dictionary> whoa = client.testInsanity(insane); + Console.Write(" = {"); + foreach (long key in whoa.Keys) + { + Dictionary val = whoa[key]; + Console.Write(key + " => {"); + + foreach (Numberz k2 in val.Keys) + { + Insanity v2 = val[k2]; + + Console.Write(k2 + " => {"); + Dictionary userMap = v2.UserMap; + + Console.Write("{"); + if (userMap != null) + { + foreach (Numberz k3 in userMap.Keys) + { + Console.Write(k3 + " => " + userMap[k3] + ", "); + } + } + else + { + Console.Write("null"); + } + Console.Write("}, "); + + List xtructs = v2.Xtructs; + + Console.Write("{"); + if (xtructs != null) + { + foreach (Xtruct x in xtructs) + { + Console.Write("{\"" + x.String_thing + "\", " + x.Byte_thing + ", " + x.I32_thing + ", " + x.I32_thing + "}, "); + } + } + else + { + Console.Write("null"); + } + Console.Write("}"); + + Console.Write("}, "); + } + Console.Write("}, "); + } + Console.WriteLine("}"); + + sbyte arg0 = 1; + int arg1 = 2; + long arg2 = long.MaxValue; + Dictionary multiDict = new Dictionary(); + multiDict[1] = "one"; + Numberz arg4 = Numberz.FIVE; + long arg5 = 5000000; + Console.Write("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + "," + multiDict + "," + arg4 + "," + arg5 + ")"); + Xtruct multiResponse = client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5); + Console.Write(" = Xtruct(byte_thing:" + multiResponse.Byte_thing + ",String_thing:" + multiResponse.String_thing + + ",i32_thing:" + multiResponse.I32_thing + ",i64_thing:" + multiResponse.I64_thing + ")\n"); + + Console.WriteLine("Test Oneway(1)"); + client.testOneway(1); + + Console.Write("Test Calltime()"); + var startt = DateTime.UtcNow; + for ( int k=0; k<1000; ++k ) + client.testVoid(); + Console.WriteLine(" = " + (DateTime.UtcNow - startt).TotalSeconds.ToString() + " ms a testVoid() call" ); + } +} diff --git a/test/haxe/src/TestServer.hx b/test/haxe/src/TestServer.hx new file mode 100644 index 00000000000..81f8e04391e --- /dev/null +++ b/test/haxe/src/TestServer.hx @@ -0,0 +1,107 @@ +/* + * 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 THttpClient( 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("- binary json"); + throw "JSON protocol not implemented yet"; + //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/lib/haxe/src/org/apache/thrift/Error.hx b/test/haxe/src/TestServerEventHandler.hx similarity index 51% rename from lib/haxe/src/org/apache/thrift/Error.hx rename to test/haxe/src/TestServerEventHandler.hx index 9925c447232..2facf85356d 100644 --- a/lib/haxe/src/org/apache/thrift/Error.hx +++ b/test/haxe/src/TestServerEventHandler.hx @@ -16,40 +16,38 @@ * specific language governing permissions and limitations * under the License. */ - -package org.apache.thrift; - -// there seems no built-in equivalent for the Error object in Haxe (or it is very well hidden) -// http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Error.html -class Error { - private var _id : Int; - private var _msg : String; - - public var errorID(get,never) : Int; - public var message(get,never) : String; - private var name(default,null) : String; // NOT IMPLEMENTED +package; - - function new(message : String = "", id : Int = 0) { - //super(); - _id = id; - _msg = message; +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 + + +public class TestServerEventHandler : TServerEventHandler +{ + public int callCount = 0; + public void preServe() + { + callCount++; } - - function get_errorID() : Int { - return _id; + public Object createContext(Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output) + { + callCount++; + return null; } - - function get_message() : String { - return _msg; + public void deleteContext(Object serverContext, Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output) + { + callCount++; } - - - // NOT IMPLEMENTED - // see http://haxe.org/manual/cr-rtti-structure.html - private function get_name() : String { - throw "not implemented"; + 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 00000000000..a72f0513743 --- /dev/null +++ b/test/haxe/src/TestServerHandler.hx @@ -0,0 +1,496 @@ +/* + * 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.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. + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + function testStruct(thing : Xtruct) : Xtruct + { + trace("testStruct({" + + "\"" + thing.String_thing + "\", " + + thing.Byte_thing + ", " + + thing.I32_thing + ", " + + 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 + */ + function testNest(thing : Xtruct2) : Xtruct2 + { + var thing : Xtruct = nest.Struct_thing; + trace("testNest({" + + nest.Byte_thing + ", {" + + "\"" + thing.String_thing + "\", " + + thing.Byte_thing + ", " + + thing.I32_thing + ", " + + 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 thing - the map to print + * @return map - returns the map 'thing' + * + * @param thing + */ + 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[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 thing - the map to print + * @return map - returns the map 'thing' + * + * @param thing + */ + 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[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 thing - the set to print + * @return set - returns the set 'thing' + * + * @param thing + */ + 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 thing - the list to print + * @return list - returns the list 'thing' + * + * @param thing + */ + 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 + */ + 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 + */ + 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> - 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 + */ + function testMapMap(hello : haxe.Int32) : IntMap< IntMap< haxe.Int32>> + { + trace("testMapMap(" + hello + ")"); + var mapmap = new IntMap< IntMap< Int, Int>>(); + + var pos = new IntMap< Int>(); + var neg = new IntMap< Int>(); + for( i in 1 ... 4) + { + pos[i] = i; + neg[-i] = -i; + } + + mapmap[4] = pos; + mapmap[-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 => , }, + * } + * @return map> - a map with the above values + * + * @param argument + */ + function testInsanity(argument : Insanity) : ObjectMap< haxe.Int64, ObjectMap< Int, Insanity>> + { + trace("testInsanity()"); + + var hello = new Xtruct(); + hello.String_thing = "Hello2"; + hello.Byte_thing = 2; + hello.I32_thing = 2; + hello.I64_thing = 2; + + var goodbye = new Xtruct(); + goodbye.String_thing = "Goodbye4"; + goodbye.Byte_thing = 4; + goodbye.I32_thing = 4; + goodbye.I64_thing = 4; + + var crazy = new Insanity(); + crazy.UserMap = new ObjectMap< Numberz, haxe.Int32>(); + crazy.UserMap[Numberz.EIGHT] = 8; + crazy.Xtructs = new List(); + crazy.Xtructs.Add(goodbye); + + var looney = new Insanity(); + crazy.UserMap[Numberz.FIVE] = 5; + crazy.Xtructs.Add(hello); + + var first_map = new ObjectMap< Numberz, Insanity>(); + var second_map = new ObjectMap< Numberz, Insanity>(); + + first_map[Numberz.TWO] = crazy; + first_map[Numberz.THREE] = crazy; + + second_map[Numberz.SIX] = looney; + + var insane = new IntMap< ObjectMap< Numberz, Insanity>>(); + insane[1] = first_map; + insane[2] = second_map; + + return insane; + } + + /** + * Prints 'testMulti()' + * @param byte arg0 - + * @param i32 arg1 - + * @param i64 arg2 - + * @param map 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 + */ + 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 + */ + function testException(arg : String) : Void + { + trace("testException(" + arg + ")"); + if (arg == "Xception") + { + var x = new Xception(); + x.ErrorCode = 1001; + x.Message = "This is an Xception"; + throw x; + } + 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 + */ + 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 + */ + function testOneway(secondsToSleep : haxe.Int32) : Void + { + trace("testOneway(" + arg + "), sleeping..."); + System.Threading.Thread.Sleep(arg * 1000); + trace("testOneway finished"); + } + + + public function testStop() : Void + { + if (server != null) + { + server.Stop(); + } + } + +} + diff --git a/tutorial/haxe/project.hide b/tutorial/haxe/project.hide index 6d23a0a1e8c..4b724c87bcd 100644 --- a/tutorial/haxe/project.hide +++ b/tutorial/haxe/project.hide @@ -82,15 +82,6 @@ ] ,"activeLine" : 79 } - ,{ - "path" : "gen-haxe\\tutorial\\CalculatorProcessor.hx" - ,"useTabs" : true - ,"indentSize" : 4 - ,"foldedRegions" : [ - - ] - ,"activeLine" : 136 - } ,{ "path" : "src\\Main.hx" ,"useTabs" : true @@ -98,34 +89,7 @@ ,"foldedRegions" : [ ] - ,"activeLine" : 235 - } - ,{ - "path" : "gen-haxe\\tutorial\\CalculatorImpl.hx" - ,"useTabs" : true - ,"indentSize" : 4 - ,"foldedRegions" : [ - - ] - ,"activeLine" : 17 - } - ,{ - "path" : "gen-haxe\\shared\\SharedServiceImpl.hx" - ,"useTabs" : true - ,"indentSize" : 4 - ,"foldedRegions" : [ - - ] - ,"activeLine" : 0 - } - ,{ - "path" : "src\\CalculatorHandler.hx" - ,"useTabs" : true - ,"indentSize" : 4 - ,"foldedRegions" : [ - - ] - ,"activeLine" : 95 + ,"activeLine" : 16 } ] ,"activeFile" : "src\\Main.hx" diff --git a/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx index 3a2803cff5e..356f20dca71 100644 --- a/tutorial/haxe/src/Main.hx +++ b/tutorial/haxe/src/Main.hx @@ -204,7 +204,7 @@ class Main { try { client.ping(); trace("ping() successful"); - } catch(error : TError) { + } catch(error : TException) { trace('ping() failed: $error'); } catch(error : Dynamic) { trace('ping() failed: $error'); @@ -213,7 +213,7 @@ class Main { try { var sum = client.add( 1, 1); trace('1+1=$sum'); - } catch(error : TError) { + } catch(error : TException) { trace('add() failed: $error'); } catch(error : Dynamic) { trace('add() failed: $error'); @@ -227,7 +227,7 @@ class Main { try { var quotient = client.calculate( 1, work); trace('Whoa we can divide by 0! Result = $quotient'); - } catch(error : TError) { + } catch(error : TException) { trace('calculate() failed: $error'); } catch(error : Dynamic) { trace('calculate() failed: $error'); @@ -239,7 +239,7 @@ class Main { try { var diff = client.calculate( 1, work); trace('15-10=$diff'); - } catch(error : TError) { + } catch(error : TException) { trace('calculate() failed: $error'); } catch(error : Dynamic) { trace('calculate() failed: $error'); @@ -250,7 +250,7 @@ class Main { var log : SharedStruct = client.getStruct( 1); var logval = log.value; trace('Check log: $logval'); - } catch(error : TError) { + } catch(error : TException) { trace('getStruct() failed: $error'); } catch(error : Dynamic) { trace('getStruct() failed: $error'); @@ -280,7 +280,7 @@ class Main { throw "Unhandled transport"; } - // optinal layered transport + // optional: layered transport var transfactory : TTransportFactory = null; if ( framed) { trace("- framed transport"); From ab2e974c880e21f91057c51c5cc22cf287be7a26 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Fri, 15 Aug 2014 19:18:14 +0200 Subject: [PATCH 13/24] added test client/server code compiles (C++), not fully tested yet --- .gitignore | 3 +- compiler/cpp/src/generate/t_haxe_generator.cc | 16 +- test/haxe/make_all.bat | 24 + test/haxe/project.hide | 46 +- test/haxe/src/Main.hx | 2 +- test/haxe/src/TestClient.hx | 502 ++++++++++-------- test/haxe/src/TestServer.hx | 4 +- test/haxe/src/TestServerHandler.hx | 497 ++++++++--------- tutorial/haxe/make_all.bat | 24 + 9 files changed, 579 insertions(+), 539 deletions(-) diff --git a/.gitignore b/.gitignore index 073a01f7f97..b4c2de8c241 100644 --- a/.gitignore +++ b/.gitignore @@ -216,6 +216,7 @@ test-driver /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/ @@ -236,9 +237,9 @@ test-driver /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/ /ylwrap -/tutorial/haxe/bin diff --git a/compiler/cpp/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc index 54d7558806b..d8a6adb9676 100644 --- a/compiler/cpp/src/generate/t_haxe_generator.cc +++ b/compiler/cpp/src/generate/t_haxe_generator.cc @@ -2592,8 +2592,8 @@ string t_haxe_generator::type_name(t_type* ttype, bool in_container, bool in_ini if (ttype->is_map()) { t_type* tkey = ((t_map*)ttype)->get_key_type(); t_type* tval = ((t_map*)ttype)->get_val_type(); - if( tkey->is_base_type()) { - t_base_type::t_base tbase = ((t_base_type*)tkey)->get_base(); + 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())) { @@ -2606,8 +2606,11 @@ string t_haxe_generator::type_name(t_type* ttype, bool in_container, bool in_ini default: break; // default to ObjectMap<> } - } - return "ObjectMap< "+type_name(tkey)+", "+type_name(tval)+">"; + } + if (tkey->is_enum()) { + return "IntMap< " + type_name(tval) + ">"; + } + return "ObjectMap< " + type_name(tkey) + ", " + type_name(tval) + ">"; } if (ttype->is_set()) { @@ -2627,7 +2630,10 @@ string t_haxe_generator::type_name(t_type* ttype, bool in_container, bool in_ini break; // default to ObjectSet } } - return "ObjectSet< "+type_name(tkey)+">"; + if (tkey->is_enum()) { + return "IntSet"; + } + return "ObjectSet< " + type_name(tkey) + ">"; } if (ttype->is_list()) { diff --git a/test/haxe/make_all.bat b/test/haxe/make_all.bat index c9e8f501048..eaeba890d42 100644 --- a/test/haxe/make_all.bat +++ b/test/haxe/make_all.bat @@ -1,4 +1,23 @@ @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 @@ -8,6 +27,7 @@ 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 ( @@ -41,4 +61,8 @@ echo HOMEPATH=%HOMEPATH% pause goto eof +:STOP +pause +goto eof + :eof diff --git a/test/haxe/project.hide b/test/haxe/project.hide index 0a8fc6c60e9..be134a9c8ff 100644 --- a/test/haxe/project.hide +++ b/test/haxe/project.hide @@ -45,40 +45,13 @@ ] ,"files" : [ { - "path" : "gen-haxe\\thrift\\test\\ThriftTestImpl.hx" + "path" : "src\\Arguments.hx" ,"useTabs" : true ,"indentSize" : 4 ,"foldedRegions" : [ ] - ,"activeLine" : 3879 - } - ,{ - "path" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\server\\TSimpleServer.hx" - ,"useTabs" : true - ,"indentSize" : 4 - ,"foldedRegions" : [ - - ] - ,"activeLine" : 102 - } - ,{ - "path" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\transport\\TServerTransport.hx" - ,"useTabs" : true - ,"indentSize" : 4 - ,"foldedRegions" : [ - - ] - ,"activeLine" : 26 - } - ,{ - "path" : "src\\TestClient.hx" - ,"useTabs" : true - ,"indentSize" : 4 - ,"foldedRegions" : [ - - ] - ,"activeLine" : 37 + ,"activeLine" : 47 } ,{ "path" : "src\\TestServer.hx" @@ -87,25 +60,16 @@ ,"foldedRegions" : [ ] - ,"activeLine" : 33 + ,"activeLine" : 70 } ,{ - "path" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\helper\\IntSet.hx" - ,"useTabs" : true - ,"indentSize" : 4 - ,"foldedRegions" : [ - - ] - ,"activeLine" : 31 - } - ,{ - "path" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\protocol\\TProtocolException.hx" + "path" : "src\\TestClient.hx" ,"useTabs" : true ,"indentSize" : 4 ,"foldedRegions" : [ ] - ,"activeLine" : 23 + ,"activeLine" : 229 } ] ,"activeFile" : "src\\TestClient.hx" diff --git a/test/haxe/src/Main.hx b/test/haxe/src/Main.hx index 08591b81e4b..a8ad147a27c 100644 --- a/test/haxe/src/Main.hx +++ b/test/haxe/src/Main.hx @@ -28,7 +28,7 @@ import org.apache.thrift.meta_data.*; import thrift.test.*; // generated code -class Program +class Main { static function main() { try { diff --git a/test/haxe/src/TestClient.hx b/test/haxe/src/TestClient.hx index df837a64218..20ad6bdf544 100644 --- a/test/haxe/src/TestClient.hx +++ b/test/haxe/src/TestClient.hx @@ -19,12 +19,25 @@ package; +import haxe.Int32; +import haxe.Int64; +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 @@ -34,146 +47,178 @@ class TestClient { { try { - //issue tests on separate threads simultaneously - Thread[] threads = new Thread[numThreads]; - DateTime start = DateTime.Now; - for( test in 0 .. (numThreads-1)) - { - Thread t = new Thread(new ParameterizedThreadStart(ClientThread)); - threads[test] = t; - if (url == null) - { - // endpoint transport - TTransport trans = null; - if (pipe != null) - trans = new TNamedPipeClientTransport(pipe); - else - { - if (encrypted) - trans = new TTLSSocket(host, port, "../../../../../keys/client.pem"); - else - trans = new TSocket(host, port); - } - - // layered transport - if (buffered) - trans = new TBufferedTransport(trans as TStreamTransport); - if (framed) - trans = new TFramedTransport(trans); - - //ensure proper open/close of transport - trans.Open(); - trans.Close(); - t.Start(trans); - } - else - { - THttpClient http = new THttpClient(new Uri(url)); - t.Start(http); + var difft = Date.now().getTime(); + + if( args.numThreads > 1) { + var threads = new List(); + for( test in 0 ... (args.numThreads-1)) { + threads.add( StartThread( args)); + } + for( thread in threads) { + Thread.readMessage(true); } + } else { + RunClient(args); } - for (int test = 0; test < numThreads; test++) - { - threads[test].Join(); - } - Console.Write("Total time: " + (DateTime.Now - start)); + difft = Date.now().getTime() - difft; + difft = (24 * 60 * 60) * difft; + trace('Total time: $difft seconds'); } - catch (Exception outerEx) + catch (e : TException) { - Console.WriteLine(outerEx.Message + " ST: " + outerEx.StackTrace); + trace('$e'); } + catch (e : Dynamic) + { + trace('$e'); + } + } - Console.WriteLine(); - Console.WriteLine(); + + private static function StartThread(args : Arguments) : Thread { + var thread = Thread.create( + function() : Void { + var main : Thread = Thread.readMessage(true); + try + { + RunClient(args); + } + catch (e : TException) + { + trace('$e'); + } + catch (e : Dynamic) + { + trace('$e'); + } + main.sendMessage("done"); + }); + + thread.sendMessage(Thread.current()); + return thread; } - public static void ClientThread(object obj) + + public static function RunClient(args : Arguments) { - TTransport transport = (TTransport)obj; - for (int i = 0; i < numIterations; i++) + var transport : TTransport = null; + switch (args.transport) { - ClientTest(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); } - transport.Close(); + + // protocol + var protocol : TProtocol = null; + switch( args.protocol) + { + case binary: + trace("- binary protocol"); + protocol = new TBinaryProtocol(transport); + case json: + trace("- json protocol"); + throw "JSON protocol not implemented yet"; + //protocol = new TJsonProtocol(transport); + default: + throw "Unhandled protocol"; + } + + + ClientTest( transport, protocol); + } - public static void ClientTest(TTransport transport) + public static function ClientTest( transport : TTransport, protocol : TProtocol) : Void { - TProtocol proto; - if (protocol == "compact") - proto = new TCompactProtocol(transport); - else if (protocol == "json") - proto = new TJSONProtocol(transport); - else - proto = new TBinaryProtocol(transport); - - ThriftTest.Client client = new ThriftTest.Client(proto); + var client = new ThriftTestImpl(protocol,protocol); try { - if (!transport.IsOpen) + if (!transport.isOpen()) { - transport.Open(); + transport.open(); } } - catch (TTransportException ttx) + catch (e : TException) { - Console.WriteLine("Connect failed: " + ttx.Message); + trace('$e'); + return; + } + catch (e : Dynamic) + { + trace('$e'); return; } - long start = DateTime.Now.ToFileTime(); + var start = Date.now(); - Console.Write("testVoid()"); + trace('testVoid()'); client.testVoid(); - Console.WriteLine(" = void"); - - Console.Write("testString(\"Test\")"); - string s = client.testString("Test"); - Console.WriteLine(" = \"" + s + "\""); - - Console.Write("testByte(1)"); - sbyte i8 = client.testByte((sbyte)1); - Console.WriteLine(" = " + i8); - - Console.Write("testI32(-1)"); - int i32 = client.testI32(-1); - Console.WriteLine(" = " + i32); - - Console.Write("testI64(-34359738368)"); - long i64 = client.testI64(-34359738368); - Console.WriteLine(" = " + i64); - - Console.Write("testDouble(5.325098235)"); - double dub = client.testDouble(5.325098235); - Console.WriteLine(" = " + dub); - - Console.Write("testStruct({\"Zero\", 1, -3, -5})"); - Xtruct o = new Xtruct(); - o.String_thing = "Zero"; - o.Byte_thing = (sbyte)1; - o.I32_thing = -3; - o.I64_thing = -5; - Xtruct i = client.testStruct(o); - Console.WriteLine(" = {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}"); - - Console.Write("testNest({1, {\"Zero\", 1, -3, -5}, 5})"); - Xtruct2 o2 = new Xtruct2(); - o2.Byte_thing = (sbyte)1; - o2.Struct_thing = o; - o2.I32_thing = 5; - Xtruct2 i2 = client.testNest(o2); - i = i2.Struct_thing; - Console.WriteLine(" = {" + i2.Byte_thing + ", {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}, " + i2.I32_thing + "}"); - - Dictionary mapout = new Dictionary(); - for (int j = 0; j < 5; j++) + trace(' = void'); + + trace('testString("Test")'); + var s = client.testString("Test"); + trace(' = "$s"'); + + trace('testByte(1)'); + var i8 = client.testByte(1); + trace(' = $i8'); + + trace('testI32(-1)'); + var i32 = client.testI32(-1); + trace(' = $i32'); + + trace('testI64(-34359738368)'); + var i64 = client.testI64( Int64.make( 0xFFFFFFF8, 0x00000000)); // -34359738368 + trace(' = $i64'); + + trace('testDouble(5.325098235)'); + var dub = client.testDouble(5.325098235); + trace(' = $dub'); + + 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 +', '+ i.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 + ", " + i.i64_thing + "}, " + + i2.i32_thing + "}"); + + var mapout = new IntMap< haxe.Int32>(); + for ( j in 0 ... 4) { - mapout[j] = j - 10; + mapout.set(j, j - 10); } - Console.Write("testMap({"); - bool first = true; - foreach (int key in mapout.Keys) + trace("testMap({"); + var first : Bool = true; + for( key in mapout.keys()) { if (first) { @@ -181,17 +226,17 @@ class TestClient { } else { - Console.Write(", "); + trace(", "); } - Console.Write(key + " => " + mapout[key]); + trace(key + " => " + mapout.get(key)); } - Console.Write("})"); + trace("})"); - Dictionary mapin = client.testMap(mapout); + var mapin = client.testMap(mapout); - Console.Write(" = {"); + trace(" = {"); first = true; - foreach (int key in mapin.Keys) + for( key in mapin.keys()) { if (first) { @@ -199,20 +244,20 @@ class TestClient { } else { - Console.Write(", "); + trace(", "); } - Console.Write(key + " => " + mapin[key]); + trace(key + " => " + mapin.get(key)); } - Console.WriteLine("}"); + trace("}"); - List listout = new List(); - for (int j = -2; j < 3; j++) + var listout = new List(); + for (j in -2 ... 2) { - listout.Add(j); + listout.add(j); } - Console.Write("testList({"); + trace("testList({"); first = true; - foreach (int j in listout) + for( j in listout) { if (first) { @@ -220,17 +265,17 @@ class TestClient { } else { - Console.Write(", "); + trace(", "); } - Console.Write(j); + trace(j); } - Console.Write("})"); + trace("})"); - List listin = client.testList(listout); + var listin = client.testList(listout); - Console.Write(" = {"); + trace(" = {"); first = true; - foreach (int j in listin) + for( j in listin) { if (first) { @@ -238,21 +283,21 @@ class TestClient { } else { - Console.Write(", "); + trace(", "); } - Console.Write(j); + trace(j); } - Console.WriteLine("}"); + trace("}"); //set - THashSet setout = new THashSet(); - for (int j = -2; j < 3; j++) + var setout = new IntSet(); + for (j in -2 ... 3) { - setout.Add(j); + setout.add(j); } - Console.Write("testSet({"); + trace("testSet({"); first = true; - foreach (int j in setout) + for( j in setout) { if (first) { @@ -260,17 +305,17 @@ class TestClient { } else { - Console.Write(", "); + trace(", "); } - Console.Write(j); + trace(j); } - Console.Write("})"); + trace("})"); - THashSet setin = client.testSet(setout); + var setin = client.testSet(setout); - Console.Write(" = {"); + trace(" = {"); first = true; - foreach (int j in setin) + for( j in setin) { if (first) { @@ -278,132 +323,137 @@ class TestClient { } else { - Console.Write(", "); + trace(", "); } - Console.Write(j); + trace(j); } - Console.WriteLine("}"); + trace("}"); - Console.Write("testEnum(ONE)"); - Numberz ret = client.testEnum(Numberz.ONE); - Console.WriteLine(" = " + ret); + trace("testEnum(ONE)"); + var ret = client.testEnum(Numberz.ONE); + trace(" = " + ret); - Console.Write("testEnum(TWO)"); + trace("testEnum(TWO)"); ret = client.testEnum(Numberz.TWO); - Console.WriteLine(" = " + ret); + trace(" = " + ret); - Console.Write("testEnum(THREE)"); + trace("testEnum(THREE)"); ret = client.testEnum(Numberz.THREE); - Console.WriteLine(" = " + ret); + trace(" = " + ret); - Console.Write("testEnum(FIVE)"); + trace("testEnum(FIVE)"); ret = client.testEnum(Numberz.FIVE); - Console.WriteLine(" = " + ret); + trace(" = " + ret); - Console.Write("testEnum(EIGHT)"); + trace("testEnum(EIGHT)"); ret = client.testEnum(Numberz.EIGHT); - Console.WriteLine(" = " + ret); + trace(" = " + ret); - Console.Write("testTypedef(309858235082523)"); - long uid = client.testTypedef(309858235082523L); - Console.WriteLine(" = " + uid); + trace("testTypedef(309858235082523)"); + var uid = client.testTypedef( Int64.make( 0x119D0, 0x7E08671B)); // 309858235082523 + trace(" = " + uid); - Console.Write("testMapMap(1)"); - Dictionary> mm = client.testMapMap(1); - Console.Write(" = {"); - foreach (int key in mm.Keys) + trace("testMapMap(1)"); + var mm = client.testMapMap(1); + trace(" = {"); + for( key in mm.keys()) { - Console.Write(key + " => {"); - Dictionary m2 = mm[key]; - foreach (int k2 in m2.Keys) + trace(key + " => {"); + var m2 = mm.get(key); + for( k2 in m2.keys()) { - Console.Write(k2 + " => " + m2[k2] + ", "); + trace(k2 + " => " + m2.get(k2) + ", "); } - Console.Write("}, "); + trace("}, "); } - Console.WriteLine("}"); - - Insanity insane = new Insanity(); - insane.UserMap = new Dictionary(); - insane.UserMap[Numberz.FIVE] = 5000L; - Xtruct truck = new Xtruct(); - truck.String_thing = "Truck"; - truck.Byte_thing = (sbyte)8; - truck.I32_thing = 8; - truck.I64_thing = 8; - insane.Xtructs = new List(); - insane.Xtructs.Add(truck); - Console.Write("testInsanity()"); - Dictionary> whoa = client.testInsanity(insane); - Console.Write(" = {"); - foreach (long key in whoa.Keys) + trace("}"); + + 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(); + insane.xtructs.add(truck); + trace("testInsanity()"); + var whoa = client.testInsanity(insane); + trace(" = {"); + for( key in whoa.keys()) { - Dictionary val = whoa[key]; - Console.Write(key + " => {"); + var val = whoa.get(key); + trace(key + " => {"); - foreach (Numberz k2 in val.Keys) + for( k2 in val.keys()) { - Insanity v2 = val[k2]; + var v2 = val.get(k2); - Console.Write(k2 + " => {"); - Dictionary userMap = v2.UserMap; + trace(k2 + " => {"); + var userMap = v2.userMap; - Console.Write("{"); + trace("{"); if (userMap != null) { - foreach (Numberz k3 in userMap.Keys) + for( k3 in userMap.keys()) { - Console.Write(k3 + " => " + userMap[k3] + ", "); + trace(k3 + " => " + userMap.get(k3) + ", "); } } else { - Console.Write("null"); + trace("null"); } - Console.Write("}, "); + trace("}, "); - List xtructs = v2.Xtructs; + var xtructs = v2.xtructs; - Console.Write("{"); + trace("{"); if (xtructs != null) { - foreach (Xtruct x in xtructs) + for( x in xtructs) { - Console.Write("{\"" + x.String_thing + "\", " + x.Byte_thing + ", " + x.I32_thing + ", " + x.I32_thing + "}, "); + trace("{\"" + x.string_thing + "\", " + + x.byte_thing + ", " + x.i32_thing + ", " + + x.i32_thing + "}, "); } } else { - Console.Write("null"); + trace("null"); } - Console.Write("}"); + trace("}"); - Console.Write("}, "); + trace("}, "); } - Console.Write("}, "); + trace("}, "); } - Console.WriteLine("}"); - - sbyte arg0 = 1; - int arg1 = 2; - long arg2 = long.MaxValue; - Dictionary multiDict = new Dictionary(); - multiDict[1] = "one"; - Numberz arg4 = Numberz.FIVE; - long arg5 = 5000000; - Console.Write("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + "," + multiDict + "," + arg4 + "," + arg5 + ")"); - Xtruct multiResponse = client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5); - Console.Write(" = Xtruct(byte_thing:" + multiResponse.Byte_thing + ",String_thing:" + multiResponse.String_thing - + ",i32_thing:" + multiResponse.I32_thing + ",i64_thing:" + multiResponse.I64_thing + ")\n"); - - Console.WriteLine("Test Oneway(1)"); + trace("}"); + + 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:" + multiResponse.i64_thing + ")\n"); + + trace("Test Oneway(1)"); client.testOneway(1); - Console.Write("Test Calltime()"); - var startt = DateTime.UtcNow; - for ( int k=0; k<1000; ++k ) + trace("Test Calltime()"); + var difft = Date.now().getTime(); + for ( k in 0 ... 999) { client.testVoid(); - Console.WriteLine(" = " + (DateTime.UtcNow - startt).TotalSeconds.ToString() + " ms a testVoid() call" ); + } + difft = Date.now().getTime() - difft; + difft = (24.0 * 60 * 60) * difft; + trace(' = $difft ms a testVoid() call'); } } diff --git a/test/haxe/src/TestServer.hx b/test/haxe/src/TestServer.hx index 81f8e04391e..8b177e9e16c 100644 --- a/test/haxe/src/TestServer.hx +++ b/test/haxe/src/TestServer.hx @@ -43,7 +43,7 @@ class TestServer case http: trace("- http"); throw "HTTP server not implemented yet"; - //transport = new THttpClient( targetHost); + //transport = new THttpServer( targetHost); default: throw "Unhandled transport"; } @@ -67,7 +67,7 @@ class TestServer trace("- binary protocol"); protfactory = new TBinaryProtocolFactory(); case json: - trace("- binary json"); + trace("- json protocol"); throw "JSON protocol not implemented yet"; //protfactory = new TJsonProtocolFactory(); default: diff --git a/test/haxe/src/TestServerHandler.hx b/test/haxe/src/TestServerHandler.hx index a72f0513743..935221035c7 100644 --- a/test/haxe/src/TestServerHandler.hx +++ b/test/haxe/src/TestServerHandler.hx @@ -24,8 +24,10 @@ 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; @@ -35,20 +37,19 @@ import thrift.test.*; // generated code class TestServerHandler implements ThriftTest { - - public var server : TServer; - public function new() { - } + public var server:TServer; + + public function new() { + } /** * Prints "testVoid()" and returns nothing. */ - function testVoid() : Void - { - trace("testVoid()"); - } - + public function testVoid():Void + { + trace("testVoid()"); + } /** * Prints 'testString("%s")' with thing as '%s' @@ -57,11 +58,11 @@ class TestServerHandler implements ThriftTest { * * @param thing */ - function testString(thing : String) : String - { - trace("teststring(\"" + thing + "\")"); - return thing; - } + public function testString(thing:String):String + { + trace("teststring(\"" + thing + "\")"); + return thing; + } /** * Prints 'testByte("%d")' with thing as '%d' @@ -70,11 +71,11 @@ class TestServerHandler implements ThriftTest { * * @param thing */ - function testByte(thing : haxe.Int32) : haxe.Int32 - { - trace("testByte(" + thing + ")"); - return thing; - } + public function testByte(thing:haxe.Int32):haxe.Int32 + { + trace("testByte(" + thing + ")"); + return thing; + } /** * Prints 'testI32("%d")' with thing as '%d' @@ -83,11 +84,11 @@ class TestServerHandler implements ThriftTest { * * @param thing */ - function testI32(thing : haxe.Int32) : haxe.Int32 - { - trace("testI32(" + thing + ")"); - return thing; - } + public function testI32(thing:haxe.Int32):haxe.Int32 + { + trace("testI32(" + thing + ")"); + return thing; + } /** * Prints 'testI64("%d")' with thing as '%d' @@ -96,11 +97,11 @@ class TestServerHandler implements ThriftTest { * * @param thing */ - function testI64(thing : haxe.Int64) : haxe.Int64 - { - trace("testI64(" + thing + ")"); - return thing; - } + public function testI64(thing:haxe.Int64):haxe.Int64 + { + trace("testI64(" + thing + ")"); + return thing; + } /** * Prints 'testDouble("%f")' with thing as '%f' @@ -109,11 +110,11 @@ class TestServerHandler implements ThriftTest { * * @param thing */ - function testDouble(thing : Float) : Float - { - trace("testDouble(" + thing + ")"); - return thing; - } + public function testDouble(thing:Float):Float + { + trace("testDouble(" + thing + ")"); + return thing; + } /** * Prints 'testStruct("{%s}")' where thing has been formatted @@ -123,15 +124,15 @@ class TestServerHandler implements ThriftTest { * * @param thing */ - function testStruct(thing : Xtruct) : Xtruct - { - trace("testStruct({" + - "\"" + thing.String_thing + "\", " + - thing.Byte_thing + ", " + - thing.I32_thing + ", " + - thing.I64_thing + "})"); - return thing; - } + public function testStruct(thing:Xtruct):Xtruct + { + trace("testStruct({" + + "\"" + thing.string_thing + "\", " + + thing.byte_thing + ", " + + thing.i32_thing + ", " + + thing.i64_thing + "})"); + return thing; + } /** * Prints 'testNest("{%s}")' where thing has been formatted @@ -141,18 +142,18 @@ class TestServerHandler implements ThriftTest { * * @param thing */ - function testNest(thing : Xtruct2) : Xtruct2 - { - var thing : Xtruct = nest.Struct_thing; - trace("testNest({" + - nest.Byte_thing + ", {" + - "\"" + thing.String_thing + "\", " + - thing.Byte_thing + ", " + - thing.I32_thing + ", " + - thing.I64_thing + "}, " + - nest.I32_thing + "})"); - return nest; - } + 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 + ", " + + thing.i64_thing + "}, " + + nest.i32_thing + "})"); + return nest; + } /** * Prints 'testMap("{%s")' where thing has been formatted @@ -163,25 +164,21 @@ class TestServerHandler implements ThriftTest { * * @param thing */ - 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[key]); - } - trace("})"); - return thing; - } + public function testMap(thing:IntMap):IntMap + { + 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 @@ -192,25 +189,21 @@ class TestServerHandler implements ThriftTest { * * @param thing */ - 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[key]); - } - trace("})"); - return thing; - } + public function testStringMap(thing:StringMap):StringMap + { + 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 @@ -221,25 +214,21 @@ class TestServerHandler implements ThriftTest { * * @param thing */ - 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; - } + 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 @@ -250,25 +239,21 @@ class TestServerHandler implements ThriftTest { * * @param thing */ - 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; - } + public function testList(thing:List):List + { + 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 @@ -277,11 +262,11 @@ class TestServerHandler implements ThriftTest { * * @param thing */ - function testEnum(thing : Int) : Int - { - trace("testEnum(" + thing + ")"); - return thing; - } + public function testEnum(thing:Int):Int + { + trace("testEnum(" + thing + ")"); + return thing; + } /** * Prints 'testTypedef("%d")' with thing as '%d' @@ -290,11 +275,11 @@ class TestServerHandler implements ThriftTest { * * @param thing */ - function testTypedef(thing : haxe.Int64) : haxe.Int64 - { - trace("testTypedef(" + thing + ")"); - return thing; - } + public function testTypedef(thing:haxe.Int64):haxe.Int64 + { + trace("testTypedef(" + thing + ")"); + return thing; + } /** * Prints 'testMapMap("%d")' with hello as '%d' @@ -305,24 +290,20 @@ class TestServerHandler implements ThriftTest { * * @param hello */ - function testMapMap(hello : haxe.Int32) : IntMap< IntMap< haxe.Int32>> - { - trace("testMapMap(" + hello + ")"); - var mapmap = new IntMap< IntMap< Int, Int>>(); - - var pos = new IntMap< Int>(); - var neg = new IntMap< Int>(); - for( i in 1 ... 4) - { - pos[i] = i; - neg[-i] = -i; - } - - mapmap[4] = pos; - mapmap[-4] = neg; - - return mapmap; - } + public function testMapMap(hello:haxe.Int32):IntMap> + { + trace("testMapMap(" + hello + ")"); + var mapmap = new IntMap>(); + var pos = new IntMap(); + var neg = new IntMap(); + for (i in 1 ... 4) { + 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? @@ -337,46 +318,45 @@ class TestServerHandler implements ThriftTest { * * @param argument */ - function testInsanity(argument : Insanity) : ObjectMap< haxe.Int64, ObjectMap< Int, Insanity>> - { - trace("testInsanity()"); - - var hello = new Xtruct(); - hello.String_thing = "Hello2"; - hello.Byte_thing = 2; - hello.I32_thing = 2; - hello.I64_thing = 2; - - var goodbye = new Xtruct(); - goodbye.String_thing = "Goodbye4"; - goodbye.Byte_thing = 4; - goodbye.I32_thing = 4; - goodbye.I64_thing = 4; - - var crazy = new Insanity(); - crazy.UserMap = new ObjectMap< Numberz, haxe.Int32>(); - crazy.UserMap[Numberz.EIGHT] = 8; - crazy.Xtructs = new List(); - crazy.Xtructs.Add(goodbye); - - var looney = new Insanity(); - crazy.UserMap[Numberz.FIVE] = 5; - crazy.Xtructs.Add(hello); - - var first_map = new ObjectMap< Numberz, Insanity>(); - var second_map = new ObjectMap< Numberz, Insanity>(); - - first_map[Numberz.TWO] = crazy; - first_map[Numberz.THREE] = crazy; - - second_map[Numberz.SIX] = looney; - - var insane = new IntMap< ObjectMap< Numberz, Insanity>>(); - insane[1] = first_map; - insane[2] = second_map; - - return insane; - } + public function testInsanity(argument : Insanity) : ObjectMap< haxe.Int64, 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(); + 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 ObjectMap< haxe.Int64, IntMap< Insanity>>(); + insane.set( Int64.make(0,1), first_map); + insane.set( Int64.make(0,2), second_map); + + return insane; + } /** * Prints 'testMulti()' @@ -397,17 +377,17 @@ class TestServerHandler implements ThriftTest { * @param arg4 * @param arg5 */ - 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; - } + public function testMulti(arg0:haxe.Int32, arg1:haxe.Int32, arg2:haxe.Int64, + arg3:IntMap, 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' @@ -418,18 +398,17 @@ class TestServerHandler implements ThriftTest { * * @param arg */ - function testException(arg : String) : Void - { - trace("testException(" + arg + ")"); - if (arg == "Xception") - { - var x = new Xception(); - x.ErrorCode = 1001; - x.Message = "This is an Xception"; - throw x; - } - return; - } + public function testException(arg:String):Void + { + trace("testException(" + arg + ")"); + if (arg == "Xception") { + var x = new Xception(); + x.errorCode = 1001; + x.message = "This is an Xception"; + throw x; + }; + return; + } /** * Print 'testMultiException(%s, %s)' with arg0 as '%s' and arg1 as '%s' @@ -444,29 +423,25 @@ class TestServerHandler implements ThriftTest { * @param arg0 * @param arg1 */ - 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; - } + 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' @@ -476,21 +451,17 @@ class TestServerHandler implements ThriftTest { * * @param secondsToSleep */ - function testOneway(secondsToSleep : haxe.Int32) : Void - { - trace("testOneway(" + arg + "), sleeping..."); - System.Threading.Thread.Sleep(arg * 1000); - trace("testOneway finished"); - } - - - public function testStop() : Void - { - if (server != null) - { - server.Stop(); - } - } - + 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/haxe/make_all.bat b/tutorial/haxe/make_all.bat index 1ea1c0a7272..656dd1530fa 100644 --- a/tutorial/haxe/make_all.bat +++ b/tutorial/haxe/make_all.bat @@ -1,4 +1,23 @@ @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 @@ -8,6 +27,7 @@ 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 ( @@ -41,4 +61,8 @@ echo HOMEPATH=%HOMEPATH% pause goto eof +:STOP +pause +goto eof + :eof From 12866fb3a7be20fddcbbe433f07a517164cacb33 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Sat, 6 Sep 2014 23:33:39 +0200 Subject: [PATCH 14/24] Haxe cross test --- compiler/cpp/src/generate/t_haxe_generator.cc | 25 ++++++++++----- lib/haxe/src/org/apache/thrift/Limits.hx | 2 +- .../apache/thrift/protocol/TBinaryProtocol.hx | 25 +++++---------- test/haxe/src/TestClient.hx | 31 ++++++++++--------- test/haxe/src/TestServerHandler.hx | 11 ++++--- 5 files changed, 49 insertions(+), 45 deletions(-) diff --git a/compiler/cpp/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc index d8a6adb9676..b53c6cd3491 100644 --- a/compiler/cpp/src/generate/t_haxe_generator.cc +++ b/compiler/cpp/src/generate/t_haxe_generator.cc @@ -201,11 +201,22 @@ class t_haxe_generator : public t_oop_generator { bool type_can_be_null(t_type* ttype) { ttype = get_true_type(ttype); - return - ttype->is_container() || - ttype->is_struct() || - ttype->is_xception() || - ttype->is_string(); + 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); @@ -2281,7 +2292,7 @@ void t_haxe_generator::generate_deserialize_container(ofstream& out, // For loop iterates over elements string i = tmp("_i"); indent(out) << - "for( " << i << " in 0 ... (" << obj << ".size-1))" << endl; + "for( " << i << " in 0 ... " << obj << ".size)" << endl; scope_up(out); @@ -2364,7 +2375,7 @@ void t_haxe_generator::generate_deserialize_list_element(ofstream& out, generate_deserialize_field(out, &felem); indent(out) << - prefix << ".push(" << elem << ");" << endl; + prefix << ".add(" << elem << ");" << endl; } diff --git a/lib/haxe/src/org/apache/thrift/Limits.hx b/lib/haxe/src/org/apache/thrift/Limits.hx index 08637c14618..7d2aa5deb82 100644 --- a/lib/haxe/src/org/apache/thrift/Limits.hx +++ b/lib/haxe/src/org/apache/thrift/Limits.hx @@ -30,7 +30,7 @@ class Limits { public static var I32_MAX = { var last : Int = 0; var next : Int = 0; - for(bit in 0 ... 31) { + for(bit in 0 ... 32) { last = next; next = last | (1 << bit); if(next < 0) { diff --git a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx index 6dd1bcc726f..9693b35c539 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx @@ -136,13 +136,10 @@ class TBinaryProtocol implements TProtocol { public function writeI64(i64 : haxe.Int64) : Void { var out = new BytesOutput(); out.bigEndian = true; - - var oneByte = Int64.make(0,0xFF); - for(i in 0 ... 7) { - out.writeByte( Int64.toInt( Int64.and(oneByte,i64))); - i64 = Int64.shr(i64,8); - } - + var hi = Int64.getHigh(i64); + var lo = Int64.getLow(i64); + out.writeInt32(hi); + out.writeInt32(lo); trans_.write(out.getBytes(), 0, 8); } @@ -259,17 +256,9 @@ class TBinaryProtocol implements TProtocol { var len = trans_.readAll( buffer, 0, 8); var inp = new BytesInput( buffer.getBytes(), 0, 8); inp.bigEndian = true; - - var mask = Int64.make(0xFFFFFFFF,0xFFFFFF00); - var result = Int64.make(0,0); - for(i in 0 ... 7) { - var nextByte = Int64.make(0,inp.readByte()); - result = Int64.shl( result, 8); - result = Int64.and( result, mask); - result = Int64.or( result, nextByte); - } - - return result; + var hi = inp.readInt32(); + var lo = inp.readInt32(); + return Int64.make(hi,lo); } public function readDouble():Float { diff --git a/test/haxe/src/TestClient.hx b/test/haxe/src/TestClient.hx index 20ad6bdf544..ac27a2c434a 100644 --- a/test/haxe/src/TestClient.hx +++ b/test/haxe/src/TestClient.hx @@ -21,6 +21,7 @@ package; import haxe.Int32; import haxe.Int64; +import haxe.Timer; import haxe.ds.IntMap; import haxe.ds.StringMap; import haxe.ds.ObjectMap; @@ -47,11 +48,11 @@ class TestClient { { try { - var difft = Date.now().getTime(); + var difft = Timer.stamp(); if( args.numThreads > 1) { var threads = new List(); - for( test in 0 ... (args.numThreads-1)) { + for( test in 0 ... args.numThreads) { threads.add( StartThread( args)); } for( thread in threads) { @@ -61,9 +62,8 @@ class TestClient { RunClient(args); } - difft = Date.now().getTime() - difft; - difft = (24 * 60 * 60) * difft; - trace('Total time: $difft seconds'); + difft = Timer.stamp() - difft; + trace('total test time: $difft seconds'); } catch (e : TException) { @@ -198,7 +198,8 @@ class TestClient { 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 +', '+ i.i64_thing + '}'); + trace(' = {"' + i.string_thing + '", ' + i.byte_thing +', ' + + i.i32_thing +', '+ Int64.toStr(i.i64_thing) + '}'); trace('testNest({1, {\"Zero\", 1, -3, -5}, 5})'); var o2 = new Xtruct2(); @@ -208,11 +209,11 @@ class TestClient { var i2 = client.testNest(o2); i = i2.struct_thing; trace(" = {" + i2.byte_thing + ", {\"" + i.string_thing + "\", " - + i.byte_thing + ", " + i.i32_thing + ", " + i.i64_thing + "}, " + + i.byte_thing + ", " + i.i32_thing + ", " + Int64.toStr(i.i64_thing) + "}, " + i2.i32_thing + "}"); var mapout = new IntMap< haxe.Int32>(); - for ( j in 0 ... 4) + for ( j in 0 ... 5) { mapout.set(j, j - 10); } @@ -251,7 +252,7 @@ class TestClient { trace("}"); var listout = new List(); - for (j in -2 ... 2) + for (j in -2 ... 3) { listout.add(j); } @@ -442,18 +443,18 @@ class TestClient { 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:" + multiResponse.i64_thing + ")\n"); + + ",i32_thing:" + multiResponse.i32_thing + + ",i64_thing:" + Int64.toStr(multiResponse.i64_thing) + ")"); trace("Test Oneway(1)"); client.testOneway(1); trace("Test Calltime()"); - var difft = Date.now().getTime(); - for ( k in 0 ... 999) { + var difft = Timer.stamp(); + for ( k in 0 ... 1000) { client.testVoid(); } - difft = Date.now().getTime() - difft; - difft = (24.0 * 60 * 60) * difft; - trace(' = $difft ms a testVoid() call'); + difft = Timer.stamp() - difft; + trace('$difft ms per testVoid() call'); } } diff --git a/test/haxe/src/TestServerHandler.hx b/test/haxe/src/TestServerHandler.hx index 935221035c7..126ef60b2e0 100644 --- a/test/haxe/src/TestServerHandler.hx +++ b/test/haxe/src/TestServerHandler.hx @@ -130,7 +130,7 @@ class TestServerHandler implements ThriftTest { "\"" + thing.string_thing + "\", " + thing.byte_thing + ", " + thing.i32_thing + ", " + - thing.i64_thing + "})"); + Int64.toStr(thing.i64_thing) + "})"); return thing; } @@ -150,7 +150,7 @@ class TestServerHandler implements ThriftTest { "\"" + thing.string_thing + "\", " + thing.byte_thing + ", " + thing.i32_thing + ", " + - thing.i64_thing + "}, " + + Int64.toStr(thing.i64_thing) + "}, " + nest.i32_thing + "})"); return nest; } @@ -296,7 +296,7 @@ class TestServerHandler implements ThriftTest { var mapmap = new IntMap>(); var pos = new IntMap(); var neg = new IntMap(); - for (i in 1 ... 4) { + for (i in 1 ... 5) { pos.set(i, i); neg.set(-i, -i); }; @@ -404,9 +404,12 @@ class TestServerHandler implements ThriftTest { if (arg == "Xception") { var x = new Xception(); x.errorCode = 1001; - x.message = "This is an Xception"; + x.message = arg; throw x; }; + if (arg == "TException") { + throw new TException(); + }; return; } From 25bf6c3adbfd8cc3bf10cf93e1702fc4a71a39c2 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Sun, 7 Sep 2014 02:10:23 +0200 Subject: [PATCH 15/24] - Int64Map added, can't use ObjectMap for haxe.Int64 - cross-test Client actually tests things now - updated lib/haxe/README.md --- compiler/cpp/src/generate/t_haxe_generator.cc | 24 +- lib/haxe/README.md | 13 +- .../src/org/apache/thrift/helper/Int64Map.hx | 265 ++++++++++++++++++ test/haxe/project.hide | 11 +- test/haxe/src/TestClient.hx | 244 +++++++++++++++- test/haxe/src/TestServerEventHandler.hx | 2 +- test/haxe/src/TestServerHandler.hx | 4 +- 7 files changed, 537 insertions(+), 26 deletions(-) create mode 100644 lib/haxe/src/org/apache/thrift/helper/Int64Map.hx diff --git a/compiler/cpp/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc index b53c6cd3491..9c71db19d8e 100644 --- a/compiler/cpp/src/generate/t_haxe_generator.cc +++ b/compiler/cpp/src/generate/t_haxe_generator.cc @@ -2601,20 +2601,22 @@ string t_haxe_generator::type_name(t_type* ttype, bool in_container, bool in_ini } if (ttype->is_map()) { - t_type* tkey = ((t_map*)ttype)->get_key_type(); - t_type* tval = ((t_map*)ttype)->get_val_type(); + 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(); + 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)+">"; - default: + 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<> } } @@ -2625,7 +2627,7 @@ string t_haxe_generator::type_name(t_type* ttype, bool in_container, bool in_ini } if (ttype->is_set()) { - t_type* tkey = ((t_list*)ttype)->get_elem_type(); + 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) { @@ -2636,8 +2638,10 @@ string t_haxe_generator::type_name(t_type* ttype, bool in_container, bool in_ini case t_base_type::TYPE_BYTE: case t_base_type::TYPE_I16: case t_base_type::TYPE_I32: - return "IntSet"; - default: + return "IntSet"; + case t_base_type::TYPE_I64: + return "Int64Set"; + default: break; // default to ObjectSet } } diff --git a/lib/haxe/README.md b/lib/haxe/README.md index 2fa76f648c9..f0299d83413 100644 --- a/lib/haxe/README.md +++ b/lib/haxe/README.md @@ -33,16 +33,19 @@ Work in progress ======================== WHAT WORKS: -- tutorial works with sockets, both client and server +- socket transport, binary protocol +- tutorial client and server +- cross-test client and server - tested with Haxe C++ target - designed to work with all other Haxe and OpenFL targets (not tested!) TODO: - build scripts and makefiles for tutorial and test -- cross-test client and server (currently working on this part) -- JSON protocol, update tutorial and test accordingly -- HTTP transport, update tutorial and test accordingly -- Tests of all components against as much as possible Haxe and/or OpenFL targets + +FURTHER DEVELOPMENTS: +- add JSON protocol, update tutorial and test accordingly +- add HTTP transport, update tutorial and test accordingly +- Tests of all components against all Haxe/OpenFL targets - Try to minimze or eliminate known restrictions (see below) 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 00000000000..8d9e4e148c8 --- /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 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 { + 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 { + return new Int64KeyIterator(SubMaps); + } + + /** + Returns an Iterator over the values of `this` Map. + The order of values is undefined. + **/ + public function iterator() : Iterator { + return new Int64ValueIterator(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 +// all class with matching methods can be used as iterator (duck typing) +private class Int64MapIteratorBase { + + 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 +// all class with matching methods can be used as iterator (duck typing) +private class Int64KeyIteratorextends Int64MapIteratorBase { + + 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 +// all class with matching methods can be used as iterator (duck typing) +private class Int64ValueIterator extends Int64MapIteratorBase { + + 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/test/haxe/project.hide b/test/haxe/project.hide index be134a9c8ff..9bb9bf9c1fc 100644 --- a/test/haxe/project.hide +++ b/test/haxe/project.hide @@ -69,7 +69,16 @@ ,"foldedRegions" : [ ] - ,"activeLine" : 229 + ,"activeLine" : 599 + } + ,{ + "path" : "src\\TestServerHandler.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 309 } ] ,"activeFile" : "src\\TestClient.hx" diff --git a/test/haxe/src/TestClient.hx b/test/haxe/src/TestClient.hx index ac27a2c434a..6f800aef8ea 100644 --- a/test/haxe/src/TestClient.hx +++ b/test/haxe/src/TestClient.hx @@ -42,8 +42,50 @@ import cpp.vm.Thread; import thrift.test.*; // generated code -class TestClient { +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 @@ -59,7 +101,9 @@ class TestClient { Thread.readMessage(true); } } else { - RunClient(args); + var rslt = new TestResults(true); + RunClient(args,rslt); + rslt.PrintSummary(); } difft = Timer.stamp() - difft; @@ -82,7 +126,9 @@ class TestClient { var main : Thread = Thread.readMessage(true); try { - RunClient(args); + var rslt = new TestResults(false); + RunClient(args,rslt); + // TODO: promote rslt values to main thread } catch (e : TException) { @@ -100,7 +146,7 @@ class TestClient { } - public static function RunClient(args : Arguments) + public static function RunClient(args : Arguments, rslt : TestResults) { var transport : TTransport = null; switch (args.transport) @@ -140,11 +186,94 @@ class TestClient { } - ClientTest( transport, protocol); + // run the test code + HaxeBasicsTest( rslt); + ClientTest( transport, protocol, rslt); } - public static function ClientTest( transport : TTransport, protocol : TProtocol) : Void + + 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(); + var map64 = new Int64Map(); + + rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map Test #1"); + rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #2"); + rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map Test #3"); + rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map 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 Test #10"); + rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #11"); + rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map Test #12"); + rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map Test #13"); + rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map Test #14"); + rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map Test #15"); + rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map Test #16"); + rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map Test #Int64.make(-5,17)"); + rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map Test #18"); + rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map Test #19"); + rslt.Expect( map32.remove( -517) == map64.remove( Int64.make(-5,17)), "Int64Map Test #20"); + rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #21"); + rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map Test #22"); + rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map Test #23"); + rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map Test #24"); + rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map Test #25"); + rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map Test #26"); + rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map Test #27"); + rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map 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 Test #30"); + + var s32 = map32.toString(); + var s64 = map64.toString(); + trace("Int64Map.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 Test #90"); + rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #91"); + rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map Test #92"); + rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map Test #93"); + rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map Test #94"); + rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map Test #95"); + rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map Test #96"); + rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map Test #97"); + rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map Test #98"); + } + + + public static function ClientTest( transport : TTransport, protocol : TProtocol, rslt : TestResults) : Void { var client = new ThriftTestImpl(protocol,protocol); try @@ -170,26 +299,33 @@ class TestClient { 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))); 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(); @@ -200,6 +336,10 @@ class TestClient { 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(); @@ -211,6 +351,12 @@ class TestClient { 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) @@ -248,8 +394,13 @@ class TestClient { 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(); for (j in -2 ... 3) @@ -290,6 +441,13 @@ class TestClient { } 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) @@ -327,33 +485,42 @@ class TestClient { 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); @@ -370,6 +537,14 @@ class TestClient { } 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)); @@ -433,6 +608,55 @@ class TestClient { } 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); @@ -446,6 +670,12 @@ class TestClient { + ",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); diff --git a/test/haxe/src/TestServerEventHandler.hx b/test/haxe/src/TestServerEventHandler.hx index 2facf85356d..b52943a22a4 100644 --- a/test/haxe/src/TestServerEventHandler.hx +++ b/test/haxe/src/TestServerEventHandler.hx @@ -28,7 +28,7 @@ import org.apache.thrift.meta_data.*; import thrift.test.*; // generated code -public class TestServerEventHandler : TServerEventHandler +class TestServerEventHandler : TServerEventHandler { public int callCount = 0; public void preServe() diff --git a/test/haxe/src/TestServerHandler.hx b/test/haxe/src/TestServerHandler.hx index 126ef60b2e0..e988adbeb21 100644 --- a/test/haxe/src/TestServerHandler.hx +++ b/test/haxe/src/TestServerHandler.hx @@ -318,7 +318,7 @@ class TestServerHandler implements ThriftTest { * * @param argument */ - public function testInsanity(argument : Insanity) : ObjectMap< haxe.Int64, IntMap< Insanity>> + public function testInsanity(argument : Insanity) : Int64Map< IntMap< Insanity>> { trace("testInsanity()"); @@ -351,7 +351,7 @@ class TestServerHandler implements ThriftTest { var second_map = new IntMap< Insanity>(); second_map.set(Numberz.SIX, looney); - var insane = new ObjectMap< haxe.Int64, IntMap< Insanity>>(); + var insane = new Int64Map< IntMap< Insanity>>(); insane.set( Int64.make(0,1), first_map); insane.set( Int64.make(0,2), second_map); From 3298a61cfdfddbb77ffc54366d28dcded62a019e Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Fri, 12 Sep 2014 01:33:52 +0200 Subject: [PATCH 16/24] Makefiles --- configure.ac | 19 ++++++++++++++ test/Makefile.am | 4 +++ test/haxe/Makefile.am | 52 +++++++++++++++++++++++++++++++++++++++ test/haxe/make_all.sh | 2 +- tutorial/Makefile.am | 4 +++ tutorial/haxe/Makefile.am | 50 +++++++++++++++++++++++++++++++++++++ 6 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 test/haxe/Makefile.am create mode 100644 tutorial/haxe/Makefile.am diff --git a/configure.ac b/configure.ac index 15aedf739b2..43e1d652abe 100755 --- a/configure.ac +++ b/configure.ac @@ -114,6 +114,7 @@ if test "$enable_libs" = "no"; then 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 @@ fi 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 @@ AC_CONFIG_FILES([ 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 @@ AC_CONFIG_FILES([ 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 Java Library ........ : $have_java" 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 @@ if test "$have_haskell" = "yes" ; then 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/test/Makefile.am b/test/Makefile.am index cc1f43d2982..23ec4988acd 100755 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -49,6 +49,10 @@ if WITH_HASKELL 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 00000000000..08c0369e755 --- /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/make_all.sh b/test/haxe/make_all.sh index 27a1f1d9135..26212587743 100644 --- a/test/haxe/make_all.sh +++ b/test/haxe/make_all.sh @@ -26,7 +26,7 @@ if [ ! -d bin ]; then mkdir bin fi -# invoke Haxe compoiler +# invoke Haxe compiler for target in *.hxml; do echo -------------------------- echo Building ${target} ... diff --git a/tutorial/Makefile.am b/tutorial/Makefile.am index 2b9be528ab7..79fd8fd65c2 100755 --- a/tutorial/Makefile.am +++ b/tutorial/Makefile.am @@ -50,6 +50,10 @@ if WITH_HASKELL 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 00000000000..d98be0af2f0 --- /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 + From ab52f076ad68381d9764e34e1910eaa113b40cf7 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Sat, 13 Sep 2014 01:48:17 +0200 Subject: [PATCH 17/24] Revised README --- lib/haxe/README.md | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/lib/haxe/README.md b/lib/haxe/README.md index f0299d83413..eae1bd15536 100644 --- a/lib/haxe/README.md +++ b/lib/haxe/README.md @@ -29,24 +29,20 @@ 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. -Work in progress +Current status ======================== - -WHAT WORKS: -- socket transport, binary protocol -- tutorial client and server -- cross-test client and server - tested with Haxe C++ target -- designed to work with all other Haxe and OpenFL targets (not tested!) +- socket transport, binary protocol available +- tutorial client and server available +- cross-test client and server available -TODO: -- build scripts and makefiles for tutorial and test -FURTHER DEVELOPMENTS: -- add JSON protocol, update tutorial and test accordingly -- add HTTP transport, update tutorial and test accordingly -- Tests of all components against all Haxe/OpenFL targets -- Try to minimze or eliminate known restrictions (see below) +Further developments +======================== +- add JSON protocol, update tutorial and tests accordingly +- 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 @@ -57,9 +53,9 @@ Depending on the desired targets, you may have to install the appropriate HaxeLi after installing Haxe itself. For example, if you plan to target C#, Java and C++, enter the following commands after installing Haxe: - haxelib install hxcs - haxelib install hxjava 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. @@ -75,5 +71,5 @@ Although designed with maximum portability in mind, for technical reasons some p may only support parts of the library, or not be compatible at all. Javascript: -- tutorial fails to build because of Sys.args +- tutorial fails to build because of unsupported Sys.args From 66f2f4a09672287fe71cf66998120a95869a7334 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Mon, 28 Jul 2014 01:25:30 +0200 Subject: [PATCH 18/24] THRIFT-2644 Haxe support Client: Haxe Patch: Jens Geyer --- .gitignore | 2 + compiler/cpp/CMakeLists.txt | 1 + compiler/cpp/Makefile.am | 1 + compiler/cpp/src/generate/t_haxe_generator.cc | 2948 +++++++++++++++++ configure.ac | 19 + lib/haxe/README.md | 75 + .../org/apache/thrift/AbstractMethodError.hx | 40 + .../src/org/apache/thrift/ArgumentError.hx | 29 + lib/haxe/src/org/apache/thrift/Limits.hx | 44 + .../apache/thrift/TApplicationException.hx | 102 + lib/haxe/src/org/apache/thrift/TBase.hx | 66 + lib/haxe/src/org/apache/thrift/TException.hx | 35 + .../apache/thrift/TFieldRequirementType.hx | 31 + lib/haxe/src/org/apache/thrift/TProcessor.hx | 30 + .../src/org/apache/thrift/helper/Int64Map.hx | 265 ++ .../src/org/apache/thrift/helper/IntSet.hx | 96 + .../src/org/apache/thrift/helper/ObjectSet.hx | 96 + .../src/org/apache/thrift/helper/StringSet.hx | 96 + .../apache/thrift/meta_data/FieldMetaData.hx | 56 + .../thrift/meta_data/FieldValueMetaData.hx | 43 + .../apache/thrift/meta_data/ListMetaData.hx | 30 + .../apache/thrift/meta_data/MapMetaData.hx | 32 + .../apache/thrift/meta_data/SetMetaData.hx | 30 + .../apache/thrift/meta_data/StructMetaData.hx | 30 + .../apache/thrift/protocol/TBinaryProtocol.hx | 296 ++ .../thrift/protocol/TBinaryProtocolFactory.hx | 45 + .../src/org/apache/thrift/protocol/TField.hx | 42 + .../src/org/apache/thrift/protocol/TList.hx | 32 + .../src/org/apache/thrift/protocol/TMap.hx | 34 + .../org/apache/thrift/protocol/TMessage.hx | 41 + .../apache/thrift/protocol/TMessageType.hx | 27 + .../org/apache/thrift/protocol/TProtocol.hx | 82 + .../thrift/protocol/TProtocolException.hx | 39 + .../thrift/protocol/TProtocolFactory.hx | 26 + .../apache/thrift/protocol/TProtocolUtil.hx | 135 + .../src/org/apache/thrift/protocol/TSet.hx | 32 + .../src/org/apache/thrift/protocol/TStruct.hx | 30 + .../src/org/apache/thrift/protocol/TType.hx | 38 + .../src/org/apache/thrift/server/TServer.hx | 105 + .../thrift/server/TServerEventHandler.hx | 41 + .../org/apache/thrift/server/TSimpleServer.hx | 125 + .../thrift/transport/TFramedTransport.hx | 142 + .../transport/TFramedTransportFactory.hx | 37 + .../thrift/transport/TFullDuplexHttpClient.hx | 247 ++ .../apache/thrift/transport/THttpClient.hx | 183 + .../apache/thrift/transport/TServerSocket.hx | 132 + .../thrift/transport/TServerTransport.hx | 43 + .../org/apache/thrift/transport/TSocket.hx | 296 ++ .../org/apache/thrift/transport/TTransport.hx | 133 + .../thrift/transport/TTransportException.hx | 36 + .../thrift/transport/TTransportFactory.hx | 44 + test/Makefile.am | 4 + test/haxe/Makefile.am | 52 + test/haxe/cpp.hxml | 41 + test/haxe/csharp.hxml | 38 + test/haxe/flash.hxml | 41 + test/haxe/java.hxml | 38 + test/haxe/javascript.hxml | 44 + test/haxe/make_all.bat | 68 + test/haxe/make_all.sh | 41 + test/haxe/neko.hxml | 38 + test/haxe/php.hxml | 38 + test/haxe/project.hide | 94 + test/haxe/python.hxml | 38 + test/haxe/src/Arguments.hx | 173 + test/haxe/src/Main.hx | 48 + test/haxe/src/TestClient.hx | 690 ++++ test/haxe/src/TestServer.hx | 107 + test/haxe/src/TestServerEventHandler.hx | 53 + test/haxe/src/TestServerHandler.hx | 470 +++ tutorial/Makefile.am | 4 + tutorial/haxe/Makefile.am | 50 + tutorial/haxe/cpp.hxml | 41 + tutorial/haxe/csharp.hxml | 38 + tutorial/haxe/flash.hxml | 41 + tutorial/haxe/java.hxml | 38 + tutorial/haxe/javascript.hxml | 44 + tutorial/haxe/make_all.bat | 68 + tutorial/haxe/make_all.sh | 41 + tutorial/haxe/neko.hxml | 38 + tutorial/haxe/php.hxml | 38 + tutorial/haxe/project.hide | 105 + tutorial/haxe/python.hxml | 38 + tutorial/haxe/src/CalculatorHandler.hx | 101 + tutorial/haxe/src/Main.hx | 331 ++ tutorial/shared.thrift | 1 + tutorial/tutorial.thrift | 1 + 87 files changed, 9794 insertions(+) create mode 100644 compiler/cpp/src/generate/t_haxe_generator.cc create mode 100644 lib/haxe/README.md create mode 100644 lib/haxe/src/org/apache/thrift/AbstractMethodError.hx create mode 100644 lib/haxe/src/org/apache/thrift/ArgumentError.hx create mode 100644 lib/haxe/src/org/apache/thrift/Limits.hx create mode 100644 lib/haxe/src/org/apache/thrift/TApplicationException.hx create mode 100644 lib/haxe/src/org/apache/thrift/TBase.hx create mode 100644 lib/haxe/src/org/apache/thrift/TException.hx create mode 100644 lib/haxe/src/org/apache/thrift/TFieldRequirementType.hx create mode 100644 lib/haxe/src/org/apache/thrift/TProcessor.hx create mode 100644 lib/haxe/src/org/apache/thrift/helper/Int64Map.hx create mode 100644 lib/haxe/src/org/apache/thrift/helper/IntSet.hx create mode 100644 lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx create mode 100644 lib/haxe/src/org/apache/thrift/helper/StringSet.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/FieldMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/FieldValueMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/ListMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/MapMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/SetMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/meta_data/StructMetaData.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocolFactory.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TField.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TList.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TMap.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TMessage.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TMessageType.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TProtocolException.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TProtocolFactory.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TProtocolUtil.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TSet.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TStruct.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TType.hx create mode 100644 lib/haxe/src/org/apache/thrift/server/TServer.hx create mode 100644 lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx create mode 100644 lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/THttpClient.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TSocket.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TTransport.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TTransportException.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TTransportFactory.hx create mode 100644 test/haxe/Makefile.am create mode 100644 test/haxe/cpp.hxml create mode 100644 test/haxe/csharp.hxml create mode 100644 test/haxe/flash.hxml create mode 100644 test/haxe/java.hxml create mode 100644 test/haxe/javascript.hxml create mode 100644 test/haxe/make_all.bat create mode 100644 test/haxe/make_all.sh create mode 100644 test/haxe/neko.hxml create mode 100644 test/haxe/php.hxml create mode 100644 test/haxe/project.hide create mode 100644 test/haxe/python.hxml create mode 100644 test/haxe/src/Arguments.hx create mode 100644 test/haxe/src/Main.hx create mode 100644 test/haxe/src/TestClient.hx create mode 100644 test/haxe/src/TestServer.hx create mode 100644 test/haxe/src/TestServerEventHandler.hx create mode 100644 test/haxe/src/TestServerHandler.hx create mode 100644 tutorial/haxe/Makefile.am create mode 100644 tutorial/haxe/cpp.hxml create mode 100644 tutorial/haxe/csharp.hxml create mode 100644 tutorial/haxe/flash.hxml create mode 100644 tutorial/haxe/java.hxml create mode 100644 tutorial/haxe/javascript.hxml create mode 100644 tutorial/haxe/make_all.bat create mode 100644 tutorial/haxe/make_all.sh create mode 100644 tutorial/haxe/neko.hxml create mode 100644 tutorial/haxe/php.hxml create mode 100644 tutorial/haxe/project.hide create mode 100644 tutorial/haxe/python.hxml create mode 100644 tutorial/haxe/src/CalculatorHandler.hx create mode 100644 tutorial/haxe/src/Main.hx diff --git a/.gitignore b/.gitignore index a3344b7eb8a..2b99c2debad 100644 --- a/.gitignore +++ b/.gitignore @@ -221,6 +221,7 @@ test-driver /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/ @@ -241,6 +242,7 @@ test-driver /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 e98adb719a3..d24210ba8a2 100644 --- a/compiler/cpp/CMakeLists.txt +++ b/compiler/cpp/CMakeLists.txt @@ -120,6 +120,7 @@ THRIFT_ADD_COMPILER(c_glib "Enable compiler for C with Glib" ON) 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 601fd3263ef..4a09b2d7716 100644 --- a/compiler/cpp/Makefile.am +++ b/compiler/cpp/Makefile.am @@ -71,6 +71,7 @@ thrift_SOURCES += src/generate/t_c_glib_generator.cc \ src/generate/t_cpp_generator.cc \ src/generate/t_java_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/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc new file mode 100644 index 00000000000..9c71db19d8e --- /dev/null +++ b/compiler/cpp/src/generate/t_haxe_generator.cc @@ -0,0 +1,2948 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include +#include + +#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& parsed_options, + const std::string& option_string) + : t_oop_generator(program) + { + (void) option_string; + std::map::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 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& members = tstruct->get_members(); + vector::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& functions = tservice->get_functions(); + vector::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 constants = tenum->get_constants(); + vector::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 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::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& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::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& val = value->get_map(); + map::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& val = value->get_list(); + vector::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& members = tstruct->get_members(); + vector::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& fields = tstruct->get_members(); + vector::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& fields = tstruct->get_members(); + vector::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& fields = tstruct->get_sorted_members(); + vector::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& fields = tstruct->get_sorted_members(); + vector::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& fields = tstruct->get_members(); + vector::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& fields = tstruct->get_members(); + vector::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& fields = tstruct->get_members(); + vector::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& fields = tstruct->get_members(); + vector::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& fields = tstruct->get_members(); + vector::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 functions = tservice->get_functions(); + vector::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 functions = tservice->get_functions(); + vector::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 functions = tservice->get_functions(); + vector::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::const_iterator fld_iter; + const vector& fields = arg_struct->get_members(); + + // Serialize the request + f_service_ << + indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", TMessageType.CALL, 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& xceptions = xs->get_members(); + vector::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 functions = tservice->get_functions(); + vector::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& fields = xs->get_members(); + vector::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& xceptions = xs->get_members(); + vector::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& fields = arg_struct->get_members(); + vector::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& fields = arg_struct->get_members(); + vector::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 + */ +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& fields = tstruct->get_members(); + vector::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& fields = tfunction->get_arglist()->get_members(); + vector::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 15aedf739b2..43e1d652abe 100755 --- a/configure.ac +++ b/configure.ac @@ -114,6 +114,7 @@ if test "$enable_libs" = "no"; then 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 @@ fi 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 @@ AC_CONFIG_FILES([ 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 @@ AC_CONFIG_FILES([ 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 Java Library ........ : $have_java" 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 @@ if test "$have_haskell" = "yes" ; then 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 00000000000..eae1bd15536 --- /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 +- socket transport, binary protocol available +- tutorial client and server available +- cross-test client and server available + + +Further developments +======================== +- add JSON protocol, update tutorial and tests accordingly +- 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 00000000000..9fb9bbbaaf4 --- /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 00000000000..8a5df6f234c --- /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 00000000000..7d2aa5deb82 --- /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 00000000000..012a80280ab --- /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 00000000000..5d8bfc10cf2 --- /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 00000000000..ed630bac241 --- /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 00000000000..70f698f9c1c --- /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 00000000000..78ce5a7320c --- /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 00000000000..8d9e4e148c8 --- /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 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 { + 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 { + return new Int64KeyIterator(SubMaps); + } + + /** + Returns an Iterator over the values of `this` Map. + The order of values is undefined. + **/ + public function iterator() : Iterator { + return new Int64ValueIterator(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 +// all class with matching methods can be used as iterator (duck typing) +private class Int64MapIteratorBase { + + 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 +// all class with matching methods can be used as iterator (duck typing) +private class Int64KeyIteratorextends Int64MapIteratorBase { + + 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 +// all class with matching methods can be used as iterator (duck typing) +private class Int64ValueIterator extends Int64MapIteratorBase { + + 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 00000000000..214f3bd72c6 --- /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(); + private var _size : Int = 0; + public var size(get,never) : Int; + + public function new( values : Array = null) { + if ( values != null) { + for ( value in values) { + add(value); + } + } + } + + public function iterator():Iterator { + 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 { + var ret : Array = new Array(); + 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 00000000000..c590c759f93 --- /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 { + + private var _elements = new haxe.ds.ObjectMap(); + private var _size : Int = 0; + public var size(get,never) : Int; + + public function new( values : Array = null) { + if ( values != null) { + for ( value in values) { + add(value); + } + } + } + + public function iterator():Iterator { + 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 { + var ret : Array = new Array(); + 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 00000000000..ee772c7197c --- /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(); + private var _size : Int = 0; + public var size(get,never) : Int; + + public function new( values : Array = null) { + if ( values != null) { + for ( value in values) { + add(value); + } + } + } + + public function iterator():Iterator { + 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 { + var ret : Array = new Array(); + 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 00000000000..147eed944d4 --- /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 00000000000..06c7f48af18 --- /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 00000000000..36bb2d1fb01 --- /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 00000000000..bf0502a0173 --- /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 00000000000..0ee6c93b0fd --- /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 00000000000..bbf11e72b7a --- /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 00000000000..9693b35c539 --- /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 00000000000..0d7c7c57efd --- /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 00000000000..9f3db62dfd3 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/protocol/TField.hx @@ -0,0 +1,42 @@ +/* + * 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 ""; + } + + public function equals(otherField:TField) : Bool { + return type == otherField.type && id == otherField.id; + } + +} 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 00000000000..d6c15c181bf --- /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 00000000000..5af8c4ec7ce --- /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 00000000000..98c883bfd27 --- /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 ""; + } + + 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 00000000000..b1419402d92 --- /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 00000000000..eeca4a364f6 --- /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; + +} \ No newline at end of file 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 00000000000..dbbcb8cb797 --- /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 00000000000..d231dbed1f6 --- /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 00000000000..794e397fd58 --- /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 00000000000..77806e674e8 --- /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 00000000000..faeef404e84 --- /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 00000000000..3c952f21baa --- /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; + +} \ No newline at end of file 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 00000000000..9b235f69b09 --- /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 00000000000..08f48b2a69e --- /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 00000000000..20a71950327 --- /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 00000000000..5d77140ba27 --- /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 00000000000..00127bf0498 --- /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 00000000000..4e898f89b72 --- /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 00000000000..d2fda79f72b --- /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 00000000000..1953244a0f6 --- /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 00000000000..e0ce6972093 --- /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 00000000000..306730d9542 --- /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 00000000000..35303d5d414 --- /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 00000000000..3db64569e98 --- /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 00000000000..f20321f47d9 --- /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 cc1f43d2982..23ec4988acd 100755 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -49,6 +49,10 @@ if WITH_HASKELL 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 00000000000..08c0369e755 --- /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 00000000000..6adb52d7e33 --- /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 00000000000..295c017e739 --- /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 00000000000..a1f0568ad4a --- /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 00000000000..c615565a9a6 --- /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 00000000000..b2b3876cf15 --- /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 00000000000..eaeba890d42 --- /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 00000000000..26212587743 --- /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 00000000000..6161f69773c --- /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 00000000000..1eaac8b2b94 --- /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 00000000000..9bb9bf9c1fc --- /dev/null +++ b/test/haxe/project.hide @@ -0,0 +1,94 @@ +{ + "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" + } + ,{ + "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" : 47 + } + ,{ + "path" : "src\\TestServer.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 70 + } + ,{ + "path" : "src\\TestClient.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 599 + } + ,{ + "path" : "src\\TestServerHandler.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 309 + } + ] + ,"activeFile" : "src\\TestClient.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 00000000000..f2c19fa93e1 --- /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 00000000000..ddb647a20cc --- /dev/null +++ b/test/haxe/src/Arguments.hx @@ -0,0 +1,173 @@ +/* + * 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(e); + trace(GetHelp()); + return; + } + #else + trace("WN: Platform does not support program arguments, using defaults."); + #end + } + + #if sys + + 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"; + */ + return "TODO: help screen"; + } + + + 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.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 00000000000..a8ad147a27c --- /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 00000000000..6f800aef8ea --- /dev/null +++ b/test/haxe/src/TestClient.hx @@ -0,0 +1,690 @@ +/* + * 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(); + 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"); + throw "JSON protocol not implemented yet"; + //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(); + var map64 = new Int64Map(); + + rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map Test #1"); + rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #2"); + rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map Test #3"); + rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map 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 Test #10"); + rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #11"); + rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map Test #12"); + rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map Test #13"); + rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map Test #14"); + rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map Test #15"); + rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map Test #16"); + rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map Test #Int64.make(-5,17)"); + rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map Test #18"); + rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map Test #19"); + rslt.Expect( map32.remove( -517) == map64.remove( Int64.make(-5,17)), "Int64Map Test #20"); + rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #21"); + rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map Test #22"); + rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map Test #23"); + rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map Test #24"); + rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map Test #25"); + rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map Test #26"); + rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map Test #27"); + rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map 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 Test #30"); + + var s32 = map32.toString(); + var s64 = map64.toString(); + trace("Int64Map.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 Test #90"); + rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map Test #91"); + rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map Test #92"); + rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map Test #93"); + rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map Test #94"); + rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map Test #95"); + rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map Test #96"); + rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map Test #97"); + rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map 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))); + + 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(); + 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(); + 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 00000000000..8b177e9e16c --- /dev/null +++ b/test/haxe/src/TestServer.hx @@ -0,0 +1,107 @@ +/* + * 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"); + throw "JSON protocol not implemented yet"; + //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 00000000000..b52943a22a4 --- /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 00000000000..e988adbeb21 --- /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 thing - the map to print + * @return map - returns the map 'thing' + * + * @param thing + */ + public function testMap(thing:IntMap):IntMap + { + 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 thing - the map to print + * @return map - returns the map 'thing' + * + * @param thing + */ + public function testStringMap(thing:StringMap):StringMap + { + 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 thing - the set to print + * @return set - returns the set '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 thing - the list to print + * @return list - returns the list 'thing' + * + * @param thing + */ + public function testList(thing:List):List + { + 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> - 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> + { + trace("testMapMap(" + hello + ")"); + var mapmap = new IntMap>(); + var pos = new IntMap(); + var neg = new IntMap(); + 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 => , }, + * } + * @return map> - 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(); + 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 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, 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 2b9be528ab7..79fd8fd65c2 100755 --- a/tutorial/Makefile.am +++ b/tutorial/Makefile.am @@ -50,6 +50,10 @@ if WITH_HASKELL 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 00000000000..d98be0af2f0 --- /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 00000000000..6adb52d7e33 --- /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 00000000000..295c017e739 --- /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 00000000000..a1f0568ad4a --- /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 00000000000..c615565a9a6 --- /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 00000000000..b2b3876cf15 --- /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 00000000000..656dd1530fa --- /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 00000000000..2ee650dce26 --- /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 00000000000..6161f69773c --- /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 00000000000..1eaac8b2b94 --- /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 00000000000..4b724c87bcd --- /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" : 16 + } + ] + ,"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 00000000000..f2c19fa93e1 --- /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 00000000000..ee75edd9d45 --- /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(); + + 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 00000000000..356f20dca71 --- /dev/null +++ b/tutorial/haxe/src/Main.hx @@ -0,0 +1,331 @@ +/* + * 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: + throw "JSON protocol not implemented yet"; + //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: + throw "JSON protocol not implemented yet"; + //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 db4b69443be..60e8e7adbd2 100644 --- a/tutorial/shared.thrift +++ b/tutorial/shared.thrift @@ -27,6 +27,7 @@ namespace d share // "shared" would collide with the eponymous D keyword. 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 3150151dece..c8710d418ca 100644 --- a/tutorial/tutorial.thrift +++ b/tutorial/tutorial.thrift @@ -67,6 +67,7 @@ namespace d tutorial 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 From 61a4c96cf39a2b5472e437e3464153b605e5de4d Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Tue, 16 Sep 2014 22:49:40 +0200 Subject: [PATCH 19/24] THRIFT-2704 generated oneway functions encode as T_CALL not T_ONEWAY --- compiler/cpp/src/generate/t_haxe_generator.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/cpp/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc index 9c71db19d8e..24457e5b67b 100644 --- a/compiler/cpp/src/generate/t_haxe_generator.cc +++ b/compiler/cpp/src/generate/t_haxe_generator.cc @@ -1730,8 +1730,9 @@ void t_haxe_generator::generate_service_client(t_service* tservice) { const vector& 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.CALL, seqid_));" << endl << + 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) { From 5517bf0bf3afa2c73ecb1962b320b5c8f2b4e4a3 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Sat, 20 Sep 2014 00:00:12 +0200 Subject: [PATCH 20/24] - added JSON transport - added cmdline args help text --- .../src/org/apache/thrift/protocol/TField.hx | 7 +- .../apache/thrift/protocol/TJSONProtocol.hx | 1074 +++++++++++++++++ .../thrift/protocol/TJSONProtocolFactory.hx | 40 + .../org/apache/thrift/protocol/TProtocol.hx | 2 +- .../src/org/apache/thrift/protocol/TType.hx | 2 +- test/haxe/project.hide | 21 +- test/haxe/src/Arguments.hx | 34 +- test/haxe/src/TestClient.hx | 10 +- test/haxe/src/TestServer.hx | 3 +- tutorial/haxe/project.hide | 2 +- tutorial/haxe/src/Main.hx | 6 +- 11 files changed, 1159 insertions(+), 42 deletions(-) create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TJSONProtocolFactory.hx diff --git a/lib/haxe/src/org/apache/thrift/protocol/TField.hx b/lib/haxe/src/org/apache/thrift/protocol/TField.hx index 9f3db62dfd3..20f3fb9f0e8 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TField.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TField.hx @@ -32,11 +32,12 @@ class TField { } public function toString() : String { - return ""; + return ''; } - public function equals(otherField:TField) : Bool { - return type == otherField.type && id == otherField.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 00000000000..edd5e12fd4f --- /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 = new GenericStack(); + + // 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 00000000000..169629aa244 --- /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/TProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx index eeca4a364f6..58873da8609 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx @@ -79,4 +79,4 @@ interface TProtocol { function readString() : String; function readBinary() : Bytes; -} \ 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 index 3c952f21baa..05343999e0d 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TType.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TType.hx @@ -35,4 +35,4 @@ class TType { public static inline var SET : Int = 14; public static inline var LIST : Int = 15; -} \ No newline at end of file +} diff --git a/test/haxe/project.hide b/test/haxe/project.hide index 9bb9bf9c1fc..f09030b5545 100644 --- a/test/haxe/project.hide +++ b/test/haxe/project.hide @@ -29,7 +29,7 @@ ,{ "pathToHxml" : "cpp.hxml" ,"runActionType" : 2 - ,"runActionText" : "bin/Main-debug.exe" + ,"runActionText" : "bin/Main-debug.exe client --json" } ,{ "pathToHxml" : "java.hxml" @@ -51,16 +51,16 @@ ,"foldedRegions" : [ ] - ,"activeLine" : 47 + ,"activeLine" : 159 } ,{ - "path" : "src\\TestServer.hx" + "path" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\protocol\\TJSONProtocol.hx" ,"useTabs" : true ,"indentSize" : 4 ,"foldedRegions" : [ ] - ,"activeLine" : 70 + ,"activeLine" : 665 } ,{ "path" : "src\\TestClient.hx" @@ -69,19 +69,10 @@ ,"foldedRegions" : [ ] - ,"activeLine" : 599 - } - ,{ - "path" : "src\\TestServerHandler.hx" - ,"useTabs" : true - ,"indentSize" : 4 - ,"foldedRegions" : [ - - ] - ,"activeLine" : 309 + ,"activeLine" : 325 } ] - ,"activeFile" : "src\\TestClient.hx" + ,"activeFile" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\protocol\\TJSONProtocol.hx" ,"openFLTarget" : null ,"openFLBuildMode" : "Debug" ,"runActionType" : null diff --git a/test/haxe/src/Arguments.hx b/test/haxe/src/Arguments.hx index ddb647a20cc..bcf3793cb2a 100644 --- a/test/haxe/src/Arguments.hx +++ b/test/haxe/src/Arguments.hx @@ -59,9 +59,8 @@ class Arguments try { ParseArgs(); } catch (e : String) { - trace(e); trace(GetHelp()); - return; + throw e; } #else trace("WN: Platform does not support program arguments, using defaults."); @@ -71,17 +70,24 @@ class Arguments #if sys 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"; - */ - return "TODO: help screen"; + 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= Choose protocol: json, binary (default binary).\n" + +" --port= Port number for socket transport, default 9090\n" + +"\n" + +"Client only options:\n" + +" --host= Host name, IP or URL, default localhost\n" + +" -n= Number of test iterations\n" + +" -t= Number of test threads\n" + +" -u= Target Host/URL (same as --host)\n" + +"\n" + +"All arguments are optional.\n"; } @@ -107,6 +113,8 @@ class Arguments 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); diff --git a/test/haxe/src/TestClient.hx b/test/haxe/src/TestClient.hx index 6f800aef8ea..8698220aa9e 100644 --- a/test/haxe/src/TestClient.hx +++ b/test/haxe/src/TestClient.hx @@ -179,8 +179,7 @@ class TestClient { protocol = new TBinaryProtocol(transport); case json: trace("- json protocol"); - throw "JSON protocol not implemented yet"; - //protocol = new TJsonProtocol(transport); + protocol = new TJSONProtocol(transport); default: throw "Unhandled protocol"; } @@ -322,6 +321,13 @@ class TestClient { 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'); diff --git a/test/haxe/src/TestServer.hx b/test/haxe/src/TestServer.hx index 8b177e9e16c..66b06e0092e 100644 --- a/test/haxe/src/TestServer.hx +++ b/test/haxe/src/TestServer.hx @@ -68,8 +68,7 @@ class TestServer protfactory = new TBinaryProtocolFactory(); case json: trace("- json protocol"); - throw "JSON protocol not implemented yet"; - //protfactory = new TJsonProtocolFactory(); + protfactory = new TJSONProtocolFactory(); default: throw "Unhandled protocol"; } diff --git a/tutorial/haxe/project.hide b/tutorial/haxe/project.hide index 4b724c87bcd..46c0a50069d 100644 --- a/tutorial/haxe/project.hide +++ b/tutorial/haxe/project.hide @@ -89,7 +89,7 @@ ,"foldedRegions" : [ ] - ,"activeLine" : 16 + ,"activeLine" : 276 } ] ,"activeFile" : "src\\Main.hx" diff --git a/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx index 356f20dca71..e65be162b5f 100644 --- a/tutorial/haxe/src/Main.hx +++ b/tutorial/haxe/src/Main.hx @@ -185,8 +185,7 @@ class Main { protocol = new TBinaryProtocol( transport); case json: throw "JSON protocol not implemented yet"; - //trace("- json protocol"); - //protocol = new TJsonProtocol( transport); + protocol = new TJSONProtocol( transport); default: throw "Unhandled protocol"; } @@ -300,8 +299,7 @@ class Main { protfactory = new TBinaryProtocolFactory(); case json: throw "JSON protocol not implemented yet"; - //trace("- json protocol"); - //protfactory = new TJsonProtocolFactory(); + protfactory = new TJSONProtocolFactory(); default: throw "Unhandled protocol"; } From 36f90f39768b00f9ea5e4bbc20d5e78204c322e3 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Sat, 20 Sep 2014 00:00:12 +0200 Subject: [PATCH 21/24] - added JSON transport - added cmdline args help text --- compiler/cpp/compiler.vcxproj | 2 +- compiler/cpp/compiler.vcxproj.filters | 3 + .../src/org/apache/thrift/protocol/TField.hx | 7 +- .../apache/thrift/protocol/TJSONProtocol.hx | 1074 +++++++++++++++++ .../thrift/protocol/TJSONProtocolFactory.hx | 40 + .../org/apache/thrift/protocol/TProtocol.hx | 2 +- .../src/org/apache/thrift/protocol/TType.hx | 2 +- test/haxe/project.hide | 21 +- test/haxe/src/Arguments.hx | 34 +- test/haxe/src/TestClient.hx | 10 +- test/haxe/src/TestServer.hx | 3 +- tutorial/haxe/project.hide | 2 +- tutorial/haxe/src/Main.hx | 6 +- 13 files changed, 1163 insertions(+), 43 deletions(-) create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx create mode 100644 lib/haxe/src/org/apache/thrift/protocol/TJSONProtocolFactory.hx diff --git a/compiler/cpp/compiler.vcxproj b/compiler/cpp/compiler.vcxproj index faac9dcb106..f49106fad73 100644 --- a/compiler/cpp/compiler.vcxproj +++ b/compiler/cpp/compiler.vcxproj @@ -60,7 +60,7 @@ - + diff --git a/compiler/cpp/compiler.vcxproj.filters b/compiler/cpp/compiler.vcxproj.filters index b31918e43d7..c400f7e4f7b 100644 --- a/compiler/cpp/compiler.vcxproj.filters +++ b/compiler/cpp/compiler.vcxproj.filters @@ -124,6 +124,9 @@ generate + + generate + generate diff --git a/lib/haxe/src/org/apache/thrift/protocol/TField.hx b/lib/haxe/src/org/apache/thrift/protocol/TField.hx index 9f3db62dfd3..20f3fb9f0e8 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TField.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TField.hx @@ -32,11 +32,12 @@ class TField { } public function toString() : String { - return ""; + return ''; } - public function equals(otherField:TField) : Bool { - return type == otherField.type && id == otherField.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 00000000000..edd5e12fd4f --- /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 = new GenericStack(); + + // 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 00000000000..169629aa244 --- /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/TProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx index eeca4a364f6..58873da8609 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx @@ -79,4 +79,4 @@ interface TProtocol { function readString() : String; function readBinary() : Bytes; -} \ 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 index 3c952f21baa..05343999e0d 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TType.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TType.hx @@ -35,4 +35,4 @@ class TType { public static inline var SET : Int = 14; public static inline var LIST : Int = 15; -} \ No newline at end of file +} diff --git a/test/haxe/project.hide b/test/haxe/project.hide index 9bb9bf9c1fc..f09030b5545 100644 --- a/test/haxe/project.hide +++ b/test/haxe/project.hide @@ -29,7 +29,7 @@ ,{ "pathToHxml" : "cpp.hxml" ,"runActionType" : 2 - ,"runActionText" : "bin/Main-debug.exe" + ,"runActionText" : "bin/Main-debug.exe client --json" } ,{ "pathToHxml" : "java.hxml" @@ -51,16 +51,16 @@ ,"foldedRegions" : [ ] - ,"activeLine" : 47 + ,"activeLine" : 159 } ,{ - "path" : "src\\TestServer.hx" + "path" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\protocol\\TJSONProtocol.hx" ,"useTabs" : true ,"indentSize" : 4 ,"foldedRegions" : [ ] - ,"activeLine" : 70 + ,"activeLine" : 665 } ,{ "path" : "src\\TestClient.hx" @@ -69,19 +69,10 @@ ,"foldedRegions" : [ ] - ,"activeLine" : 599 - } - ,{ - "path" : "src\\TestServerHandler.hx" - ,"useTabs" : true - ,"indentSize" : 4 - ,"foldedRegions" : [ - - ] - ,"activeLine" : 309 + ,"activeLine" : 325 } ] - ,"activeFile" : "src\\TestClient.hx" + ,"activeFile" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\protocol\\TJSONProtocol.hx" ,"openFLTarget" : null ,"openFLBuildMode" : "Debug" ,"runActionType" : null diff --git a/test/haxe/src/Arguments.hx b/test/haxe/src/Arguments.hx index ddb647a20cc..bcf3793cb2a 100644 --- a/test/haxe/src/Arguments.hx +++ b/test/haxe/src/Arguments.hx @@ -59,9 +59,8 @@ class Arguments try { ParseArgs(); } catch (e : String) { - trace(e); trace(GetHelp()); - return; + throw e; } #else trace("WN: Platform does not support program arguments, using defaults."); @@ -71,17 +70,24 @@ class Arguments #if sys 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"; - */ - return "TODO: help screen"; + 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= Choose protocol: json, binary (default binary).\n" + +" --port= Port number for socket transport, default 9090\n" + +"\n" + +"Client only options:\n" + +" --host= Host name, IP or URL, default localhost\n" + +" -n= Number of test iterations\n" + +" -t= Number of test threads\n" + +" -u= Target Host/URL (same as --host)\n" + +"\n" + +"All arguments are optional.\n"; } @@ -107,6 +113,8 @@ class Arguments 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); diff --git a/test/haxe/src/TestClient.hx b/test/haxe/src/TestClient.hx index 6f800aef8ea..8698220aa9e 100644 --- a/test/haxe/src/TestClient.hx +++ b/test/haxe/src/TestClient.hx @@ -179,8 +179,7 @@ class TestClient { protocol = new TBinaryProtocol(transport); case json: trace("- json protocol"); - throw "JSON protocol not implemented yet"; - //protocol = new TJsonProtocol(transport); + protocol = new TJSONProtocol(transport); default: throw "Unhandled protocol"; } @@ -322,6 +321,13 @@ class TestClient { 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'); diff --git a/test/haxe/src/TestServer.hx b/test/haxe/src/TestServer.hx index 8b177e9e16c..66b06e0092e 100644 --- a/test/haxe/src/TestServer.hx +++ b/test/haxe/src/TestServer.hx @@ -68,8 +68,7 @@ class TestServer protfactory = new TBinaryProtocolFactory(); case json: trace("- json protocol"); - throw "JSON protocol not implemented yet"; - //protfactory = new TJsonProtocolFactory(); + protfactory = new TJSONProtocolFactory(); default: throw "Unhandled protocol"; } diff --git a/tutorial/haxe/project.hide b/tutorial/haxe/project.hide index 4b724c87bcd..46c0a50069d 100644 --- a/tutorial/haxe/project.hide +++ b/tutorial/haxe/project.hide @@ -89,7 +89,7 @@ ,"foldedRegions" : [ ] - ,"activeLine" : 16 + ,"activeLine" : 276 } ] ,"activeFile" : "src\\Main.hx" diff --git a/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx index 356f20dca71..e65be162b5f 100644 --- a/tutorial/haxe/src/Main.hx +++ b/tutorial/haxe/src/Main.hx @@ -185,8 +185,7 @@ class Main { protocol = new TBinaryProtocol( transport); case json: throw "JSON protocol not implemented yet"; - //trace("- json protocol"); - //protocol = new TJsonProtocol( transport); + protocol = new TJSONProtocol( transport); default: throw "Unhandled protocol"; } @@ -300,8 +299,7 @@ class Main { protfactory = new TBinaryProtocolFactory(); case json: throw "JSON protocol not implemented yet"; - //trace("- json protocol"); - //protfactory = new TJsonProtocolFactory(); + protfactory = new TJSONProtocolFactory(); default: throw "Unhandled protocol"; } From cf2d54253c3c864bccd919f196a98bd2084cc0d6 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Mon, 22 Sep 2014 23:07:46 +0200 Subject: [PATCH 22/24] JSON protocol added to tutorial; revised README.md --- lib/haxe/README.md | 4 ++-- tutorial/haxe/src/Main.hx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/haxe/README.md b/lib/haxe/README.md index eae1bd15536..3335b431706 100644 --- a/lib/haxe/README.md +++ b/lib/haxe/README.md @@ -32,14 +32,14 @@ If you are using HIDE, you'll find the HIDE project files in these folders. Current status ======================== - tested with Haxe C++ target -- socket transport, binary protocol available +- transports: socket +- protocols: binary, JSON - tutorial client and server available - cross-test client and server available Further developments ======================== -- add JSON protocol, update tutorial and tests accordingly - 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 diff --git a/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx index e65be162b5f..5c9345ef6ce 100644 --- a/tutorial/haxe/src/Main.hx +++ b/tutorial/haxe/src/Main.hx @@ -184,7 +184,7 @@ class Main { trace("- binary protocol"); protocol = new TBinaryProtocol( transport); case json: - throw "JSON protocol not implemented yet"; + trace("- JSON protocol"); protocol = new TJSONProtocol( transport); default: throw "Unhandled protocol"; @@ -298,7 +298,7 @@ class Main { trace("- binary protocol"); protfactory = new TBinaryProtocolFactory(); case json: - throw "JSON protocol not implemented yet"; + trace("- JSON protocol"); protfactory = new TJSONProtocolFactory(); default: throw "Unhandled protocol"; From d8c1cc00ed8d7781830e86f7bdc333afa135d752 Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Wed, 1 Oct 2014 02:22:48 +0200 Subject: [PATCH 23/24] Test improvements - added missing testException tests - aligned cross test return codes - aligned cross test command line arguments - added --skip-speed-test switch Code generator improvements - added suffix "_FIELD_ID" to the fieldIDs to prevent name collisions with uppercase-only members (like ID, VAT) - always render enum type with full namespace to prevent name collisions with class members Library improvements - HTTP transport client added - Generic Stream transport added, implemented FileStream transport - fixed possible double UTF-8 encoding/decoding in JSON protocol - Haxe Thrift library test project added --- .gitignore | 1 + compiler/cpp/src/generate/t_haxe_generator.cc | 14 +- configure.ac | 1 + lib/haxe/README.md | 12 +- .../apache/thrift/protocol/TJSONProtocol.hx | 67 ++-- .../src/org/apache/thrift/server/TServer.hx | 2 +- .../thrift/server/TServerEventHandler.hx | 2 +- .../org/apache/thrift/server/TSimpleServer.hx | 2 +- .../apache/thrift/transport/TFileStream.hx | 100 ++++++ .../thrift/transport/TFramedTransport.hx | 2 +- .../transport/TFramedTransportFactory.hx | 2 +- .../apache/thrift/transport/THttpClient.hx | 102 +----- .../apache/thrift/transport/TServerSocket.hx | 2 +- .../thrift/transport/TServerTransport.hx | 2 +- .../org/apache/thrift/transport/TStream.hx | 32 ++ .../thrift/transport/TStreamTransport.hx | 103 ++++++ lib/haxe/test/Makefile.am | 50 +++ lib/haxe/test/cpp.hxml | 41 +++ lib/haxe/test/csharp.hxml | 38 ++ lib/haxe/test/flash.hxml | 38 ++ lib/haxe/test/java.hxml | 38 ++ lib/haxe/test/javascript.hxml | 44 +++ lib/haxe/test/make_all.bat | 68 ++++ lib/haxe/test/make_all.sh | 41 +++ lib/haxe/test/neko.hxml | 38 ++ lib/haxe/test/php.hxml | 38 ++ lib/haxe/test/project.hide | 67 ++++ lib/haxe/test/python.hxml | 38 ++ lib/haxe/test/src/Main.hx | 45 +++ lib/haxe/test/src/StreamTest.hx | 93 +++++ lib/haxe/test/src/TestBase.hx | 39 ++ test/haxe/Makefile.am | 4 +- test/haxe/project.hide | 21 +- test/haxe/src/Arguments.hx | 333 +++++++++++++----- test/haxe/src/Main.hx | 3 + test/haxe/src/TestClient.hx | 146 ++++++-- test/haxe/src/TestServer.hx | 20 +- tutorial/haxe/project.hide | 2 +- tutorial/haxe/src/Main.hx | 6 +- 39 files changed, 1409 insertions(+), 288 deletions(-) create mode 100644 lib/haxe/src/org/apache/thrift/transport/TFileStream.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TStream.hx create mode 100644 lib/haxe/src/org/apache/thrift/transport/TStreamTransport.hx create mode 100644 lib/haxe/test/Makefile.am create mode 100644 lib/haxe/test/cpp.hxml create mode 100644 lib/haxe/test/csharp.hxml create mode 100644 lib/haxe/test/flash.hxml create mode 100644 lib/haxe/test/java.hxml create mode 100644 lib/haxe/test/javascript.hxml create mode 100644 lib/haxe/test/make_all.bat create mode 100644 lib/haxe/test/make_all.sh create mode 100644 lib/haxe/test/neko.hxml create mode 100644 lib/haxe/test/php.hxml create mode 100644 lib/haxe/test/project.hide create mode 100644 lib/haxe/test/python.hxml create mode 100644 lib/haxe/test/src/Main.hx create mode 100644 lib/haxe/test/src/StreamTest.hx create mode 100644 lib/haxe/test/src/TestBase.hx diff --git a/.gitignore b/.gitignore index 2b99c2debad..120de3267b2 100644 --- a/.gitignore +++ b/.gitignore @@ -161,6 +161,7 @@ test-driver /lib/erl/.eunit /lib/erl/ebin /lib/erl/deps/ +/lib/haxe/test/bin /lib/hs/dist /lib/java/build /lib/js/test/build diff --git a/compiler/cpp/src/generate/t_haxe_generator.cc b/compiler/cpp/src/generate/t_haxe_generator.cc index 24457e5b67b..aaa6d0182bf 100644 --- a/compiler/cpp/src/generate/t_haxe_generator.cc +++ b/compiler/cpp/src/generate/t_haxe_generator.cc @@ -759,7 +759,7 @@ void t_haxe_generator::generate_haxe_struct_definition(ofstream &out, 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; + indent(out) << "inline static var " << upcase_string((*m_iter)->get_name()) << "_FIELD_ID : Int = " << (*m_iter)->get_key() << ";" << endl; } out << endl; @@ -869,7 +869,7 @@ void t_haxe_generator::generate_haxe_struct_reader(ofstream& 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; + "case " << upcase_string((*f_iter)->get_name()) << "_FIELD_ID:" << endl; indent_up(); indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; @@ -1079,7 +1079,7 @@ void t_haxe_generator::generate_haxe_struct_result_writer(ofstream& out, 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(out) << "case " << upcase_string(field_name) << "_FIELD_ID:" << endl; indent_up(); indent(out) << "return this." << field_name << ";" << endl; indent_down(); @@ -1088,7 +1088,7 @@ void t_haxe_generator::generate_reflection_getters(ostringstream& out, t_type* t 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(out) << "case " << upcase_string(field_name) << "_FIELD_ID:" << endl; indent_up(); indent(out) << "if (value == null) {" << endl; indent(out) << " unset" << get_cap_name(field_name) << "();" << endl; @@ -1170,7 +1170,7 @@ void t_haxe_generator::generate_generic_isset_method(std::ofstream& out, t_struc 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(out) << "case " << upcase_string(field->get_name()) << "_FIELD_ID:" << endl; indent_up(); indent(out) << "return " << generate_isset_check(field) << ";" << endl; indent_down(); @@ -1347,7 +1347,7 @@ void t_haxe_generator::generate_haxe_meta_data_map(ofstream& 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 << "\", "; + indent(out) << "metaDataMap[" << upcase_string(field_name) << "_FIELD_ID] = new FieldMetaData(\"" << field_name << "\", "; // Set field requirement type (required, optional, etc.) if (field->get_req() == t_field::T_REQUIRED) { @@ -2937,7 +2937,7 @@ void t_haxe_generator::generate_isset_set(ofstream& out, t_field* field) { 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_) { + if (program != NULL /*&& program != program_*/) { package = program->get_namespace("haxe") + "."; } return package + type->get_name(); diff --git a/configure.ac b/configure.ac index 43e1d652abe..2f20a68b0c8 100755 --- a/configure.ac +++ b/configure.ac @@ -652,6 +652,7 @@ AC_CONFIG_FILES([ lib/erl/Makefile lib/go/Makefile lib/go/test/Makefile + lib/haxe/test/Makefile lib/hs/Makefile lib/java/Makefile lib/js/test/Makefile diff --git a/lib/haxe/README.md b/lib/haxe/README.md index 3335b431706..82525d4df65 100644 --- a/lib/haxe/README.md +++ b/lib/haxe/README.md @@ -32,17 +32,17 @@ 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 +- transports: Socket, HTTP (client only), Stream +- 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 +- add HTTP server, update tutorial and tests accordingly Dependencies @@ -53,9 +53,9 @@ Depending on the desired targets, you may have to install the appropriate HaxeLi 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 + 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. diff --git a/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx index edd5e12fd4f..eafa7c9a030 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx @@ -1,4 +1,4 @@ -/** +/* * 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 @@ -58,6 +58,9 @@ class TJSONProtocol implements TProtocol { // Reader that manages a 1-byte buffer private var reader : LookaheadReader; + // whether the underlying system holds Strings as UTF-8 + // http://old.haxe.org/manual/encoding + private static var utf8Strings = haxe.Utf8.validate("Ç-ß-Æ-Ю-Ш"); // TJSONProtocol Constructor public function new( trans : TTransport) @@ -74,7 +77,7 @@ class TJSONProtocol implements TProtocol { public function writeMessageBegin(message:TMessage) : Void { WriteJSONArrayStart(); WriteJSONInteger( JSONConstants.VERSION); - WriteJSONString( Utf8Encode(message.name)); + WriteJSONString( BytesFromString(message.name)); WriteJSONInteger( message.type); WriteJSONInteger( message.seqid); } @@ -94,7 +97,7 @@ class TJSONProtocol implements TProtocol { public function writeFieldBegin(field:TField) : Void { WriteJSONInteger( field.id ); WriteJSONObjectStart(); - WriteJSONString( Utf8Encode( JSONConstants.GetTypeNameForTypeID( field.type))); + WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( field.type))); } public function writeFieldEnd() : Void { @@ -105,8 +108,8 @@ class TJSONProtocol implements TProtocol { public function writeMapBegin(map:TMap) : Void { WriteJSONArrayStart(); - WriteJSONString( Utf8Encode( JSONConstants.GetTypeNameForTypeID( map.keyType))); - WriteJSONString( Utf8Encode( JSONConstants.GetTypeNameForTypeID( map.valueType))); + WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( map.keyType))); + WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( map.valueType))); WriteJSONInteger( map.size); WriteJSONObjectStart(); } @@ -118,7 +121,7 @@ class TJSONProtocol implements TProtocol { public function writeListBegin(list:TList) : Void { WriteJSONArrayStart(); - WriteJSONString( Utf8Encode( JSONConstants.GetTypeNameForTypeID( list.elemType ))); + WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( list.elemType ))); WriteJSONInteger( list.size); } @@ -128,7 +131,7 @@ class TJSONProtocol implements TProtocol { public function writeSetBegin(set:TSet) : Void { WriteJSONArrayStart(); - WriteJSONString( Utf8Encode( JSONConstants.GetTypeNameForTypeID( set.elemType))); + WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( set.elemType))); WriteJSONInteger( set.size); } @@ -164,7 +167,7 @@ class TJSONProtocol implements TProtocol { } public function writeString(str : String) : Void { - WriteJSONString( Utf8Encode(str)); + WriteJSONString( BytesFromString(str)); } public function writeBinary(bin:Bytes) : Void { @@ -180,8 +183,7 @@ class TJSONProtocol implements TProtocol { "Message contained bad version."); } - var buf = ReadJSONString(false); - message.name = Utf8Decode(buf); + message.name = ReadJSONString(false); message.type = ReadJSONInteger(); message.seqid = ReadJSONInteger(); return message; @@ -211,7 +213,7 @@ class TJSONProtocol implements TProtocol { { field.id = ReadJSONInteger(); ReadJSONObjectStart(); - field.type = JSONConstants.GetTypeIDForTypeName( Utf8Decode( ReadJSONString(false))); + field.type = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false)); } return field; } @@ -222,8 +224,8 @@ class TJSONProtocol implements TProtocol { public function readMapBegin() : TMap { ReadJSONArrayStart(); - var KeyType = JSONConstants.GetTypeIDForTypeName( Utf8Decode( ReadJSONString(false))); - var ValueType = JSONConstants.GetTypeIDForTypeName( Utf8Decode( ReadJSONString(false))); + var KeyType = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false)); + var ValueType = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false)); var Count : Int = ReadJSONInteger(); ReadJSONObjectStart(); @@ -238,7 +240,7 @@ class TJSONProtocol implements TProtocol { public function readListBegin():TList { ReadJSONArrayStart(); - var ElementType = JSONConstants.GetTypeIDForTypeName( Utf8Decode( ReadJSONString(false))); + var ElementType = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false)); var Count : Int = ReadJSONInteger(); var list = new TList( ElementType, Count); @@ -251,7 +253,7 @@ class TJSONProtocol implements TProtocol { public function readSetBegin() : TSet { ReadJSONArrayStart(); - var ElementType = JSONConstants.GetTypeIDForTypeName( Utf8Decode( ReadJSONString(false))); + var ElementType = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false)); var Count : Int = ReadJSONInteger(); var set = new TSet( ElementType, Count); @@ -263,7 +265,7 @@ class TJSONProtocol implements TProtocol { } public function readBool() : Bool { - return (ReadJSONInteger() == 0 ? false : true); + return (ReadJSONInteger() != 0); } public function readByte() : Int { @@ -287,8 +289,7 @@ class TJSONProtocol implements TProtocol { } public function readString() : String { - var buf = ReadJSONString(false); - return Utf8Decode(buf); + return ReadJSONString(false); } public function readBinary() : Bytes { @@ -402,7 +403,6 @@ class TJSONProtocol implements TProtocol { str += JSONConstants.QUOTE; } -trace('WriteJSONInt64($str)'); var tmp = BytesFromString( str); trans.write( tmp, 0, tmp.length); } @@ -502,7 +502,7 @@ trace('WriteJSONInt64($str)'); // Read in a JSON string, unescaping as appropriate. // Skip Reading from the context if skipContext is true. - private function ReadJSONString(skipContext : Bool) : Bytes + private function ReadJSONString(skipContext : Bool) : String { if (!skipContext) { @@ -560,7 +560,7 @@ trace('WriteJSONInt64($str)'); buffer.addString( String.fromCharCode(charcode)); } - return buffer.getBytes(); + return StringFromBytes( buffer.getBytes()); } // Return true if the given byte could be a valid part of a JSON number. @@ -642,8 +642,6 @@ trace('WriteJSONInt64($str)'); ReadJSONSyntaxChar( JSONConstants.QUOTE); } -trace('ReadJSONInt64() = $str'); - // process sign var bMinus = false; var startAt = 0; @@ -689,7 +687,7 @@ trace('ReadJSONInt64() = $str'); var str : String = ""; if (StringFromBytes(reader.Peek()) == JSONConstants.QUOTE) { - str = StringFromBytes( ReadJSONString(true)); + str = ReadJSONString(true); // special cases if( str == JSONConstants.FLOAT_IS_NAN) { @@ -729,7 +727,7 @@ trace('ReadJSONInt64() = $str'); // Read in a JSON string containing base-64 encoded data and decode it. private function ReadJSONBase64() : Bytes { - var str = StringFromBytes( ReadJSONString(false)); + var str = ReadJSONString(false); return Base64.decode( str); } @@ -758,21 +756,20 @@ trace('ReadJSONInt64() = $str'); public static function BytesFromString( str : String) : Bytes { var buf = new BytesBuffer(); - buf.addString( str); + if( utf8Strings) + buf.addString( str); // no need to encode on UTF8 targets, the string is just fine + else + buf.addString( Utf8.encode( 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)); + var str = inp.readString( buf.length); + if( utf8Strings) + return str; // no need to decode on UTF8 targets, the string is just fine + else + return Utf8.decode( str); } // Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its corresponding hex value diff --git a/lib/haxe/src/org/apache/thrift/server/TServer.hx b/lib/haxe/src/org/apache/thrift/server/TServer.hx index 9b235f69b09..37105bd46b4 100644 --- a/lib/haxe/src/org/apache/thrift/server/TServer.hx +++ b/lib/haxe/src/org/apache/thrift/server/TServer.hx @@ -1,4 +1,4 @@ -/** +/* * 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 diff --git a/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx b/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx index 08f48b2a69e..83bff959642 100644 --- a/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx +++ b/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx @@ -1,4 +1,4 @@ -/** +/* * 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 diff --git a/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx b/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx index 20a71950327..c516b786054 100644 --- a/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx +++ b/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx @@ -1,4 +1,4 @@ -/** +/* * 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 diff --git a/lib/haxe/src/org/apache/thrift/transport/TFileStream.hx b/lib/haxe/src/org/apache/thrift/transport/TFileStream.hx new file mode 100644 index 00000000000..03e031f978e --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/transport/TFileStream.hx @@ -0,0 +1,100 @@ +/* + * 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.Input; +import haxe.io.Output; + + +enum TFileMode { + CreateNew; + Append; + Read; +} + + +class TFileStream implements TStream { + + public var FileName(default,null) : String; + + private var Input : sys.io.FileInput; + private var Output : sys.io.FileOutput; + + + public function new( fname : String, mode : TFileMode) { + FileName = fname; + switch ( mode) + { + case TFileMode.CreateNew: + Output = sys.io.File.write( fname, true); + + case TFileMode.Append: + Output = sys.io.File.append( fname, true); + + case TFileMode.Read: + Input = sys.io.File.read( fname, true); + + default: + throw new TTransportException( TTransportException.UNKNOWN, + "Unsupported mode"); + } + + } + + public function Close() : Void { + if( Input != null) { + Input.close(); + Input = null; + } + if( Output != null) { + Output.close(); + Output = null; + } + } + + public function Peek() : Bool { + if( Input == null) + throw new TTransportException( TTransportException.NOT_OPEN, "File not open for input"); + + return (! Input.eof()); + } + + public function Read( buf : Bytes, offset : Int, count : Int) : Int { + if( Input == null) + throw new TTransportException( TTransportException.NOT_OPEN, "File not open for input"); + + return Input.readBytes( buf, offset, count); + } + + public function Write( buf : Bytes, offset : Int, count : Int) : Void { + if( Output == null) + throw new TTransportException( TTransportException.NOT_OPEN, "File not open for output"); + + Output.writeBytes( buf, offset, count); + } + + public function Flush() : Void { + if( Output != null) + Output.flush(); + } + +} diff --git a/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx index 5d77140ba27..77335e75515 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx @@ -7,7 +7,7 @@ * "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 + * 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 diff --git a/lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx b/lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx index 00127bf0498..3cca1f8908f 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx @@ -7,7 +7,7 @@ * "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 + * 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 diff --git a/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx index d2fda79f72b..52a9d2697e8 100644 --- a/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx +++ b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx @@ -25,30 +25,7 @@ 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 @@ -62,29 +39,15 @@ 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 { } @@ -100,24 +63,10 @@ class THttpClient extends TTransport { 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 { @@ -125,59 +74,30 @@ class THttpClient extends TTransport { } - #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); + var tmp = new BytesBuffer(); + tmp.addString(data); + responseBuffer_ = new BytesInput(tmp.getBytes()); + if( callback != null) { + callback(null); + } }; + request_.onError = function(msg : String) { - callback(new TTransportException(TTransportException.UNKNOWN, "IOError: " + msg)); + if( callback != null) { + 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 index 1953244a0f6..0eae93122ea 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx @@ -1,4 +1,4 @@ -/** +/* * 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 diff --git a/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx index e0ce6972093..58198036da3 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx @@ -1,4 +1,4 @@ -/** +/* * 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 diff --git a/lib/haxe/src/org/apache/thrift/transport/TStream.hx b/lib/haxe/src/org/apache/thrift/transport/TStream.hx new file mode 100644 index 00000000000..0e1b52df909 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/transport/TStream.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.transport; + +import haxe.io.Bytes; +import haxe.io.BytesBuffer; + + +interface TStream { + function Close() : Void; + function Peek() : Bool; + function Read( buf : Bytes, offset : Int, count : Int) : Int; + function Write( buf : Bytes, offset : Int, count : Int) : Void; + function Flush() : Void; +} diff --git a/lib/haxe/src/org/apache/thrift/transport/TStreamTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TStreamTransport.hx new file mode 100644 index 00000000000..99203b4d996 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/transport/TStreamTransport.hx @@ -0,0 +1,103 @@ +/* + * 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 org.apache.thrift.helper.*; + +import haxe.io.Bytes; +import haxe.io.BytesBuffer; +import haxe.io.BytesOutput; +import haxe.io.BytesInput; + + +class TStreamTransport extends TTransport { + + public var InputStream(default,null) : TStream; + public var OutputStream(default,null) : TStream; + + + public function new( input : TStream, output : TStream) { + this.InputStream = input; + this.OutputStream = output; + } + + public override function isOpen() : Bool { + return true; + } + + public override function peek() : Bool { + return (InputStream != null); + } + + public override function open() : Void { + } + + public override function close() : Void { + if (InputStream != null) + { + InputStream.Close(); + InputStream = null; + } + if (OutputStream != null) + { + OutputStream.Close(); + OutputStream = null; + } + } + + public override function read( buf : BytesBuffer, off : Int, len : Int) : Int { + if (InputStream == null) + { + throw new TTransportException( TTransportException.NOT_OPEN, + "Cannot read from null InputStream"); + } + + var data : Bytes = Bytes.alloc(len); + var size = InputStream.Read( data, off, len); + buf.addBytes( data, 0, size); + return size; + } + + public override function write(buf:Bytes, off : Int, len : Int) : Void { + if (OutputStream == null) + { + throw new TTransportException( TTransportException.NOT_OPEN, + "Cannot write to null OutputStream"); + } + + OutputStream.Write(buf, off, len); + } + + public override function flush(callback:Dynamic->Void =null) : Void { + if (OutputStream == null) + { + var err = new TTransportException( TTransportException.NOT_OPEN, + "Cannot flush null OutputStream"); + if(callback != null) + callback(err); + else + throw err; + } + + OutputStream.Flush(); + } + +} diff --git a/lib/haxe/test/Makefile.am b/lib/haxe/test/Makefile.am new file mode 100644 index 00000000000..8bcb89c92ef --- /dev/null +++ b/lib/haxe/test/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_srcdir)/compiler/cpp/thrift +THRIFTCMD = $(THRIFT) --gen haxe -r +THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift + +BIN_CPP = bin/Main-debug + +gen-haxe/thrift/test/ThriftTest.hx: $(THRIFTTEST) + $(THRIFTCMD) $(THRIFTTEST) + +all-local: $(BIN_CPP) + +$(BIN_CPP): gen-haxe/thrift/test/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) + $(BIN_CPP) + diff --git a/lib/haxe/test/cpp.hxml b/lib/haxe/test/cpp.hxml new file mode 100644 index 00000000000..73848a8bce1 --- /dev/null +++ b/lib/haxe/test/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 ../src +-cp gen-haxe + +#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/lib/haxe/test/csharp.hxml b/lib/haxe/test/csharp.hxml new file mode 100644 index 00000000000..4c34b0d948f --- /dev/null +++ b/lib/haxe/test/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 ../src +-cp gen-haxe + +#this class wil be used as entry point for your app. +-main Main + +#CSHARP target +-cs bin/Test.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/lib/haxe/test/flash.hxml b/lib/haxe/test/flash.hxml new file mode 100644 index 00000000000..8b176319098 --- /dev/null +++ b/lib/haxe/test/flash.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 ../src +-cp gen-haxe + +#this class wil be used as entry point for your app. +-main Main + +#Flash target +-swf bin/Test.swf + +#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/lib/haxe/test/java.hxml b/lib/haxe/test/java.hxml new file mode 100644 index 00000000000..c9471597cae --- /dev/null +++ b/lib/haxe/test/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 ../src +-cp gen-haxe + +#this class wil be used as entry point for your app. +-main Main + +#Java target +-java bin/Test.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/lib/haxe/test/javascript.hxml b/lib/haxe/test/javascript.hxml new file mode 100644 index 00000000000..18d9964c2db --- /dev/null +++ b/lib/haxe/test/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 ../src +-cp gen-haxe + +#this class wil be used as entry point for your app. +-main Main + +#JavaScript target +-js bin/Test.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/lib/haxe/test/make_all.bat b/lib/haxe/test/make_all.bat new file mode 100644 index 00000000000..ee18f104708 --- /dev/null +++ b/lib/haxe/test/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 ..\..\..\test\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/lib/haxe/test/make_all.sh b/lib/haxe/test/make_all.sh new file mode 100644 index 00000000000..13b57549b19 --- /dev/null +++ b/lib/haxe/test/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 ../../../test/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/lib/haxe/test/neko.hxml b/lib/haxe/test/neko.hxml new file mode 100644 index 00000000000..2db70c8e696 --- /dev/null +++ b/lib/haxe/test/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 ../src +-cp gen-haxe + +#this class wil be used as entry point for your app. +-main Main + +#neko target +-neko bin/Test.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/lib/haxe/test/php.hxml b/lib/haxe/test/php.hxml new file mode 100644 index 00000000000..b86e64c3982 --- /dev/null +++ b/lib/haxe/test/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 ../src +-cp gen-haxe + +#this class wil be used as entry point for your app. +-main Main + +#PHP target +-php bin/Test.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/lib/haxe/test/project.hide b/lib/haxe/test/project.hide new file mode 100644 index 00000000000..16ef98e98a6 --- /dev/null +++ b/lib/haxe/test/project.hide @@ -0,0 +1,67 @@ +{ + "type" : 0 + ,"target" : 4 + ,"name" : "Test" + ,"main" : null + ,"projectPackage" : "" + ,"company" : "" + ,"license" : "" + ,"url" : "" + ,"targetData" : [ + { + "pathToHxml" : "flash.hxml" + ,"runActionType" : 1 + ,"runActionText" : "bin/Test.swf" + } + ,{ + "pathToHxml" : "javascript.hxml" + ,"runActionType" : 1 + ,"runActionText" : "bin\\index.html" + } + ,{ + "pathToHxml" : "neko.hxml" + ,"runActionType" : 2 + ,"runActionText" : "neko bin/Test.n" + } + ,{ + "pathToHxml" : "php.hxml" + } + ,{ + "pathToHxml" : "cpp.hxml" + ,"runActionType" : 2 + ,"runActionText" : "bin/Main-debug.exe" + } + ,{ + "pathToHxml" : "java.hxml" + } + ,{ + "pathToHxml" : "csharp.hxml" + } + ,{ + "pathToHxml" : "python.hxml" + ,"runActionType" : 2 + ,"runActionText" : "python bin/Test.py" + } + ] + ,"files" : [ + { + "path" : "src\\Main.hx" + ,"useTabs" : true + ,"indentSize" : 4 + ,"foldedRegions" : [ + + ] + ,"activeLine" : 13 + } + ] + ,"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/lib/haxe/test/python.hxml b/lib/haxe/test/python.hxml new file mode 100644 index 00000000000..4d6a133d6f9 --- /dev/null +++ b/lib/haxe/test/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 ../src +-cp gen-haxe + +#this class wil be used as entry point for your app. +-main Main + +#Python target +-python bin/Test.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/lib/haxe/test/src/Main.hx b/lib/haxe/test/src/Main.hx new file mode 100644 index 00000000000..fff8be50a3d --- /dev/null +++ b/lib/haxe/test/src/Main.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; + +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 public function main() + { + try + { + StreamTest.Run(); + + trace("All tests completed."); + } + catch( e: Dynamic) + { + trace('$e'); + } + } +} \ No newline at end of file diff --git a/lib/haxe/test/src/StreamTest.hx b/lib/haxe/test/src/StreamTest.hx new file mode 100644 index 00000000000..b28c8e91197 --- /dev/null +++ b/lib/haxe/test/src/StreamTest.hx @@ -0,0 +1,93 @@ +/* + * 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.Int64; + +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 StreamTest extends TestBase { + + + private inline static var tmpfile : String = "bin/data.tmp"; + + + private static function Expect( expr : Bool, info : String, ?pos : haxe.PosInfos) : Void { + if( ! expr) { + throw ('Test "$info" failed at '+pos.methodName+' in '+pos.fileName+':'+pos.lineNumber); + } + } + + private static function MakeTestData() : Xtruct { + var data : Xtruct = new Xtruct(); + data.string_thing = "Streamtest"; + data.byte_thing = -128; + data.i32_thing = 4711; + data.i64_thing = Int64.make(0x12345678,0x9ABCDEF0); + return data; + } + + public static function WriteData() : Xtruct + { + var stream : TStream = new TFileStream( tmpfile, CreateNew); + var trans : TTransport = new TStreamTransport( null, stream); + var prot = new TJSONProtocol( trans); + + var data = MakeTestData(); + data.write(prot); + trans.close(); + + return data; + } + + public static function ReadData() : Xtruct + { + var stream : TStream = new TFileStream( tmpfile, Read); + var trans : TTransport = new TStreamTransport( stream, null); + var prot = new TJSONProtocol( trans); + + var data : Xtruct = new Xtruct(); + data.read(prot); + trans.close(); + + return data; + } + + public static override function Run() : Void + { + var written = WriteData(); + var read = ReadData(); + + Expect( read.string_thing == written.string_thing, "string data"); + Expect( read.byte_thing == written.byte_thing, "byte data"); + Expect( read.i32_thing == written.i32_thing, "i32 data"); + Expect( Int64.compare( read.i64_thing, written.i64_thing) == 0, "i64 data"); + } + +} + + diff --git a/lib/haxe/test/src/TestBase.hx b/lib/haxe/test/src/TestBase.hx new file mode 100644 index 00000000000..03b66dd7f88 --- /dev/null +++ b/lib/haxe/test/src/TestBase.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; + +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 TestBase { + + private function new() { + // override, if necessary + } + + public static function Run() : Void { + throw new AbstractMethodError(); + } +} diff --git a/test/haxe/Makefile.am b/test/haxe/Makefile.am index 08c0369e755..1751bb2766a 100644 --- a/test/haxe/Makefile.am +++ b/test/haxe/Makefile.am @@ -23,12 +23,12 @@ THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift BIN_CPP = bin/Main-debug -gen-haxe/ThriftTest/ThriftTest.hx: $(THRIFTTEST) +gen-haxe/thrift/test/ThriftTest.hx: $(THRIFTTEST) $(THRIFTCMD) $(THRIFTTEST) all-local: $(BIN_CPP) -$(BIN_CPP): gen-haxe/ThriftTest/ThriftTest.hx +$(BIN_CPP): gen-haxe/thrift/test/ThriftTest.hx $(HAXE) --cwd . cpp.hxml diff --git a/test/haxe/project.hide b/test/haxe/project.hide index f09030b5545..a1c09bac39a 100644 --- a/test/haxe/project.hide +++ b/test/haxe/project.hide @@ -29,7 +29,7 @@ ,{ "pathToHxml" : "cpp.hxml" ,"runActionType" : 2 - ,"runActionText" : "bin/Main-debug.exe client --json" + ,"runActionText" : "bin/Main-debug.exe client --protocol json" } ,{ "pathToHxml" : "java.hxml" @@ -45,34 +45,25 @@ ] ,"files" : [ { - "path" : "src\\Arguments.hx" - ,"useTabs" : true - ,"indentSize" : 4 - ,"foldedRegions" : [ - - ] - ,"activeLine" : 159 - } - ,{ - "path" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\protocol\\TJSONProtocol.hx" + "path" : "src\\TestClient.hx" ,"useTabs" : true ,"indentSize" : 4 ,"foldedRegions" : [ ] - ,"activeLine" : 665 + ,"activeLine" : 188 } ,{ - "path" : "src\\TestClient.hx" + "path" : "src\\TestServer.hx" ,"useTabs" : true ,"indentSize" : 4 ,"foldedRegions" : [ ] - ,"activeLine" : 325 + ,"activeLine" : 88 } ] - ,"activeFile" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\protocol\\TJSONProtocol.hx" + ,"activeFile" : "src\\TestClient.hx" ,"openFLTarget" : null ,"openFLBuildMode" : "Debug" ,"runActionType" : null diff --git a/test/haxe/src/Arguments.hx b/test/haxe/src/Arguments.hx index bcf3793cb2a..ae23fa17b98 100644 --- a/test/haxe/src/Arguments.hx +++ b/test/haxe/src/Arguments.hx @@ -24,34 +24,49 @@ import org.apache.thrift.protocol.*; import org.apache.thrift.transport.*; import org.apache.thrift.server.*; import org.apache.thrift.meta_data.*; +import haxe.io.Path; using StringTools; -enum Prot { +enum ProtocolType { binary; json; } -enum Trns { +enum EndpointTransport { socket; - http; + http; +} + +enum ServerType { + simple; + /* + threadpool; + threaded; + nonblocking; + */ } class Arguments { + public var printHelpOnly(default,null) : Bool = false; + 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 servertype(default,null) : ServerType = simple; + public var host(default,null) : String = "localhost"; public var port(default,null) : Int = 9090; + + public var protocol(default,null) : ProtocolType = binary; + public var transport(default,null) : EndpointTransport = socket; + public var framed(default,null) : Bool = false; + public var buffered(default,null) : Bool = false; public var numIterations(default,null) : Int = 1; public var numThreads(default,null) : Int = 1; + public var skipSpeedTest(default,null) : Bool = false; public function new() { @@ -70,112 +85,244 @@ class Arguments #if sys private static function GetHelp() : String { + var sProg = Path.withoutDirectory( Sys.executablePath()); return "\n" - +Sys.executablePath()+" [client|server] [options]\n" + +sProg+" [client|server] [options]\n" + +"\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= Choose protocol: json, binary (default binary).\n" - +" --port= Port number for socket transport, default 9090\n" + +"Common options:\n" + +" -h [ --help ] produce help message\n" + +" --port arg (=9090) Port number to listen / connect to\n" + /* not supported yet + +" --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)\n" + +" --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe)\n" + */ + +" --protocol arg (=binary) protocol: binary, compact, json\n" + /* not supported yet + +" --ssl Encrypted Transport using SSL\n" + */ + +"\n" + +"Server only options:\n" + +" --transport arg (=sockets) Transport: buffered, framed, http, anonpipe\n" + /* not supported yet + +" --processor-events processor-events\n" + +" --server-type arg (=simple) type of server, \"simple\", \"thread-pool\", \n" + +" \"threaded\", or \"nonblocking\"\n" + +" -n [ --workers ] arg (=4) Number of thread pools workers. Only valid for \n" + +" thread-pool server type\n" + */ +"\n" +"Client only options:\n" - +" --host= Host name, IP or URL, default localhost\n" - +" -n= Number of test iterations\n" - +" -t= Number of test threads\n" - +" -u= Target Host/URL (same as --host)\n" + +" --host arg (=localhost) Host to connect\n" + +" --transport arg (=sockets) Transport: buffered, framed, http, evhttp\n" + /* not supported yet + +" --anon-pipes hRead hWrite Windows Anonymous Pipes pair (handles)\n" + */ + +" -n [ --testloops ] arg (=1) Number of Tests\n" + +" -t [ --threads ] arg (=1) Number of Test threads\n" + +" --skip-speed-test Skip the speed test\n" +"\n" - +"All arguments are optional.\n"; + +"All arguments are optional.\n" + ; } private function ParseArgs() : Void { - var step = 0; - for (arg in Sys.args()) { + + var args = Sys.args().copy(); + if( (args == null) || (args.length <= 0)) { + server = false; + numThreads = 1; + return; + } + + var arg = args.shift(); + if ( arg == "client") { + server = false; + numThreads = 1; + } + else if ( arg == "server") { + server = true; + numThreads = 4; + } + else if ( (arg == "-h") || (arg == "--help")) { + // -h [ --help ] produce help message + Sys.println( GetHelp()); + printHelpOnly = true; + return; + } + else { + throw "First argument must be 'server' or 'client'"; + } + - // 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")){ + while( args.length > 0) { + arg = args.shift(); + + if ( (arg == "-h") || (arg == "--help")) { + // -h [ --help ] produce help message + Sys.println( GetHelp()); + printHelpOnly = true; + return; + } + else if (arg == "--port") { + // --port arg (=9090) Port number to listen + arg = args.shift(); + var tmp = Std.parseInt(arg); + if( tmp != null) { + port = tmp; + } else { + throw "Invalid port number "+arg; + } + } + else if (arg == "--domain-socket") { + // --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift) + throw "domain sockets not supported yet"; + } + else if (arg == "--named-pipe") { + // --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe) + throw "named pipes not supported yet"; + } + else if (arg == "--protocol") { + // --protocol arg (=binary) protocol: binary, compact, json + arg = args.shift(); + if( arg == "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 if( arg == "compact") { + throw "Compact protocol not supported yet"; + } else if( arg == "json") { + protocol = json; } 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"; + InvalidArg(arg); + } + } + else if (arg == "--ssl") { + // --ssl Encrypted Transport using SSL + throw "SSL not supported yet"; + } + else { + //Server only options: + if( server) { + ParseServerArgument( arg, args); + } else { + ParseClientArgument( arg, args); + } } + } + } + - - if ( framed && buffered) - { - trace("WN: framed supersedes buffered transport"); - } + private function ParseServerArgument( arg : String, args : Array) : Void { + if (arg == "--transport") { + // --transport arg (=sockets) Transport: buffered, framed, http, anonpipe + arg = args.shift(); + if( arg == "buffered") { + buffered = true; + } else if( arg == "framed") { + framed = true; + } else if( arg == "http") { + transport = http; + } else if( arg == "anonpipe") { + throw "Anon pipes transport not supported yet"; + } else { + InvalidArg(arg); + } + } + else if (arg == "--processor-events") { + throw "Processor events not supported yet"; + } + else if (arg == "--server-type") { + // --server-type arg (=simple) type of server, + // one of "simple", "thread-pool", "threaded", "nonblocking" + arg = args.shift(); + if( arg == "simple") { + servertype = simple; + } else if( arg == "thread-pool") { + throw arg+" server not supported yet"; + } else if( arg == "threaded") { + throw arg+" server not supported yet"; + } else if( arg == "nonblocking") { + throw arg+" server not supported yet"; + } else { + InvalidArg(arg); + } + } + else if ((arg == "-n") || (arg == "--workers")) { + // -n [ --workers ] arg (=4) Number of thread pools workers. Only valid for + // thread-pool server type + arg = args.shift(); + var tmp = Std.parseInt(arg); + if( tmp != null) { + numThreads = tmp; + } else{ + throw "Invalid number "+arg; + } + } + else { + InvalidArg(arg); + } + } + + private function ParseClientArgument( arg : String, args : Array) : Void { + if (arg == "--host") { + // --host arg (=localhost) Host to connect + host = args.shift(); + } + else if (arg == "--transport") { + // --transport arg (=sockets) Transport: buffered, framed, http, evhttp + arg = args.shift(); + if( arg == "buffered") { + buffered = true; + } else if( arg == "framed") { + framed = true; + } else if( arg == "http") { + transport = http; + } else if( arg == "evhttp") { + throw "evhttp transport not supported yet"; + } else { + InvalidArg(arg); + } + } + else if (arg == "--anon-pipes") { + // --anon-pipes hRead hWrite Windows Anonymous Pipes pair (handles) + throw "Anon pipes transport not supported yet"; + } + else if ((arg == "-n") || (arg == "--testloops")) { + // -n [ --testloops ] arg (=1) Number of Tests + arg = args.shift(); + var tmp = Std.parseInt(arg); + if( tmp != null) { + numIterations = tmp; + } else { + throw "Invalid number "+arg; + } + } + else if ((arg == "-t") || (arg == "--threads")) { + // -t [ --threads ] arg (=1) Number of Test threads + arg = args.shift(); + var tmp = Std.parseInt(arg); + if( tmp != null) { + numThreads = tmp; + } else { + throw "Invalid number "+arg; + } + } + else if (arg == "--skip-speed-test") { + // --skip-speed-test Skip the speed test + skipSpeedTest = true; + } + else { + InvalidArg(arg); } } + #end - private function ClientOnlyOption( arg : String) { - if( server) { - throw "Unexpected argument in client mode: "+arg; - } + private function InvalidArg( arg : String) : Void { + throw 'Invalid argument $arg'; } } diff --git a/test/haxe/src/Main.hx b/test/haxe/src/Main.hx index a8ad147a27c..6d80c21f98c 100644 --- a/test/haxe/src/Main.hx +++ b/test/haxe/src/Main.hx @@ -34,6 +34,9 @@ class Main try { var args = new Arguments(); + if( args.printHelpOnly) + return; + if (args.server) TestServer.Execute(args); else diff --git a/test/haxe/src/TestClient.hx b/test/haxe/src/TestClient.hx index 8698220aa9e..3c98e6aba3e 100644 --- a/test/haxe/src/TestClient.hx +++ b/test/haxe/src/TestClient.hx @@ -47,16 +47,36 @@ class TestResults { private var errorCnt : Int = 0; private var failedTests : String = ""; private var print_direct : Bool = false; + + public static var EXITCODE_SUCCESS = 0x00; // no errors bits set + // + public static var EXITCODE_FAILBIT_BASETYPES = 0x01; + public static var EXITCODE_FAILBIT_STRUCTS = 0x02; + public static var EXITCODE_FAILBIT_CONTAINERS = 0x04; + public static var EXITCODE_FAILBIT_EXCEPTIONS = 0x08; + // + public static var EXITCODE_ALL_FAILBITS = 0x0F; + // + private var testsExecuted : Int = 0; + private var testsFailed : Int = 0; + private var currentTest : Int = 0; + public function new(direct : Bool) { print_direct = direct; } + public function StartTestGroup( groupBit : Int) : Void { + currentTest = groupBit; + testsExecuted |= groupBit; + } + public function Expect( expr : Bool, msg : String) : Void { if ( expr) { ++successCnt; } else { ++errorCnt; + testsFailed |= currentTest; failedTests += "\n " + msg; if( print_direct) { trace('FAIL: $msg'); @@ -64,6 +84,10 @@ class TestResults { } } + public function CalculateExitCode() : Int { + var notExecuted : Int = EXITCODE_ALL_FAILBITS & (~testsExecuted); + return testsFailed | notExecuted; + } public function PrintSummary() : Void { var total = successCnt + errorCnt; @@ -88,57 +112,67 @@ class TestClient { public static function Execute(args : Arguments) : Void { + var exitCode = 0xFF; try { var difft = Timer.stamp(); - + if( args.numThreads > 1) { var threads = new List(); for( test in 0 ... args.numThreads) { threads.add( StartThread( args)); } + exitCode = 0; for( thread in threads) { - Thread.readMessage(true); + exitCode |= Thread.readMessage(true); } } else { var rslt = new TestResults(true); RunClient(args,rslt); rslt.PrintSummary(); + exitCode = rslt.CalculateExitCode(); } - difft = Timer.stamp() - difft; + difft = Timer.stamp() - difft; trace('total test time: $difft seconds'); } catch (e : TException) { trace('$e'); + exitCode = 0xFF; } catch (e : Dynamic) { trace('$e'); + exitCode = 0xFF; } + + #if sys + Sys.exit( exitCode); + #end } private static function StartThread(args : Arguments) : Thread { var thread = Thread.create( function() : Void { + var rslt = new TestResults(false); 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) { + rslt.Expect( false, '$e'); trace('$e'); } catch (e : Dynamic) { + rslt.Expect( false, '$e'); trace('$e'); } - main.sendMessage("done"); + main.sendMessage( rslt.CalculateExitCode()); }); thread.sendMessage(Thread.current()); @@ -154,8 +188,7 @@ class TestClient { case socket: transport = new TSocket(args.host, args.port); case http: - throw "http transport not supported yet"; - //transport = new THttpClient(args.host); + transport = new THttpClient(args.host); default: throw "Unhandled transport"; } @@ -164,7 +197,8 @@ class TestClient { if ( args.framed) { trace("- framed transport"); transport = new TFramedTransport(transport); - } else if ( args.buffered) { + } + if ( args.buffered) { trace("- buffered transport"); throw "TBufferedTransport not implemented yet"; //transport = new TBufferedTransport(transport); @@ -186,16 +220,18 @@ class TestClient { // run the test code - HaxeBasicsTest( rslt); - ClientTest( transport, protocol, rslt); - + HaxeBasicsTest( args, rslt); + for( i in 0 ... args.numIterations) { + ClientTest( transport, protocol, args, rslt); + } } - public static function HaxeBasicsTest( rslt : TestResults) : Void + public static function HaxeBasicsTest( args : Arguments, 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 + rslt.StartTestGroup( 0); var map32 = new IntMap(); var map64 = new Int64Map(); @@ -272,7 +308,8 @@ class TestClient { } - public static function ClientTest( transport : TTransport, protocol : TProtocol, rslt : TestResults) : Void + public static function ClientTest( transport : TTransport, protocol : TProtocol, + args : Arguments, rslt : TestResults) : Void { var client = new ThriftTestImpl(protocol,protocol); try @@ -295,6 +332,54 @@ class TestClient { var start = Date.now(); + rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_EXCEPTIONS); + + // if arg == "Xception" throw Xception with errorCode = 1001 and message = arg + trace('testException("Xception")'); + try { + client.testException("Xception"); + rslt.Expect( false, 'testException("Xception") should throw'); + } + catch (e : Xception) + { + rslt.Expect( e.message == "Xception", 'testException("Xception") - e.message == "Xception"'); + rslt.Expect( e.errorCode == 1001, 'testException("Xception") - e.errorCode == 1001'); + } + catch (e : Dynamic) + { + rslt.Expect( false, 'testException("Xception") - $e'); + } + + // if arg == "TException" throw TException + trace('testException("TException")'); + try { + client.testException("TException"); + rslt.Expect( false, 'testException("TException") should throw'); + } + catch (e : TException) + { + rslt.Expect( true, 'testException("TException") - $e'); + } + catch (e : Dynamic) + { + rslt.Expect( false, 'testException("TException") - $e'); + } + + // else do not throw anything + trace('testException("bla")'); + try { + client.testException("bla"); + rslt.Expect( true, 'testException("bla") should not throw'); + } + catch (e : Dynamic) + { + rslt.Expect( false, 'testException("bla") - $e'); + } + + + + rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES); + trace('testVoid()'); client.testVoid(); trace(' = void'); @@ -333,6 +418,9 @@ class TestClient { trace(' = $dub'); rslt.Expect(dub == 5.325098235, '$dub == 5.325098235'); + + rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_STRUCTS); + trace('testStruct({"Zero", 1, -3, -5})'); var o = new Xtruct(); o.string_thing = "Zero"; @@ -341,7 +429,7 @@ class TestClient { 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) + '}'); + + 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"); @@ -364,6 +452,9 @@ class TestClient { 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"); + + rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_CONTAINERS); + var mapout = new IntMap< haxe.Int32>(); for ( j in 0 ... 5) { @@ -497,6 +588,8 @@ class TestClient { rslt.Expect(setin.size == setout.size, "setin.length == setout.length"); + rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES); + trace("testEnum(ONE)"); var ret = client.testEnum(Numberz.ONE); trace(" = " + ret); @@ -528,6 +621,9 @@ class TestClient { rslt.Expect( Int64.compare( uid, Int64.make( 0x119D0, 0x7E08671B)) == 0, Int64.toStr(uid)+" == "+Int64.toStr(Int64.make( 0x119D0, 0x7E08671B))); + + rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_CONTAINERS); + trace("testMapMap(1)"); var mm = client.testMapMap(1); trace(" = {"); @@ -551,6 +647,9 @@ class TestClient { rslt.Expect( neg.get(-i) == -i, 'neg.get(-$i) == -$i'); } + + rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_STRUCTS); + var insane = new Insanity(); insane.userMap = new IntMap< Int64>(); insane.userMap.set( Numberz.FIVE, Int64.make(0,5000)); @@ -614,6 +713,7 @@ class TestClient { } 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)"); @@ -682,15 +782,19 @@ class TestClient { rslt.Expect( Int64.compare( multiResponse.i64_thing, arg2) == 0, 'multiResponse.I64_thing == arg2'); + rslt.StartTestGroup( 0); + trace("Test Oneway(1)"); client.testOneway(1); - trace("Test Calltime()"); - var difft = Timer.stamp(); - for ( k in 0 ... 1000) { - client.testVoid(); + if( ! args.skipSpeedTest) { + trace("Test Calltime()"); + var difft = Timer.stamp(); + for ( k in 0 ... 1000) { + client.testVoid(); + } + difft = Timer.stamp() - difft; + trace('$difft ms per testVoid() call'); } - difft = Timer.stamp() - difft; - trace('$difft ms per testVoid() call'); } } diff --git a/test/haxe/src/TestServer.hx b/test/haxe/src/TestServer.hx index 66b06e0092e..92fab01b359 100644 --- a/test/haxe/src/TestServer.hx +++ b/test/haxe/src/TestServer.hx @@ -53,7 +53,8 @@ class TestServer if ( args.framed) { trace("- framed transport"); transfactory = new TFramedTransportFactory(); - } else if ( args.buffered) { + } + if ( args.buffered) { trace("- buffered transport"); throw "TBufferedTransport not implemented yet"; //transfactory = new TBufferedTransportFactory(); @@ -79,14 +80,23 @@ class TestServer var processor = new ThriftTestProcessor(handler); // Simple Server - var server = new TSimpleServer( processor, transport, transfactory, protfactory); + var server : TServer = null; + switch( args.servertype) + { + case simple: + server = new TSimpleServer( processor, transport, transfactory, protfactory); + default: + throw "Unhandled server type"; + } /* // Server event handler - var events = new TestServerEventHandler(); - server.setEventHandler(serverEvents); - handler.server = serverEngine; + if( args.serverEvents) { + var events = new TestServerEventHandler(); + server.setEventHandler(serverEvents); + handler.server = serverEngine; + } */ // Run it diff --git a/tutorial/haxe/project.hide b/tutorial/haxe/project.hide index 46c0a50069d..8d5d4ec56b9 100644 --- a/tutorial/haxe/project.hide +++ b/tutorial/haxe/project.hide @@ -89,7 +89,7 @@ ,"foldedRegions" : [ ] - ,"activeLine" : 276 + ,"activeLine" : 0 } ] ,"activeFile" : "src\\Main.hx" diff --git a/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx index 5c9345ef6ce..41d8945476c 100644 --- a/tutorial/haxe/src/Main.hx +++ b/tutorial/haxe/src/Main.hx @@ -154,12 +154,8 @@ class Main { 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 + trace('- HTTP transport $targetHost'); transport = new THttpClient( targetHost); - #end default: throw "Unhandled transport"; } From 3157d70b0409925f7fdd5a18dc844f3c630062eb Mon Sep 17 00:00:00 2001 From: Jens Geyer Date: Fri, 3 Oct 2014 02:00:14 +0200 Subject: [PATCH 24/24] FIX: BytesInput.readString() returns null instead of empty strings --- lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx index eafa7c9a030..1a93332c76d 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx @@ -765,6 +765,8 @@ class TJSONProtocol implements TProtocol { public static function StringFromBytes( buf : Bytes) : String { var inp = new BytesInput( buf); + if( buf.length == 0) + return ""; // readString() would return null in that case, which is wrong var str = inp.readString( buf.length); if( utf8Strings) return str; // no need to decode on UTF8 targets, the string is just fine