-
Notifications
You must be signed in to change notification settings - Fork 1
Example of how .adf file is processed
%% %% Global pointcuts: %% {pointcut, [ {id, "clean_msg_send"}, {undefined, "This attribute is useless to the compiler. Only to illustrate processing of .adf"}, {send_msg, "{clean, _Id, _From}"} ]}. {pointcut, [ {id, "clean_msg_receive"}, {receive_msg, "{clean, _Id, _From}"} ]}. {pointcut, [ {id, "all_service_calls"}, {functiondef, "program", "\\w*_service", "2"} ]}. %% %% Global advices: %% {advice, [ {id, "log_services"}, {type, before}, {mf, advices, log_service}, {ptcuts, ["all_service_calls"]} ]}. %% %% Aspects: %% {aspect, [ {id, "logging"}, {advice, [ {id, "log_services"}, {type, 'after'} ]}, {advice, [ {type, 'after'}, {mf, advices, log_clean}, {ptcuts, ["clean_msg_send", "clean_msg_receive", {pointcut, [ {send_msg, "{abort, _Id, _From}"} ]} ]} ]}, {pointcut, [ {id, "clean_msg_send"}, {send_msg, "{clean, _Id}"} ]} ]}.
In the example, there are 3 global pointcut definitions, 1 global advice definition, and 1 global aspect. The global pointcut and advice definitions server only to be included (referred to) from aspect definitions. Ultimately, it is the aspect definitions which will affect the weaving process (the transformation of your source code).
The "logging" aspect contains 4 attributes: an id, 2 advices, and a pointcut. Advices and pointcuts within an aspect are local to that aspect definition. This means that their scope is restricted to the aspect in which they are defined. Advices and pointcuts outside of aspects can be referenced from any aspect by id.
-
What is the point of an "id" attribute within a local advice? A local advice with the same id as a global one imports all the attributes of the global advice with the same id. However, if the local advice defines attributes which are already defined in the global advice, those attributes are not imported and the local attributes are used (clash free attributes are imported).
-
What is the point of an "id" attribute within a local pointcut? A similar mechanism (to that of local advices) applies to local pointcuts. However, pointcuts ultimately need to be included within an advice (itself included within an aspect) to have any effect in the weaving process. Pointcuts are included in advices via the ptcuts attribute of an advice. ptcuts contains a list of strings and/or pointcut definitions. The pointcut definitions are included in the advice as is. The strings are references to pointcuts defined outside the advice. In the example, the second advice in the aspect is referring to the pointcuts "clean_msg_send" and "clean_msg_receive". "clean_msg_receive" is defined as a global pointcut so it is included in the advice. "clean_msg_send" is defined both as a local pointcut (in the same aspect the advice is defined in) and as a global pointcut. In this case, the common attributes in the local pointcut take precedence over the ones in the global, but any attribute which is not found in the local is imported from the global.
In order to make sure that you have the correct aspect definitions you can run your .adf files through eaop:read_aspects/1. This function takes a list of file names (as opposed to the optional directory names which can be included in eaop:compile/2/3), so you will have to list each file explicitly.
Assuming the example was saved in 1.adf:
8> eaop:read_aspects(["../demo4doc/dir_structure/aspects1/1.adf"]). [{aspect,[{id,"logging"}, {advice,[{id,"log_services"}, {type,'after'}, {mf,advices,log_service}, {ptcuts,[{pointcut,[{id,"all_service_calls"}, {functiondef,"program","\\w*_service","2"}]}]}]}, {advice,[{type,'after'}, {mf,advices,log_clean}, {ptcuts,[{pointcut,[{id,"clean_msg_send"}, {send_msg,"{clean, _Id}"}, {undefined,"This attribute is useless to the compiler. Only to illustrate processing of .adf"}]}, {pointcut,[{id,"clean_msg_receive"}, {receive_msg,"{clean, _Id, _From}"}]}, {pointcut,[{send_msg,"{abort, _Id, _From}"}]}]}]}, {pointcut,[{id,"clean_msg_send"}, {send_msg,"{clean, _Id}"}, {undefined,"This attribute is useless to the compiler. Only to illustrate processing of .adf"}]}]}]
This will give you back a list of aspects which will be used during compilation. Note that the "clean_msg_send" pointcut is included in the output (the last attribute of the aspect), and it inherited from the global pointcut. However, this pointcut is irrelevant. Only the pointcuts within advices have any effect. It is the "clean_msg_send" pointcut within the second advice in the aspect (it was given no "id" because it did not need to import any attributes) which matters. This pointcut has included the correct send_msg attribute from the local pointcut and the undefined attribute from the global pointcut. The undefined attribute is used only for illustration of how the importing of attributes process works.
Note that more than one .adf file can be used to feed aspects to the compiler. If in the example all global elements except for the aspect are defined in "../demo4doc/dir_struture/aspects2/2a.adf", then the following will give the same result as above:
eaop:read_aspects(["../demo4doc/dir_structure/aspects1/1.adf", "../demo4doc/dir_structure/aspects2/2a.adf"]).
It is important to avoid id clashes between global elements as no error will be thrown. The first element with a matching id will be used and that may not be the element you wanted to refer to.