• No results found

Dependendo do tipo de reconfiguração que se deseje realizar sobre um componente, considerando o critério da dinamicidade, estratégias diferentes devem serão aplicadas. No caso das alterações dinâmicas, faremos uso da porta de reconfiguração, enquanto que para as alterações estáticas a estratégia será a escrita de componentes utilizando herança funcional.

Porta de Reconfiguração

A realização de reconfigurações dinâmicas na plataforma HPE se dará através da especificação de um script que descreve as alterações a serem realizadas no componente. Para isso, foi definida uma linguagem de reconfiguração, também baseada em XML, de forma a permitir a descrição de um procedimento de reconfiguração. A gramática apresentada na Figura 4.15 define a sintaxe abstrata do script de reconfiguração.

4.3. Reconfigurações Estáticas e Dinâmicas 84

de configuração definida na gramática 4.1, sofrendo pequenas alterações. A reconfiguração é definida pelo símbolo não terminal reconfig, o qual declara um cabeçalho (header), um conjunto de componentes aninhados (inner) e um conjunto de unidades (unit). O cabeçalho indica o nome do componente alvo a ser reconfigurado pela plataforma através do terminal targetConfigId. As variáveis InnerId e paramType assumem um significado levemente diferente na reconfiguração. Deverão ser descritas pelo innerId apenas novos componentes aninhados a ser inseridos ou componentes aninhados que sofrerão modificação. Estas alterações estarão detalhadas no não-terminal inner. paramType segue o mesmo raciocínio, sendo explicitado apenas os parâmetros que terão o seu valor alterado. Caso deseje-se suprir algum, poderá ser atribuído valor null (nulo) para o respectivo instTypeNoVar.

Como adiantamos, inner deverá citar apenas os componentes aninhados que sofrerão alteração em sintonia com os InnerId.

Unidades (unit) também só deverão ser declaradas caso haja alteração no comportamento de suas ações, condições ou validação. Caso haja necessidade de inclusão de novas fatias, esta operação também poderá ser realizada. A variável unit dispensa explicações tendo em vista que o seu uso é exatamente como na descrição de uma configuração, com exceção de que não há necessidade de declarar as fatias já pertencentes ao conector original.

A novidade fica por conta da action. Além de declarar o identificador da ação a ser alterada, o programador opcionalmente poderá indicar um ponto de reconfiguração (reconfigPointId). Este ponto serve para alterar parcialmente o comportamento desta ação. Uma vez indicado o ponto de reconfiguração, o protocolo descrito na variável protocol irá substituir a respectiva chamada a ação primitiva ou combinador, indicado pelo reconfigPointId. Caso a protocol seja nula, entende-se que a ação indicada pelo ponto de reconfiguração deverá ser removida.

Com todos os recursos oferecidos por esta sintaxe, é possível a realização, mediante script, de qualquer uma dos três tipos de reconfiguração, a saber: reconfiguração comportamental, reconfiguração estrutural explícita e reconfiguração estrutural implícita.

Seja qual for o tipo de reconfiguração a ser realizada, o procedimento será o mesmo. Considerando que o conector exógeno já encontra-se em execução, o programador deverá submeter o seu script ao HPE através do método EvaluateReconfiguration da porta ConfigurationPort, a qual, como vimos, atende a

interface IConfigurationPort exibida na Figura 4.4. Após a recepção da requisição, similarmente ao que ocorre com as configurações, os scripts de reconfiguração passam por um processo de tradução da HCL para a linguagem intermediária.

Novamente o XmlLoader assume a responsabilidade de gerar os metadados a partir do linguagem intermediária. Os metadados são traduzidos em classes que descrevem a reconfiguração, as quais são apresentadas na Figura 4.16 por um diagrama UML.

Figura 4.16: Diagrama das Classes de Metadados

!"#$%&'($)*#$+," -./#!0'112 3&&)456&%1 78%)'&4*+1 -.(/0./($)*#$+," -./#!0'112 3&&)456&%1 78%)'&4*+1 1($+2&.&'+ -./#!0'112 3&&)456&%1 78%)'&4*+1 9 :)'+14&4*+1 9 3".$40.&'+ -./#!0'112 3&&)456&%1 78%)'&4*+1 3".$5++"(*'67'+"+. -./#!0'112 3&&)456&%1 78%)'&4*+1 3".$8$($6"."( -./#!0'112 3&&)456&%1 78%)'&4*+1 3".$-)&0" -./#!0'112 3&&)456&%1 78%)'&4*+1 9 ;%<=04!%1 9 3".$9+&. -./#!0'112 3&&)456&%1 78%)'&4*+1 9 =04!%1 9 9 3!&4*+1> 9 9 70" > 9 ;%< > 9 ?+4& > !"#$%&'($):"0'+;&,/($.&'+:"</"2. -./#!0'112 3&&)456&%1 78%)'&4*+1 9 ;%<@++%).*$8*+%+&1 9 9 .A'+B%1 9 -.(/0./($):"0'+;&,/($.&'+:"</"2. -./#!0'112 3&&)456&%1 78%)'&4*+1 9 .A'+B%"C')'$%&%)1 9 9 .A'+B%1 > :"0'+;&,/($.&'+:"</"2. -./#!0'112 3&&)456&%1 78%)'&4*+1 > D%A'E4*)'0F%G6%1&1 9 > =&)6!&6)'0F%G6%1& >

Fonte: Próprio autor.

