• Nenhum resultado encontrado

6.2 Gera¸ c˜ ao de relat´ orios

6.2.3 Constru¸ c˜ ao e processamento dos relat´ orios

J´a foi explicada a concep¸c˜ao e implementa¸c˜ao do Report e j´a se estabeleceu a forma como o componente observador se relaciona com o elemento observado, para que o primeiro possa ter acesso aos relat´orios gerados pelo ´ultimo. Falta agora explicar como ´e que se constr´oi um objecto do tipo Report, isto ´e, quando, onde e como inserir a informa¸c˜ao dos m´etodos invocados em Report ; e explicar como ´e que o componente observador pode/deve processar a informa¸c˜ao do Report.

A constru¸c˜ao dos objectos Report est´a relacionada com a implementa¸c˜ao da inter- face Observed, cuja adapta¸c˜ao `a DIR e mais genericamente `a vers˜ao original da framework Dolphin ´e explicada na Sec¸c˜ao 7.3. Fica no entanto aqui um pequeno exemplo, represen- tado na Figura 6.13, que ilustra como ´e que o processo se desenrola para o m´etodo bool ins- Node(FlowNode*) de CFG. Como ´e explicado na Sec¸c˜ao7.3, os m´etodos que alteram o estado dos elementos tˆem que ser reescritos. Por exemplo, neste caso bool O CFG::insNode(FlowNode*) reescreve o m´etodo base (bool R CFG::insNode(FlowNode*)). Isto n˜ao significa que o m´e- todo base deixa de existir, apenas que o utilizador passa a ver o m´etodo reescrito, em vez do m´etodo base.

As opera¸c˜oes efectuadas pelo m´etodo reescrito visam essencialmente assegurar a manu- ten¸c˜ao do Report. N˜ao s˜ao efectuadas opera¸c˜oes que estejam directamente relacionadas com o elemento em causa (elemento observado). Assim, o m´etodo reescrito come¸ca por invocar o m´etodo base (bool st= R CFG::insNode(n);); depois testa a vari´avel rep para determinar se Report existe, se assim for, ´e criado um objecto do tipo Method, no qual se inserem os valores dos parˆametros, o valor do resultado e o identificador do m´etodo e da classe. Por fim, faz-se a notifica¸c˜ao dos observadores atrav´es de Observed::notify(), enviando o relat´orio, se este tiver sido solicitado.

(1) bool _O_CFG::insNode(FlowNode *n){

(2) bool st=_R_CFG::insNode(n);

(3) if(___rep){

(4) Method<bool,TL1(FlowNode*)> *m

(5) =new Method<bool,TL1(FlowNode*) >(n);

(6) if(m){ (7) m->setR(st); (8) m->setMID("insNode"); (9) m->setCID("CFG"); (10) ___rep->enqueue(m); (11) } (12) } (13) Observed::notify(); (14) return st; (15) }

Figura 6.13: Exemplo da constru¸c˜ao de um objecto do tipo Report.

Falta apenas explicar o que acontece do lado do componente observador. Este tem que processar cada um dos AbstractMethods contidos na fila de Report. Acontece no entanto, que atrav´es de AbstractMethod n˜ao ´e poss´ıvel utilizar os m´etodos definidos em Method, funda-

mentais para se aceder aos parˆametros e ao valor de retorno. Infelizmente e tanto quanto foi poss´ıvel apurar, em C++ n˜ao h´a muitas mais alternativas do que efectuar um dynamic cast para determinar o tipo concreto de Method representado por AbstractMethod. Isto ´e feito, indicando ao dynamic cast o tipo de Method que se espera obter, isto ´e, assinalando o tipo de retorno e os tipos dos parˆametros. Se a opera¸c˜ao de casting for poss´ıvel de efectuar, o que significa que o AbstractMethod realmente corresponde ao Method que se pretende obter, ent˜ao ser´a devolvido um apontador para este ´ultimo, caso contr´ario ser´a devolvido NULL.

´

E evidente que o componente n˜ao tem como saber qual o Method concreto representado por AbstractMethod, pelo que o processo de identifica¸c˜ao ´e efectuado por tentativas. Isto ´e particularmente grave se o componente estiver a observar muitos elementos da RIC e se esses elementos possu´ırem muitos m´etodos que permitam alterar o seu estado. O que implica por um lado ter que efectuar muitos testes para identificar o m´etodo, e por outro lado, ter que implementar muitos contra-m´etodos, colocando em quest˜ao a utiliza¸c˜ao desta solu¸c˜ao.

