diff --git a/src/object.erl b/src/object.erl index 05cd5f2..1850c8e 100644 --- a/src/object.erl +++ b/src/object.erl @@ -1,558 +1,558 @@ -% -% object.erl -% -% ---------------------------------------------------------------------- -% -% eXAT, an erlang eXperimental Agent Tool -% Copyright (C) 2005-07 Corrado Santoro (csanto@diit.unict.it) -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see -% -% --module (object). --export ([new/1, - new/2, - delete/1, - start/1, - do/2, - join/1, - stop/1, - bind/2, - agentof/1, - aclqueueof/1, - executorof/1, - property_server/1, - executor/0, - call/2, - call/3, - super_class/2, - super_class/3, - super_class/4, - super/1, - super/2, - super/3, - super_/1, - set/3, - get/2, - getClass/1, - getParent/1, - getAttributes/1, - getAttributeNames/1]). --author ('csanto@diit.unict.it'). --include ("object.hrl"). - --define (PROPERTY_STATUS, '__status__'). --define (TERMINATING, '__terminating__'). --define (JOINING_SYNC, '__joining__'). --define (INIT_STATUS, '__init__'). --define (END_STATUS, '__end__'). --define (BOUND_AGENT, '__agent__'). --define (ACL_QUEUE, '__acl_queue__'). --define (NO_AGENT, '__no_agent__'). --define (MULTISYNC, '__multisync__'). - - -new (Class, P) -> - PropertyServerPid = spawn (object, property_server, [dict:new()]), - server_call (PropertyServerPid, - {self (), set, ?PROPERTY_STATUS, ?INIT_STATUS}), - server_call (PropertyServerPid, - {self (), set, ?TERMINATING, false}), - server_call (PropertyServerPid, - {self (), set, ?JOINING_SYNC, nil}), - server_call (PropertyServerPid, - {self (), set, ?MULTISYNC, nil}), - server_call (PropertyServerPid, - {self (), set, class, Class}), - ExecutorPid = spawn (object, executor, []), - Object = #object {class=Class, - context=Class, - property_server = PropertyServerPid, - executor = ExecutorPid}, - c_tor_call (Object, Class, P), - Object. - -new (Class) -> - new (Class, []). - -delete (Object) -> - Class = Object#object.class, - %io:format ("Before d_tor ~w\n", [Object]), - d_tor_call (Object, Class, []), - S = get (Object, ?JOINING_SYNC), - %io:format ("Before d_tor ~w\n", [S]), - if - S =/= nil -> delete (S); - true -> nil - end, - M = get (Object, ?MULTISYNC), - if - S =/= nil -> catch (multisync:abort (M)); - true -> nil - end, - % Destroy the property server - %io:format ("After d_tor II ~w\n", [Object]), - catch (exit (Object#object.property_server, kill)), - % Destroy the executor - %io:format ("After d_tor ~w\n", [Object]), - catch (exit (Object#object.executor, kill)), - ok. - -set (Object, AttributeName, AttributeValue) -> - server_call (Object#object.property_server, - {self (), set, AttributeName, AttributeValue}), - AttributeValue. - -get (Object, AttributeName) -> - %io:format ("GET: ~w\n", [[Object, AttributeName]]), - V = server_call (Object#object.property_server, - {self (), get, AttributeName}), - case V of - {value, Value} -> Value; - _ -> exit ({undef, [attribute, Object, AttributeName]}) - end. - -call (Object, Method) -> - call (Object, Method, []). - -call (Object, Method, Params) -> - % only the virtual inheritance is implemented - %io:format ("Calling1 ~w,~w\n", [Object,Method]), - Obj1 = Object#object {context = Object#object.class}, - X = call (Obj1, Method, Object#object.class, Params), - %%io:format ("Result is ~w,~w\n", [Object,X]), - X. - -call (Object, Method, nil, _) -> - exit ({undef, [method, Object, Method]}); - -call (Object, Method, Class, Params) -> - case public_call (Object, Method, Class, Params, fun (M,C) -> M end) of - {error, Error} -> - %exit ({undef, [method, Object, Method]}); - exit (Error); - {ok, Value} -> Value - end. - - -super_class (Object, Class) -> - super_class (Object, Class, Class, []). - -super_class (Object, Class, Method) -> - super_class (Object, Class, Method, []). - -super_class (Object, Class, Method, Params) -> - Obj1 = Object#object {context = Class}, - call (Obj1, Method, Obj1#object.context, Params). +%% +%% object.erl +%% +%% ---------------------------------------------------------------------- +%% +%% eXAT, an erlang eXperimental Agent Tool +%% Copyright (C) 2005-07 Corrado Santoro (csanto@diit.unict.it) +%% +%% This program is free software: you can redistribute it and/or modify +%% it under the terms of the GNU General Public License as published by +%% the Free Software Foundation, either version 3 of the License, or +%% (at your option) any later version. +%% +%% This program is distributed in the hope that it will be useful, +%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +%% GNU General Public License for more details. +%% +%% You should have received a copy of the GNU General Public License +%% along with this program. If not, see +%% +%% +-module(object). +-export([new/1, + new/2, + delete/1, + start/1, + do/2, + join/1, + stop/1, + bind/2, + agentof/1, + aclqueueof/1, + executorof/1, + property_server/1, + executor/0, + call/2, + call/3, + super_class/2, + super_class/3, + super_class/4, + super/1, + super/2, + super/3, + super_/1, + set/3, + get/2, + getClass/1, + getParent/1, + getAttributes/1, + getAttributeNames/1]). +-author('csanto@diit.unict.it'). +-include("object.hrl"). + +-define(PROPERTY_STATUS, '__status__'). +-define(TERMINATING, '__terminating__'). +-define(JOINING_SYNC, '__joining__'). +-define(INIT_STATUS, '__init__'). +-define(END_STATUS, '__end__'). +-define(BOUND_AGENT, '__agent__'). +-define(ACL_QUEUE, '__acl_queue__'). +-define(NO_AGENT, '__no_agent__'). +-define(MULTISYNC, '__multisync__'). + + +new(Class, P) -> + PropertyServerPid = spawn(object, property_server, [dict:new()]), + server_call(PropertyServerPid, + {self(), set, ?PROPERTY_STATUS, ?INIT_STATUS}), + server_call(PropertyServerPid, + {self(), set, ?TERMINATING, false}), + server_call(PropertyServerPid, + {self(), set, ?JOINING_SYNC, nil}), + server_call(PropertyServerPid, + {self(), set, ?MULTISYNC, nil}), + server_call(PropertyServerPid, + {self(), set, class, Class}), + ExecutorPid = spawn(object, executor, []), + Object = #object {class=Class, + context=Class, + property_server = PropertyServerPid, + executor = ExecutorPid}, + c_tor_call(Object, Class, P), + Object. + +new(Class) -> + new(Class, []). + +delete(Object) -> + Class = Object#object.class, + %%io:format("Before d_tor ~w\n", [Object]), + d_tor_call(Object, Class, []), + S = get(Object, ?JOINING_SYNC), + %%io:format("Before d_tor ~w\n", [S]), + if + S =/= nil -> delete(S); + true -> nil + end, + M = get(Object, ?MULTISYNC), + if + S =/= nil -> catch(multisync:abort(M)); + true -> nil + end, + %% Destroy the property server + %%io:format("After d_tor II ~w\n", [Object]), + catch(exit(Object#object.property_server, kill)), + %% Destroy the executor + %%io:format("After d_tor ~w\n", [Object]), + catch(exit(Object#object.executor, kill)), + ok. + +set(Object, AttributeName, AttributeValue) -> + server_call(Object#object.property_server, + {self(), set, AttributeName, AttributeValue}), + AttributeValue. + +get(Object, AttributeName) -> + %%io:format("GET: ~w\n", [[Object, AttributeName]]), + V = server_call(Object#object.property_server, + {self(), get, AttributeName}), + case V of + {value, Value} -> Value; + _ -> exit({undef, [attribute, Object, AttributeName]}) + end. + +call(Object, Method) -> + call(Object, Method, []). + +call(Object, Method, Params) -> + %% only the virtual inheritance is implemented + %%io:format("Calling1 ~w,~w\n", [Object,Method]), + Obj1 = Object#object {context = Object#object.class}, + X = call(Obj1, Method, Object#object.class, Params), + %%io:format("Result is ~w,~w\n", [Object,X]), + X. + +call(Object, Method, nil, _) -> + exit({undef, [method, Object, Method]}); + +call(Object, Method, Class, Params) -> + case public_call(Object, Method, Class, Params, fun(M,C) -> M end) of + {error, Error} -> + %%exit({undef, [method, Object, Method]}); + exit(Error); + {ok, Value} -> Value + end. + + +super_class(Object, Class) -> + super_class(Object, Class, Class, []). + +super_class(Object, Class, Method) -> + super_class(Object, Class, Method, []). + +super_class(Object, Class, Method, Params) -> + Obj1 = Object#object {context = Class}, + call(Obj1, Method, Obj1#object.context, Params). %% calls the constructor of the ancestor class -super (Object) -> - super_class (Object, getParent (Object#object.context)). +super(Object) -> + super_class(Object, getParent(Object#object.context)). %% calls the constructor of the ancestor class with the given arguments -super (Object, Arguments) when is_list (Arguments) -> - Parent = getParent (Object#object.context), - super_class (Object, Parent, Parent, Arguments); +super(Object, Arguments) when is_list(Arguments) -> + Parent = getParent(Object#object.context), + super_class(Object, Parent, Parent, Arguments); %% calls the method of the ancestor class -super (Object, Method) -> - Parent = getParent (Object#object.context), - super_class (Object, Parent, Method). +super(Object, Method) -> + Parent = getParent(Object#object.context), + super_class(Object, Parent, Method). %% calls the method of the ancestor class with the given arguments -super (Object, Method, Arguments) -> - Parent = getParent (Object#object.context), - super_class (Object, Parent, Method, Arguments). +super(Object, Method, Arguments) -> + Parent = getParent(Object#object.context), + super_class(Object, Parent, Method, Arguments). %% calls the destructor of the ancestor class super_ (Object) -> - Parent = getParent (Object#object.context), - Method = Parent ++ "_", - super_class (Object, Parent, Method, []). - - -% -% behavioural procedures -% -start (Object) -> - V = get (Object, ?PROPERTY_STATUS), - if - V == ?INIT_STATUS -> - do (Object, start); - true -> nil - end, - ok. - -do (Object, State) -> - set (Object, ?TERMINATING, false), %% FIXME: ????? - V = get (Object, ?PROPERTY_STATUS), - set (Object, ?PROPERTY_STATUS, State), - if - V == ?INIT_STATUS -> - case catch (object:call (Object, on_starting)) of - {'EXIT', {undef, _}} -> ok; - {'EXIT', Error} -> - io:format ("Error in 'on_starting' for object ~w: ~w\n", - [Object, Error]); - _ -> ok - end, - set (Object, ?JOINING_SYNC, object:new (sync)), - trigger_executor (Object); - true -> nil - end, - ok. - -stop (Object) -> - set (Object, ?TERMINATING, true). - -join (Object) -> - S = get (Object, ?JOINING_SYNC), - object:call (S, wait). - -bind (Object, Agent) -> - set (Object, ?BOUND_AGENT, Agent), - set (Object, ?ACL_QUEUE, list_to_atom (atom_to_list (Agent) ++ "__queue")). - -agentof (Object) -> - get (Object, ?BOUND_AGENT). - -aclqueueof (Object) -> - get (Object, ?ACL_QUEUE). - -executorof (Object) -> - Object#object.executor. - -% -% reflection API -% -getClass (Obj) -> - Obj#object.class. - -getParent (Class) -> - % calls "extends/0" function to obtain the parent class - %io:format ("Calling getParent ~w\n", [Class]), - X = call_ (Class, extends), - %io:format ("Called getParent ~w,~w\n", [Class, X]), - X. - - -% getMethods (Class) -> -% % calls "public/0" function to obtain the method list -% call_ (Class, public). - -getAttributeNames (Object) -> - server_call (Object#object.property_server, {self (), list}). - -getAttributes (Object) -> - server_call (Object#object.property_server, {self (), list_values}). - -% ---------------------------------------------- -% -% INTERNAL ROUTINES -% -% ---------------------------------------------- - -% -% Calling a function of a module -% + Parent = getParent(Object#object.context), + Method = Parent ++ "_", + super_class(Object, Parent, Method, []). + + +%% +%% behavioural procedures +%% +start(Object) -> + V = get(Object, ?PROPERTY_STATUS), + if + V == ?INIT_STATUS -> + do(Object, start); + true -> nil + end, + ok. + +do(Object, State) -> + set(Object, ?TERMINATING, false), %% FIXME: ????? + V = get(Object, ?PROPERTY_STATUS), + set(Object, ?PROPERTY_STATUS, State), + if + V == ?INIT_STATUS -> + case catch(object:call(Object, on_starting)) of + {'EXIT', {undef, _}} -> ok; + {'EXIT', Error} -> + io:format("Error in 'on_starting' for object ~w: ~w\n", + [Object, Error]); + _ -> ok + end, + set(Object, ?JOINING_SYNC, object:new(sync)), + trigger_executor(Object); + true -> nil + end, + ok. + +stop(Object) -> + set(Object, ?TERMINATING, true). + +join(Object) -> + S = get(Object, ?JOINING_SYNC), + object:call(S, wait). + +bind(Object, Agent) -> + set(Object, ?BOUND_AGENT, Agent), + set(Object, ?ACL_QUEUE, list_to_atom(atom_to_list(Agent) ++ "__queue")). + +agentof(Object) -> + get(Object, ?BOUND_AGENT). + +aclqueueof(Object) -> + get(Object, ?ACL_QUEUE). + +executorof(Object) -> + Object#object.executor. + +%% +%% reflection API +%% +getClass(Obj) -> + Obj#object.class. + +getParent(Class) -> + %% calls "extends/0" function to obtain the parent class + %%io:format("Calling getParent ~w\n", [Class]), + X = call_ (Class, extends), + %%io:format("Called getParent ~w,~w\n", [Class, X]), + X. + + +%% getMethods(Class) -> +%% %% calls "public/0" function to obtain the method list +%% call_ (Class, public). + +getAttributeNames(Object) -> + server_call(Object#object.property_server, {self(), list}). + +getAttributes(Object) -> + server_call(Object#object.property_server, {self(), list_values}). + +%% ---------------------------------------------- +%% +%% INTERNAL ROUTINES +%% +%% ---------------------------------------------- + +%% +%% Calling a function of a module +%% call_ (Module, Func) -> - call_ (Module, Func, []). + call_ (Module, Func, []). call_ (Module, Func, P) -> - apply ({Module, Func}, P). - -% -% Performing a virtual call to a method of an object -% -public_call (Object, Method, Class, Params, NameFun) -> - public_call (Object, Method, Class, Params, NameFun, - {undef, [method, Object, Method]}). - -public_call (Object, Method, nil, Params, NameFun, LastException) -> - {error, LastException}; - -public_call (Object, Method, Class, Params, NameFun, LastException) -> - Parents = tolist (getParent (Class)), - %%io:format ("Parents = ~w,~w\n", [Object, Parents]), - list_call (Object, Method, Class, Parents, Params, NameFun, LastException). - -list_call (Object, Method, Class, [], Params, NameFun, LastException) -> - {error, LastException}; %%{undef, [method, Object, Method]}}; - -list_call (Object, Method, Class, [ParentH | ParentT], - Params, NameFun, LastException) -> - {Result, Value} = deep_call (Object, Method, Class, - ParentH, Params, NameFun), - if - Result == ok -> {Result, Value}; - true -> list_call (Object, Method, Class, ParentT, - Params, NameFun, LastException) - end. - -deep_call (Object, Method, Class, Parent, Params, NameFun) -> - case call_a_method (Object, Method, Class, Params, NameFun) of - {ok, Value} -> - {ok, Value}; - {to_parent, Exception} -> - Obj1 = Object#object {context = Parent}, - public_call (Obj1, Method, Parent, Params, NameFun, Exception); - {error, Exception} -> - exit (Exception) - end. - -call_a_method (Object, Method, Class, Params, NameFun) -> - %%io:format ("Calling a method ~w,~w\n", [Object, Method]), - MethodName = NameFun (Method, Class), - case catch (call_ (Class, MethodName, [Object | Params])) of - {'EXIT', Error = {undef, [ {Module, Function, _} | _]}} -> - MethodNotPresend = (Module == Class) and (Function == MethodName), - check_for_returning_error (Error, MethodNotPresend); - {'EXIT', Error = {function_clause, [ {Module, Function, _} | _]}} -> - ClauseNotPresend = (Module == Class) and (Function == MethodName), - check_for_returning_error (Error, ClauseNotPresend); - {'EXIT', Other} -> - %%io:format ("Error in calling ~w:~w = ~w\n", [Object, MethodName, - %% Other]), - {error, Other}; - Val -> - {ok, Val} - end. - - -check_for_returning_error (Error, true) -> % the method is not present - {to_parent, Error}; -check_for_returning_error (Error, _) -> % an internal exception occurred - exit (Error). - - -% -% Performing a virtual call to the Ctor of an object -% -c_tor_call (Object, Class, Params) -> - case catch (public_call (Object, Class, Class, Params, - fun (M,C) -> C end)) of - {'EXIT', {undef, _}} -> nil; - {'EXIT', Other} -> exit (Other); - _ -> nil - end. - -% c_tor_call (Object, nil, Params) -> -% nil; -% c_tor_call (Object, Class, Params) -> -% Parents = tolist (getParent (Class)), -% ctor_list_call (Object, Class, Parents, Params). - -% ctor_list_call (Object, nil, _, Params) -> -% nil; - -% ctor_list_call (Object, Class, [], Params) -> -% nil; - -% ctor_list_call (Object, Class, [ParentH | ParentT], Params) -> -% ctor_deep_call (Object, Class, ParentH, Params), -% ctor_list_call (Object, Class, ParentT, Params). - -% ctor_deep_call (Object, Class, Parent, Params) -> -% {Result, Value} = call_a_method (Object, method, Class, Params, -% fun (M,C) -> C end), -% if -% Result == error -> throw ({bad_constructor, {Object, Class}}); -% true -> nil -% end, -% Obj1 = Object#object {context = Parent}, -% c_tor_call (Obj1, Parent, Params). - - -% -% Performing a virtual call to the Dtor of an object -% -d_tor_call (Object, nil, Params) -> - nil; -d_tor_call (Object, Class, Params) -> - Parents = tolist (getParent (Class)), - dtor_list_call (Object, Class, Parents, Params). - -dtor_list_call (Object, nil, _, Params) -> - nil; - -dtor_list_call (Object, Class, [], Params) -> - nil; - -dtor_list_call (Object, Class, [ParentH | ParentT], Params) -> - dtor_deep_call (Object, Class, ParentH, Params), - dtor_list_call (Object, Class, ParentT, Params). - -dtor_deep_call (Object, Class, Parent, Params) -> - call_a_method (Object, method, Class, Params, - fun (M,C) -> - list_to_atom (atom_to_list (C) ++ "_") - end), - Obj1 = Object#object {context = Parent}, - d_tor_call (Obj1, Parent, Params). - - -tolist (X) when is_atom (X) -> [X]; -tolist (X) -> X. - -% -% Execution Management -% -trigger_executor (Object) -> - Object#object.executor ! {go, Object}. - -% -% Executor Server -% -executor () -> - receive - {go, Object} -> executor_loop (Object); - Other -> io:format ("Executor[~w]: Invalid message ~w\n", - [self (), Other]) - end. - -executor_loop (Object) -> - %io:format ("Executor: ~w\n", [Object]), - V = get (Object, ?PROPERTY_STATUS), - T = not (get (Object, ?TERMINATING)), - %io:format ("Value: ~w,~w\n", [Object, V]), - if - T -> - case catch (executor_do (Object, V)) of - {'EXIT', Reason} -> - io:format ("\n=ERROR REPORT====\nError in object behaviour ~w, state ~w, error value: ~w\n", [Object, V, Reason]), - set (Object, ?TERMINATING, true); - Other -> nil - end, - executor_loop (Object); - true -> - case catch (object:call (Object, on_stopping)) of - {'EXIT', {undef, _}} -> ok; - {'EXIT', Error} -> - io:format ("Error in 'on_stopping' for object ~w: ~w\n", - [Object, Error]); - _ -> ok - end, - S = get (Object, ?JOINING_SYNC), - if - S =/= nil -> object:call (S, signal_all); + apply({Module, Func}, P). + +%% +%% Performing a virtual call to a method of an object +%% +public_call(Object, Method, Class, Params, NameFun) -> + public_call(Object, Method, Class, Params, NameFun, + {undef, [method, Object, Method]}). + +public_call(Object, Method, nil, Params, NameFun, LastException) -> + {error, LastException}; + +public_call(Object, Method, Class, Params, NameFun, LastException) -> + Parents = tolist(getParent(Class)), + %%io:format("Parents = ~w,~w\n", [Object, Parents]), + list_call(Object, Method, Class, Parents, Params, NameFun, LastException). + +list_call(Object, Method, Class, [], Params, NameFun, LastException) -> + {error, LastException}; %%{undef, [method, Object, Method]}}; + +list_call(Object, Method, Class, [ParentH | ParentT], + Params, NameFun, LastException) -> + {Result, Value} = deep_call(Object, Method, Class, + ParentH, Params, NameFun), + if + Result == ok -> {Result, Value}; + true -> list_call(Object, Method, Class, ParentT, + Params, NameFun, LastException) + end. + +deep_call(Object, Method, Class, Parent, Params, NameFun) -> + case call_a_method(Object, Method, Class, Params, NameFun) of + {ok, Value} -> + {ok, Value}; + {to_parent, Exception} -> + Obj1 = Object#object {context = Parent}, + public_call(Obj1, Method, Parent, Params, NameFun, Exception); + {error, Exception} -> + exit(Exception) + end. + +call_a_method(Object, Method, Class, Params, NameFun) -> + %%io:format("Calling a method ~w,~w\n", [Object, Method]), + MethodName = NameFun(Method, Class), + case catch(call_ (Class, MethodName, [Object | Params])) of + {'EXIT', Error = {undef, [ {Module, Function, _} | _]}} -> + MethodNotPresend = (Module == Class) and(Function == MethodName), + check_for_returning_error(Error, MethodNotPresend); + {'EXIT', Error = {function_clause, [ {Module, Function, _} | _]}} -> + ClauseNotPresend = (Module == Class) and(Function == MethodName), + check_for_returning_error(Error, ClauseNotPresend); + {'EXIT', Other} -> + %%io:format("Error in calling ~w:~w = ~w\n", [Object, MethodName, + %% Other]), + {error, Other}; + Val -> + {ok, Val} + end. + + +check_for_returning_error(Error, true) ->%% the method is not present + {to_parent, Error}; +check_for_returning_error(Error, _) ->%% an internal exception occurred + exit(Error). + + +%% +%% Performing a virtual call to the Ctor of an object +%% +c_tor_call(Object, Class, Params) -> + case catch(public_call(Object, Class, Class, Params, + fun(M,C) -> C end)) of + {'EXIT', {undef, _}} -> nil; + {'EXIT', Other} -> exit(Other); + _ -> nil + end. + +%% c_tor_call(Object, nil, Params) -> +%% nil; +%% c_tor_call(Object, Class, Params) -> +%% Parents = tolist(getParent(Class)), +%% ctor_list_call(Object, Class, Parents, Params). + +%% ctor_list_call(Object, nil, _, Params) -> +%% nil; + +%% ctor_list_call(Object, Class, [], Params) -> +%% nil; + +%% ctor_list_call(Object, Class, [ParentH | ParentT], Params) -> +%% ctor_deep_call(Object, Class, ParentH, Params), +%% ctor_list_call(Object, Class, ParentT, Params). + +%% ctor_deep_call(Object, Class, Parent, Params) -> +%% {Result, Value} = call_a_method(Object, method, Class, Params, +%% fun(M,C) -> C end), +%% if +%% Result == error -> throw({bad_constructor, {Object, Class}}); +%% true -> nil +%% end, +%% Obj1 = Object#object {context = Parent}, +%% c_tor_call(Obj1, Parent, Params). + + +%% +%% Performing a virtual call to the Dtor of an object +%% +d_tor_call(Object, nil, Params) -> + nil; +d_tor_call(Object, Class, Params) -> + Parents = tolist(getParent(Class)), + dtor_list_call(Object, Class, Parents, Params). + +dtor_list_call(Object, nil, _, Params) -> + nil; + +dtor_list_call(Object, Class, [], Params) -> + nil; + +dtor_list_call(Object, Class, [ParentH | ParentT], Params) -> + dtor_deep_call(Object, Class, ParentH, Params), + dtor_list_call(Object, Class, ParentT, Params). + +dtor_deep_call(Object, Class, Parent, Params) -> + call_a_method(Object, method, Class, Params, + fun(M,C) -> + list_to_atom(atom_to_list(C) ++ "_") + end), + Obj1 = Object#object {context = Parent}, + d_tor_call(Obj1, Parent, Params). + + +tolist(X) when is_atom(X) -> [X]; +tolist(X) -> X. + +%% +%% Execution Management +%% +trigger_executor(Object) -> + Object#object.executor ! {go, Object}. + +%% +%% Executor Server +%% +executor() -> + receive + {go, Object} -> executor_loop(Object); + Other -> io:format("Executor[~w]: Invalid message ~w\n", + [self(), Other]) + end. + +executor_loop(Object) -> + %%io:format("Executor: ~w\n", [Object]), + V = get(Object, ?PROPERTY_STATUS), + T = not(get(Object, ?TERMINATING)), + %%io:format("Value: ~w,~w\n", [Object, V]), + if + T -> + case catch(executor_do(Object, V)) of + {'EXIT', Reason} -> + io:format("\n=ERROR REPORT====\nError in object behaviour ~w, state ~w, error value: ~w\n", [Object, V, Reason]), + set(Object, ?TERMINATING, true); + Other -> nil + end, + executor_loop(Object); + true -> + case catch(object:call(Object, on_stopping)) of + {'EXIT', {undef, _}} -> ok; + {'EXIT', Error} -> + io:format("Error in 'on_stopping' for object ~w: ~w\n", + [Object, Error]); + _ -> ok + end, + S = get(Object, ?JOINING_SYNC), + if + S =/= nil -> object:call(S, signal_all); + true -> nil + end + %%io:format("Behaviour[~w]: Stopped.\n", [Object]) + end. + +executor_do(Object, State) -> + %%io:format("Executor_Do: ~w,~w\n", [Object, State]), + Class = Object#object.class, + %% get the event & proc list + EventProc = call(Object, action, [State]), + %% convert event-proc to a list(if not) + if + is_list(EventProc) -> EventProcList = EventProc; + true -> EventProcList = [EventProc] + end, + CompleteEventList = make_event_list(Object, EventProcList), + %% + %% CompleteEventList is made of: + %% [ {EventType, Pattern, Proc}, .... ] + %% + %% now get the bound agent + %% + case catch(agentof(Object)) of + {'EXIT', _ } -> Agent = ?NO_AGENT; + Other -> Agent = Other + end, + %%io:format("Event list = ~w\n", [CompleteEventList]), + M = multisync:new(), + set(Object, ?MULTISYNC, M), + make_multi_sync_tasks(M, Agent, CompleteEventList), + {FiredEvent, PatternValue, Proc} = multisync:wait_one(M), + set(Object, ?MULTISYNC, nil), + %%io:format("~w,~w\n", [FiredEvent, PatternValue]), + call(Object, Proc, [FiredEvent, PatternValue, State]). + + +make_event_list(Object, []) -> []; +make_event_list(Object, [{Event, Proc}|T]) -> + {EventType, PatternName} = call(Object, event, [Event]), + Pattern = getpattern(Object, PatternName), + [ {EventType, Pattern, Proc} | make_event_list(Object, T)]. + +make_multi_sync_tasks(M, Agent, []) -> ok; +make_multi_sync_tasks(M, Agent, [{acl, Pattern, Proc}|T]) -> + if + Agent =/= ?NO_AGENT -> + multisync:add_task(M, eventmanager, + eventmanager:eventof(acl), + [Agent, Pattern, Proc]); true -> nil - end - %io:format ("Behaviour[~w]: Stopped.\n", [Object]) - end. - -executor_do (Object, State) -> - %io:format ("Executor_Do: ~w,~w\n", [Object, State]), - Class = Object#object.class, - % get the event & proc list - EventProc = call (Object, action, [State]), - % convert event-proc to a list (if not) - if - is_list (EventProc) -> EventProcList = EventProc; - true -> EventProcList = [EventProc] - end, - CompleteEventList = make_event_list (Object, EventProcList), - % - % CompleteEventList is made of: - % [ {EventType, Pattern, Proc}, .... ] - % - % now get the bound agent - % - case catch (agentof (Object)) of - {'EXIT', _ } -> Agent = ?NO_AGENT; - Other -> Agent = Other - end, - %io:format ("Event list = ~w\n", [CompleteEventList]), - M = multisync:new (), - set (Object, ?MULTISYNC, M), - make_multi_sync_tasks (M, Agent, CompleteEventList), - {FiredEvent, PatternValue, Proc} = multisync:wait_one (M), - set (Object, ?MULTISYNC, nil), - %io:format ("~w,~w\n", [FiredEvent, PatternValue]), - call (Object, Proc, [FiredEvent, PatternValue, State]). - - -make_event_list (Object, []) -> []; -make_event_list (Object, [{Event, Proc}|T]) -> - {EventType, PatternName} = call (Object, event, [Event]), - Pattern = getpattern (Object, PatternName), - [ {EventType, Pattern, Proc} | make_event_list (Object, T)]. - -make_multi_sync_tasks (M, Agent, []) -> ok; -make_multi_sync_tasks (M, Agent, [{acl, Pattern, Proc}|T]) -> - if - Agent =/= ?NO_AGENT -> - multisync:add_task (M, eventmanager, - eventmanager:eventof (acl), - [Agent, Pattern, Proc]); - true -> nil - end, - make_multi_sync_tasks (M, Agent, T); -make_multi_sync_tasks (M, Agent, [{EventType, Pattern, Proc}|T]) -> - multisync:add_task (M, eventmanager, - eventmanager:eventof (EventType), - [Agent, Pattern, Proc]), - make_multi_sync_tasks (M, Agent, T). - -getpattern (Object, $_) -> nil; -getpattern (Object, nil) -> nil; -getpattern (Object, PatternName) -> call (Object, pattern, [PatternName]). - -% get_matching_acl_message (AclQueue, Pattern) -> -% %Message = lq:dequeue (AclQueue), -% Message = agent:get_acl (AclQueue), -% %io:format ("~w\n", [Message]), -% Match = match_lib:match (Pattern, Message), -% case Match of -% false -> get_matching_acl_message (AclQueue, Pattern); -% true -> Message -% end. - -% -% Property Management Server -% -server_call (Server, Data) -> - %io:format ("~w\n", [[Server, Data]]), - Server ! Data, - receive - {ack, X} -> X; - Other -> io:format ("Invalid reply = ~p on call ~p: ~p\n", - [Server, Data, Other]), - exit ({badtransaction, Other}) - end. - -property_server (Dict) -> - receive - {From, get, AttributeName} -> - case catch (dict:fetch (AttributeName, Dict)) of - {'EXIT', _} -> From ! {ack, undef}; - Other -> From ! {ack, {value, Other}} - end, - property_server (Dict); - {From, set, AttributeName, AttributeValue} -> - From ! {ack, ok}, - property_server (dict:store (AttributeName, AttributeValue, Dict)); - {From, list} -> - X = dict:fetch_keys (Dict), - From ! {ack, X}, - property_server (Dict); - {From, list_values} -> - X = dict:to_list (Dict), - From ! {ack, X}, - property_server (Dict); - {From, exit } -> - From ! {ack, ok}; - Other -> - property_server (Dict) - end. + end, + make_multi_sync_tasks(M, Agent, T); +make_multi_sync_tasks(M, Agent, [{EventType, Pattern, Proc}|T]) -> + multisync:add_task(M, eventmanager, + eventmanager:eventof(EventType), + [Agent, Pattern, Proc]), + make_multi_sync_tasks(M, Agent, T). + +getpattern(Object, $_) -> nil; +getpattern(Object, nil) -> nil; +getpattern(Object, PatternName) -> call(Object, pattern, [PatternName]). + +%% get_matching_acl_message(AclQueue, Pattern) -> +%% %Message = lq:dequeue(AclQueue), +%% Message = agent:get_acl(AclQueue), +%% %io:format("~w\n", [Message]), +%% Match = match_lib:match(Pattern, Message), +%% case Match of +%% false -> get_matching_acl_message(AclQueue, Pattern); +%% true -> Message +%% end. + +%% +%% Property Management Server +%% +server_call(Server, Data) -> + %%io:format("~w\n", [[Server, Data]]), + Server ! Data, + receive + {ack, X} -> X; + Other -> io:format("Invalid reply = ~p on call ~p: ~p\n", + [Server, Data, Other]), + exit({badtransaction, Other}) + end. + +property_server(Dict) -> + receive + {From, get, AttributeName} -> + case catch(dict:fetch(AttributeName, Dict)) of + {'EXIT', _} -> From ! {ack, undef}; + Other -> From ! {ack, {value, Other}} + end, + property_server(Dict); + {From, set, AttributeName, AttributeValue} -> + From ! {ack, ok}, + property_server(dict:store(AttributeName, AttributeValue, Dict)); + {From, list} -> + X = dict:fetch_keys(Dict), + From ! {ack, X}, + property_server(Dict); + {From, list_values} -> + X = dict:to_list(Dict), + From ! {ack, X}, + property_server(Dict); + {From, exit } -> + From ! {ack, ok}; + Other -> + property_server(Dict) + end.