Cada requisição de reconfiguração é instanciada como um objeto da classe ReconfigurationRequest. Nessa requisição, pode opcionalmente haver uma requisição de mudança estrutural e, também opcionalmente, várias requisições de mudanças comportamentais. A requisição de mudança estrutural é representada pela classe StructuralReconfiguraionRequest. Essa classe representa apenas as reconfigurações estruturais implícitas. Conforme vimos, as reconfigurações estruturais explícitas só trazem real benefício quando associadas à uma reconfiguração comportamental. Assim, as duas serão tratadas conjuntamente pela classe BehavioralReconfigurationRequest.

O XmlLoader irá criar uma StructuralReconfiguraionRequest sempre que houver reescrita de um ou mais parâmetros de contexto, os quais serão instanciados na forma de MetaParameter e associados ao atributo ChangedParameter. A instanciação

4.3. Reconfigurações Estáticas e Dinâmicas 86

das StructuralChange ocorrerá num segundo momento.

Por sua vez, instâncias do BehavioralReconfigurationRequest serão criadas mediante a reescrita de ações, podendo incluir novos componentes aninhados, representados pelo relacionamento com a classe MetaInnerComponent. Será criada uma nova instância para cada unidade que sofrer alteração, sendo uma instância da classe BehavioralChange para cada ação modificada nesta unidade. Esta última, irá descrever o trecho do protocolo da ação a ser alterada, através da propriedade Transitions, além de incluir as novas fatias que são citadas nesta ação, apresentada através do relacionamento com a classe MetaSlice.

Uma vez carregada a requisição, é iniciado o processo de geração das StructuralChange. Cada instância de StructuralChange corresponde ao efeito causado sobre um componente aninhado pela substituição dos parâmetros de contexto sobre o componente #. O processo de geração consiste em avaliar se o novo conjunto de parâmetros resulta em um componente concreto diferente do atual mediante a avaliação do HTS. Para cada caso em que isso ocorra, uma instância de StructuralChange é criada relacionando-a a um par de MetaUnit onde o primeira, indicado por old, é a unidade a ser removida, enquanto que a segunda, indicada por new, é a sua substituta.

Ao finalizar este procedimento, todas as informações da requisição estarão presentes nos metadados, restando apenas a validação e verificação de segurança.

Assim, o próximo passo é submeter a requisição ao SecurityAnalyzer. Os critérios utilizados nesta validação serão expostos na Seção 4.3.3. Assumindo que a requisição seja aprovada, o SecurityAnalyzer irá retornar um conjunto de avaliações na forma da classe ExecutionStateEvaluation, as quais listam os possíveis estados do autômato onde a execução deverá ser suspensa para que a reconfiguração ocorra com segurança. Essas informações são então passadas ao programador, de modo a solicitar a confirmação ou suspensão da reconfiguração, o qual informa a sua decisão através dos métodos CommitReconfiguration e CancelReconfiguration, respectivamente. Em caso de cancelamento, o processo de reconfiguração é suspenso e o ConfigurationManager volta a estar apto a receber novas requisições de reconfiguração. Em caso de confirmação, esta mesma classe inicia o processo de modificação do conector mediante a suspensão da execução dos estados listados na ExecutionStateEvaluation. Uma vez que a execução alcança um estado desejado, o ConfigurationManager procede com as substituições das unidades, como também a reescrita das transições do autômato alterado. No primeiro caso, esse gerenciador faz uso da porta

BuilderService para realizar a desconexão dos componentes antigos e conexão dos novos. Conforme veremos, o SecurityAnalyzer garante que essa substituição não atinja componentes que possuam estado interno observável.

Ao final de todo o procedimento, os estados do autômato que estavam em suspensão são novamente ativados para execução e o ConfigurationManager volta a estar apto a receber novas requisições de reconfiguração.

Herança Funcional

Suponha que o programador realize frequentemente a mesma reconfiguração em um determinado componente. Apesar dessa frequente reconfiguração, o componente não pode ser alterado em definitivo, seja pela ausência de permissão sobre alteração do código-fonte, ou por seu uso original em outras aplicações.

Ao invés de replicar todo o código-fonte da configuração, alterando apenas os pontos de mudança, a HCL será capaz de realizar herança funcional.

Em função da popularidade de linguagens como C++, Java e C#, tende-se a compreender o conceito de herança de forma limitada. Apesar de ser a mais difundida, a herança de subtipo empregada nessas linguagens não é a única forma de utilizar esta técnica. Sejam A e B abstrações dos conjuntos A’ e B’. Dizemos que a relação B herda de A é uma herança de subtipo se B’ é um subconjunto de A’ e o conjunto modelado por qualquer outro subtipo que herde de A é disjunto de B’ [53]. Na prática, uma das consequências da herança de subtipos é a necessidade de manutenção de compatibilidade de interfaces entre A e B. Todas as formas de interação externas de A devem ser mantidas nos seus subtipos.

Na herança funcional, essa suposição não é mais verdadeira. Nessa classe de herança, se B herda de A, B tem a liberdade de alterar tanto o comportamento quanto as interfaces herdadas de A.

No HPE, a herança entre componentes abstratos segue a herança de subtipos. Já para os componentes concretos, não era previsto pelo modelo nenhum tipo de herança, apenas a relação de implementação de componentes abstratos. Agora, iremos permitir a realização de heranças funcionais para derivação tanto de componentes abstratos quanto concretos. Esta é a estratégia utilizada para a realização de mudanças estáticas.

As mudanças estáticas não irão fazer uso do script de reconfiguração, mas sim da sintaxe de escrita da configuração.

4.3. Reconfigurações Estáticas e Dinâmicas 88