1 %%% Copyright (c) 2007- Facebook
2 %%% Distributed under the Thrift Software License
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
).
13 -include("thrift.hrl").
15 -include("transport/tTransportException.hrl").
16 -include("protocol/tProtocolException.hrl").
23 -export([init
/1, handle_call
/3, handle_cast
/2, handle_info
/2, terminate
/2, code_change
/3]).
25 -define(SERVER
, ?MODULE
).
32 gen_server:start_link({local
, ?SERVER
}, ?MODULE
, [], []).
35 gen_server:cast(?SERVER
, stop
).
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
)]),
48 E
-> {stop
, {new_failed
, E
}}
52 {stop
, invalid_params
}.
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]),
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
);
79 reply(Type
, ?
CLASS(State
), State
);
82 handle_method(Type
, State
, Method
, Args
);
85 ?
ERROR("thrift no match for Request = ~p", [Request
]),
86 {stop
, server_error
, State
}
87 %% {reply, server_error, State}
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",
101 {stop
, server_error
, State
};
105 reply(Type
, Retval
, State
)
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
);
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
});
122 E1
= tException:add_backtrace_element(E
, Stack
),
123 exit({thrift_exception
, E1
});
125 ?
ERROR("exception wasn't really a tException ~p", [E
]),
130 %%% info, terminate, and code_change
133 handle_info({'EXIT', Pid
, Except
} = All
, State
) ->
140 error_logger:format("unhandled exit ~p", [All
]),
144 handle_info(Info
, State
) ->
148 terminate(Reason
, State
) ->
151 code_change(OldVsn
, State
, Extra
) ->