You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by br...@apache.org on 2010/08/19 07:06:04 UTC

svn commit: r987018 [2/2] - in /incubator/thrift/trunk: compiler/cpp/src/generate/ lib/erl/ lib/erl/build/ lib/erl/include/ lib/erl/src/ test/erl/ test/erl/src/ tutorial/erl/

Modified: incubator/thrift/trunk/lib/erl/src/thrift_processor.erl
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/erl/src/thrift_processor.erl?rev=987018&r1=987017&r2=987018&view=diff
==============================================================================
--- incubator/thrift/trunk/lib/erl/src/thrift_processor.erl (original)
+++ incubator/thrift/trunk/lib/erl/src/thrift_processor.erl Thu Aug 19 05:06:02 2010
@@ -24,55 +24,54 @@
 -include("thrift_constants.hrl").
 -include("thrift_protocol.hrl").
 
--record(thrift_processor, {handler, in_protocol, out_protocol, service}).
+-record(thrift_processor, {handler, protocol, service}).
 
-init({Server, ProtoGen, Service, Handler}) when is_function(ProtoGen, 0) ->
-    {ok, IProt, OProt} = ProtoGen(),
-    loop(#thrift_processor{in_protocol = IProt,
-                           out_protocol = OProt,
+init({_Server, ProtoGen, Service, Handler}) when is_function(ProtoGen, 0) ->
+    {ok, Proto} = ProtoGen(),
+    loop(#thrift_processor{protocol = Proto,
                            service = Service,
                            handler = Handler}).
 
-loop(State = #thrift_processor{in_protocol  = IProto,
-                               out_protocol = OProto}) ->
-    case thrift_protocol:read(IProto, message_begin) of
+loop(State0 = #thrift_processor{protocol  = Proto0}) ->
+    {Proto1, MessageBegin} = thrift_protocol:read(Proto0, message_begin),
+    State1 = State0#thrift_processor{protocol = Proto1},
+    case MessageBegin of
         #protocol_message_begin{name = Function,
                                 type = ?tMessageType_CALL} ->
-            ok = handle_function(State, list_to_atom(Function)),
-            loop(State);
+            {State2, ok} = handle_function(State1, list_to_atom(Function)),
+            loop(State2);
         #protocol_message_begin{name = Function,
                                 type = ?tMessageType_ONEWAY} ->
-            ok = handle_function(State, list_to_atom(Function)),
-            loop(State);
+            {State2, ok} = handle_function(State1, list_to_atom(Function)),
+            loop(State2);
         {error, timeout} ->
-            thrift_protocol:close_transport(OProto),
+            thrift_protocol:close_transport(Proto1),
             ok;
         {error, closed} ->
             %% error_logger:info_msg("Client disconnected~n"),
-            thrift_protocol:close_transport(OProto),
+            thrift_protocol:close_transport(Proto1),
             exit(shutdown)
     end.
 
-handle_function(State=#thrift_processor{in_protocol = IProto,
-                                        out_protocol = OProto,
-                                        handler = Handler,
-                                        service = Service},
+handle_function(State0=#thrift_processor{protocol = Proto0,
+                                         handler = Handler,
+                                         service = Service},
                 Function) ->
     InParams = Service:function_info(Function, params_type),
 
-    {ok, Params} = thrift_protocol:read(IProto, InParams),
+    {Proto1, {ok, Params}} = thrift_protocol:read(Proto0, InParams),
+    State1 = State0#thrift_processor{protocol = Proto1},
 
     try
         Result = Handler:handle_function(Function, Params),
         %% {Micro, Result} = better_timer(Handler, handle_function, [Function, Params]),
         %% error_logger:info_msg("Processed ~p(~p) in ~.4fms~n",
         %%                       [Function, Params, Micro/1000.0]),
-        handle_success(State, Function, Result)
+        handle_success(State1, Function, Result)
     catch
-        Type:Data ->
-            handle_function_catch(State, Function, Type, Data)
-    end,
-    after_reply(OProto).
+        Type:Data when Type =:= throw orelse Type =:= error ->
+            handle_function_catch(State1, Function, Type, Data)
+    end.
 
 handle_function_catch(State = #thrift_processor{service = Service},
                       Function, ErrType, ErrData) ->
