[thrift] gut Erlang exception handling

Summary: * move type field to tException from subclasses
          * add backtrace to tException
          * add oop:is_a
          * on exit, wrap exceptions in {thrift_exception, E} ... otherwise can't distinguish e.g. exit:{{tBinProtException, {tException, ...}}, Stack} vs. exit:{tBinProtException, {tException, ...} -- I hate erlang
          * all throws/exits to tException:throw which does the wrapping described above

Reviewed By: eletuchy

Test Plan: been using this code on my live server ^_^

Revert: OK


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665350 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/erl/src/tException.erl b/lib/erl/src/tException.erl
index 0ec4c94..6dd3084 100644
--- a/lib/erl/src/tException.erl
+++ b/lib/erl/src/tException.erl
@@ -1,31 +1,36 @@
 %%% Copyright (c) 2007- Facebook
 %%% Distributed under the Thrift Software License
-%%% 
+%%%
 %%% See accompanying file LICENSE or visit the Thrift site at:
 %%% http://developers.facebook.com/thrift/
 
 -module(tException).
 
 -include("oop.hrl").
+-include("thrift.hrl").
 -include("tException.hrl").
 
 -behavior(oop).
 
 -export([attr/4, super/0, inspect/1]).
 
--export([new/1]).
+-export([new/2, add_backtrace_element/2, throw/2, inspect_with_backtrace/2, inspect_with_backtrace/3]).
+
+-export([read/1]).
 
 %%%
 %%% define attributes
 %%% 'super' is required unless ?MODULE is a base class
 %%%
 
-?DEFINE_ATTR(message).
-   
+?DEFINE_ATTR(message);
+?DEFINE_ATTR(type);
+?DEFINE_ATTR(backtrace).
+
 %%%
 %%% behavior callbacks
 %%%
- 
+
 %%% super() -> SuperModule = atom()
 %%%             |  none
 
@@ -35,16 +40,54 @@
 %%% inspect(This) -> string()
 
 inspect(This) ->
-    ?FORMAT_ATTR(message).
+    BT = ?ATTR(backtrace),
+    Depth =
+        if
+            is_list(BT) -> integer_to_list(length(BT));
+            true -> "?"
+        end,
+    ?FORMAT_ATTR(message) ++ ", " ++
+    ?FORMAT_ATTR(type)    ++ ", "
+        " backtrace:" ++ Depth.
 
 %%%
 %%% class methods
 %%%
 
-new(Message) ->
-    #?MODULE{message=Message}.
+new(Type, Message) ->
+    #?MODULE{type=Type, message=Message, backtrace=[]}.
 
-%%%
-%%% instance methods
-%%%
+add_backtrace_element(E, Info) ->
+    BT = oop:get(E, backtrace),
+    E1 = oop:set(E, backtrace, [Info|BT]),
+    E1.
 
+throw(Class, Args) ->
+    E = apply(Class, new, Args),
+    exit({thrift_exception, E}).
+
+
+inspect_with_backtrace(E, Where, Info) ->
+    E1 = add_backtrace_element(E, Info),
+    inspect_with_backtrace(E1, Where).
+
+inspect_with_backtrace(E, Where) ->
+    thrift_utils:sformat("** ~s~n** ~s", [Where, oop:inspect(E)]) ++
+        case oop:get(E, backtrace) of
+            [] ->
+                "";
+            BT when is_list(BT) ->
+                thrift_utils:sformat("~n** trace = ~p", [lists:reverse(BT)]);
+            Else ->
+                thrift_utils:sformat("<ERROR BT NOT A LIST = ~p>", [Else])
+        end.
+
+read(E) ->
+    case oop:class(E) of
+        none ->
+            none;
+        Class ->
+            Type = oop:get(E, type),
+            BT   = oop:get(E, backtrace),
+            {Class, Type, BT}
+    end.