No entanto, a experiˆencia adquirida com a aplica¸c˜ao do Report `a framework Dolphin (vers˜ao definitiva), permitiu constatar que se a escolha dos elementos a observar for bem feita, raramente ´e necess´ario observar mais do que um ou dois tipos diferentes de elementos. Constatou-se tamb´em, que normalmente o n´umero de m´etodos para os quais o componente tem que identificar e implementar contra-m´etodos, ´e bastante restrito. Isto porque:

• Em muitos casos, apenas parte da informa¸c˜ao de um elemento, interfere com o estado do componente. Como tal, apenas ´e necess´ario controlar os m´etodos que alteram a informa¸c˜ao da qual o componente ´e dependente, e n˜ao todos os m´etodos do elemento observado;

• Constata-se tamb´em que muitos m´etodos s˜ao implementados exclusivamente com base noutros m´etodos mais primitivos. Nestes casos, ´e suficiente implementar contra-m´etodos para os m´etodos primitivos. Os restantes apenas necessitam que se mantenha o estado do componente em UPDATED ;

• E tamb´em, porque em determinados componentes nem sempre ´e f´acil ou vantajosa a implementa¸c˜ao de contra-m´etodos.

De notar que, por omiss˜ao e no sentido de precaver o correcto funcionamento de todo o sistema, quando um m´etodo n˜ao ´e identificado ou quando n˜ao existem contra-m´etodos, o estado do componente deve ser colocado em OUTDATED. Isto permite que a identifica¸c˜ao dos m´etodos seja feita, considerando apenas os m´etodos para os quais se implementou contra- m´etodos, o que reduz substancialmente o n´umero de opera¸c˜oes de dynamic cast. Conv´em no entanto explicar que h´a alguns casos particulares. Por exemplo, como anteriormente se disse, um m´etodo que invoque exclusivamente m´etodos mais primitivos, n˜ao requer a implementa¸c˜ao de contra-m´etodos no sentido estrito do termo. Na pr´atica, ´e necess´ario implementar um contra-m´etodo, n˜ao para contrapor as altera¸c˜oes ocorridas na RIC, mas para evitar que o estado do componente passe a OUTDATED. ´E como tal necess´aria a identifica¸c˜ao pr´evia deste tipo de m´etodos.

A Figura 6.14 ilustra como ´e que, segundo esta solu¸c˜ao, ´e poss´ıvel implementar os contra-m´etodos e o m´etodo bool notify(Observed*,Report*), para o exemplo da Figura6.5. O Cap´ıtulo 8cont´em um exemplo completo feito com um componente da framework Dolphin. Esta forma de processar o Report n˜ao ´e certamente a solu¸c˜ao ideal, mas foi a solu¸c˜ao encontrada que melhor se adequava `as necessidades do problema em causa. N˜ao est˜ao no entanto exploradas todas as alternativas, pelo que poder´a haver solu¸c˜oes melhores para este problema em concreto.

6.2. Gera¸c˜ao de relat´orios 121

(1) bool Comp::procM(Observed *obs,Method<int,TL1(char*)> *m){...}

(2) bool Comp::procM(Observed *obs,Method<int,TL1(int)> *m){...}

(3) bool Comp::procM(Observed *obs,Method<int,TL2(char*,int)> *m){...}

(4)

(5) bool Comp::notify(Observed *obs,Report *r){

(6) bool st; (7) AbstractMethod *m; (8) if(r && getState()==UPDATED){ (9) int i, nn=r->howMany(); (10) for(i=0;i<nn;i++){ (11) m=r->dequeue(); (12) st=false;

(13) Method<int,TL1(char*)> *m1

(14) =dynamic_cast<Method<int,TL1(char*)>*>(m);

(15) if(m1) st=procM(obs,m1);

(16) else{

(17) Method<int,TL1(int)> *m2

(18) =dynamic_cast<Method<int,TL1(int)>*>(m);

(19) if(m2) st=procM(obs,m2);

(20) else{

(21) Method<int,TL2(char*,int)> *m3

(22) =dynamic_cast<Method<int,TL2(char*,int)>*>(m);

(23) if(m3) st=procM(obs,m3); (24) } (25) } (26) if(!st) setState(OUTDATED); (27) r->enqueue(m); (28) } (29) } (30) return st; (31) }

Figura 6.14: Exemplo do processamento do Report.