Conhecendo a SMartyAnnotations
Este artigo apresenta a SMartyAnnotations, que é uma biblioteca de anotações Java baseada na abordagem SMarty para gerenciamento de variabilidades em linha de produto de software.
Autores: Edson A. Oliveira Junior e Luiz Toshimitsu Nakahara Junior
Este artigo apresenta a biblioteca de anotações Java SMartyAnnotation. Por meio desta, questões de variabilidade em linha de produto de software (LPS) podem ser facilmente transcritas de um diagrama de casos de uso ou diagrama de classes diretamente para código fonte anotado Java. Esse novo código gerado carregaria anotações pertinentes e representativas das variabilidades encontradas e descritas anteriormente em modelos UML com o uso da abordagem SMarty.
SMartyAnnotations é composta por várias classes de anotação Java, onde cada uma representa um elemento descrito no SMartyProfile para representação de variabilidade. LPS pode ser entendida como uma prática de reuso sistemático e organizado de software que se destina a atender um segmento de mercado ou uma missão particular.
Em LPS são estudadas as características de cada produto que a compõe. Tais características são classificadas como comuns ou variáveis. As características comuns representam as funcionalidades que estão presentes em todos os produtos da linha e as características variáveis representam as diferenças existentes entre produtos específicos desta linha de produtos.
Neste trabalho é apresentado uma base de conhecimento sobre LPS, variabilidade, SMarty e SMartyProfile, visando auxiliar o entendimento de SMartyAnnotations, uma biblioteca de anotações Java que é o foco principal deste artigo. Para facilitar o entendimento, utilizaremos a LPS AGM (Arcade Game Maker) como exemplo de aplicação e utilização da biblioteca criada.
Linhas de produto de software e variabilidades
LPS representa um conjunto de produtos que unidos podem compor um segmento de mercado em que estão inseridos. Também pode ser compreendida como uma prática de reuso sistemático e organizado de software que se destina a atender um segmento de mercado ou missão particular.
Ao estudar LPS, outros conceitos tornam-se extremamente importantes para uma melhor compreensão do assunto:
· Variabilidade: corresponde às características diferentes (variáveis) existentes entre produtos de uma mesma linha, sendo uma das atividades mais complexas no desenvolvimento e manutenção de uma LPS;
· Ponto de variação: corresponde ao local onde a variabilidade se manifesta. Pode ser entendida como uma situação que permite mais de uma solução para a resolução de uma variabilidade;
· Variante: pode ser entendida como uma solução de um dado ponto de variação. A utilização de variantes diferentes leva à uma diferença entre os produtos da linha.
SMarty tem se destacado como uma abordagem para gerência de variabilidade fornecendo indícios de sua efetividade. A abordagem Stereotype-based Management of Variability (SMarty) é composta de um perfil UML, o SMartyProfile, e um processo, o SMartyProcess.
O perfil SMartyProfile contém um conjunto de estereótipos e meta-atributos para representar variabilidade em modelos UML de LPS. O SMartyProfile tem o intuito de permitir a representação gráfica de conceitos de variabilidade com base em uma notação clara.
A Figura 1 apresenta o SMartyProfile. Note que os estereótipos estão no pacote SMartyProfile anotado com <<profile>>. O pacote UML2 metamodel contém as metaclasses às quais os estereótipos podem ser aplicados.
abrir imagem em nova janela
Figura 1. Diagrama de classes do SMartyProfile.
Um detalhamento de cada estereótipo é apresentado a seguir:
· <<variantionPoint>>: ponto de variação estende as metaclasses UML DecisionNode, Actor, UseCase, Interface e Class, podendo ser aplicado a nós de decisão, atores, casos de uso, interface, classes e pacotes. Ele é composto dos meta-atributos:
o numberOfVariants: número de variantes associadas ao ponto de variação para que o mesmo seja resolvido;
o bindingTime: representado pela classe BingindTime, indica o momento em que uma variabilidade deve ser resolvida;
o allowsAddingVar: indica se há possibilidade de se incluir novas variantes após uma variabilidade ser resolvida;
o variants: coleção de instâncias associadas à variabilidade;
o realizes: coleção de variabilidades de modelos de menor nível de abstração que realiza a variabilidade.
· <<variants>>: é um estereótipo abstrato e não pode ser aplicado diretamente a nenhum elemento UML. Suas especializações (<<alternative_OR>>, <<alternative_XOR>>, <<option>>, <<mandatory>>), no entanto, são aplicáveis em atores, casos de uso, interfaces, classes, ações, partição de atividade, componente, dependência, comentário, fragmento combinado, mensagem e pacotes. Ele estende as metaclasses UML Actor, UseCase, Interface, Class, Action, ActivityPartition, Component, Dependency e Comment, e possui os meta-atributos:
o rootVP: ponto de variação ao qual está associado;
o variabilities: coleção de variabilidades as quais essa variante está associada.
· <<mandatory>>: variante obrigatória presente em todos os produtos da LPS;
· <<optional>>: variante que pode ser escolhida para resolver uma variabilidade ou ponto de variação;
· <<alternative_OR>>: variante que faz parte de um grupo de variantes inclusivas. Combinações diferentes dessas variantes podem resolver pontos de variação de maneiras diferentes, gerando produtos distintos;
· <<alternative_XOR>>: variante que pertence a um grupo de variantes exclusivas na qual apenas uma variante desse grupo pode ser escolhida para resolver um ponto de variação;
· <<mutex>>: expressa o conceito de “exclusão mútua”. É um relacionamento mutuamente exclusivo entre variantes. Indica que para uma variante ser escolhida, a variante relacionada não pode ser selecionada;
· <<requires>>: expressa o conceito de restrição “complemento”. É um relacionamento entre variantes em que uma variante selecionada requer que outra variante relacionada também seja escolhida;
· <<variable>>: extensão da metaclasse UML Component. Pode indicar que um componente é formado por um conjunto de classes com variabilidades explícitas. Contém apenas um meta-atributo:
o classSet: coleção de instâncias das classes variáveis que formam o componente.
· <<variability>>: variabilidade, extensão da metaclasse UML Comment, aplicável assim somente em notas UML. Seus meta-atributos são:
o name: nome que referencia a variabilidade;
o minSelection: quantidade mínima de variantes a serem selecionadas na resolução do ponto de variação ou variabilidade;
o maxSelection: quantidade máxima de variantes a serem selecionadas na resolução do ponto de variação ou variabilidade;
o allowsAddingVar: indica se há possibilidade de se incluir novas variantes após uma variabilidade ser resolvida;
o variants: coleção de instâncias associadas à variabilidade;
o realizes: coleção de variabilidades de modelos de menor nível de abstração que realiza a variabilidade.
Para exemplificar o uso do SMartyProfile utilizaremos o diagrama de casos de uso em UML da LPS AGM (Arcade Game Maker) anotado pelo SMartyProfile (vide Figura 2). A LPS AGM é uma linha de produto criada para auxiliar o aprendizado e experimentação em softwares de linha de produto.
Figura 2. Diagrama de Casos de Uso da LPS AGM.
Na Figura 2 pode-se ver o funcionamento do SMartyProfile, denotando cada caso de uso do diagrama com uma determinada anotação apropriada a seu tipo de variabilidade.
Inicialmente temos as funcionalidades obrigatórias Install Game, Save Game, Play Selected Game, Exit Gale e Uninstall Game. Essas são anotadas com <<mandatory>> que denota obrigatoriedade na presença desta função. Um ponto que se deve destacar é a função Play Selected Game, que além de obrigatória (anotada com <<mandatory>>), também expressa um ponto de variação, <<variationPoint>>, pois a partir dali se pode escolher qual jogo se quer jogar (Play Brickles, Play Pong, Play Bowling), que são funções alternativas, <<alternative_OR>>. Ainda há a função Check Previous Best Score, <<optional>>, expressando um sentido de “opcionalidade” à função, que é opcional e requer (<<requires>>) que tenha sido realizado anteriormente o uso de outra função opcional, a Save Score.
As caixas de anotação, anotadas com <<variability>>, indicam como se pode solucionar a variabilidade que elas representam. Por exemplo, a <<variability>> “play game” pode ser solucionada com a escolha de uma variante (minSelection = 1) e no máximo três variantes (maxSelection = 3), sendo as variantes Play Brickles, Play Pong e Play Bowling.
Anotações Java
Anotações Java existem desde o lançamento do Java 5 e são um recurso usado para anotar classes, campos de atributos e métodos, visando marcá-los de forma que posteriormente essas anotações possam ser lidas pelo compilador, ferramentas de desenvolvimento ou bibliotecas, servindo como metadados para esses. Normalmente são usadas com os seguintes propósitos: instruções de compilação instruções de tempo de montagem e instruções de tempo de corrida.
Um exemplo de uso de anotações Java bem difundido e conhecido é o Hibernate, uma ferramenta ORM (Object Relational Mapping) de código aberto que lidera o mercado. Hibernate é utilizado quando se precisa realizar o mapeamento objeto relacional para banco de dados. O uso de anotações nesse caso demonstra, de forma simples, a funcionalidade das mesmas e como facilitam a programação e persistência de dados desde programas simples até os mais complexos.
Vejamos na Listagem 1 uma classe simples, sem nenhum mapeamento objeto relacional.
Listagem 1. Código da Classe Java Carro simplificada.
public class Carro {
private String cor;
private Double capacidadeMotor;
private Double velocidade;
...
}
Em programas pequenos e/ou com dados descartáveis, provavelmente uma coleção de dados seria usada para armazenar uma lista de carros. Com o uso do Hibernate, esses dados seriam guardados pelo tempo que o usuário desejasse, mesmo após o encerramento do processo. O mapeamento funciona da seguinte maneira: deve-se antes de tudo ter a biblioteca do Hibernate adicionada às bibliotecas padrão do projeto, criar uma conexão com banco local e anotar as classes desejadas, como demonstrado na Listagem 2.
Listagem
2. Código
da classe Carro com anotações do Hibernate.
@Entity
@Table(name = “carros”)
Public class Carro {
@Id
@GeneratedValue
Private Long id;
private String cor;
private Double capacidadeMotor;
private Double velocidade;
...
}
Com apenas o acréscimo de um atributo, que serve de índice para a numeração/identificação de cada objeto, está criada a tabela com o nome de carros especificada pela anotação table. Além disso, atribuímos a string “carros” ao atributo name dessa anotação, que armazenará os objetos persistidos dessa classe.
O uso de anotações Java, em geral, é idêntico ao uso do Hibernate. SMartyAnnotations, que será apresentada no próximo tópico, não foge a essa regra.
SMartyAnnotations
Assim como o SMartyProfile que é utilizado para especificar variabilidades a nível de modelos UML, o SMartyAnnotations tem o intuito de transcrever as variabilidades expressas em modelos UML anotadas pelo SMartyProfile para código fonte Java anotado.
Para cada elemento do SMartyProfile tem-se uma anotação Java utilizando @interface, construção padrão para a criação de anotações Java, e seus meta-atributos. A seguir apresenta-se classes de anotações Java para exemplificar a implementação de SMartyAnnotations.
Na Listagem 3 pode-se ver o uso da construção @interface na declaração dessa classe. Essa é a maneira padrão de se criar anotações. Nesse código é possível ver a anotação @Retention, que indica que a anotação Alternative_OR pode ser acessada em tempo de execução. @Repeatable indica que esta anotação pode ser utilizada repetidas vezes em uma mesma classe.
Listagem 3. Código da classe referente
ao estereótipo <<Alternative_OR>>.
package br.uem.din.grsse.smarty.annotations;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import multiplos.Alternatives_OR;
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Alternatives_OR.class)
public @interface Alternative_OR {
String variantName();
String rootVP();
String[] variabilities();
}
Na Listagem 4 é apresentado o código da classe Alternative_XOR. O uso de @Retention nesta classe indica a possibilidade de acesso em tempo de execução. @Repeatable indica que esta anotação pode ser usada repetidas vezes em uma mesma classe e o parâmetro Alternatives_XOR.class é a classe contêiner de todas as repetições da anotação Alternative_XOR de uma mesma classe Java.
Listagem 4. Código da classe referente
ao estereótipo <<Alternative_XOR>>.
package br.uem.din.grsse.smarty.annotations;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import multiplos.Alternatives_XOR;
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Alternatives_XOR.class)
public @interface Alternative_XOR {
String variantName();
//ponto de variação ao qual está associado rootVP();
String rootVP();
//coleção de variabilidades com as quais esse ponto de variação está associado variabilities();
String[] variabilities();
}
Na Listagem 5 apresentamos a classe Mandatory. Esta anotação indica obrigatoriedade, portanto, classes Java que possuam essa anotação são obrigatórias na construção de todos os produtos da LP. O uso de @Retention nesta classe indica que a anotação pode ser acessada em tempo de execução. Ainda nesse trecho de código, pode-se identificar a anotação @Target, que indica que tipos de elementos podem ter essa anotação associada. TYPE representa todos os tipos de alvos possíveis como classes, interfaces, enumerações ou anotações.
Listagem 5. Código da Classe referente
ao estereótipo <<Mandatory>>.
package br.uem.din.grsse.smarty.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Mandatory {
String variantName();
//ponto de variação ao qual está associado rootVP();
String rootVP();
//coleção de variabilidades com as quais esse ponto de variação está associado variabilities();
String[] variabilities();
}
Na Listagem 6 é apresentada a classe de anotação Mutex. Este estereótipo exprime um sentido de exclusão mútua. Uma classe anotada com essa anotação fica proibida de ser utilizada em conjunto com as classes que estiverem contidas dentro do atributo mutexClasses desta anotação na construção de um mesmo produto da LP. @Target nesta classe indica a possibilidade de ela ser atribuída a todos os tipos de elementos elegíveis para receber anotações e @Retention indica a possibilidade desta anotação ser acessível em tempo de execução.
Listagem 6. Código da Classe referente
ao estereótipo <<Mutex>>.
package br.uem.din.grsse.smarty.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Mutex {
String[] mutexClasses();
//Deve existir algum atributo que indique quais são as variantes conflitantes
//com a variante marcada como Mutex.
}
Na Listagem 7 é apresentada a classe Optional. O uso deste estereótipo indica que a classe Java anotada é uma possível solução para resolver um ponto de variação ou variante. @Target indica a possibilidade de ela ser usada em vários tipos de alvos e @Retention indica que esta anotação pode ser acessada em tempo de execução.
Listagem 7. Código da Classe referente
ao estereótipo <<Optional>>.
package br.uem.din.grsse.smarty.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Optional {
String variantName();
//ponto de variação ao qual está associado rootVP();
String rootVP();
//coleção de variabilidades com as quais esse ponto de variação está associado variabilities();
String[] variabilities();
}
Na Listagem 8 é apresentada a classe Requires e, diferente do estereótipo Mutex, esta anotação indica um conjunto de outras classes, armazenadas no atributo requiresClasses, que devem ser utilizadas juntamente com a classe anotada com esta anotação para a criação de um produto específico da LPS.
Listagem 8. Código da Classe referente
ao estereótipo <<Requires>>.
package br.uem.din.grsse.smarty.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Requires {
String[] requiresClasses();
//Deve haver alguma forma de associação com as demais variantes envolvidas.
}
Na Listagem 9 é apresentada a classe Variability. Este estereótipo representa uma variabilidade que precisa ser resolvida para a geração de produtos específicos. Suas anotações são @Repeatable e @Retentional. Em nível de diagrama UML, este estereótipo somente é utilizado em notas UML que são vinculadas a outros objetos UML. Em nível de código é utilizada diretamente nas classes as quais as notas UML são vinculadas.
Listagem 9. Código da Classe referente
ao estereótipo <<Variability>>
package br.uem.din.grsse.smarty.annotations;
import multiplos.Variabilities;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import br.uem.din.grsse.smarty.annotations.util.BindingTime;
@Repeatable(Variabilities.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface Variability {
String name();
int minSelection();
int maxSelection();
BindingTime bindingTime();
boolean allowsAddingVar();
String[] variants();
String [] realize();
}
A classe apresentada na Listagem 10 é a VariationPoint. Esta classe representa um ponto de variação. O uso de @Repeatable indica que esta mesma anotação pode ser utilizada diversas vezes em uma mesma classe Java e @Retention diz que esta anotação é visível em tempo de execução e que também pode ser consultada.
Listagem 10. Código da Classe referente
ao estereótipo <<VariationPoint>>.
package br.uem.din.grsse.smarty.annotations;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import multiplos.VariationPoints;
import br.uem.din.grsse.smarty.annotations.util.BindingTime;
@Repeatable(VariationPoints.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface VariationPoint {
String nameVP();
int numberOfVariants();
BindingTime bindingTime();
String[] variants();
String[] variabilities();
}
Utilizar SMartyAnnotations baseia-se em dois aspectos importantes, o de anotação Java comum e o uso de diagramas UML anotados com o SMartyProfile. Tendo em mãos esses dois aspectos, torna-se simples o uso da SMartyAnnotations.
Os atributos comuns entre as anotações possuem o mesmo significado e sentido. Por exemplo: o atributo “variantName” é um modo de identificação das anotações individualmente; “bindingTime” representa o momento em que a variabilidade será resolvida e; “variabilities” é uma coleção de variabilidades cuja classe anotada se relaciona, respeitando a limitação individual de cada anotação e no sentido que ela exprime.
Exemplo de aplicação de SMartyAnnotations
Para exemplificar o uso da SMartyAnnotations, utilizaremos a LPS AGM. A Figura 2 compõe a modelagem da LPS AGM segundo a abordagem SMarty. A seguir apresentamos a demonstração da aplicação da SMartyAnnotations com os códigos fonte de algumas classes do pacote CoreAssets da LPS AGM.
No trecho de código da Listagem 11 é descrita a classe StationarySprite. Seguindo o diagrama apresentado na Figura 2, as devidas anotações do SMartyAnnotations foram usadas e seus atributos equivalem aos apresentados no diagrama. Neste caso, usou-se apenas a anotação @Alternative_OR.
Listagem 11. Código da classe StationarySprite,
da LPS AGM.
@Alternative_OR(variantName = "StationarySprite",rootVP = "",variabilities = {""})
public abstract class StationarySprite extends GameSprite {
public StationarySprite(Rectangle r) {
super(r);
name = "StationarySprite";
}
}
No trecho apresentado na Listagem 12, a anotação utilizada foi a @Mandatory, que representa uma variabilidade obrigatória para todos os produtos dessa linha. Seus atributos também foram preenchidos de acordo com o diagrama da Figura 2.
Listagem 12. Código da classe Rectangle,
da LPS AGM.
@Mandatory(variantName = "Rectangle", rootVP = "", variabilities = {"game sprite","sprite pair"})
public class Rectangle {
private Point p;
private Size s;
...
}
Na Listagem 13 é apresentada a classe MovableSprite. As anotações utilizadas foram a @Alternative_OR, que indica que esta classe faz parte de um grupo de variantes inclusivas e que o uso desta classe pode resolver um determinado ponto de variação, e @VariationPoint, que indica que essa classe é um ponto de variação. <
Listagem 13. Código da classe
MovableSprite, da LPS AGM.
@Alternative_OR(variantName = "MovableSprite",rootVP = "movable sprite", variabilities = {"movable sprite"})
@VariationPoint(nameVP = "MovableSprite", numberOfVariants = 0, bindingTime = BindingTime.DESIGN_TIME, variants = {"Velocity"}, variabilities = {"movable sprite"})
public class MovableSprite extends GameSprite {
protected Velocity v;
private boolean moving;
...
}
Na Listagem 14 apresenta-se o código da classe GameSprite, onde as anotações @Mandatory, que indica obrigatoriedade no uso, e @VariationPoint, que indica que esta classe representa um ponto de variação, são utilizadas.
Listagem 14. Código da classe
GameSprite, da LPS AGM.
@Mandatory(variantName = "GameSprite", rootVP = "game sprite", variabilities = {"game sprite","sprite pair"})
@VariationPoint(nameVP = "GameSprite", numberOfVariants = 0, bindingTime = BindingTime.DESIGN_TIME, variants = "game sprite", variabilities = {"game sprite", "sprite pair"})
public abstract class GameSprite {
public String name;
protected Rectangle r;
...
}
Na Listagem 15 é apresentado o código da classe GameMenu, onde a anotação @Mandatory é utilizada para indicar que esta classe é obrigatória a todos os produtos da LP.
Listagem 15. Código da classe GameMenu,
da LPS AGM.
@Mandatory(variantName = "GameMenu", rootVP = "", variabilities = {""})
public abstract class GameMenu extends Form implements CommandListener {
protected Command selectCmd;
protected Command resumeCmd;
protected Board board;
protected Display display;
...
}
Por fim, no trecho de código da Listagem 16, a anotação utilizada foi a @Optional, indicando que a utilização desta classe é opcional segundo o SMartyProfile e o diagrama da Figura 2.
Listagem 16. Código da classe
SpritePair, da LPS AGM.
@Optional(variantName = "SpritePair", rootVP = "sprite pair", variabilities = "sprite pair")
public class SpritePair {
private GameSprite first;
private GameSprite second;
...
}
Este artigo apresentou SMartyAnnotations. Ela estende SMarty e serve de base para a montagem de um gerador de código Java em que a entrada principal serão diagramas UML anotados pelo SMartyProfile e a saída será código Java anotado com SMartyAnnotations equivalente ao que é apresentado nos diagramas UML.
Links
Java Annotations
http://tutorials.jenkov.com/java/annotations.html
Criando anotações em Java
http://blog.hallanmedeiros.com/2009/06/11/criar-anotacoes-em-java/
Referências
Marcolino, A. S.; Oliveira Junior, E. A.; Gimenes, I. M. S.; Maldonado, J. C. Towards the Effectiveness of a Variability Management Approach at Use Case Level. In: Proceedings of the International Conference on Software Engineering and Knowledge Engineering, 2013, Boston,MA. Skokie, IL: Knowledge Systems Institute Graduate School, 2013. v. 1. p. 214-219.(2013a).
Marcolino, A. S.; Oliveira Junior, E. A.; Gimenes, I. M. S.; Barbosa, E. F. Empirically Based Evolution of a Variability Management Approach at UML Class Level. In: Proceedings of the IEEE Annual Computer Software and Applications Conference, 2014, Vasteras. 2014. v. 1. p. 354-363.(2014a).
Marcolino, A. S.; Oliveira Junior, E. A.; Gimenes, I. M. S. Towards the Effectiveness of the SMarty Approach for Variability Management at Sequence Diagram Level. In: 16th International Conference on Enterprise Information Systems, 2014, Lisbon. Proceedings of the 16th International Conference on Enterprise Information Systems. v. 2. P. 249-256.
Oliveira Junior, E. A.; Gimenes, I. M. S.; Maldonado, J. C. Systematic Management of Variability in UML-based Software Product Lines. Journal of Universal Computer Science, 2010, v. 16, p. 2374-2393, 2010. (2010a).
Artigos relacionados
-
Artigo
-
Vídeo
-
Vídeo
-
DevCast
-
DevCast