r1319@opsdev009 (orig r70531): cpiro | 2007-11-17 18:10:20 -0800
[amiethrift.git] / lib / erl / src / thrift_oop_server.erl
blobd3bc72073c8717131acc6f2073a2184059a605b0
1 %%% Copyright (c) 2007- Facebook
2 %%% Distributed under the Thrift Software License
3 %%%
4 %%% See accompanying file LICENSE or visit the Thrift site at:
5 %%% http://developers.facebook.com/thrift/
7 -module(thrift_oop_server).
9 -behaviour(gen_server).
11 -include("oop.hrl").
13 -include("thrift.hrl").
15 -include("transport/tTransportException.hrl").
16 -include("protocol/tProtocolException.hrl").
18 -export([
19 start_link/0,
20 stop/0
21 ]).
23 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
25 -define(SERVER, ?MODULE).
27 %%%
28 %%% api
29 %%%
31 start_link() ->
32 gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
34 stop() ->
35 gen_server:cast(?SERVER, stop).
37 %%%
38 %%% init
39 %%%
41 init({Class, Args}) ->
42 process_flag(trap_exit, true),
43 try %% TODO use apply_if_defined
44 State = apply(Class, new, Args),
45 ?INFO("thrift ~p:new(~s) = ~s", [Class, thrift_utils:unbrack(Args), oop:inspect(State)]),
46 {ok, State}
47 catch
48 E -> {stop, {new_failed, E}}
49 end;
51 init(_) ->
52 {stop, invalid_params}.
54 %%%
55 %%% call and cast
56 %%%
58 handle_call(Request, From, State) -> handle_call_cast(call, Request, From, State).
59 handle_cast(stop, State) -> {stop, normal, State};
60 handle_cast({Method, Args}, State) -> handle_call_cast(cast, {Method, Args}, undefined, State).
62 reply(call, Value, State) -> {reply, Value, State};
63 reply(cast, _Value, State) -> {noreply, State}.
65 handle_call_cast(Type, Request, From, State) ->
66 %% ?INFO("~p: ~p", [?SERVER, oop:inspect(State)]),
67 %% ?INFO("handle_call(Request=~p, From=~p, State)", [Request, From]),
69 case Request of
70 {get, [Field]} ->
71 Value = oop:get(State, Field),
72 reply(Type, Value, State);
74 {set, [Field, Value]} ->
75 State1 = oop:set(State, Field, Value),
76 reply(Type, Value, State1);
78 {class, []} ->
79 reply(Type, ?CLASS(State), State);
81 {Method, Args} ->
82 handle_method(Type, State, Method, Args);
84 _ ->
85 ?ERROR("thrift no match for Request = ~p", [Request]),
86 {stop, server_error, State}
87 %% {reply, server_error, State}
88 end.
90 handle_method(Type, State, Method, Args) ->
91 Is_effectful = lists:prefix("effectful_", atom_to_list(Method)),
93 try {Is_effectful, oop:call(State, Method, Args)} of
94 {true, {Retval, State1}} ->
95 reply(Type, Retval, State1);
97 {true, _MalformedReturn} ->
98 %% TODO(cpiro): bad match -- remove when we're done converting
99 ?ERROR("oop:call(effectful_*,..,..) malformed return value ~p",
100 [_MalformedReturn]),
101 {stop, server_error, State};
102 %% {noreply, State};
104 {false, Retval} ->
105 reply(Type, Retval, State)
107 catch
108 exit:{thrift_exception, E} -> handle_exception(E, nothing);
109 exit:{{thrift_exception, E}, Stack} -> handle_exception(E, Stack);
110 exit:normal -> exit(normal);
111 exit:(X = {timeout, _}) -> exit(X);
112 exit:Other ->
113 exit(Other)
114 end.
116 handle_exception(E, Stack) ->
117 %% ?ERROR("texception ~p", [E]),
118 case {oop:is_a(E, tException), Stack} of
119 {true, nothing} -> % good
120 exit({thrift_exception, E});
121 {true, _} -> % good
122 E1 = tException:add_backtrace_element(E, Stack),
123 exit({thrift_exception, E1});
124 false -> % shit
125 ?ERROR("exception wasn't really a tException ~p", [E]),
126 exit(bum)
127 end.
130 %%% info, terminate, and code_change
133 handle_info({'EXIT', Pid, Except} = All, State) ->
134 case Except of
135 normal ->
136 {noreply, State};
137 {normal, _} ->
138 {noreply, State};
139 _unhandled ->
140 error_logger:format("unhandled exit ~p", [All]),
141 {stop, All, State}
142 end;
144 handle_info(Info, State) ->
145 ?INFO("~p", [Info]),
146 {noreply, State}.
148 terminate(Reason, State) ->
151 code_change(OldVsn, State, Extra) ->
152 {ok, State}.