THRIFT-2110 Erlang: Support for Multiplexing Services on any Transport, Protocol and Server
Client: Erlang
Patch: David Robakowski rebased by Nobuaki Sukegawa

Modification: Return value fix in thrift_client uncovered by added tests
diff --git a/lib/erl/src/thrift_socket_server.erl b/lib/erl/src/thrift_socket_server.erl
index e9ad6f4..4e3c052 100644
--- a/lib/erl/src/thrift_socket_server.erl
+++ b/lib/erl/src/thrift_socket_server.erl
@@ -21,12 +21,19 @@
 
 -behaviour(gen_server).
 
--export([start/1, stop/1]).
+-include ("thrift_constants.hrl").
 
--export([init/1, handle_call/3, handle_cast/2, terminate/2, code_change/3,
-         handle_info/2]).
+-ifdef(TEST).
+    -compile(export_all).
+    -export_records([thrift_socket_server]).
+-else.
+    -export([start/1, stop/1]).
 
--export([acceptor_loop/1]).
+    -export([init/1, handle_call/3, handle_cast/2, terminate/2, code_change/3,
+             handle_info/2]).
+
+    -export([acceptor_loop/1]).
+-endif.
 
 -record(thrift_socket_server,
         {port,
@@ -94,10 +101,46 @@
     parse_options(Rest, State#thrift_socket_server{ip=ParsedIp});
 parse_options([{socket_opts, L} | Rest], State) when is_list(L), length(L) > 0 ->
     parse_options(Rest, State#thrift_socket_server{socket_opts=L});
-parse_options([{handler, Handler} | Rest], State) ->
+
+parse_options([{handler, []} | _Rest], _State) ->
+    throw("At least an error handler must be defined.");
+parse_options([{handler, ServiceHandlerPropertyList} | Rest], State) when is_list(ServiceHandlerPropertyList) ->
+    ServiceHandlerMap =
+    case State#thrift_socket_server.handler of
+        undefined ->
+            lists:foldl(
+                fun ({ServiceName, ServiceHandler}, Acc) when is_list(ServiceName), is_atom(ServiceHandler) ->
+                        thrift_multiplexed_map_wrapper:store(ServiceName, ServiceHandler, Acc);
+                    (_, _Acc) ->
+                        throw("The handler option is not properly configured for multiplexed services. It should be a kind of [{\"error_handler\", Module::atom()}, {SericeName::list(), Module::atom()}, ...]")
+                end, thrift_multiplexed_map_wrapper:new(), ServiceHandlerPropertyList);
+        _ -> throw("Error while parsing the handler option.")
+    end,
+    case thrift_multiplexed_map_wrapper:find(?MULTIPLEXED_ERROR_HANDLER_KEY, ServiceHandlerMap) of
+        {ok, _ErrorHandler} -> parse_options(Rest, State#thrift_socket_server{handler=ServiceHandlerMap});
+        error -> throw("The handler option is not properly configured for multiplexed services. It should be a kind of [{\"error_handler\", Module::atom()}, {SericeName::list(), Module::atom()}, ...]")
+    end;
+parse_options([{handler, Handler} | Rest], State) when State#thrift_socket_server.handler == undefined, is_atom(Handler) ->
     parse_options(Rest, State#thrift_socket_server{handler=Handler});
-parse_options([{service, Service} | Rest], State) ->
+
+parse_options([{service, []} | _Rest], _State) ->
+    throw("At least one service module must be defined.");
+parse_options([{service, ServiceModulePropertyList} | Rest], State) when is_list(ServiceModulePropertyList) ->
+    ServiceModuleMap =
+    case State#thrift_socket_server.service of
+        undefined ->
+            lists:foldl(
+                fun ({ServiceName, ServiceModule}, Acc) when is_list(ServiceName), is_atom(ServiceModule) ->
+                        thrift_multiplexed_map_wrapper:store(ServiceName, ServiceModule, Acc);
+                    (_, _Acc) ->
+                        throw("The service option is not properly configured for multiplexed services. It should be a kind of [{SericeName::list(), ServiceModule::atom()}, ...]")
+                end, thrift_multiplexed_map_wrapper:new(), ServiceModulePropertyList);
+        _ -> throw("Error while parsing the service option.")
+    end,
+    parse_options(Rest, State#thrift_socket_server{service=ServiceModuleMap});
+parse_options([{service, Service} | Rest], State) when State#thrift_socket_server.service == undefined, is_atom(Service) ->
     parse_options(Rest, State#thrift_socket_server{service=Service});
+
 parse_options([{max, Max} | Rest], State) ->
     MaxInt = case Max of
                  Max when is_list(Max) ->