@@ -84,39 +83,37 @@ handle_function_catch(State = #thrift_pr
             error_logger:warning_msg(
               "oneway void ~p threw error which must be ignored: ~p",
               [Function, {ErrType, ErrData, Stack}]),
-            ok;
+            {State, ok};
 
         {throw, Exception} when is_tuple(Exception), size(Exception) > 0 ->
-            error_logger:warning_msg("~p threw exception: ~p~n", [Function, Exception]),
-            handle_exception(State, Function, Exception),
-            ok;   % we still want to accept more requests from this client
+            %error_logger:warning_msg("~p threw exception: ~p~n", [Function, Exception]),
+            handle_exception(State, Function, Exception);
+            % we still want to accept more requests from this client
 
         {error, Error} ->
-            ok = handle_error(State, Function, Error)
+            handle_error(State, Function, Error)
     end.
 
-handle_success(State = #thrift_processor{out_protocol = OProto,
-                                         service = Service},
+handle_success(State = #thrift_processor{service = Service},
                Function,
                Result) ->
     ReplyType  = Service:function_info(Function, reply_type),
     StructName = atom_to_list(Function) ++ "_result",
 
-    ok = case Result of
-             {reply, ReplyData} ->
-                 Reply = {{struct, [{0, ReplyType}]}, {StructName, ReplyData}},
-                 send_reply(OProto, Function, ?tMessageType_REPLY, Reply);
-
-             ok when ReplyType == {struct, []} ->
-                 send_reply(OProto, Function, ?tMessageType_REPLY, {ReplyType, {StructName}});
-
-             ok when ReplyType == oneway_void ->
-                 %% no reply for oneway void
-                 ok
-         end.
+    case Result of
+        {reply, ReplyData} ->
+            Reply = {{struct, [{0, ReplyType}]}, {StructName, ReplyData}},
+            send_reply(State, Function, ?tMessageType_REPLY, Reply);
+
+        ok when ReplyType == {struct, []} ->
+            send_reply(State, Function, ?tMessageType_REPLY, {ReplyType, {StructName}});
+
+        ok when ReplyType == oneway_void ->
+            %% no reply for oneway void
+            {State, ok}
+    end.
 
-handle_exception(State = #thrift_processor{out_protocol = OProto,
-                                           service = Service},
+handle_exception(State = #thrift_processor{service = Service},
                  Function,
                  Exception) ->
     ExceptionType = element(1, Exception),
@@ -141,9 +138,9 @@ handle_exception(State = #thrift_process
                                                 % Make sure we got at least one defined
     case lists:all(fun(X) -> X =:= undefined end, ExceptionList) of
         true ->
-            ok = handle_unknown_exception(State, Function, Exception);
+            handle_unknown_exception(State, Function, Exception);
         false ->
-            ok = send_reply(OProto, Function, ?tMessageType_REPLY, {ReplySpec, ExceptionTuple})
+            send_reply(State, Function, ?tMessageType_REPLY, {ReplySpec, ExceptionTuple})
     end.
 
 %%
@@ -154,7 +151,7 @@ handle_unknown_exception(State, Function
     handle_error(State, Function, {exception_not_declared_as_thrown,
                                    Exception}).
 
-handle_error(#thrift_processor{out_protocol = OProto}, Function, Error) ->
+handle_error(State, Function, Error) ->
     Stack = erlang:get_stacktrace(),
     error_logger:error_msg("~p had an error: ~p~n", [Function, {Error, Stack}]),
 
@@ -170,19 +167,14 @@ handle_error(#thrift_processor{out_proto
              #'TApplicationException'{
                 message = Message,
                 type = ?TApplicationException_UNKNOWN}},
-    send_reply(OProto, Function, ?tMessageType_EXCEPTION, Reply).
+    send_reply(State, Function, ?tMessageType_EXCEPTION, Reply).
 
-send_reply(OProto, Function, ReplyMessageType, Reply) ->
-    ok = thrift_protocol:write(OProto, #protocol_message_begin{
-                                 name = atom_to_list(Function),
-                                 type = ReplyMessageType,
-                                 seqid = 0}),
-    ok = thrift_protocol:write(OProto, Reply),
-    ok = thrift_protocol:write(OProto, message_end),
-    ok = thrift_protocol:flush_transport(OProto),
-    ok.
-
-after_reply(OProto) ->
-    ok = thrift_protocol:flush_transport(OProto)
-    %%     ok = thrift_protocol:close_transport(OProto)
-    .
+send_reply(State = #thrift_processor{protocol = Proto0}, Function, ReplyMessageType, Reply) ->
+    {Proto1, ok} = thrift_protocol:write(Proto0, #protocol_message_begin{
+                                           name = atom_to_list(Function),
+                                           type = ReplyMessageType,
+                                           seqid = 0}),
+    {Proto2, ok} = thrift_protocol:write(Proto1, Reply),
+    {Proto3, ok} = thrift_protocol:write(Proto2, message_end),
+    {Proto4, ok} = thrift_protocol:flush_transport(Proto3),
+    {State#thrift_processor{protocol = Proto4}, ok}.

Modified: incubator/thrift/trunk/lib/erl/src/thrift_protocol.erl
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/erl/src/thrift_protocol.erl?rev=987018&r1=987017&r2=987018&view=diff
==============================================================================
--- incubator/thrift/trunk/lib/erl/src/thrift_protocol.erl (original)
+++ incubator/thrift/trunk/lib/erl/src/thrift_protocol.erl Thu Aug 19 05:06:02 2010
@@ -49,10 +49,13 @@ new(Module, Data) when is_atom(Module) -
     {ok, #protocol{module = Module,
                    data = Data}}.
 
-flush_transport(#protocol{module = Module,
-                          data = Data}) ->
-    Module:flush_transport(Data).
+-spec flush_transport(#protocol{}) -> {#protocol{}, ok}.
+flush_transport(Proto = #protocol{module = Module,
+                                  data = Data}) ->
+    {NewData, Result} = Module:flush_transport(Data),
+    {Proto#protocol{data = NewData}, Result}.
 
+-spec close_transport(#protocol{}) -> ok.
 close_transport(#protocol{module = Module,
                           data = Data}) ->
     Module:close_transport(Data).
@@ -86,7 +89,8 @@ term_to_typeid({list, _}) -> ?tType_LIST
 
 %% Structure is like:
 %%    [{Fid, Type}, ...]
-read(IProto, {struct, Structure}, Tag)
+-spec read(#protocol{}, {struct, _StructDef}, atom()) -> {#protocol{}, {ok, tuple()}}.
+read(IProto0, {struct, Structure}, Tag)
   when is_list(Structure), is_atom(Tag) ->
 
     % If we want a tagged tuple, we need to offset all the tuple indices
@@ -103,14 +107,23 @@ read(IProto, {struct, Structure}, Tag)
     % Fid -> {Type, Index}
     SDict = dict:from_list(SWithIndices),
 
-    ok = read(IProto, struct_begin),
+    {IProto1, ok} = read(IProto0, struct_begin),
     RTuple0 = erlang:make_tuple(length(Structure) + Offset, undefined),
     RTuple1 = if Tag =/= undefined -> setelement(1, RTuple0, Tag);
                  true              -> RTuple0
               end,
 
-    RTuple2 = read_struct_loop(IProto, SDict, RTuple1),
-    {ok, RTuple2}.
+    {IProto2, RTuple2} = read_struct_loop(IProto1, SDict, RTuple1),
+    {IProto2, {ok, RTuple2}}.
+
+
+%% NOTE: Keep this in sync with thrift_protocol_behaviour:read
+-spec read
+        (#protocol{}, {struct, _Info}) ->    {#protocol{}, {ok, tuple()}      | {error, _Reason}};
+        (#protocol{}, tprot_cont_tag()) ->   {#protocol{}, {ok, term()}       | {error, _Reason}};
+        (#protocol{}, tprot_empty_tag()) ->  {#protocol{},  ok                | {error, _Reason}};
+        (#protocol{}, tprot_header_tag()) -> {#protocol{}, tprot_header_val() | {error, _Reason}};
+        (#protocol{}, tprot_data_tag()) ->   {#protocol{}, {ok, term()}       | {error, _Reason}}.
 
 read(IProto, {struct, {Module, StructureName}}) when is_atom(Module),
                                                      is_atom(StructureName) ->
@@ -119,137 +132,165 @@ read(IProto, {struct, {Module, Structure
 read(IProto, S={struct, Structure}) when is_list(Structure) ->
     read(IProto, S, undefined);
 
-read(IProto, {list, Type}) ->
-    #protocol_list_begin{etype = EType, size = Size} =
-        read(IProto, list_begin),
-    List = [Result || {ok, Result} <-
-                          [read(IProto, Type) || _X <- lists:duplicate(Size, 0)]],
-    ok = read(IProto, list_end),
-    {ok, List};
-
-read(IProto, {map, KeyType, ValType}) ->
-    #protocol_map_begin{size = Size} =
-        read(IProto, map_begin),
-
-    List = [{Key, Val} || {{ok, Key}, {ok, Val}} <-
-                              [{read(IProto, KeyType),
-                                read(IProto, ValType)} || _X <- lists:duplicate(Size, 0)]],
-    ok = read(IProto, map_end),
-    {ok, dict:from_list(List)};
-
-read(IProto, {set, Type}) ->
-    #protocol_set_begin{etype = _EType,
-                        size = Size} =
-        read(IProto, set_begin),
-    List = [Result || {ok, Result} <-
-                          [read(IProto, Type) || _X <- lists:duplicate(Size, 0)]],
-    ok = read(IProto, set_end),
-    {ok, sets:from_list(List)};
-
-read(#protocol{module = Module,
-               data = ModuleData}, ProtocolType) ->
-    Module:read(ModuleData, ProtocolType).
-
-read_struct_loop(IProto, SDict, RTuple) ->
-    #protocol_field_begin{type = FType, id = Fid, name = Name} =
-        thrift_protocol:read(IProto, field_begin),
+read(IProto0, {list, Type}) ->
+    {IProto1, #protocol_list_begin{etype = EType, size = Size}} =
+        read(IProto0, list_begin),
+    {EType, EType} = {term_to_typeid(Type), EType},
+    {List, IProto2} = lists:mapfoldl(fun(_, ProtoS0) ->
+                                             {ProtoS1, {ok, Item}} = read(ProtoS0, Type),
+                                             {Item, ProtoS1}
+                                     end,
+                                     IProto1,
+                                     lists:duplicate(Size, 0)),
+    {IProto3, ok} = read(IProto2, list_end),
+    {IProto3, {ok, List}};
+
+read(IProto0, {map, KeyType, ValType}) ->
+    {IProto1, #protocol_map_begin{size = Size, ktype = KType, vtype = VType}} =
+        read(IProto0, map_begin),
+    {KType, KType} = {term_to_typeid(KeyType), KType},
+    {VType, VType} = {term_to_typeid(ValType), VType},
+    {List, IProto2} = lists:mapfoldl(fun(_, ProtoS0) ->
+                                             {ProtoS1, {ok, Key}} = read(ProtoS0, KeyType),
+                                             {ProtoS2, {ok, Val}} = read(ProtoS1, ValType),
+                                             {{Key, Val}, ProtoS2}
+                                     end,
+                                     IProto1,
+                                     lists:duplicate(Size, 0)),
+    {IProto3, ok} = read(IProto2, map_end),
+    {IProto3, {ok, dict:from_list(List)}};
+
+read(IProto0, {set, Type}) ->
+    {IProto1, #protocol_set_begin{etype = EType, size = Size}} =
+        read(IProto0, set_begin),
+    {EType, EType} = {term_to_typeid(Type), EType},
+    {List, IProto2} = lists:mapfoldl(fun(_, ProtoS0) ->
+                                             {ProtoS1, {ok, Item}} = read(ProtoS0, Type),
+                                             {Item, ProtoS1}
+                                     end,
+                                     IProto1,
+                                     lists:duplicate(Size, 0)),
+    {IProto3, ok} = read(IProto2, set_end),
+    {IProto3, {ok, sets:from_list(List)}};
+
+read(Protocol, ProtocolType) ->
+    read_specific(Protocol, ProtocolType).
+
+%% NOTE: Keep this in sync with thrift_protocol_behaviour:read
+-spec read_specific
+        (#protocol{}, tprot_empty_tag()) ->  {#protocol{},  ok                | {error, _Reason}};
+        (#protocol{}, tprot_header_tag()) -> {#protocol{}, tprot_header_val() | {error, _Reason}};
+        (#protocol{}, tprot_data_tag()) ->   {#protocol{}, {ok, term()}       | {error, _Reason}}.
+read_specific(Proto = #protocol{module = Module,
+                                data = ModuleData}, ProtocolType) ->
+    {NewData, Result} = Module:read(ModuleData, ProtocolType),
+    {Proto#protocol{data = NewData}, Result}.
+
+read_struct_loop(IProto0, SDict, RTuple) ->
+    {IProto1, #protocol_field_begin{type = FType, id = Fid}} =
+        thrift_protocol:read(IProto0, field_begin),
     case {FType, Fid} of
         {?tType_STOP, _} ->
-            RTuple;
+            {IProto1, RTuple};
         _Else ->
             case dict:find(Fid, SDict) of
                 {ok, {Type, Index}} ->
                     case term_to_typeid(Type) of
                         FType ->
-                            {ok, Val} = read(IProto, Type),
-                            thrift_protocol:read(IProto, field_end),
+                            {IProto2, {ok, Val}} = read(IProto1, Type),
+                            {IProto3, ok} = thrift_protocol:read(IProto2, field_end),
                             NewRTuple = setelement(Index, RTuple, Val),
-                            read_struct_loop(IProto, SDict, NewRTuple);
+                            read_struct_loop(IProto3, SDict, NewRTuple);
                         Expected ->
                             error_logger:info_msg(
                               "Skipping field ~p with wrong type (~p != ~p)~n",
                               [Fid, FType, Expected]),
-                            skip_field(FType, IProto, SDict, RTuple)
+                            skip_field(FType, IProto1, SDict, RTuple)
                     end;
                 _Else2 ->
                     error_logger:info_msg("Skipping field ~p with unknown fid~n", [Fid]),
-                    skip_field(FType, IProto, SDict, RTuple)
+                    skip_field(FType, IProto1, SDict, RTuple)
             end
     end.
 
-skip_field(FType, IProto, SDict, RTuple) ->
+skip_field(FType, IProto0, SDict, RTuple) ->
     FTypeAtom = thrift_protocol:typeid_to_atom(FType),
-    thrift_protocol:skip(IProto, FTypeAtom),
-    read(IProto, field_end),
-    read_struct_loop(IProto, SDict, RTuple).
-
-
-skip(Proto, struct) ->
-    ok = read(Proto, struct_begin),
-    ok = skip_struct_loop(Proto),
-    ok = read(Proto, struct_end);
-
-skip(Proto, map) ->
-    Map = read(Proto, map_begin),
-    ok = skip_map_loop(Proto, Map),
-    ok = read(Proto, map_end);
-
-skip(Proto, set) ->
-    Set = read(Proto, set_begin),
-    ok = skip_set_loop(Proto, Set),
-    ok = read(Proto, set_end);
-
-skip(Proto, list) ->
-    List = read(Proto, list_begin),
-    ok = skip_list_loop(Proto, List),
-    ok = read(Proto, list_end);
-
-skip(Proto, Type) when is_atom(Type) ->
-    _Ignore = read(Proto, Type),
-    ok.
+    {IProto1, ok} = thrift_protocol:skip(IProto0, FTypeAtom),
+    {IProto2, ok} = read(IProto1, field_end),
+    read_struct_loop(IProto2, SDict, RTuple).
+
+-spec skip(#protocol{}, term()) -> {#protocol{}, ok}.
+
+skip(Proto0, struct) ->
+    {Proto1, ok} = read(Proto0, struct_begin),
+    {Proto2, ok} = skip_struct_loop(Proto1),
+    {Proto3, ok} = read(Proto2, struct_end),
+    {Proto3, ok};
+
+skip(Proto0, map) ->
+    {Proto1, Map} = read(Proto0, map_begin),
+    {Proto2, ok} = skip_map_loop(Proto1, Map),
+    {Proto3, ok} = read(Proto2, map_end),
+    {Proto3, ok};
+
+skip(Proto0, set) ->
+    {Proto1, Set} = read(Proto0, set_begin),
+    {Proto2, ok} = skip_set_loop(Proto1, Set),
+    {Proto3, ok} = read(Proto2, set_end),
+    {Proto3, ok};
+
+skip(Proto0, list) ->
+    {Proto1, List} = read(Proto0, list_begin),
+    {Proto2, ok} = skip_list_loop(Proto1, List),
+    {Proto3, ok} = read(Proto2, list_end),
+    {Proto3, ok};
+
+skip(Proto0, Type) when is_atom(Type) ->
+    {Proto1, _Ignore} = read(Proto0, Type),
+    {Proto1, ok}.
 
 
-skip_struct_loop(Proto) ->
-    #protocol_field_begin{type = Type} = read(Proto, field_begin),
+skip_struct_loop(Proto0) ->
+    {Proto1, #protocol_field_begin{type = Type}} = read(Proto0, field_begin),
     case Type of
         ?tType_STOP ->
-            ok;
+            {Proto1, ok};
         _Else ->
-            skip(Proto, Type),
-            ok = read(Proto, field_end),
-            skip_struct_loop(Proto)
+            {Proto2, ok} = skip(Proto1, Type),
+            {Proto3, ok} = read(Proto2, field_end),
+            skip_struct_loop(Proto3)
     end.
 
-skip_map_loop(Proto, Map = #protocol_map_begin{ktype = Ktype,
-                                               vtype = Vtype,
-                                               size = Size}) ->
+skip_map_loop(Proto0, Map = #protocol_map_begin{ktype = Ktype,
+                                                vtype = Vtype,
+                                                size = Size}) ->
     case Size of
         N when N > 0 ->
-            skip(Proto, Ktype),
-            skip(Proto, Vtype),
-            skip_map_loop(Proto,
+            {Proto1, ok} = skip(Proto0, Ktype),
+            {Proto2, ok} = skip(Proto1, Vtype),
+            skip_map_loop(Proto2,
                           Map#protocol_map_begin{size = Size - 1});
-        0 -> ok
+        0 -> {Proto0, ok}
     end.
 
-skip_set_loop(Proto, Map = #protocol_set_begin{etype = Etype,
-                                               size = Size}) ->
+skip_set_loop(Proto0, Map = #protocol_set_begin{etype = Etype,
+                                                size = Size}) ->
     case Size of
         N when N > 0 ->
-            skip(Proto, Etype),
-            skip_set_loop(Proto,
+            {Proto1, ok} = skip(Proto0, Etype),
+            skip_set_loop(Proto1,
                           Map#protocol_set_begin{size = Size - 1});
-        0 -> ok
+        0 -> {Proto0, ok}
     end.
 
-skip_list_loop(Proto, Map = #protocol_list_begin{etype = Etype,
-                                                 size = Size}) ->
+skip_list_loop(Proto0, Map = #protocol_list_begin{etype = Etype,
+                                                  size = Size}) ->
     case Size of
         N when N > 0 ->
-            skip(Proto, Etype),
-            skip_list_loop(Proto,
+            {Proto1, ok} = skip(Proto0, Etype),
+            skip_list_loop(Proto1,
                            Map#protocol_list_begin{size = Size - 1});
-        0 -> ok
+        0 -> {Proto0, ok}
     end.
 
 
@@ -271,86 +312,91 @@ skip_list_loop(Proto, Map = #protocol_li
 %%
 %% Description:
 %%--------------------------------------------------------------------
-write(Proto, {{struct, StructDef}, Data})
+-spec write(#protocol{}, term()) -> {#protocol{}, ok | {error, _Reason}}.
+
+write(Proto0, {{struct, StructDef}, Data})
   when is_list(StructDef), is_tuple(Data), length(StructDef) == size(Data) - 1 ->
 
     [StructName | Elems] = tuple_to_list(Data),
-    ok = write(Proto, #protocol_struct_begin{name = StructName}),
-    ok = struct_write_loop(Proto, StructDef, Elems),
-    ok = write(Proto, struct_end),
-    ok;
+    {Proto1, ok} = write(Proto0, #protocol_struct_begin{name = StructName}),
+    {Proto2, ok} = struct_write_loop(Proto1, StructDef, Elems),
+    {Proto3, ok} = write(Proto2, struct_end),
+    {Proto3, ok};
 
 write(Proto, {{struct, {Module, StructureName}}, Data})
   when is_atom(Module),
        is_atom(StructureName),
        element(1, Data) =:= StructureName ->
-    StructType = Module:struct_info(StructureName),
     write(Proto, {Module:struct_info(StructureName), Data});
 
-write(Proto, {{list, Type}, Data})
+write(Proto0, {{list, Type}, Data})
   when is_list(Data) ->
-    ok = write(Proto,
+    {Proto1, ok} = write(Proto0,
                #protocol_list_begin{
                  etype = term_to_typeid(Type),
                  size = length(Data)
                 }),
-    lists:foreach(fun(Elem) ->
-                          ok = write(Proto, {Type, Elem})
-                  end,
-                  Data),
-    ok = write(Proto, list_end),
-    ok;
-
-write(Proto, {{map, KeyType, ValType}, Data}) ->
-    ok = write(Proto,
-               #protocol_map_begin{
-                 ktype = term_to_typeid(KeyType),
-                 vtype = term_to_typeid(ValType),
-                 size  = dict:size(Data)
-                }),
-    dict:fold(fun(KeyData, ValData, _Acc) ->
-                      ok = write(Proto, {KeyType, KeyData}),
-                      ok = write(Proto, {ValType, ValData})
-              end,
-              _AccO = ok,
-              Data),
-    ok = write(Proto, map_end),
-    ok;
+    Proto2 = lists:foldl(fun(Elem, ProtoIn) ->
+                                 {ProtoOut, ok} = write(ProtoIn, {Type, Elem}),
+                                 ProtoOut
+                         end,
+                         Proto1,
+                         Data),
+    {Proto3, ok} = write(Proto2, list_end),
+    {Proto3, ok};
+
+write(Proto0, {{map, KeyType, ValType}, Data}) ->
+    {Proto1, ok} = write(Proto0,
+                         #protocol_map_begin{
+                           ktype = term_to_typeid(KeyType),
+                           vtype = term_to_typeid(ValType),
+                           size  = dict:size(Data)
+                          }),
+    Proto2 = dict:fold(fun(KeyData, ValData, ProtoS0) ->
+                               {ProtoS1, ok} = write(ProtoS0, {KeyType, KeyData}),
+                               {ProtoS2, ok} = write(ProtoS1, {ValType, ValData}),
+                               ProtoS2
+                       end,
+                       Proto1,
+                       Data),
+    {Proto3, ok} = write(Proto2, map_end),
+    {Proto3, ok};
 
-write(Proto, {{set, Type}, Data}) ->
+write(Proto0, {{set, Type}, Data}) ->
     true = sets:is_set(Data),
-    ok = write(Proto,
-               #protocol_set_begin{
-                 etype = term_to_typeid(Type),
-                 size  = sets:size(Data)
-                }),
-    sets:fold(fun(Elem, _Acc) ->
-                      ok = write(Proto, {Type, Elem})
-              end,
-              _Acc0 = ok,
-              Data),
-    ok = write(Proto, set_end),
-    ok;
-
-write(#protocol{module = Module,
-                data = ModuleData}, Data) ->
-    Module:write(ModuleData, Data).
-
-struct_write_loop(Proto, [{Fid, Type} | RestStructDef], [Data | RestData]) ->
-    case Data of
-        undefined ->
-            % null fields are skipped in response
-            skip;
-        _ ->
-            ok = write(Proto,
-                       #protocol_field_begin{
-                         type = term_to_typeid(Type),
-                         id = Fid
-                        }),
-            ok = write(Proto, {Type, Data}),
-            ok = write(Proto, field_end)
-    end,
-    struct_write_loop(Proto, RestStructDef, RestData);
+    {Proto1, ok} = write(Proto0,
+                         #protocol_set_begin{
+                           etype = term_to_typeid(Type),
+                           size  = sets:size(Data)
+                          }),
+    Proto2 = sets:fold(fun(Elem, ProtoIn) ->
+                               {ProtoOut, ok} = write(ProtoIn, {Type, Elem}),
+                               ProtoOut
+                       end,
+                       Proto1,
+                       Data),
+    {Proto3, ok} = write(Proto2, set_end),
+    {Proto3, ok};
+
+write(Proto = #protocol{module = Module,
+                        data = ModuleData}, Data) ->
+    {NewData, Result} = Module:write(ModuleData, Data),
+    {Proto#protocol{data = NewData}, Result}.
+
+struct_write_loop(Proto0, [{Fid, Type} | RestStructDef], [Data | RestData]) ->
+    NewProto = case Data of
+                   undefined ->
+                       Proto0; % null fields are skipped in response
+                   _ ->
+                       {Proto1, ok} = write(Proto0,
+                                           #protocol_field_begin{
+                                             type = term_to_typeid(Type),
+                                             id = Fid
+                                            }),
+                       {Proto2, ok} = write(Proto1, {Type, Data}),
+                       {Proto3, ok} = write(Proto2, field_end),
+                       Proto3
+               end,
+    struct_write_loop(NewProto, RestStructDef, RestData);
 struct_write_loop(Proto, [], []) ->
-    ok = write(Proto, field_stop),
-    ok.
+    write(Proto, field_stop).

Modified: incubator/thrift/trunk/lib/erl/src/thrift_server.erl
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/erl/src/thrift_server.erl?rev=987018&r1=987017&r2=987018&view=diff
==============================================================================
--- incubator/thrift/trunk/lib/erl/src/thrift_server.erl (original)
+++ incubator/thrift/trunk/lib/erl/src/thrift_server.erl Thu Aug 19 05:06:02 2010
@@ -126,7 +126,7 @@ handle_info({inet_async, ListenSocket, R
             {stop, Reason, State}
     end;
 
-handle_info({inet_async, ListenSocket, Ref, Error}, State) ->
+handle_info({inet_async, _ListenSocket, _Ref, Error}, State) ->
     error_logger:error_msg("Error in acceptor: ~p~n", [Error]),
     {stop, Error, State};
 
@@ -177,7 +177,7 @@ start_processor(Socket, Service, Handler
                        {ok, SocketTransport} = thrift_socket_transport:new(Socket),
                        {ok, BufferedTransport} = thrift_buffered_transport:new(SocketTransport),
                        {ok, Protocol} = thrift_binary_protocol:new(BufferedTransport),
-                       {ok, Protocol, Protocol}
+                       {ok, Protocol}
                end,
 
     spawn(thrift_processor, init, [{Server, ProtoGen, Service, Handler}]).

Modified: incubator/thrift/trunk/lib/erl/src/thrift_socket_server.erl
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/erl/src/thrift_socket_server.erl?rev=987018&r1=987017&r2=987018&view=diff
==============================================================================
--- incubator/thrift/trunk/lib/erl/src/thrift_socket_server.erl (original)
+++ incubator/thrift/trunk/lib/erl/src/thrift_socket_server.erl Thu Aug 19 05:06:02 2010
@@ -166,13 +166,12 @@ gen_tcp_listen(Port, Opts, State) ->
 new_acceptor(State=#thrift_socket_server{max=0}) ->
     error_logger:error_msg("Not accepting new connections"),
     State#thrift_socket_server{acceptor=null};
-new_acceptor(State=#thrift_socket_server{acceptor=OldPid, listen=Listen,
+new_acceptor(State=#thrift_socket_server{listen=Listen,
                                          service=Service, handler=Handler,
                                          socket_opts=Opts, framed=Framed
                                         }) ->
     Pid = proc_lib:spawn_link(?MODULE, acceptor_loop,
                               [{self(), Listen, Service, Handler, Opts, Framed}]),
-%%     error_logger:info_msg("Spawning new acceptor: ~p => ~p", [OldPid, Pid]),
     State#thrift_socket_server{acceptor=Pid}.
 
 acceptor_loop({Server, Listen, Service, Handler, SocketOpts, Framed})
@@ -188,7 +187,7 @@ acceptor_loop({Server, Listen, Service, 
                                        false -> thrift_buffered_transport:new(SocketTransport)
                                    end,
                                {ok, Protocol}          = thrift_binary_protocol:new(Transport),
-                               {ok, IProt=Protocol, OProt=Protocol}
+                               {ok, Protocol}
                        end,
             thrift_processor:init({Server, ProtoGen, Service, Handler});
         {error, closed} ->

Modified: incubator/thrift/trunk/lib/erl/src/thrift_socket_transport.erl
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/erl/src/thrift_socket_transport.erl?rev=987018&r1=987017&r2=987018&view=diff
==============================================================================
--- incubator/thrift/trunk/lib/erl/src/thrift_socket_transport.erl (original)
+++ incubator/thrift/trunk/lib/erl/src/thrift_socket_transport.erl Thu Aug 19 05:06:02 2010
@@ -29,6 +29,8 @@
 
 -record(data, {socket,
                recv_timeout=infinity}).
+-type state() :: #data{}.
+-include("thrift_transport_behaviour.hrl").
 
 new(Socket) ->
     new(Socket, []).
@@ -45,25 +47,26 @@ new(Socket, Opts) when is_list(Opts) ->
     thrift_transport:new(?MODULE, State).
 
 %% Data :: iolist()
-write(#data{socket = Socket}, Data) ->
-    gen_tcp:send(Socket, Data).
+write(This = #data{socket = Socket}, Data) ->
+    {This, gen_tcp:send(Socket, Data)}.
 
-read(#data{socket=Socket, recv_timeout=Timeout}, Len)
+read(This = #data{socket=Socket, recv_timeout=Timeout}, Len)
   when is_integer(Len), Len >= 0 ->
     case gen_tcp:recv(Socket, Len, Timeout) of
         Err = {error, timeout} ->
             error_logger:info_msg("read timeout: peer conn ~p", [inet:peername(Socket)]),
             gen_tcp:close(Socket),
-            Err;
-        Data -> Data
+            {This, Err};
+        Data ->
+            {This, Data}
     end.
 
 %% We can't really flush - everything is flushed when we write
-flush(_) ->
-    ok.
+flush(This) ->
+    {This, ok}.
 
-close(#data{socket = Socket}) ->
-    gen_tcp:close(Socket).
+close(This = #data{socket = Socket}) ->
+    {This, gen_tcp:close(Socket)}.
 
 
 %%%% FACTORY GENERATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Modified: incubator/thrift/trunk/lib/erl/src/thrift_transport.erl
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/erl/src/thrift_transport.erl?rev=987018&r1=987017&r2=987018&view=diff
==============================================================================
--- incubator/thrift/trunk/lib/erl/src/thrift_transport.erl (original)
+++ incubator/thrift/trunk/lib/erl/src/thrift_transport.erl Thu Aug 19 05:06:02 2010
@@ -37,21 +37,42 @@ behaviour_info(callbacks) ->
 
 -record(transport, {module, data}).
 
+-ifdef(transport_wrapper_module).
+-define(debug_wrap(Transport),
+        case Transport#transport.module of
+            ?transport_wrapper_module ->
+                Transport;
+            _Else ->
+                {ok, Result} = ?transport_wrapper_module:new(Transport),
+                Result
+        end).
+-else.
+-define(debug_wrap(Transport), Transport).
+-endif.
+
 new(Module, Data) when is_atom(Module) ->
-    {ok, #transport{module = Module,
-                    data = Data}}.
+    Transport0 = #transport{module = Module, data = Data},
+    Transport1 = ?debug_wrap(Transport0),
+    {ok, Transport1}.
 
-%% Data :: iolist()
+-spec write(#transport{}, iolist() | binary()) -> {#transport{}, ok | {error, _Reason}}.
 write(Transport, Data) ->
     Module = Transport#transport.module,
-    Module:write(Transport#transport.data, Data).
+    {NewTransData, Result} = Module:write(Transport#transport.data, Data),
+    {Transport#transport{data = NewTransData}, Result}.
 
+-spec read(#transport{}, non_neg_integer()) -> {#transport{}, {ok, binary()} | {error, _Reason}}.
 read(Transport, Len) when is_integer(Len) ->
     Module = Transport#transport.module,
-    Module:read(Transport#transport.data, Len).
-
-flush(#transport{module = Module, data = Data}) ->
-    Module:flush(Data).
+    {NewTransData, Result} = Module:read(Transport#transport.data, Len),
+    {Transport#transport{data = NewTransData}, Result}.
 
-close(#transport{module = Module, data = Data}) ->
-    Module:close(Data).
+-spec flush(#transport{}) -> {#transport{}, ok | {error, _Reason}}.
+flush(Transport = #transport{module = Module, data = Data}) ->
+    {NewTransData, Result} = Module:flush(Data),
+    {Transport#transport{data = NewTransData}, Result}.
+
+-spec close(#transport{}) -> {#transport{}, ok | {error, _Reason}}.
+close(Transport = #transport{module = Module, data = Data}) ->
+    {NewTransData, Result} = Module:close(Data),
+    {Transport#transport{data = NewTransData}, Result}.

Added: incubator/thrift/trunk/lib/erl/src/thrift_transport_state_test.erl
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/erl/src/thrift_transport_state_test.erl?rev=987018&view=auto
==============================================================================
--- incubator/thrift/trunk/lib/erl/src/thrift_transport_state_test.erl (added)
+++ incubator/thrift/trunk/lib/erl/src/thrift_transport_state_test.erl Thu Aug 19 05:06:02 2010
@@ -0,0 +1,117 @@
+%%
+%% 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.
+%%
+
+-module(thrift_transport_state_test).
+
+-behaviour(gen_server).
+-behaviour(thrift_transport).
+
+%% API
+-export([new/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+         terminate/2, code_change/3]).
+
+%% thrift_transport callbacks
+-export([write/2, read/2, flush/1, close/1]).
+
+-record(trans, {wrapped, % #thrift_transport{}
+                version :: integer(),
+                counter :: pid()
+               }).
+-type state() :: #trans{}.
+-include("thrift_transport_behaviour.hrl").
+
+-record(state, {cversion :: integer()}).
+
+
+new(WrappedTransport) ->
+    case gen_server:start_link(?MODULE, [], []) of
+        {ok, Pid} ->
+            Trans = #trans{wrapped = WrappedTransport,
+                           version = 0,
+                           counter = Pid},
+            thrift_transport:new(?MODULE, Trans);
+        Else ->
+            Else
+    end.
+
+%%====================================================================
+%% thrift_transport callbacks
+%%====================================================================
+
+write(Transport0 = #trans{wrapped = Wrapped0}, Data) ->
+    Transport1 = check_version(Transport0),
+    {Wrapped1, Result} = thrift_transport:write(Wrapped0, Data),
+    Transport2 = Transport1#trans{wrapped = Wrapped1},
+    {Transport2, Result}.
+
+flush(Transport0 = #trans{wrapped = Wrapped0}) ->
+    Transport1 = check_version(Transport0),
+    {Wrapped1, Result} = thrift_transport:flush(Wrapped0),
+    Transport2 = Transport1#trans{wrapped = Wrapped1},
+    {Transport2, Result}.
+
+close(Transport0 = #trans{wrapped = Wrapped0}) ->
+    Transport1 = check_version(Transport0),
+    shutdown_counter(Transport1),
+    {Wrapped1, Result} = thrift_transport:close(Wrapped0),
+    Transport2 = Transport1#trans{wrapped = Wrapped1},
+    {Transport2, Result}.
+
+read(Transport0 = #trans{wrapped = Wrapped0}, Len) ->
+    Transport1 = check_version(Transport0),
+    {Wrapped1, Result} = thrift_transport:read(Wrapped0, Len),
+    Transport2 = Transport1#trans{wrapped = Wrapped1},
+    {Transport2, Result}.
+
+
+%%====================================================================
+%% gen_server callbacks
+%%====================================================================
+
+init([]) ->
+    {ok, #state{cversion = 0}}.
+
+handle_call(check_version, _From, State = #state{cversion = Version}) ->
+    {reply, Version, State#state{cversion = Version+1}}.
+
+handle_cast(shutdown, State) ->
+    {stop, normal, State}.
+
+handle_info(_Info, State) -> {noreply, State}.
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
+terminate(_Reason, _State) -> ok.
+
+%%--------------------------------------------------------------------
+%% Internal functions
+%%--------------------------------------------------------------------
+
+check_version(Transport = #trans{version = Version, counter = Counter}) ->
+    case gen_server:call(Counter, check_version) of
+        Version ->
+            Transport#trans{version = Version+1};
+        _Else ->
+            % State wasn't propagated properly.  Die.
+            erlang:error(state_not_propagated)
+    end.
+
+shutdown_counter(#trans{counter = Counter}) ->
+    gen_server:cast(Counter, shutdown).

Modified: incubator/thrift/trunk/test/erl/Makefile
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/test/erl/Makefile?rev=987018&r1=987017&r2=987018&view=diff
==============================================================================
--- incubator/thrift/trunk/test/erl/Makefile (original)
+++ incubator/thrift/trunk/test/erl/Makefile Thu Aug 19 05:06:02 2010
@@ -29,7 +29,7 @@ SRCDIR=src
 ALL_INCLUDEDIR=$(GEN_INCLUDEDIR) $(INCLUDEDIR) ../../lib/erl/include
 INCLUDEFLAGS=$(patsubst %,-I%, ${ALL_INCLUDEDIR})
 
-MODULES = stress_server test_server test_disklog test_membuffer test_tether
+MODULES = stress_server test_server test_client test_disklog test_membuffer
 
 INCLUDES = 
 TARGETS = $(patsubst %,${TARGETDIR}/%.beam,${MODULES})
@@ -55,11 +55,11 @@ ${GENDIR}/: ${RPCFILE}
 ${GEN_TARGETDIR}/: ${GENDIR}/
 	rm -rf ${GEN_TARGETDIR}
 	mkdir -p ${GEN_TARGETDIR}
-	erlc ${INCLUDEFLAGS} -o ${GEN_TARGETDIR} ${GEN_SRCDIR}/*.erl
+	erlc ${ERLC_FLAGS} ${INCLUDEFLAGS} -o ${GEN_TARGETDIR} ${GEN_SRCDIR}/*.erl
 
 $(TARGETS): ${TARGETDIR}/%.beam: ${SRCDIR}/%.erl ${GEN_INCLUDEDIR}/ ${HEADERS}
 	mkdir -p ${TARGETDIR}
-	erlc ${INCLUDEFLAGS} -o ${TARGETDIR} $<
+	erlc ${ERLC_FLAGS} ${INCLUDEFLAGS} -o ${TARGETDIR} $<
 
 clean:
 	rm -f ${TARGETDIR}/*.beam

Added: incubator/thrift/trunk/test/erl/src/test_client.erl
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/test/erl/src/test_client.erl?rev=987018&view=auto
==============================================================================
--- incubator/thrift/trunk/test/erl/src/test_client.erl (added)
+++ incubator/thrift/trunk/test/erl/src/test_client.erl Thu Aug 19 05:06:02 2010
@@ -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.
+%%
+
+-module(test_client).
+
+-export([start/0, start/1]).
+
+-include("thriftTest_types.hrl").
+
+-record(options, {port = 9090,
+                  client_opts = []}).
+
+parse_args(Args) -> parse_args(Args, #options{}).
+parse_args([], Opts) -> Opts;
+parse_args([Head | Rest], Opts) ->
+    NewOpts =
+        case catch list_to_integer(Head) of
+            Port when is_integer(Port) ->
+                Opts#options{port = Port};
+            _Else ->
+                case Head of
+                    "framed" ->
+                        Opts#options{client_opts = [{framed, true} | Opts#options.client_opts]};
+                    "" ->
+                        Opts;
+                    _Else ->
+                        erlang:error({bad_arg, Head})
+                end
+        end,
+    parse_args(Rest, NewOpts).
+
+
+start() -> start([]).
+start(Args) ->
+  #options{port = Port, client_opts = ClientOpts} = parse_args(Args),
+  {ok, Client0} = thrift_client_util:new(
+    "127.0.0.1", Port, thriftTest_thrift, ClientOpts),
+
+  DemoXtruct = #xtruct{
+    string_thing = <<"Zero">>,
+    byte_thing = 1,
+    i32_thing = 9128361,
+    i64_thing = 9223372036854775807},
+
+  DemoNest = #xtruct2{
+    byte_thing = 7,
+    struct_thing = DemoXtruct,
+    % Note that we don't set i32_thing, it will come back as undefined
+    % from the Python server, but 0 from the C++ server, since it is not
+    % optional
+    i32_thing = 2},
+
+  % Is it safe to match these things?
+  DemoDict = dict:from_list([ {Key, Key-10} || Key <- lists:seq(0,10) ]),
+  DemoSet = sets:from_list([ Key || Key <- lists:seq(-3,3) ]),
+
+  %DemoInsane = #insanity{
+  %  userMap = dict:from_list([{?thriftTest_FIVE, 5000}]),
+  %  xtructs = [#xtruct{ string_thing = <<"Truck">>, byte_thing = 8, i32_thing = 8, i64_thing = 8}]},
+
+  {Client01, {ok, ok}} = thrift_client:call(Client0, testVoid, []),
+
+  {Client02, {ok, <<"Test">>}}      = thrift_client:call(Client01, testString, ["Test"]),
+  {Client03, {ok, <<"Test">>}}      = thrift_client:call(Client02, testString, [<<"Test">>]),
+  {Client04, {ok, 63}}              = thrift_client:call(Client03, testByte, [63]),
+  {Client05, {ok, -1}}              = thrift_client:call(Client04, testI32, [-1]),
+  {Client06, {ok, 0}}               = thrift_client:call(Client05, testI32, [0]),
+  {Client07, {ok, -34359738368}}    = thrift_client:call(Client06, testI64, [-34359738368]),
+  {Client08, {ok, -5.2098523}}      = thrift_client:call(Client07, testDouble, [-5.2098523]),
+  {Client09, {ok, DemoXtruct}}      = thrift_client:call(Client08, testStruct, [DemoXtruct]),
+  {Client10, {ok, DemoNest}}        = thrift_client:call(Client09, testNest, [DemoNest]),
+  {Client11, {ok, DemoDict}}        = thrift_client:call(Client10, testMap, [DemoDict]),
+  {Client12, {ok, DemoSet}}         = thrift_client:call(Client11, testSet, [DemoSet]),
+  {Client13, {ok, [-1,2,3]}}        = thrift_client:call(Client12, testList, [[-1,2,3]]),
+  {Client14, {ok, 1}}               = thrift_client:call(Client13, testEnum, [?thriftTest_ONE]),
+  {Client15, {ok, 309858235082523}} = thrift_client:call(Client14, testTypedef, [309858235082523]),
+
+  % No python implementation, but works with C++ and Erlang.
+  %{Client16, {ok, InsaneResult}}    = thrift_client:call(Client15, testInsanity, [DemoInsane]),
+  %io:format("~p~n", [InsaneResult]),
+  Client16 = Client15,
+
+  {Client17, {ok, #xtruct{string_thing = <<"Message">>}}} =
+    thrift_client:call(Client16, testMultiException, ["Safe", "Message"]),
+
+  Client18 =
+    try
+      {ClientS1, Result1} = thrift_client:call(Client17, testMultiException, ["Xception", "Message"]),
+      io:format("Unexpected return! ~p~n", [Result1]),
+      ClientS1
+    catch
+      throw:{ClientS2, {exception, ExnS1 = #xception{}}} ->
+        #xception{errorCode = 1001, message = <<"This is an Xception">>} = ExnS1,
+        ClientS2;
+      throw:{ClientS2, {exception, _ExnS1 = #xception2{}}} ->
+        io:format("Wrong exception type!~n", []),
+        ClientS2
+    end,
+
+  Client19 =
+    try
+      {ClientS3, Result2} = thrift_client:call(Client18, testMultiException, ["Xception2", "Message"]),
+      io:format("Unexpected return! ~p~n", [Result2]),
+      ClientS3
+    catch
+      throw:{ClientS4, {exception, _ExnS2 = #xception{}}} ->
+        io:format("Wrong exception type!~n", []),
+        ClientS4;
+      throw:{ClientS4, {exception, ExnS2 = #xception2{}}} ->
+        #xception2{errorCode = 2002,
+                   struct_thing = #xtruct{
+                     string_thing = <<"This is an Xception2">>}} = ExnS2,
+        ClientS4
+    end,
+
+  thrift_client:close(Client19).

Modified: incubator/thrift/trunk/test/erl/src/test_disklog.erl
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/test/erl/src/test_disklog.erl?rev=987018&r1=987017&r2=987018&view=diff
==============================================================================
--- incubator/thrift/trunk/test/erl/src/test_disklog.erl (original)
+++ incubator/thrift/trunk/test/erl/src/test_disklog.erl Thu Aug 19 05:06:02 2010
@@ -29,20 +29,21 @@ t() ->
            {size, {1024*1024, 10}}]),
     {ok, ProtocolFactory} = thrift_binary_protocol:new_protocol_factory(
                               TransportFactory, []),
-    {ok, Client} = thrift_client:start_link(ProtocolFactory, thriftTest_thrift),
+    {ok, Proto} = ProtocolFactory(),
+    {ok, Client0} = thrift_client:new(Proto, thriftTest_thrift),
 
     io:format("Client started~n"),
 
     % We have to make oneway calls into this client only since otherwise it will try
     % to read from the disklog and go boom.
-    {ok, ok} = thrift_client:call(Client, testOneway, [16#deadbeef]),
+    {Client1, {ok, ok}} = thrift_client:call(Client0, testOneway, [16#deadbeef]),
     io:format("Call written~n"),
 
     % Use the send_call method to write a non-oneway call into the log
-    ok = thrift_client:send_call(Client, testString, [<<"hello world">>]),
+    {Client2, ok} = thrift_client:send_call(Client1, testString, [<<"hello world">>]),
     io:format("Non-oneway call sent~n"),
 
-    ok = thrift_client:close(Client),
+    {_Client3, ok} = thrift_client:close(Client2),
     io:format("Client closed~n"),
 
     ok.
@@ -61,21 +62,22 @@ t_base64() ->
         thrift_buffered_transport:new_transport_factory(B64Factory),
     {ok, ProtocolFactory} = thrift_binary_protocol:new_protocol_factory(
                               BufFactory, []),
-    {ok, Client} = thrift_client:start_link(ProtocolFactory, thriftTest_thrift),
+    {ok, Proto} = ProtocolFactory(),
+    {ok, Client0} = thrift_client:new(Proto, thriftTest_thrift),
 
     io:format("Client started~n"),
 
     % We have to make oneway calls into this client only since otherwise it will try
     % to read from the disklog and go boom.
-    {ok, ok} = thrift_client:call(Client, testOneway, [16#deadbeef]),
+    {Client1, {ok, ok}} = thrift_client:call(Client0, testOneway, [16#deadbeef]),
     io:format("Call written~n"),
 
     % Use the send_call method to write a non-oneway call into the log
-    ok = thrift_client:send_call(Client, testString, [<<"hello world">>]),
+    {Client2, ok} = thrift_client:send_call(Client1, testString, [<<"hello world">>]),
     io:format("Non-oneway call sent~n"),
 
-    ok = thrift_client:close(Client),
+    {_Client3, ok} = thrift_client:close(Client2),
     io:format("Client closed~n"),
 
     ok.
-    
+

Modified: incubator/thrift/trunk/test/erl/src/test_membuffer.erl
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/test/erl/src/test_membuffer.erl?rev=987018&r1=987017&r2=987018&view=diff
==============================================================================
--- incubator/thrift/trunk/test/erl/src/test_membuffer.erl (original)
+++ incubator/thrift/trunk/test/erl/src/test_membuffer.erl Thu Aug 19 05:06:02 2010
@@ -30,12 +30,12 @@ test_data() ->
 
 t1() ->
     {ok, Transport} = thrift_memory_buffer:new(),
-    {ok, Protocol} = thrift_binary_protocol:new(Transport),
+    {ok, Protocol0} = thrift_binary_protocol:new(Transport),
     TestData = test_data(),
-    ok = thrift_protocol:write(Protocol,
+		{Protocol1, ok} = thrift_protocol:write(Protocol0,
 			       {{struct, element(2, thriftTest_types:struct_info('xtruct'))},
 				TestData}),
-    {ok, Result} = thrift_protocol:read(Protocol,
+		{_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
 					{struct, element(2, thriftTest_types:struct_info('xtruct'))},
 					'xtruct'),
 
@@ -44,12 +44,12 @@ t1() ->
 
 t2() ->
     {ok, Transport} = thrift_memory_buffer:new(),
-    {ok, Protocol} = thrift_binary_protocol:new(Transport),
+    {ok, Protocol0} = thrift_binary_protocol:new(Transport),
     TestData = test_data(),
-    ok = thrift_protocol:write(Protocol,
+		{Protocol1, ok} = thrift_protocol:write(Protocol0,
 			       {{struct, element(2, thriftTest_types:struct_info('xtruct'))},
 				TestData}),
-    {ok, Result} = thrift_protocol:read(Protocol,
+		{_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
 					{struct, element(2, thriftTest_types:struct_info('xtruct3'))},
 					'xtruct3'),
 
@@ -61,12 +61,12 @@ t2() ->
 
 t3() ->
     {ok, Transport} = thrift_memory_buffer:new(),
-    {ok, Protocol} = thrift_binary_protocol:new(Transport),
+    {ok, Protocol0} = thrift_binary_protocol:new(Transport),
     TestData = #bools{im_true = true, im_false = false},
-    ok = thrift_protocol:write(Protocol,
+		{Protocol1, ok} = thrift_protocol:write(Protocol0,
 			       {{struct, element(2, thriftTest_types:struct_info('bools'))},
 				TestData}),
-    {ok, Result} = thrift_protocol:read(Protocol,
+		{_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
 					{struct, element(2, thriftTest_types:struct_info('bools'))},
 					'bools'),
 
@@ -74,8 +74,23 @@ t3() ->
     true = TestData#bools.im_false =:= Result#bools.im_false.
 
 
+t4() ->
+    {ok, Transport} = thrift_memory_buffer:new(),
+    {ok, Protocol0} = thrift_binary_protocol:new(Transport),
+    TestData = #insanity{xtructs=[]},
+		{Protocol1, ok} = thrift_protocol:write(Protocol0,
+			       {{struct, element(2, thriftTest_types:struct_info('insanity'))},
+				TestData}),
+		{_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
+					{struct, element(2, thriftTest_types:struct_info('insanity'))},
+					'insanity'),
+
+    TestData = Result.
+
+
 t() ->
     t1(),
     t2(),
-    t3().
+    t3(),
+    t4().
 

Modified: incubator/thrift/trunk/test/erl/src/test_server.erl
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/test/erl/src/test_server.erl?rev=987018&r1=987017&r2=987018&view=diff
==============================================================================
--- incubator/thrift/trunk/test/erl/src/test_server.erl (original)
+++ incubator/thrift/trunk/test/erl/src/test_server.erl Thu Aug 19 05:06:02 2010
@@ -19,12 +19,42 @@
 
 -module(test_server).
 
--export([start_link/1, handle_function/2]).
+-export([go/0, go/1, start_link/2, handle_function/2]).
 
 -include("thriftTest_types.hrl").
 
-start_link(Port) ->
-    thrift_server:start_link(Port, thriftTest_thrift, ?MODULE).
+-record(options, {port = 9090,
+                  server_opts = []}).
+
+parse_args(Args) -> parse_args(Args, #options{}).
+parse_args([], Opts) -> Opts;
+parse_args([Head | Rest], Opts) ->
+    NewOpts =
+        case catch list_to_integer(Head) of
+            Port when is_integer(Port) ->
+                Opts#options{port = Port};
+            _Else ->
+                case Head of
+                    "framed" ->
+                        Opts#options{server_opts = [{framed, true} | Opts#options.server_opts]};
+                    "" ->
+                        Opts;
+                    _Else ->
+                        erlang:error({bad_arg, Head})
+                end
+        end,
+    parse_args(Rest, NewOpts).
+
+go() -> go([]).
+go(Args) ->
+    #options{port = Port, server_opts = ServerOpts} = parse_args(Args),
+    spawn(fun() -> start_link(Port, ServerOpts), receive after infinity -> ok end end).
+
+start_link(Port, ServerOpts) ->
+    thrift_socket_server:start([{handler, ?MODULE},
+                                {service, thriftTest_thrift},
+                                {port, Port}] ++
+                               ServerOpts).
 
 
 handle_function(testVoid, {}) ->
@@ -124,12 +154,12 @@ handle_function(testInsanity, {Insanity}
                                {?thriftTest_THREE, Crazy}]),
 
     SecondMap = dict:from_list([{?thriftTest_SIX, Looney}]),
-    
+
     Insane = dict:from_list([{1, FirstMap},
                              {2, SecondMap}]),
-    
+
     io:format("Return = ~p~n", [Insane]),
-    
+
     {reply, Insane};
 
 handle_function(testMulti, Args = {Arg0, Arg1, Arg2, _Arg3, Arg4, Arg5})
@@ -150,7 +180,7 @@ handle_function(testException, {String})
     case String of
         <<"Xception">> ->
             throw(#xception{errorCode = 1001,
-                            message = <<"This is an Xception">>});
+                            message = String});
         _ ->
             ok
     end;

Modified: incubator/thrift/trunk/tutorial/erl/client.erl
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/tutorial/erl/client.erl?rev=987018&r1=987017&r2=987018&view=diff
==============================================================================
--- incubator/thrift/trunk/tutorial/erl/client.erl (original)
+++ incubator/thrift/trunk/tutorial/erl/client.erl Thu Aug 19 05:06:02 2010
@@ -29,46 +29,50 @@ p(X) ->
 
 t() ->
     Port = 9999,
-    
-    {ok, Client} = thrift_client:start_link("127.0.0.1",
-                                            Port,
-                                            calculator_thrift),
 
-    thrift_client:call(Client, ping, []),
+    {ok, Client0} = thrift_client_util:new("127.0.0.1",
+                                           Port,
+                                           calculator_thrift,
+                                           []),
+
+    {Client1, {ok, ok}} = thrift_client:call(Client0, ping, []),
     io:format("ping~n", []),
 
-    {ok, Sum} = thrift_client:call(Client, add,  [1, 1]),
+    {Client2, {ok, Sum}} = thrift_client:call(Client1, add,  [1, 1]),
     io:format("1+1=~p~n", [Sum]),
 
-    {ok, Sum1} = thrift_client:call(Client, add, [1, 4]),
+    {Client3, {ok, Sum1}} = thrift_client:call(Client2, add, [1, 4]),
     io:format("1+4=~p~n", [Sum1]),
 
     Work = #work{op=?tutorial_SUBTRACT,
                  num1=15,
                  num2=10},
-    {ok, Diff} = thrift_client:call(Client, calculate, [1, Work]),
+    {Client4, {ok, Diff}} = thrift_client:call(Client3, calculate, [1, Work]),
     io:format("15-10=~p~n", [Diff]),
 
-    {ok, Log} = thrift_client:call(Client, getStruct, [1]),
+    {Client5, {ok, Log}} = thrift_client:call(Client4, getStruct, [1]),
     io:format("Log: ~p~n", [Log]),
 
-    try
-        Work1 = #work{op=?tutorial_DIVIDE,
-                      num1=1,
-                      num2=0},
-        {ok, _Quot} = thrift_client:call(Client, calculate, [2, Work1]),
-
-        io:format("LAME: exception handling is broken~n", [])
-    catch
-        Z ->
-            io:format("Got exception where expecting - the " ++
-                      "following is NOT a problem!!!~n"),
-            p(Z)
-    end,
+    Client6 =
+        try
+            Work1 = #work{op=?tutorial_DIVIDE,
+                          num1=1,
+                          num2=0},
+            {ClientS1, {ok, _Quot}} = thrift_client:call(Client5, calculate, [2, Work1]),
+
+            io:format("LAME: exception handling is broken~n", []),
+            ClientS1
+        catch
+            throw:{ClientS2, Z} ->
+                io:format("Got exception where expecting - the " ++
+                          "following is NOT a problem!!!~n"),
+                p(Z),
+                ClientS2
+        end,
 
 
-    {ok, ok} = thrift_client:call(Client, zip, []),
+    {Client7, {ok, ok}} = thrift_client:call(Client6, zip, []),
     io:format("zip~n", []),
 
-    ok = thrift_client:close(Client),
+    {_Client8, ok} = thrift_client:close(Client7),
     ok.