80
FGP-FACULDADE GENNARI & PEARTREE Sistemas de Informação SURF FRAMEWORK – UM FRAMEWORK MVP EM JAVA TM Daniel Fernandes Martins PEDERNEIRAS – SP 2006

tcc - surf

Embed Size (px)

Citation preview

Page 1: tcc - surf

FGP-FACULDADE GENNARI & PEARTREE

Sistemas de Informação

SURF FRAMEWORK – UM FRAMEWORK MVP EM JAVATM

Daniel Fernandes Martins

PEDERNEIRAS – SP2006

Page 2: tcc - surf

FGP-FACULDADE GENNARI & PEARTREE

Sistemas de Informação

SURF FRAMEWORK – UM FRAMEWORK MVP EM JAVATM

Daniel Fernandes Martins

Trabalho apresentado como requisito obrigatório à conclusão do Curso de Bacharelado em Sistemas de Informação da Faculdade Gennari & Peartree.

Orientadora: Vânia

PEDERNEIRAS – SP2006

Page 3: tcc - surf

FOLHA DE APROVAÇÃO

Pederneiras, 01 de Dezembro de 2006.

Orientadora:

Examinador:

Examinador:

Page 4: tcc - surf

LISTA DE ILUSTRAÇÕES

Ilustração 1: Modelo MVC...................................................................................................................8Ilustração 2: Diferença entre o padrão MVC e o padrão MVP..........................................................10Ilustração 3: Organização arquitetural do Surf Framework...............................................................13Ilustração 4: View da aplicação..........................................................................................................17Ilustração 5: Model da aplicação........................................................................................................17Ilustração 6: Mensagem de confirmação............................................................................................17Ilustração 7: Obtendo os dados do Model..........................................................................................18Ilustração 8: Nested properties...........................................................................................................27Ilustração 9: Janela principal da aplicação.........................................................................................58Ilustração 10: Janela de manutenção de tarefas..................................................................................59Ilustração 11: Modelo da aplicação....................................................................................................59

Page 5: tcc - surf

LISTAGENS

Listagem 1: Código da View..............................................................................................................19Listagem 2: Presenter da aplicação....................................................................................................20Listagem 3: Classe principal da aplicação..........................................................................................21Listagem 4: Configuração manual......................................................................................................23Listagem 5: Arquivo XML de configuração do Spring......................................................................25Listagem 6: Utilização do BeanFactory do Spring.............................................................................26Listagem 7: Configuração do Framework usando o Pico..................................................................26Listagem 8: Obtendo referência de um Presenter criado pelo framework Pico.................................27Listagem 9: Utilizando a anotação @Bind.........................................................................................29Listagem 10: Utilizando a anotação @Formatter...............................................................................30Listagem 11: Executando um evento mapeado com @Interaction....................................................30Listagem 12: Reutilizando configuração através do atributo copyFrom............................................31Listagem 13: Reutilização parcial dos parâmetros de interação.........................................................32Listagem 14: Command que fecha a janela ao clicar no botão..........................................................32Listagem 15: Adicionando Commands em mais de um tipo de evento.............................................33Listagem 16: Usando a anotação @Property.....................................................................................34Listagem 17: Recuperando uma propriedade informada na anotação @Interaction..........................34Listagem 18: Utilização de subviews com @SubView......................................................................35Listagem 19: Aplicando Commands a componentes de uma subview..............................................36Listagem 20: Informando o tipo de um componente com a anotação @Type...................................37Listagem 21: Definindo um atributo do Presenter como Model........................................................38Listagem 22: Evento de fechamento da View....................................................................................39Listagem 23: Declarando um Presenter..............................................................................................41Listagem 24: Exemplo de Presenter...................................................................................................43Listagem 25: Definindo um atributo como Model.............................................................................43Listagem 26: Exemplo de Command.................................................................................................44Listagem 27: Exemplo de Command, utilizando Generics................................................................44Listagem 28: Comparando um Command com e sem Generics........................................................45Listagem 29: Uso do atributo methodName da anotação @Interaction.............................................45Listagem 30: Método que será executado pelo Surf ao disparar o evento.........................................46Listagem 31: Omissão do parâmetro methodName na anotação @Interaction.................................46Listagem 32: Método a ser executado pelo Surf ao disparar o evento...............................................46Listagem 33: Configurando um evento com dois Commands...........................................................47Listagem 34: Setando um parâmetro no contexto de Commands......................................................48Listagem 35: Obtendo um parâmetro do contexto de Commands.....................................................48Listagem 36: Passagem de dados entre a View e o Model.................................................................49Listagem 37: Sincronizando atributos individuais.............................................................................49Listagem 38: Indicando o nome do Model que deve ser utilizado na sincronia................................50Listagem 39: Sincronizando sub-atributos.........................................................................................50Listagem 40: Exemplo de uma construção Enum..............................................................................50Listagem 41: Exemplo de uso de uma construção Enum...................................................................51Listagem 42: Setando valores na View..............................................................................................51Listagem 43: Obtendo referência a um componente da View...........................................................52Listagem 44: Habilitando e desabilitando componentes....................................................................52Listagem 45: Utilização da classe GenericListModel........................................................................53Listagem 46: Criação de um TableModel no Surf.............................................................................54Listagem 47: Usando JRadioButtons.................................................................................................55Listagem 48: Binding de um grupo de componentes JRadioButton..................................................56Listagem 49: Obtendo dados de seleção de um componente.............................................................56

Page 6: tcc - surf

Listagem 50: Trabalhando com seleções de texto..............................................................................57Listagem 51: Lógica de apresentação.................................................................................................60Listagem 52: Extenção da lógica de apresentação.............................................................................60Listagem 53: Interface do Presenter da janela principal da aplicação................................................61Listagem 54: Interface do Presenter da janela de edição de tarefas...................................................61Listagem 55: Definição do Presenter da janela principal...................................................................61Listagem 56: Método do Presenter para manipulação da View.........................................................62Listagem 57: Método para filtragem de tarefas..................................................................................63Listagem 58: Interação com o banco de dados...................................................................................63Listagem 59: Definição do Presenter da janela de manutenção.........................................................64Listagem 60: Manipulação dos componentes da View......................................................................65Listagem 61: Exemplo de Command.................................................................................................66Listagem 62: Criação simplificada de Commands.............................................................................66Listagem 63: Método executado quando o evento é disparado..........................................................67Listagem 64: Configuração da View da janela principal...................................................................68Listagem 65: Configuração da View da janela de manutenção.........................................................69Listagem 66: Arquivo de configuração do Spring.............................................................................71Listagem 67: Interface de gerenciamento dos Presenters da aplicação..............................................71Listagem 68: Classe de obtenção de Presenters via Spring................................................................72Listagem 69: Classe de obtenção de Presenters via Pico...................................................................73Listagem 70: Classe principal da aplicação........................................................................................74

Page 7: tcc - surf

SUMÁRIO

1 INTRODUÇÃO.................................................................................................................................81.1. Nome do framework.................................................................................................................81.2. Descrição do problema.............................................................................................................8

1.2.1. Limitações do MVC..........................................................................................................91.2.2. Origem do MVP..............................................................................................................10

1.3. Objetivos do Surf Framework.................................................................................................101.4. Procedimentos de instalação...................................................................................................11

1.4.1. Requisitos básicos...........................................................................................................111.4.1.1. Requisitos de hardware...........................................................................................111.4.1.2. Requisitos de software.............................................................................................11

1.4.2. Procedimento para instalação..........................................................................................111.4.3. Procedimento para configuração.....................................................................................11

1.4.3.1. Eclipse 3.2...............................................................................................................121.4.3.2. NetBeans 5.5...........................................................................................................12

1.4.4. Aplicativo de demonstração............................................................................................122 DESCRIÇÃO DO FUNCIONAMENTO........................................................................................13

2.1. Arquitetura do framework......................................................................................................132.1.1. Models e View................................................................................................................132.1.2. Swing..............................................................................................................................132.1.3. Configurações do Surf....................................................................................................14

2.1.3.1. Adaptadores de componentes..................................................................................142.1.3.2. Conversores.............................................................................................................142.1.3.3. Formatadores...........................................................................................................14

2.1.4. Configurações do Presenter............................................................................................142.1.5. Binding............................................................................................................................142.1.6. Commands......................................................................................................................152.1.7. Presenter..........................................................................................................................16

2.2. Desenvolvendo a primeira aplicação......................................................................................162.2.1. Construindo a aplicação..................................................................................................18

2.2.1.1. Criando o model......................................................................................................182.2.1.2. Criando a view.........................................................................................................192.2.1.3. Criando o presenter.................................................................................................202.2.1.4. Criando a classe principal........................................................................................21

3 CONHECENDO O SURF FRAMEWORK....................................................................................233.1. Configurando o Surf...............................................................................................................23

3.1.1. Configuração manual......................................................................................................233.1.2. Configuração via Spring.................................................................................................243.1.3. Configuração via Pico.....................................................................................................26

3.2. Nested properties....................................................................................................................273.2.1. Referenciando um atributo aninhado..............................................................................27

3.3. Anotações do Surf...................................................................................................................283.3.1. Apresentando as anotações.............................................................................................28

3.3.1.1. Anotações de view...................................................................................................283.3.1.1.1. @Bind..............................................................................................................283.3.1.1.2. @Formatter......................................................................................................293.3.1.1.3. @Interaction....................................................................................................303.3.1.1.4. @InteractionList..............................................................................................323.3.1.1.5. @Property........................................................................................................333.3.1.1.6. @SubView.......................................................................................................34

Page 8: tcc - surf

3.3.1.1.7. @Type.............................................................................................................363.3.1.1.8. @Widget..........................................................................................................37

3.3.1.2. Anotações de presenter............................................................................................373.3.1.2.1. @Model...........................................................................................................373.3.1.2.2. @OnViewActivate..........................................................................................383.3.1.2.3. @OnViewClose...............................................................................................393.3.1.2.4. @OnViewClosed.............................................................................................393.3.1.2.5. @OnViewDeactivate.......................................................................................393.3.1.2.6. @OnViewDeiconify........................................................................................403.3.1.2.7. @OnViewGainFocus.......................................................................................403.3.1.2.8. @OnViewIconify............................................................................................403.3.1.2.9. @OnViewLostFocus.......................................................................................403.3.1.2.10. @OnViewOpened..........................................................................................413.3.1.2.11. @Presenter.....................................................................................................413.3.1.2.12. @View...........................................................................................................41

3.3.2. Mais exemplos de uso das anotações..............................................................................423.4. Criando os models..................................................................................................................423.5. Criando as views.....................................................................................................................423.6. Criando os presenters..............................................................................................................42

3.6.1. Definindo os models.......................................................................................................433.7. Criando commands.................................................................................................................43

3.7.1. Combinando generics com commands...........................................................................443.7.2. Criação simplificada de commands................................................................................45

3.8. Command Context..................................................................................................................463.9. Utilizando o recurso de data binding......................................................................................48

3.9.1. Sincronizando a view e o model.....................................................................................493.9.2. Trabalhando com enums.................................................................................................50

3.10. Operações comuns................................................................................................................513.10.1. Obtendo uma referência a um componente da View....................................................523.10.2. Habilitando e desabilitando componentes.....................................................................52

3.11. Componentes especiais.........................................................................................................523.11.1. Componente JList.........................................................................................................523.11.2. Componente JTable.......................................................................................................533.11.3. Componente JRadioButton...........................................................................................55

3.12. Trabalhando com seleções....................................................................................................564 SEGUNDA APLICAÇÃO: GERENCIADOR DE TAREFAS......................................................58

4.1. Criação do model....................................................................................................................594.2. Interfaces dos presenters.........................................................................................................604.3. Implementação do presenter da janela principal.....................................................................614.4. Implementação do presenter da janela de manutenção...........................................................644.5. Criação dos commands...........................................................................................................654.6. Criação das views...................................................................................................................67

4.6.1. Criação da view principal...............................................................................................674.6.2. Criação da view de manutenção......................................................................................69

4.7. Configuração da camada intermediária..................................................................................704.7.1. Utilizando o Spring.........................................................................................................704.7.2. Utilizando o Pico.............................................................................................................72

4.8. Iniciando a aplicação..............................................................................................................745 CONSIDERAÇÕES FINAIS..........................................................................................................756 TRABALHOS FUTUROS..............................................................................................................767 REFERÊNCIAS BIBLIOGRÁFICAS............................................................................................77

Page 9: tcc - surf

8

1 INTRODUÇÃO

1.1. Nome do framework

Surf Framework, ou apenas Surf.

1.2. Descrição do problema

O modelo de programação Model-View-Presenter (MVP), pode ser considerado como uma derivação do modelo Model-View-Controller (MVC), que surgiu com o Smalltalk1. No Smalltalk, os componentes visuais, como as caixas de texto e botões, são regidos por três abstrações centrais: Model, View e Controller.

• Model: São informações que indicam o estado do componente, como, por exemplo, o texto de um campo de texto ou a indicação de que um ckeckbox está marcado ou desmarcado;

• View: Acessa os dados do Model e especifica como os seus dados são exibidos ao usuário;

• Controller: Componente cuja responsabilidade é mapear as ações do usuário na View, as quais ocorrem através de eventos, e modificar o Model de acordo com o evento disparado. Para citar um exemplo, quando um o usuário modifica o conteúdo de um campo de texto, o Controller intercepta o evento de pressionamento de teclas disparado na View, alterando o Model com o novo valor.

Abaixo segue a representação visual da interação entre os três componentes explicados:

1 O Smalltalk foi uma das primeiras linguagens Orientadas a Objetos que surgiram e o Model-View-Controller (MVC) foi um framework de criação de interfaces com o usuário desenvolvido para Smalltalk.

Ilustração 1: Modelo MVC

Page 10: tcc - surf

9

Conforme mostrado na ilustração 1, essa separação permite que os desenvolvedores possam efetuar modificações em um componente sem que as mudanças tenham influência negativa em outros componentes. Por exemplo: pode-se alterar a visualização de um componente, permitindo que este seja desenhado de uma forma diferente na tela, sem que isso acarrete em mudanças no Model.

1.2.1. Limitações do MVC

O padrão MVC funciona muito bem no contexto de componentes individuais, como explicado anteriormente. Porém, durante o desenvolvimento de qualquer aplicação, torna-se necessário agrupar vários desses componentes sob contextos específicos que, juntos, representam o domínio do problema a ser solucionado pelo sistema.

Para ilustrar melhor essa situação, vamos tomar como exemplo um formulário que sirva para cadastrar clientes. A View é o formulário, cuja responsabilidade é agrupar os componentes visuais que representam os dados do cliente e fornecer um meio para que o usuário interaja com o sistema. O Model são os objetos Cliente, cuja responsabilidade é armazenar os dados de um cliente e prover a funcionalidade necessária para que sejam satisfeitos os requisitos da aplicação. O Controller, por sua vez, é responsável por observar a interação do usuário com o formulário (View) e traduzir essa interação em eventos, que servem para controlar o fluxo da aplicação e modificar o estado dos controles da janela, atualizando também os objetos de negócio (Model).

Em um contexto mais abrangente, como mostrado no parágrafo anterior, o padrão MVC perde sua grande vantagem, que é permitir que os seus componentes possam ser modificados sem que haja impacto em outro, principalmente quando os componentes em questão são a View e o Model. Como pode ser visto na ilustração 1, a View se comunica diretamente com o Model, através de notificações, onde o primeiro se atualiza com base na informação armazenada pelo segundo. Pensando no padrão MVC em termos de implementação, para que o Model consiga notificar a View de que seu estado foi modificado, o Model deve conter código para isso, sendo, normalmente, uma variante do padrão Subject/Observer2.

Podemos concluir então que, ao aplicar o padrão MVC, temos informações pertinentes à lógica de exibição dos dados codificadas diretamente no Model, ou seja, o Model deve conter código responsável por notificar a View assim que o seu estado é modificado pelo Controller. A ausência de um limite bem definido entre os componentes faz com que determinadas funções e responsabilidades sejam inseridas nos lugares errados, tornando o código mais difícil de reaproveitar, testar e modificar.

Apenas para concluir o raciocínio, pode-se dizer que não é desejável que a classe Cliente, do exemplo anterior, implemente alguma interface ou estenda alguma classe que não seja relacionada ao negócio que ela se propõe a resolver. Além disso, o Model não deve saber quando ou como as informações devem ser repassadas para a View.

2 O padrão Subject/Observer define a dependência um-para-muitos entre objetos para que quando um objeto mude de estado, todos os seus dependentes sejam avisados e atualizados automaticamente. [GAMMA, 2000]

Page 11: tcc - surf

10

1.2.2. Origem do MVP

O Model-View-Presenter (MVP), surge a partir dessa necessidade de se conseguir uma melhor independência entre os componentes, principalmente entre a View e o Model.

As mudanças são de caráter conceitual, já que, estruturalmente, o MVC é muito parecido com o MVP. O Model e a View são iguais nos dois padrões, e o Controller do MVC é equivalente ao Presenter do MVP. A mudança pode ser vista na forma com que os componentes interagem entre si:

Como mostra a ilustração 2, no padrão MVP, o Model não interage com a View, enquanto que, no padrão MVC, o Model é responsável por notificar a View quando seu conteúdo é modificado. No MVP, a View também não conhece qualquer informação pertinente ao Model, enquanto que, no padrão MVC, a View é obrigada a conhecer o Model para que ela consiga se atualizar com os dados contidos no Model. No MVP, essas tarefas são desempenhadas pelo Presenter.

A lógica de apresentação é codificada dentro do Presenter, que observa a interação do usuário na View. A View, por não conhecer detalhes do Model, também não precisa mais conter nenhum código que sirva para se atualizar de acordo com os dados contidos no Model. A View então acaba se tornando um simples contêiner de componentes visuais sem nenhuma lógica, tornando possível a modificação da View – ou até mesmo a sua substituição – sem impactos negativos em nenhum código escrito anteriormente.

O Model será então responsável por implementar código relacionado ao negócio a ser modelado, eliminando a necessidade de incluir qualquer código ou dependência relacionada à componentes externos, como, no caso do MVC, a tarefa de notificação à View quando seu estado é modificado.

1.3. Objetivos do Surf Framework

O objetivo do Surf Framework é utilizar os conceitos relacionados ao padrão Model-

Ilustração 2: Diferença entre o padrão MVC e o padrão MVP

Page 12: tcc - surf

11

View-Presenter (MVP) e implementa-los, de modo a prover uma ferramenta que facilite o desenvolvimento de aplicações JavaTM com Swing, através da definição de uma arquitetura modular e de fácil manutenção.

1.4. Procedimentos de instalação

1.4.1. Requisitos básicos

1.4.1.1. Requisitos de hardware3

● Multi-plataforma (Windows 98 2nd Edition ou superior, Linux, Unix, Solaris);● 128mb RAM;

1.4.1.2. Requisitos de software

● JavaTM Standard Edition SDK [7], versão 1.5.0;● Biblioteca Apache Commons-Logging [8];

1.4.2. Procedimento para instalação

Primeiramente é necessário baixar o Surf Framework através do site do projeto [4]. A versão disponível no momento da entrega deste trabalho é a 0.1 beta, sendo então esta a versão abordada neste documento.

Uma vez baixados os arquivos do servidor, os arquivos JAR contidos nos diretórios lib e dist devem ser copiados para um diretório que possam ser referenciados pela aplicação a ser desenvolvida. Caso o desenvolvedor esteja utilizando alguma IDE4 para desenvolver a aplicação, será necessário adicionar os arquivos descompactados no CLASSPATH do projeto através de algum assistente fornecido pela própria ferramenta.

O Surf Framework, na versão 0.1 beta, têm como dependência obrigatória apenas o arquivo commons-logging.jar. Caso seja necessário utilizar o Surf Framework com algum framework de injeção de dependências – como o Spring [11] ou o Pico [12] – copie também o arquivo surf-ioc.jar.

Leia, no tópico abaixo, como configurar o Surf Framework em duas das principais IDEs JavaTM: Eclipse [9] e NetBeans [10].

1.4.3. Procedimento para configuração

3 Os requisitos do JavaTM se aplicam ao Surf Framework.4 IDE é a abreviação de Integrated Development Environment, ou Ambiente de Desenvolvimento Integrado.

Os melhores exemplos de IDEs para JavaTM são o Eclipse e o NetBeans.

Page 13: tcc - surf

12

1.4.3.1. Eclipse 3.2

Depois de criar o projeto, selecione-o no package explorer e pressione ALT+ENTER. Na janela que aparecer, selecione a opção Java Build Path e utilize os botões Add JARs... ou Add External JARs... para referenciar os JARs do Surf Framework. Para finalizar, pressione OK.

1.4.3.2. NetBeans 5.5

Depois de criar o projeto, clique com o botão direito sobre ele e selecione a opção Properties. Na janela que aparecer, selecione a opção Libraries e utilize o botão Add JAR/Folder para referenciar os JARs do Surf Framework. Para finalizar, pressione OK.

1.4.4. Aplicativo de demonstração

Dentro do arquivo do Surf Framework, existe também uma aplicação de exemplo, onde podemos ver mais detalhadamente o framework em funcionamento. A aplicação foi desenvolvida no NetBeans 5.5 beta 2. Portanto, basta utilizar a opção Open... do NetBeans que, automaticamente, o diretório da aplicação será reconhecido como um projeto do NetBeans. Tal aplicação é explicada, em detalhes, no último ítem deste documento.

Para executar a aplicação fora do NetBeans, basta rodar o arquivo run.sh (Linux) ou run.bat (Windows), situados no diretório raiz da aplicação.

Page 14: tcc - surf

13

2 DESCRIÇÃO DO FUNCIONAMENTO

2.1. Arquitetura do framework

O Surf Framework está organizado de acordo com a seguinte ilustração:

Abaixo, serão explicados cada um dos elementos dispostos na ilustração 3.

2.1.1. Models e View

Pode-se perceber na ilustração 3 que os componentes Models e View estão desacoplados do framework. Isso significa que, para poder utilizar o Surf Framework, não é necessário fazer o com que suas Views e Models implementem interfaces ou estendam classes do framework. Dessa forma, pode-se reaproveitar parte de um Model criado em outro projeto sem nenhuma alteração. Isso também permite a utilização de ferramentas para design de interfaces com o usuário sem que seja necessária nenhuma customização na ferramenta, já que o Surf se integra com os componentes já implementados pelo Swing.

Outra grande vantagem é que, caso seja necessário deixar de utilizar o Surf Framework, as Views e Models do sistema não precisam sofrer nenhum processo de restauração ou manutenção, pois a utilização do Surf Framework não implica em nenhuma alteração do código JavaTM desses componentes.

2.1.2. Swing

O Surf Framework foi desenvolvido sobre o Swing pelo simples fato de que esta é a toolkit5 de criação de interfaces com o usuário mais utilizada no mundo. Além disso, existe muito material de referência e amplo suporte pelas IDEs atuais, tornando a utilização do Swing mais intuitiva.

5 Toolkit é uma biblioteca ou framework que fornece um conjunto de elementos básicos para a construção de interfaces com o usuário.

Ilustração 3: Organização arquitetural do Surf Framework

Page 15: tcc - surf

14

2.1.3. Configurações do Surf

O módulo de configurações do Surf Framework é responsável por armazenar as configurações de base para que o framework possa funcionar adequadamente. As configurações contidas dentro deste componente são detalhadas abaixo.

2.1.3.1. Adaptadores de componentes

O framework consegue interagir com os componentes Swing através de classes denominadas adaptadoras, cujo papel é unificar as diferentes interfaces (assinaturas de métodos) disponíveis nos componentes Swing sob uma interface única, permitindo que o framework trabalhe com esses componentes. Caso o desenvolvedor possua um componente customizado, ele deverá implementar um adaptador para este componente e adicioná-lo nas configurações do framework. Assim, o desenvolvedor poder usufruir do recurso de data binding automático em um componente customizado. O recurso de data binding será detalhado posteriormente neste documento.

2.1.3.2. Conversores

Para que possamos atribuir valores a componentes e objetos de negócio de uma maneira flexível e prática para o desenvolvedor, o framework possui a capacidade de converter objetos automaticamente caso o desenvolvedor precise ligar dois objetos de tipos diferentes. O framework já implementa conversores para todos os tipos primitivos e para os tipos Date, Calendar e Enum. Caso seja necessário um procedimento customizado para conversão de dados, pode-se criar conversores de acordo com a necessidade e permitir que outros tipos de dados possam ser gerenciados automaticamente pelo framework.

2.1.3.3. Formatadores

O framework permite que o desenvolvedor escolha a forma que os dados devem ser apresentados na View. Podemos, por exemplo, exibir um valor booleano na View de diferentes maneiras. Podemos também criar formatadores ou utilizar os formatadores existentes na API JavaTM (como a classe SimpleDateFormat, utilizada para formatar datas).

2.1.4. Configurações do Presenter

Uma vez que o módulo de configuração já monta o ambiente básico de funcionamento do framework, devemos então mapear as classes, informando, para cada tríade MVP, qual classe é o Presenter, qual classe é a View e quais atributos do Presenter são os Models.

2.1.5. Binding

Page 16: tcc - surf

15

Em determinados momentos durante a interação do usuário com o aplicativo, torna-se necessário capturar as informações que estão sendo fornecidas na View da aplicação de modo a realizar a tarefa que o usuário deseja. Então, para tornar mais simples o transporte de informações entre a View e o Model, o Surf Framework implementa um sistema bem simples de data binding6.

Com o sistema de data binding, pode-se ligar componentes de uma View a propriedades de algum Model do sistema, sem que haja nenhuma dependência entre eles no código. Assim, quando o desenvolvedor quiser transportar as informações digitadas em uma View para o Model (ou vice-versa), basta utilizar métodos já implementado pelo Surf Framework.

Para facilitar ainda mais a vida do desenvolvedor, o Surf Framework permite que componentes da View sejam ligados a propriedades do Model cujos tipos são incompatíveis. Para citar um exemplo, o desenvolvedor pode querer mostrar a idade de um cliente (objeto Short) em um componente JTextField (que serve para entrada de texto). Caso o Surf Framework perceba que as propriedades que estão sendo ligadas sejam incompatíveis - como o objetos String e Short mostrados no exemplo - os dados são automaticamente convertidos.

Isso facilita bastante a vida do desenvolvedor pois, em um dado momento ele pode simplesmente trocar o JTextField por um JSpinner para exibir a idade do cliente, sem que ele precise modificar código nenhum.

2.1.6. Commands

Através dos Commands é que podemos fazer com que a aplicação responda aos comandos do usuário. A razão da existência dos Commands é tratar uma deficiência dos Listeners7, do Swing.

A deficiência referida no parágrafo anterior basicamente se resume na seguinte sentença: Os Listeners do Swing são, por natureza, classes de difícil reúso.

Para citar apenas um exemplo que demonstra tal afirmação, vamos supor que nossa aplicação possua uma classe que implementa a interface ActionListener, cujo código é a implementação necessária para persistir um objeto Cliente no banco de dados. Então, podemos utilizar tal classe em um componente JButton para que, quando este for clicado, o objeto Cliente seja persistido no banco de dados. Mas, vamos supor também que, devido a uma mudança nos requisitos, o objeto Cliente não deve mais ser persistido quando um componente é acionado, e sim, quando o usuário fecha a janela de cadastro. Como um objeto do tipo ActionListener não pode ser utilizado para executar um evento de janela (que trabalha apenas com objetos do tipo WindowListener), então um novo objeto que implementa WindowListener deve ser criado com a lógica de persistência para que este

6 Habilidade de se conectar dois objetos de modo que se possa atribuir uma informação a ambos os objetos de forma homogênea.

7 Os Listeners, ou Ouvintes, são classes que possuem métodos de callback que são executados em pontos bem definidos durante a interação do usuário com a aplicação, como, por exemplo, ao acionar um botão ou fechar um formulário.

Page 17: tcc - surf

16

possa ser executado quando o formulário for fechado.

Além dos Commands propriamente ditos, este módulo também engloba os componentes responsáveis por instalar os Commands nos componentes visuais, que são os CommandAppliers. A função dessas classes é simples: converter um Command em um Listener Swing e instalá-lo no componente. Para citar um exemplo, imagine que desejamos executar o Command FecharJanelaCommand quando o usuário clicar em um JButton. O CommandApplier converte o Command FecharJanelaCommand em um objeto que implementa a interface ActionListener e o instala no JButton (através de uma chamada ao método addActionListener()), fazendo com que este, ao receber um clique, dispare a execução do código implementado no Command FecharJanelaCommand. Todas essas operações são transparentes para o desenvolvedor, sendo tratadas automaticamente pelo Surf Framework.

Podemos também fazer com que vários Commands sejam executados quando um determinado evento é disparado. Isso possibilita que o desenvolvedor divida um código mais complexo em pequenas partes que podem ser combinadas de diferentes formas, diminuindo o índice de duplicação de código.

2.1.7. Presenter

O Presenter é a peça chave do padrão MVP e é através do Presenter que o desenvolvedor consegue usufruir de muitos dos recursos que estão sendo descritos neste documento. Basicamente, o Presenter possui uma referência ao objeto do formulário (View), objetos de negócio (Model) e métodos que representam a lógica de apresentação. Os objetos e informações necessárias para o funcionamento dos Commands e do data dinding, por exemplo, já estão implementadas e o desenvolvedor não precisa se preocupar em como o framework trabalha internamente para conseguir utilizá-lo.

Basicamente, um Presenter é uma classe que implementa a interface Presenter ou estende uma de suas subclasses. Por exemplo, para criar um Presenter capaz de interagir com Views Swing, o Presenter deverá estender a classe SwingPresenter, que já possui implementado todo o comportamento necessário.

2.2. Desenvolvendo a primeira aplicação

Para tornar mais fácil de entender o funcionamento do framework, a primeira aplicação é bem simples, no estilo “Hello World”, onde temos um formulário que permite que o usuário entre com os dados de uma pessoa:

Page 18: tcc - surf

17

Os componentes utilizados para a confecção desta View foram: três JLabel, dois JTextField, um JSpinner e dois JButton.

A aplicação funciona da seguinte forma: depois de preencher os dados da pessoa, o usuário deve pressionar o botão “Set” para que os dados digitados no formulário sejam transferidos para um objeto Person, cujo modelo é mostrado abaixo:

Então, para mostrar que as informações foram transferidas, a seguinte mensagem é exibida ao usuário:

Caso o usuário deseje transferir as informações do Model para a View, basta que ele limpe os campos e pressione o botão “Get”. Ao pressionar o botão, as informações do Model são atualizadas na View:

Ilustração 4: View da aplicação

Ilustração 5: Model da aplicação

Ilustração 6: Mensagem de confirmação

Page 19: tcc - surf

18

Abaixo, o procedimento para criação da aplicação é detalhado.

2.2.1. Construindo a aplicação

2.2.1.1. Criando o model

Primeiramente, o Model da aplicação deve ser criado:

public class Person { private String fullname; private String email; private int age; public String getFullname() { return fullname; } public void setFullname(String fullname) { this.fullname = fullname; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }

Ilustração 7: Obtendo os dados do Model

Page 20: tcc - surf

19

public String toString() { return "full name: " + fullname + ", age: " + age + ", email: " + email; }}

Note que este é um objeto que nos permite apenas armazenar e manipular as informações referentes a uma pessoa. Este objeto também não possui nenhuma dependência em relação ao Surf.

2.2.1.2. Criando a view

Depois de criado o Model, a View deve ser construída, de forma manual ou utilizando qualquer ferramenta de desenho de interfaces Swing. Para que o Surf consiga acessar os componentes da View, devemos criar métodos get para cada um dos componentes:

public class PersonFrame extends JFrame {

// ...

@Bind public javax.swing.JSpinner getAge() { return age; } @Bind public javax.swing.JTextField getEmail() { return email; } @Bind public javax.swing.JTextField getFullname() { return fullname; } @Interaction public javax.swing.JButton getSendToModel() { // Botão “Set” return sendToModel; } @Interaction public javax.swing.JButton getSendToView() { // Botão “Get” return sendToView; }

// ...}

Listagem 1: Código da View

Page 21: tcc - surf

20

Como pode ser visto na listagem 1, além dos métodos get existem anotações8 nestes métodos.

Para habilitar a passagem de dados entre a View e o Model, os métodos getFullname(), getAge() e getEmail() estão anotados com @Bind. Já os métodos getSendToModel() e getSendToView() estão anotados com @Interaction, que servem para adicionar um evento nos botões “Set” e “Get”, respectivamente. Estes eventos então executarão, no Presenter, os métodos sendToModel() e sendToView().

2.2.1.3. Criando o presenter

O código do Presenter da aplicação é listado abaixo:

@Presenter("personPresenter")@View(PersonFrame.class)public class PersonPresenter extends SwingPresenter { private Person person; public void sendToModel() { getDataTransferer().updateModel(); JOptionPane.showMessageDialog(null, person); } public void sendToView() { getDataTransferer().updateView(); } @Model public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; }}

Listagem 2: Presenter da aplicação

Todo Presenter que manipula Views Swing deve estender a classe SwingPresenter. Além disso, o Presenter deve ser configurado com as anotações @Presenter e @View, que indicam, respectivamente, o nome que identifica o Presenter e a classe que será utilizada como View, sendo que esta deve estender de JDialog ou JFrame.

Para que o desenvolvedor possa receber e passar dados para a View, o Presenter deve

8 Anotações, ou annotations é a implementação de uma especificação de definição de meta-dados, incluído na versão 5.0 (Tiger) do JavaTM.

Page 22: tcc - surf

21

ter atributos cujos métodos get são identificados com a anotação @Model. Nesta aplicação o Model é o atributo person, portanto o método getPerson() deve ser anotado com @Model.

Note que existem dois métodos, sendToModel() e sendToView(), que serão chamados pelo Surf quando os botões “Set” e “Get”, presentes na View forem acionados pelo usuário. O método sendToModel() utiliza a instrução getDataTransferer().updateModel() para que os dados digitados na View sejam transferidos para o Model. De forma semelhante, o método sendToView() utiliza a instrução getDataTransferer().updateView() para que os dados do Model sejam transferidos para a View.

2.2.1.4. Criando a classe principal

A aplicação está praticamente pronta, faltando apenas criar a classe que mostra o formulário para que o usuário possa interagir com o mesmo:

public class Main { public Main() { SurfConfig config = new SwingSurfConfig();

config.addPresenterMapping(new AnnotationPresenterConfigFactory(config) .getMapping(PersonPresenter.class));

new SwingPresenterFactory(config) .createPresenter("personPresenter").showView(true); } public static void main(String[] args) { new Main(); }}

Listagem 3: Classe principal da aplicação

O objeto config é o objeto responsável por armazenar todas as configurações do framework. A classe SwingSurfConfig foi utilizada pois estamos trabalhando com uma aplicação Swing.

Depois de criado o objeto config, obtemos o objeto de mapeamento do Presenter através do uso de um objeto da classe AnnotationPresenterConfigFactory, cuja responsabilidade é ler as anotações das classes e gerar tais objetos de mapeamento.

Finalmente, para que possamos criar o objeto Presenter, precisamos utilizar o método createPresenter() da classe SwingPresenterFactory. O método createPresenter() recebe uma String como parâmetro, que indica qual é o Presenter que deve ser criado. Note que este parâmetro deve ser igual ao valor definido na anotação @Presenter. Finalmente a

Page 23: tcc - surf

22

View do Presenter criado é exibida para o usuário através do método showView().

A aplicação está finalizada e pronta para ser executada. Os conceitos e códigos mostrados nesta aplicação serão reforçados nas próximas páginas, que mostram com detalhes todos os recursos fornecidos pelo Surf Framework.

Page 24: tcc - surf

23

3 CONHECENDO O SURF FRAMEWORK

3.1. Configurando o Surf

Atualmente, podemos fazer a configuração do Surf de três maneiras distintas: manualmente, utilizando o framework Spring ou utilizando o framework Pico. Todas as possibilidades são detalhadas a seguir.

3.1.1. Configuração manual

Quando se deseja fazer a configuração manualmente, o código para tal geralmente é inserido dentro do método main() da aplicação, podendo ser também colocado em um método estático.

O código necessário para configurar o Surf manualmente é parecido com o trecho que segue:

1: SurfConfig config = new SwingSurfConfig();2: 3: PresenterConfigFactory configFactory = new AnnotationPresenterConfigFactory(config);4: PresenterFactory presenterFactory = new SwingPresenterFactory(config);5: 6: config.addPresenterMapping( configFactory.getMapping(MainPresenterImpl.class));7: 8: Presenter p = presenterFactory.createPresenter("MainPresenter");9: p.showView(true);

Listagem 4: Configuração manual

Na linha 1, instanciamos um objeto SwingSurfConfig. Este objeto contém todas as configurações necessárias para que o Surf consiga trabalhar com o Swing.

Na linha 3, definimos qual é a classe responsável por obter os dados de configuração, que, no caso, é o AnnotationPresenterConfigFactory, cuja função é interpretar anotações no código JavaTM e convertê-las em objetos apropriados.

Na linha 4, instanciamos um objeto do tipo SwingPresenterFactory, cuja função é criar Presenters que utilizam um formulário Swing como View (JFrame ou JDialog).

Na linha 6, as anotações da classe MainPresenter são lidas e os dados obtidos nesse processo são utilizados para registrar tal classe na lista de Presenters da aplicação. Isso é necessário para que possamos criar um Presenter, onde cada Presenter é associado a um nome exclusivo. Caso o desenvolvedor tente registrar um Presenter cujo nome já está em uso, uma exceção é disparada quando a aplicação for executada.

Em relação ao ciclo de vida dos objetos criados na listagem 4, geralmente existirá

Page 25: tcc - surf

24

apenas um objeto da classe SwingSurfConfig para toda a aplicação, onde todos os Presenters são registrados. O mesmo acontece com o objeto da classe SwingPresenterFactory, sendo que este é o que efetivamente será utilizado para criar instâncias dos Presenters da aplicação. De modo a manter tais objetos acessíveis, é recomendado a criação de uma classe singleton9 para facilitar o acesso ao objeto SwingPresenterFactory acessível.

Uma vez que o Surf tenha sido devidamente configurado e os Presenters da aplicação tenham sido registrados, podemos então criar instâncias dos Presenters através do objeto presenterFactory e torná-los visíveis para que o usuário possa interagir com os mesmos. A instrução da linha 8 serve para obter um Presenter registrado sob o nome “MainPresenter”. Então, depois de obtido o Presenter, o exibimos sua View para o usuário através do método showView().

Para saber quais são os outros métodos fornecidos na interface Presenter, utilize a documentação Javadoc [13].

3.1.2. Configuração via Spring

O framework Spring é um framework de Injeção de Dependências10 para JavaTM que é configurado através de um arquivo XML, denominado arquivo de contexto. É neste arquivo que declaramos os Presenters da aplicação e outras dependências, como DAOs11, objetos de conexão com banco de dados, entre outros. Então, podemos configurar tais dependências de modo que, quando um objeto for obtido através do Spring, todas as dependências desse objeto já estejam configuradas, sem que seja preciso fazer tal configuração no meio do código (hardcoded), diminuindo a dependência direta entre as classes, tornando-as mais fáceis de reusar e testar.

Um exemplo de arquivo de configuração pode ser visto a seguir:

9 A intenção do padrão Singleton é garantir que uma classe tenha somente uma instância e fornecer um ponto global de acesso para a mesma. [GAMMA, 2000]

10 O padrão Injeção de Dependências é um princípio da Orientação a Objetos que inverte a forma com que um objeto obtém suas dependências, sendo estas externalizadas em outro componente centralizado, de fácil modificação, de forma que tal objeto não precise satisfazer suas dependências através de instruções ad hoc.

11 DAO significa Data Access Object e é um padrão de projeto cuja função é isolar o código que manipula diretamente o banco de dados do restante do código da aplicação, permitindo que o desenvolvedor utilize diferentes bancos de dados apenas substituindo os objetos DAO.

Page 26: tcc - surf

25

<!-- Presenters --><bean id="mainPresenter" class="surfdemo.presenter.MainPresenterImpl" />

<bean id="aboutPresenter" class="surfdemo.presenter.AboutPresenterImpl"> <property name="parentPresenter" ref="mainPresenter" /></bean>

<!-- Configura os Presenters --><bean id="presenterSetup" class="br.com.surf.integration.spring.SwingSpringPresenterSetup">

<!-- Configuração dos Presenters baseada em anotações --> <property name="configFactory" value="br.com.surf.annotation.parser.AnnotationPresenterConfigFactory" />

<!-- Lista de Presenters que devem ser configurados --> <property name="presenterList"> <list> <ref bean="mainPresenter" /> <ref bean="aboutPresenter" /> </list> </property></bean>

Listagem 5: Arquivo XML de configuração do Spring

Os dois primeiros elementos <bean> declaram dois Presenters da aplicação. No segundo elemento <bean>, declaramos uma dependência para com o primeiro Presenter. Então, se solicitarmos o bean “aboutPresenter” ao Spring, ele automaticamente irá instanciar o bean “mainPresenter” e irá passá-lo ao bean “aboutPresenter” através do método setParentPresenter(). Vale lembrar que o Spring é capaz de trabalhar com qualquer classe que siga a especificação JavaBeans12.

O bean presenterSetup é uma classe de integração fornecida pelo Surf para que o framework possa interceptar mudanças no ciclo de vida dos beans declarados no arquivo de configuração e, quando os Presenters forem criados pelo Spring, fazer a configuração desses Presenters.

Uma vez definido o arquivo de configurações, precisamos instanciar uma classe do Spring chamada BeanFactory, cuja responsabilidade é ler o arquivo XML e fornecer instâncias das classes declaradas neste arquivo. Ainda considerando o arquivo XML mostrado a pouco, o seguinte trecho de código pode ser utilizado para obter uma instância do objeto “mainPresenter”:

12 JavaBeans é uma especificação que define algumas diretrizes de codificação de classes de modo que tais classes possam ser manipuladas e instanciadas em tempo de execução, através da API Reflection.

Page 27: tcc - surf

26

1: BeanFactory beanFactory = new ClassPathXmlApplicationContext("ApplicationContext.xml");2: MainPresenter presenter = (MainPresenter)beanFactory.getBean(“mainPresenter”);

Listagem 6: Utilização do BeanFactory do Spring

Mais detalhes sobre o Spring não fazem parte do escopo deste documento, podendo ser obtidos na página do projeto.

3.1.3. Configuração via Pico

O framework Pico é, assim como o Spring, um framework que implementa o padrão Injeção de Dependências. Apesar de ambos servirem para propósitos semelhantes, os frameworks Spring e Pico são estruturados de formas diferentes.

Enquanto o Spring faz uso de um arquivo XML para definição das dependências, o Pico é configurado através de código JavaTM. O Pico é um framework altamente “embarcável”: possui apenas um JAR com aproximadamente 110KB, enquanto que o Spring possui em torno de 1.8MB, tornando então o Pico uma excelente opção quando não se deseja gastar muito espaço com dependências.

Segue o mesmo exemplo de configuração mostrado no tópico anterior adaptado para o Pico:

1: MutablePicoContainer pico = new DefaultPicoContainer();2: 3: /* Necessário para integrar o Surf Framework com o Pico */4: pico.registerComponentImplementation(SwingSurfConfig.class);5: pico.registerComponentImplementation(SwingPresenterFactory.class);6: pico.registerComponentImplementation( AnnotationPresenterConfigFactory.class);7: pico.registerComponentImplementation(PicoPresenterSetup.class);8: 9: /* Presenters da aplicação */10: pico.registerComponentImplementation(MainPresenterImpl.class);11: pico.registerComponentImplementation(AboutPresenterImpl.class);12: 13: pico.start(); // Cria os objetos com o Pico

Listagem 7: Configuração do Framework usando o Pico

Nas linhas 10 e 11, registramos os nossos Presenters.

Nas linhas 4, 5, 6 e 7 são registrados os componentes do Surf Framework que são responsáveis por obter os Presenters e configurá-los.

Depois de executada a linha 13, já podemos utilizar o Pico para obter instâncias dos objetos registrados. Isso pode ser feito da seguinte forma:

Page 28: tcc - surf

27

1: MainPresenter p = (MainPresenter)pico.getComponentInstanceOfType(MainPresenter.class);

Listagem 8: Obtendo referência de um Presenter criado pelo framework Pico

Esse código retorna uma instância da classe MainPresenter com todas suas dependências resolvidas.

Mais detalhes sobre o Pico não fazem parte do escopo deste documento, podendo ser obtidos na página do projeto.

3.2. Nested properties

Para aproveitarem ao máximo os recursos que o Surf oferece, os desenvolvedores precisam se familiarizar com um recurso muito simples e interessante, que ajuda a criar um código mais organizado, reusável e orientado a objetos: Nested Properties.

Traduzindo, 'nested properties' significa algo como 'propriedades aninhadas'. O diagrama que segue ilustra melhor esse conceito:

A classe Pessoa possui um Endereço e um Telefone. Então, na classe Pessoa existem dois atributos, sendo que cada um deles é do tipo Endereço e Telefone. Sendo assim, podemos dizer que o atributo cidade, que está na classe Endereco é um atributo aninhado contido dentro da classe Pessoa, sendo acessível através do atributo endereco.

3.2.1. Referenciando um atributo aninhado

Para referenciar um atributo aninhado no Surf Framework é muito simples. Seguem

Ilustração 8: Nested properties

Page 29: tcc - surf

28

alguns exemplos, ainda relacionados à ilustração 8, mostrada à pouco. Suponha que o “objeto de partida” é o objeto Cliente:

● atributo rua (classe Endereco) = endereco.rua● atributo residencial (classe Telefone) = telefone.residencial

Ou seja, essa é uma forma de indicar qual é o “caminho” do atributo dentro do grafo de objetos. Esse “caminho” são os nomes de propriedades separadas por “.” (ponto).

3.3. Anotações do Surf

Nos tópicos anteriores foram mostrados o que deve ser feito para deixar o framework devidamente configurado para que ele possa gerenciar os componentes da nossa aplicação: Models, Views e Presenters. Então, este tópico irá mostrar como deve ser feito para que tais componentes possam ser integrados.

O Surf implementa uma série de anotações que devem ser utilizadas no código de modo a tornar a configuração dos Presenters, Views e Models o mais simples quanto possível.

3.3.1. Apresentando as anotações

Abaixo estão relacionadas as anotações fornecidas pelo Surf. De modo a facilitar o entendimento, elas estão organizadas em dois grupos: Anotações de View e Anotações de Presenter. Todas essas anotações são utilizadas nos programas de exemplo que acompanham o Surf, sendo estes, portanto, uma fonte de referência quanto à aplicação prática das mesmas.

3.3.1.1. Anotações de view

3.3.1.1.1. @Bind

● Sintaxe: @Bind (String model = “”, String field = “”)● Descrição: Esta anotação é utilizada para ligar uma propriedade de um objeto de

negócio com um componente na View. Por exemplo, podemos relacionar o atributo nome do objeto cliente com um JTextField que está na View.

● Atributos:● model: Indica qual é nome do objeto de negócio situado no Presenter (e anotado

com @Model) que se relaciona com o componente anotado. Esse nome nada mais é que o nome do método get do objeto de negócio anotado com @Model. Se o componente é relacionado com o Model cliente no Presenter, e, no Presenter existe um método getCliente(), então devemos setar model da anotação @Bind com o valor “cliente”.

● field: Informa, dentro do objeto de negócio indicado na propriedade anterior, qual é a propriedade que efetivamente será relacionada com o componente. Por

Page 30: tcc - surf

29

exemplo, se o objeto cliente possui um atributo nome e o desenvolvedor queira ligar este atributo a um JTextField, então o atributo model da anotação deve ser configurado para “cliente” e o atributo field deve ser setado para “nome”. Esta propriedade suporta o uso de nested properties, como mostrado anteriormente.

● Onde ela é usada: Esta anotação é usada nas Views da aplicação. Vamos supor que existe um JFrame que contém um JTextField, como dito anteriormente. Então, precisamos criar um método get para o JTextField e anotar o método get com a anotação @Bind:

public class View extends JFrame {

private JTextField field;

@Bind public JTextField getField() { return field; }}

Listagem 9: Utilizando a anotação @Bind

● Observações: ● Caso o Presenter possua apenas um objeto de negócio, a propriedade model pode

ser ignorada e o Surf detectará automaticamente que há apenas um Model sendo utilizado naquele Presenter.

● A propriedade field também é opcional caso o desenvolvedor opte por programar por convenções. Se o objeto cliente possui um atributo nome e o componente na View também chama nome (método getNome()), então o Surf determina que tal atributo deve ser relacionado com tal componente. Para desabilitar este recurso, basta utilizar as propriedades model e field da anotação para fazer a configuração do Model e seu atributo de acordo com o desejado.

3.3.1.1.2. @Formatter

● Sintaxe: @Formatter (Class<? extends Format> type, String pattern = “”)● Descrição: Esta anotação é utilizada para formatação de valores na View. Podemos

utilizar esta anotação para mostrar datas em formatos específicos, formatar valores booleanos, mensagens de texto, números ou qualquer outra informação.

● Atributos:● type: Este parâmetro recebe um objeto qualquer Class que estende Format.● pattern: Definimos qual será o padrão (ou formato) que deverá ser aplicado ao

valor. Por exemplo, para formatarmos uma data no padrão brasileiro, utilizamos o pattern “dd/MM/yyyy”, instruindo a classe SimpleDateFormat a formatar a data seguindo a forma dia/mes/ano.

● Onde ela é usada: A utilização desta anotação é semelhante ao especificado na anotação @Bind:

Page 31: tcc - surf

30

public class View extends JFrame {

private JTextField dateField;

@Formatter(type=SimpleDateFormat.class, pattern=”dd/MM/yyyy”) public JTextField getDateField() { return dateField; }}

Listagem 10: Utilizando a anotação @Formatter

● Observações: O Surf fornece um único Format: o BooleanFormat. O desenvolvedor pode utilizá-lo para formatar valores do tipo boolean, e deixá-los mais “apresentáveis” para o usuário, substituindo o true e o false por outros valores mais significativos. Outros Formats estão disponíveis no JavaTM SE13, sendo os mais comuns o MessageFormat (para formatar Strings), DecimalFormat (para formatar números) e SimpleDateFormat (para formatar datas).

3.3.1.1.3. @Interaction

● Sintaxe:@Interaction (String name=””,Class<? extends Command>[] command = PresenterMethodCallerCommand,String methodName = “”, String target = “”,EventType event = ACTION, boolean shortCircuiting = true,@Property[] properties = {})

● Descrição: Esta anotação é utilizada para que possamos adicionar eventos aos componentes da View.

● Atributos: ● name: Este atributo só é utilizado caso o desenvolvedor deseje recuperar o objeto

que representa esse evento de dentro de algum Presenter ou Command, de modo a permitir que o código associado ao evento possa ser executado arbitrariamente. Para recuperar o evento no Presenter, por exemplo, o seguinte código pode ser utilizado:

// “refresh” é o valor do atributo name, da anotação @InteractionEventCallback callback = getCallback("refresh");callback.execute(); // Executa o(s) Command(s)

Listagem 11: Executando um evento mapeado com @Interaction

● command: Este atributo recebe um vetor de Class que implementam a interface Command. Os Commands nada mais são do que classes que definem um comportamento que deve ser executado quando o evento em questão é disparado. Caso o desenvolvedor defina mais de um Command, então o Surf irá executar todos os Commands definidos nesta lista, na mesma ordem em que são declarados,

13 JavaTM SE é o mesmo que JavaTM Standard Edition, distribuição básica da plataforma JavaTM.

Page 32: tcc - surf

31

permitindo que o desenvolvedor consiga um bom nível de reusabilidade de código através da combinação de vários Commands. Mais adiante será mostrado como criar os Commands.

● methodName: Existe outra forma de se tratar eventos, sem que seja necessário criar uma classe que estende de Command, como mostrado na descrição do parâmetro command. Trata-se de uma alternativa, ideal para eventos mais simples e que não precisam ser reutilizados em outros lugares na aplicação. Basicamente, em vez disso, o desenvolvedor cria um método no Presenter que será executado quando o evento for disparado. Então, em vez de se definir o atributo command, este é ignorado e configuramos em seu lugar o atributo methodName. Mais adiante será mostrado com detalhes como funciona este recurso.

● target: Este atributo indica em qual propriedade do componente o Listener (no caso do Swing) deverá ser adicionado. Em outras palavras, este atributo indica ao Surf em qual propriedade pertencente ao componente ele deverá chamar o método addXxxListener().

● event: Indica qual é o tipo de evento que irá disparar a execução dos Commands. Pode ser um clique do mouse, o pressionamento de uma tecla e assim por diante. Os comportamentos disponíveis estão relacionados como constantes na interface EventType. Caso este atributo não seja configurado explicitamente pelo desenvolvedor, o Surf considera então que o evento que irá disparar a execução dos Commands é o evento de ação.

● shortCircuiting: Este atributo serve para informar o que o Surf deve fazer caso um dos Commands retorne um código de falha (algo diferente de CONTINUE). Se um dos Commands não retornar CONTINUE e o este parâmetro for definido como true, então o restante dos Commands não serão executados. Se este parâmetro for definido como false, então os Commands restantes serão executados, independentemente de algum Command ter falhado.

● properties: Podemos passar valores para os Commands através deste atributo, sendo estes acessíveis de dentro dos Commands através do método getParameters(). Mais detalhes podem ser vistos na descrição da anotação @Property.

● copyFrom: O desenvolvedor pode reutilizar a configuração da anotação @Interaction de outro componente, tornando mais simples a declaração de eventos semelhantes. Por exemplo:

public class View extends JFrame {

@Interaction(methodName=”editCategory”) public JButton getEditCategoryButton() { return editCategoryButton; }

@Interaction(copyFrom=”editCategoryItem”) public JMenuItem getEditCategoryItem() { return editCategoryItem; }}

Listagem 12: Reutilizando configuração através do atributo copyFrom

Page 33: tcc - surf

32

Especificamente sobre a anotação em destaque na listagem 12, note a utilização do atributo copyFrom para copiar as configurações de interação de outro componente da View. Podemos também fazer a reutilização parcial das configurações de interação de outro componente e, através dos outros atributos da anotação @Interaction, indicar valores para os atributos que devem possuir um valor diferente:

public class View extends JFrame {

@Interaction(methodName=”editCategory”) public JButton getEditCategoryButton() { return editCategoryButton; }

@Interaction(copyFrom=”editCategoryItem”, event=EventType.MOUSE_ENTERED) public JMenuItem getEditCategoryItem() { return editCategoryItem; }}

Listagem 13: Reutilização parcial dos parâmetros de interação

A anotação em destaque na listagem 13 reutiliza os dados informados na anotação @Interaction do component editCategoryButton, mas modifica o evento no qual o método editCategory() é disparado.

● Onde ela é usada: A utilização desta anotação é semelhante ao especificado na anotação @Bind:

public class View extends JFrame {

private JButton button;

@Interaction(command=CloseWindowCommand.class) public JTextField getButton() { return button; }}

Listagem 14: Command que fecha a janela ao clicar no botão

● Observações: Apesar de parecer complexa, esta anotação é bastante simples pois seus valores padrão são suficientes para resolver a maioria das situações.

3.3.1.1.4. @InteractionList

● Sintaxe: @InteractionList (@Interaction[] value)

Page 34: tcc - surf

33

● Descrição: A anotação @Interaction é utilizada com a finalidade de se configurar um código para execução assim que um determinado evento for disparado pelo usuário. Então, para que possamos configurar vários eventos em um mesmo componente da View, utilizamos a anotação @InteractionList onde, dentro dela, definimos várias anotações @Interaction, sendo que estas são as que, efetivamente, representam os dados da interação.

● Atributos:● value: Este atributo nada mais é do que uma lista de anotações @Interaction, que

são definidas conforme explicado no item anterior.● Onde ela é usada: Abaixo segue um exemplo de uso desta anotação:

public class View extends JFrame {

private JButton button;

@InteractionList({ @Interaction(command=CloseWindowCommand.class), @Interaction(command=AnotherCommand.class, event=EventType.MOUSE_ENTERED) }) public JTextField getButton() { return button; }}

Listagem 15: Adicionando Commands em mais de um tipo de evento

● Observações: Nenhuma.

3.3.1.1.5. @Property

● Sintaxe: @Property (String name, String value)● Descrição: Esta é uma anotação de propósito geral, utilizada quando se deseja passar

valores para uma determinada anotação.● Atributos:

● name: Qual deve ser o nome da propriedade. Deve se ter cuidado ao definir o nome, pois ele deve ser único no contexto ao qual está inserido, de modo a identificar a propriedade;

● value: Valor que deve ser passado.● Onde ela é usada: Essa anotação é usada atualmente como um atributo da anotação

@Interaction, podendo ser reaproveitada futuramente para outros propósitos. Abaixo, um trecho de código que mostra a anotação em uso:

Page 35: tcc - surf

34

public class View extends JFrame {

private JButton button;

@Interaction( command=CloseWindowCommand.class, properties={ @Property(name=”propName”, value=”propValue”), @Property(name=”propName2”, value=”propValue2”) } ) public JTextField getButton() { return button; }}

Listagem 16: Usando a anotação @Property

Então, as propriedades “propName” e “propName2” pode ser recuperada de dentro do Command CloseWindowCommand:

public class CloseWindowCommand extends AbstractCommand {

public String execute() {

String value1 = (String) getParameters().get(“propName”); String value2 = (String) getParameters().get(“propName2”);

/* Faz alguma coisa com o valor aqui... */

return CONTINUE; }}

Listagem 17: Recuperando uma propriedade informada na anotação @Interaction

Se existirem vários Commands registrados para tratar um determinado evento, e esse evento setar uma propriedade conforme mostrado nas listagens anteriores, então todos os Commands serão capazes de recuperar o valor da propriedade definido na anotação.

● Observações: Nenhuma.

3.3.1.1.6. @SubView

● Sintaxe: @SubView (String model = “”)● Descrição: Um outro recurso muito interessante do Surf é que ele permite que a View

seja composta tanto de componentes simples – como um JTextField – como de componentes compostos – como JPanel. Então, o desenvolvedor pode simplificar o

Page 36: tcc - surf

35

design da View, seccionando-a em painéis, de modo a simplificar a manutenção e tornar tais painéis reutilizáveis em outras Views.

Para criar uma subview, crie uma classe que estenda de JPanel. Esta classe, assim como as outras, não precisa implementar nenhuma interface especial para que esta possa ser utilizada como subview. Depois de criar o painel e adicionar os componentes desejados nele, já podemos utilizá-lo da mesma forma que um componente comum na nossa View:

public class View extends JFrame { private MyPanel myPanel; @Subview(model=”model”) public MyPanel getMyPanel() { return myPanel; }}

class MyPanel extends JPanel { private JTextField field1; private JTextField field2;

@Bind public JTextField getField1() { return field1; }

@Bind public JTextField getField2() { return field2; }}

Listagem 18: Utilização de subviews com @SubView

● Atributos:● model: Devemos indicar qual Model é representado pela subview. Este atributo

funciona de maneira análoga ao atributo model da anotação @Bind.● Onde ela é usada: Ela é utilizada na View, no método get de algum componente que

estende JPanel.● Observações: As regras do parâmetro Model são as mesmas do parâmetro Model da

anotação @Bind. É possível utilizar as anotações @Interaction e @InteractionList em conjunto com a anotação @SubView, tornando possível a definição dos eventos relacionados aos componentes internos ao painel:

Page 37: tcc - surf

36

public class View extends JFrame { private MyPanel myPanel; @Subview @Interaction(target=”button”, command=DoSomethingCommand.class) public MyPanel getMyPanel() { return myPanel; }}

class MyPanel extends JPanel { private JTextField field1; private JTextField field2; private JButton button;

@Bind public JTextField getField1() { return field1; }

@Bind public JTextField getField2() { return field2; }

@Widget public JButton getButton() { return button; }}

Listagem 19: Aplicando Commands a componentes de uma subview

3.3.1.1.7. @Type

● Sintaxe: @Type (Class value)● Descrição: Esta anotação serve para indicar qual é o tipo que um determinado

componente da View representa. Existe, dentro do Surf, uma mapeamento que indica quais são os tipos de dados “padrão” para cada componente Swing. Mas existem componentes que são genéricos o bastante para que o Surf possa atribuir um tipo que funcione na maioria dos casos. Por exemplo, o componente JComboBox, que pode conter objetos do tipo String, Cliente ou Produto. Então, para que o Surf saiba exatamente o tipo de objeto que será armazenado em tal componente, esta anotação é utilizada.

● Atributos:● value: Classe que indica o tipo representado pelo componente anotado.

● Onde ela é usada: Esta anotação é utilizada em conjunto com as anotações @Bind ou @Widget, da seguinte forma:

Page 38: tcc - surf

37

public class View extends JFrame { public JComboBox field;

@Bind @Type(Customer.class) public JComboBox getField() { return field; }}

Listagem 20: Informando o tipo de um componente com a anotação @Type

● Observações: Nenhuma.

3.3.1.1.8. @Widget

● Sintaxe: @Widget ()● Descrição: Quando um componente é anotado com @Bind, o Surf já o reconhece no

contexto de execução da aplicação. Porém, quando temos um componente que não deve ser ligado a nenhum Model (binding), mas deve ser utilizado para um propósito qualquer – como mostrar um valor ou tratar gestos do usuário (através de eventos) – então, este componente pode ser anotado com @Widget.

● Atributos: Nenhum.● Onde ela é usada: É usada de forma semelhante à anotação @Bind.● Observações: A utilização desta anotação pode ser omitida quando um determinado

componente já está anotado com @Bind, @Interaction ou @InteractionList, pois, ao utilizar tais anotações, o Surf já adiciona tal componente nas configurações, permitindo que a aplicação manipule este componente através das classes e métodos fornecidos pelo Surf. A anotação @Widget costuma ser utilizada com mais freqüência em SubViews, para permitir que os componentes internos à SubView possam receber configurações de acordo com a View em que tal SubView é utilizada. Um exemplo sobre como isso é feito pode ser conferido nas listagens relacionadas à anotação @SubView.

3.3.1.2. Anotações de presenter

3.3.1.2.1. @Model

● Sintaxe: @Model ()● Descrição: Esta anotação indica se um determinado atributo do Presenter é um

Model, permitindo que este atributo seja configurado para receber valores dos componentes da View e mandar valores para os componentes da View, de forma semi-automática. Mais detalhes serão explicados no capítulo sobre data binding.

● Atributos: Nenhum.● Onde ela é usada: Dentro da classe Presenter, é necessário declarar atributos que

serão usados como Model. Então, para que o desenvolvedor possa indicar um atributo

Page 39: tcc - surf

38

como sendo um Model, o método get desse atributo deve ser anotado com @Model:

@Presenter(“presenterID”)public class MyPresenter extends SwingPresenter {

private Customer customer;

@Model public Customer getCustomer() { return customer; }

public void setCustomer(Customer customer) { this.customer = customer; }}

Listagem 21: Definindo um atributo do Presenter como Model

● Observações: Todo objeto de negócio que precisa ser utilizado como Model deve possuir um método get e um método set, além da anotação @Model, que deve estar localizada no método get. Um outro ponto importante é que, caso o atributo anotado com @Model não seja inicializado explicitamente pelo desenvolvedor no construtor do Presenter, o Surf cria uma nova instância do objeto (chamando o construtor padrão sem argumentos) e o injeta através do método set correspondente. Caso o atributo anotado seja uma coleção (tipos Collection, List, Map ou Set), então um objeto do tipo apropriado à interface é criado e injetado através do método set:● atributo tipo Collection ou List = injeta uma instância de ArrayList;● atributo tipo Map = injeta uma instância de HashMap;● atributo tipo Set = injeta uma instância de HashSet.

3.3.1.2.2. @OnViewActivate

● Sintaxe: @OnViewActivate()● Descrição: Esta anotação serve para executar um determinado método quando a View

é ativada.● Atributos: Nenhum.● Onde ela é usada: Ela é usada em um método qualquer do Presenter que se deseja

executar quando a View é ativada. O método deve ser público e não receber nenhum parâmetro:

@Presenter(“MyPresenter”) @View (MyView.class)public class MyPresenter extends SwingPresenter {

@OnViewActivate public void doOnActivate() { // Este método será executado quando a View for ativada }}

Page 40: tcc - surf

39

● Observações: Nenhuma.

3.3.1.2.3. @OnViewClose

● Sintaxe: @OnViewClose()● Descrição: Esta anotação serve para executar um determinado método quando a View

tenta ser fechada pelo usuário.● Atributos: Nenhum.● Onde ela é usada: Ela é usada em um método qualquer do Presenter que se deseja

executar quando a View é ativada. O método deve ser público, não receber nenhum parâmetro e pode retornar um boolean, que indica se a View deve ser fechada (true) ou se o fechamento deve ser interrompido (false). No exemplo abaixo, toda vez que o usuário tentar fechar a View, o método doOnClose() será executado:

1: @Presenter("mainPressenter")2: @View(SubscriptionFrame.class)3: public class MainPresenterImpl extends SwingPresenter implements MainPresenter {4:5: @OnViewClose6: public boolean doOnClose() { return askForExit(); }7: }

Listagem 22: Evento de fechamento da View

● Observações: Ao contrário dos Commands, os métodos anotados com @OnViewClose não são executados em uma thread a parte. Portanto, é necessário tomar um certo cuidado para não prejudicar o nível de resposta da aplicação através da execução de métodos demorados.

3.3.1.2.4. @OnViewClosed

● Sintaxe: @OnViewClosed()● Descrição: Esta anotação serve para executar um determinado método quando a View

for fechada pelo usuário.● Atributos: Nenhum.● Onde ela é usada: Ela é usada em um método qualquer do Presenter que se deseja

executar quando a View é fechada pelo usuário. O método anotado deve ser público e não receber nenhum argumento.

● Observações: Nenhuma.

3.3.1.2.5. @OnViewDeactivate

● Sintaxe: @OnViewDeactivate()● Descrição: Esta anotação serve para executar um determinado método quando a View

Page 41: tcc - surf

40

é desativada, ou seja, quando a View em questão não é mais a View ativa.● Atributos: Nenhum.● Onde ela é usada: Ela é usada em um método qualquer do Presenter que se deseja

executar quando a View é desativada. O método anotado deve ser público e não receber nenhum argumento.

● Observações: Nenhuma.

3.3.1.2.6. @OnViewDeiconify

● Sintaxe: @OnViewDeiconify()● Descrição: Esta anotação serve para executar um determinado método quando a View

for restaurada, ou seja, quando o estado da View passa de minimizada para restaurada ou maximizada.

● Atributos: Nenhum.● Onde ela é usada: Ela é usada em um método qualquer do Presenter que se deseja

executar quando a View for restaurada. O método anotado deve ser público e não receber nenhum argumento.

● Observações: Nenhuma.

3.3.1.2.7. @OnViewGainFocus

● Sintaxe: @OnViewGainFocus()● Descrição: Esta anotação serve para executar um determinado método quando a View

ganhar foco.● Atributos: Nenhum.● Onde ela é usada: Ela é usada em um método qualquer do Presenter que se deseja

executar quando a View ganhar foco. O método anotado deve ser público e não receber nenhum argumento.

● Observações: Nenhuma.

3.3.1.2.8. @OnViewIconify

● Sintaxe: @OnViewIconify()● Descrição: Esta anotação serve para executar um determinado método quando a View

for minizada.● Atributos: Nenhum.● Onde ela é usada: Ela é usada em um método qualquer do Presenter que se deseja

executar quando a View for minimizada. O método anotado deve ser público e não receber nenhum argumento.

● Observações: Nenhuma.

3.3.1.2.9. @OnViewLostFocus

● Sintaxe: @OnViewLostFocus()

Page 42: tcc - surf

41

● Descrição: Esta anotação serve para executar um determinado método quando a View perder o foco.

● Atributos: Nenhum.● Onde ela é usada: Ela é usada em um método qualquer do Presenter que se deseja

executar quando a View perder o foco. O método anotado deve ser público e não receber nenhum argumento.

● Observações: Nenhuma.

3.3.1.2.10. @OnViewOpened

● Sintaxe: @OnViewOpened()● Descrição: Esta anotação serve para executar um determinado método quando a View

é exibida pela primeira vez.● Atributos: Nenhum.● Onde ela é usada: Ela é usada em um método qualquer do Presenter que se deseja

executar quando a View exibida pela primeira vez. O método anotado deve ser público e não receber nenhum argumento.

● Observações: Nenhuma.

3.3.1.2.11. @Presenter

● Sintaxe: @Presenter (String value)● Descrição: Esta anotação serve para associar um Presenter a um identificador.● Atributos:

● value: Uma String que serve para identificar o Presenter. Essa String deve ser única, ou seja, não deve haver dois ou mais Presenters configurados sob o mesmo identificador. Caso isto ocorra, uma exceção em tempo de execução é lançada.

● Onde ela é usada: Na definição de uma classe que estende direta ou indiretamente de Presenter:

@Presenter(“presenterID”) @View(MyView.class)public class MyPresenter extends SwingPresenter {

// ...

}

Listagem 23: Declarando um Presenter

● Observações: Para que uma classe possa ser anotada com a anotação @Presenter, ela deve estender direta ou indiretamente de Presenter. Por exemplo, um Presenter que manipula Views Swing, deve estender a classe SwingPresenter.

3.3.1.2.12. @View

Page 43: tcc - surf

42

● Sintaxe: @View (Class value)● Descrição: Indicar qual é a View de um determinado Presenter.● Atributos:

● value: Classe que será utilizada como View.● Onde ela é usada: Esta anotação deve ser utilizada em conjunto com a anotação

@Presenter.● Observações: Em Swing, as Views são objetos JFrame ou JDialog (ou subclasses

destas).

3.3.2. Mais exemplos de uso das anotações

Além dos exemplos mostrados durante a explicação das anotações, para maiores detalhes em relação a aplicação das anotações, basta uma olhada na aplicação de exemplo que acompanha o framework.

3.4. Criando os models

Para criar objetos de negócio utilizáveis na sua aplicação Surf basta que a classe siga o padrão JavaBeans. Ela não precisa estender nenhuma classe ou interface. Basta uma olhada nos programas que acompanham o Surf para ver que os Models dos programas são apenas POJOs14.

3.5. Criando as views

Para criar as Views, basta que a classe estenda de JFrame ou JDialog (no caso de a aplicação ser Swing). Assim como dito no tópico anterior, as Views devem seguir o padrão JavaBeans, sem que seja necessário estender de nenhuma classe ou interface do Surf.

A única exigência é que sejam criados métodos get para todos os componentes que se deseja utilizar recursos do Surf. Apesar de isso parecer ruim, é algo que se resolve com um par de cliques nas IDEs JavaTM mais modernas. São através desses métodos get que o Surf consegue acessar os componentes. Não é necessário implementar métodos set para os componentes.

3.6. Criando os presenters

Os procedimentos descritos aqui são para mostrar como criar Presenters para Views Swing.

O primeiro procedimento a ser feito é criar uma classe que estende de SwingPresenter e anotá-la com os dados necessários para configurar o Presenter dentro do Surf:

14 Abreviação de Plain Old Java Object, que serve para classificar classes java que não estendem nenhuma classe ou interface, ou seja, objetos simples como componentes.

Page 44: tcc - surf

43

1: @Presenter(“nome_presenter”)2: @View(View.class)3: public class Presenter extends SwingPresenter {4: // ...5: }

Listagem 24: Exemplo de Presenter

Na primeira linha, definimos um nome para este Presenter dentro do Surf. Na segunda linha, indicamos qual é a classe que será a View (um JFrame ou um JDialog). Na terceira linha criamos a classe em si.

3.6.1. Definindo os models

No exemplo que segue, criamos um Presenter e definimos a propriedade cliente como sendo um Model. Definir Models faz com que o módulo de data binding possa ser ativado nesses objetos e, portanto, habilita a troca de dados entre a View e os Models apenas com a chamada de um método.

1: @Presenter(“nome_presenter”)2: @View(View.class)3: public class Presenter extends SwingPresenter {4: 5: private Cliente cliente;6:7: @Model8: public Cliente getCliente() {9: return cliente;10: }11: 12: public void setCliente(Cliente cliente) {13: this.cliente = cliente;14: }15: }

Listagem 25: Definindo um atributo como Model

Para definir um atributo como sendo um Model, bastou utilizar a anotação @Model no método get do atributo desejado. Se não existir nenhuma propriedade no Presenter que deva ser sincronizada com a View, então não há a necessidade de se utilizar a anotação @Model em nenhum dos métodos get do Presenter.

3.7. Criando commands

Para que possamos adicionar código para ser executado quando o usuário interage com a aplicação, devemos criar classes chamadas de Commands. Um exemplo de Command

Page 45: tcc - surf

44

pode ser visto a seguir:

1: public class ShowAboutDialogCommand extends AbstractCommand {2: 3: public String execute() {4: 5: Presenter aboutPresenter = PicoPresenterManager.getInstance().getAboutPresenter();6: aboutPresenter.showView(true);7: 8: return CONTINUE;9: }10: }

Listagem 26: Exemplo de Command

Todo Command deve estender de Command (ou, preferencialmente, da classe abstrata AbstractCommand). Então, o método execute() deve ser implementado. É justamente neste método execute() que a lógica a ser executada deve ser inserida, assim que um evento for disparado pelo usuário.

As linhas 3 e 8 merecem explicações. Note que o método execute() deve retornar um objeto String. Esse objeto tem a função de informar se o método foi executado com sucesso ou não. A interface Command possui algumas constantes que servem para fazer essa indicação de sucesso ou erro. Embora exista outras constantes, as que mais serão usadas pelos desenvolvedores são as seguintes: CONTINUE e STOP. Use CONTINUE quando o Command foi executado com sucesso, ou STOP para indicar alguma falha na execução.

Recapitulando, a anotação @Interaction possui um atributo chamado shortCircuiting. Então, dependendo do valor deste atributo, a execução de outros Commands posteriores ao que falhou pode ser interrompida ou não. Mais detalhes na descrição da anotação @Interaction.

3.7.1. Combinando generics com commands

Ainda sobre a declaração da classe Command, podemos declarar a classe de uma forma ligeiramente diferente:

1: public class ShowAboutDialogCommand extends AbstractCommand<TaskDetailsPresenter> {2: // ...3: }

Listagem 27: Exemplo de Command, utilizando Generics

Na linha 1, podemos utilizar o conceito de Generics15, presente no JavaTM 1.5, para

15 Similar aos templates de C++, Generics são estruturas para abstração de tipos, permitindo a criação de

Page 46: tcc - surf

45

indicar qual é o tipo do Presenter relacionado a este Command. Então, não é necessário fazer casting para obter os dados relativos ao Presenter:

1: /* Sem usar Generics */2: ((PresenterTal)presenter).foo(); // Cast necessário3: 4: /* Usando Generics*/5: presenter.foo(); // Cast desnecessário!

Listagem 28: Comparando um Command com e sem Generics

Este recurso deve ser usado com cautela pois, ao utilizar Gennerics em um Command, se está “amarrando” um Command a um determinado Presenter, tornando impossível a utilização deste Command com outros Presenters que não sejam o especificado. Portanto, os comportamentos dos Presenters devem ser modelados como interfaces de modo que os Commands sejam “amarrados” à comportamentos, e não a implementações.

3.7.2. Criação simplificada de commands

A forma mostrada para se criar Commands deve ser utilizada quando o foco principal é prover uma melhor reusabilidade de código. Porém existem casos onde o desenvolvedor deseja executar uma ação que não será reaproveitada em nenhum outro lugar, fazendo com que o trabalho de se implementar essa ação seja descompensador. E, se a aplicação sendo desenvolvida possui um grande número de ações que, por natureza, são pouco ou nada reutilizáveis, então a utilização da abordagem “uma classe por Command” resulta em inúmeras classes pequenas e que são usadas em apenas um lugar. De modo a ajudar o desenvolvedor a solucionar esse problema, o Surf permite que os Commands possam ser definidos de uma forma diferenciada.

A anotação @Interaction define um atributo chamado methodName. Este atributo serve para que o desenvolvedor indique um nome de método existente no Presenter para que, quando o evento for disparado, o Surf execute o método indicado.

Por exemplo, vamos analisar o seguinte trecho de código que pertence a uma View qualquer:

// ...@Interaction(methodName=”executar”)public Jbutton getButton() { return button;}

Listagem 29: Uso do atributo methodName da anotação @Interaction

classes e métodos onde os tipos de objetos tratados por eles são definidos na hora em que são invocados. Este recurso foi adicionado na versão 5.0 (Tiger) do JavaTM.

Page 47: tcc - surf

46

Quando o evento de clique no botão for disparado, o Surf executará o método executar(), codificado no Presenter:

@Presenter(“MyPresenter”) @View(MyView.class)public class MyPresenter extends SwingPresenter {

// ...

public void executar() { // Faz alguma coisa aqui... }}

Listagem 30: Método que será executado pelo Surf ao disparar o evento

Existe uma outra forma de se fazer isso. O desenvolvedor pode omitir o parâmetro methodName, na anotação @Interaction e, quando o evento for disparado, um método de mesmo nome ao método anotado com @Interaction (sem o 'get'), será executado no Presenter:

// ...@Interactionpublic Jbutton getCadastrarUsuario() { return button;}

Listagem 31: Omissão do parâmetro methodName na anotação @Interaction

@Presenter(“MyPresenter”) @View(MyView.class)public class MyPresenter extends SwingPresenter {

// ...

public void cadastrarUsuario() { // Faz alguma coisa aqui... }}

Listagem 32: Método a ser executado pelo Surf ao disparar o evento

3.8. Command Context

Apesar da natureza “independente” dos Commands, às vezes é necessário fazer com que tais classes possam ser capazes de se comunicar para realizar uma certa tarefa. Então, de modo a tornar possível essa comunicação entre diferentes Commands que respondem a um determinado evento, o Surf implementa um conceito chamado Command Context.

O Command Context é um objeto que serve para representar um “contexto” durante

Page 48: tcc - surf

47

a execução de um evento, podendo este ser composto por vários Commands. A instância desse objeto de contexto é criada e passada a todos os Commands antes que o evento comece a ser efetivamente processado.

Então, caso algum Command em execução queira disponibilizar alguma informação para o próximo Command a ser executado, existem alguns métodos no objeto de contexto que permitem adicionar/obter atributos e obter informações de status sobre a execução dos Commands.

Quando um Command adiciona um determinado atributo no contexto, automaticamente tal atributo é visível a todos os outros Commands que executarão posteriormente, no mesmo evento em execução. É através deste mecanismo que podemos fazer com que os Commands se tornem interoperantes.

Para mostrar um exemplo de como o contexto funciona, imagine que um evento é composto por dois Commands: ValidateCommand e ExecuteCommand. Estes Commands responderão a um evento de ação de um botão da nossa View:

public class MyView extends JFrame {

private JButton button; @Interaction(command={ValidateCommand.class, ExecuteCommand.class}) public JButton getButton() { return button; }}

Listagem 33: Configurando um evento com dois Commands

Digamos que o Command ValidateCommand verificará se os dados digitados na View são válidos e adicionará ao contexto um atributo que indica a validade das informações entradas pelo usuário. Então, quando o Command ExecuteCommand for executado, ele resgatará este atributo e, com base nele, decidirá qual atitude deve ser tomada. Note que este é apenas um exemplo e a mesma funcionalidade pode ser implementada mais facilmente de outras formas.

Abaixo, seguem os códigos das classes ValidateCommand e ExecuteCommand, respectivamente:

Page 49: tcc - surf

48

public class ValidateCommand extends AbstractCommand {

public String execute() { boolean valid = false;

// Código que verifica se os dados são válidos

getCommandContext().setParameter(“valid”, valid);

return CONTINUE; }}

Listagem 34: Setando um parâmetro no contexto de Commands

public class ExecuteCommand extends AbstractCommand {

public String execute() {

boolean valid = ((Boolean)getCommandContext().getParameter("valid")).booleanValue();

if (valid) { // Faz qualquer coisa... } else { // Faz outra coisa... }

return CONTINUE; }}

Listagem 35: Obtendo um parâmetro do contexto de Commands

Tornamos então possível a comunicação entre dois Commands através da criação e leitura de parâmetros do contexto. Apesar de facilitar bastante, é necessário tomar algum cuidado ao utilizar este recurso pois pode estar tornando um Command dependente de um parâmetro de contexto.

3.9. Utilizando o recurso de data binding

Os desenvolvedores que escrevem aplicações Swing se vêem freqüentemente criando código para manter valores de componentes da View em sincronia com o Model. Fazer essa codificação manualmente é uma tarefa dispendiosa e propensa a erros.

Então, de modo a tornar essa sincronia mais simples, o Surf fornece um módulo de data binding que transporta e converte os dados automaticamente, através da invocação de

Page 50: tcc - surf

49

um método pré-implementado pelo Surf.

3.9.1. Sincronizando a view e o model

Depois de configurados o Presenter e View com as anotações vistas anteriormente, basta chamar os seguintes métodos para sincronizar a View ou o Model:

1: /* Atualiza o Model com os dados da View */2: presenter.getDataTransferer().updateModel();3:4: /* Atualiza a View com os dados Model */5: presenter.getDataTransferer().updateView();

Listagem 36: Passagem de dados entre a View e o Model

O objeto retornado pelo método getDataTransferer() é o responsável pelo trabalho de sincronização entre a View e o Model, sendo, portanto, necessário obter este objeto para que o transporte dos dados possa ser feito. O método updateModel() e updateView() fazem a sincronia de todos os atributos do Model e da View, respectivamente, onde os atributos que serão sincronizados estão anotados com @Bind e @Model, como mostrado no capítulo que descreve tais anotações.

Caso não seja necessário sincronizar todos os atributos, podemos também fazer a sincronização de atributos individuais ou de uma lista de atributos. Por exemplo:

1: presenter.getDataTransferer().updateModel(null, “nome”);2: presenter.getDataTransferer().updateView(new String[] {“nome”, “endereco”});3: 4: List<String> attrs = new ArrayList<String>();5: attrs.add(“nome”);6: attrs.add(“endereco”);7: presenter.getDataTransferer().updateView(attrs);

Listagem 37: Sincronizando atributos individuais

Na linha 1, o programa solicita ao Surf a sincronia do atributo nome. Note que o primeiro parâmetro (que representa o nome do Model) está sendo setado como null, o que significa que o Surf deve atualizar os atributos nome de todos os Models que possuam tal atributo.

Na linha 2, o programa solicita a sincronia de dois atributos da View: nome e endereco.

Na linha 7, o programa utiliza um objeto List contendo todos os atributos que devem ser sincronizados e o passa para o método updateView(), fazendo com que tais propriedades da View sejam atualizadas. O resultado obtido nesta instrução é idêntico ao obtido na

Page 51: tcc - surf

50

instrução da linha 2.

Caso tenhamos mais de um Model declarado no Presenter, podemos informar ao Surf o Model que desejamos utilizar na sincronização. No próximo exemplo, indicamos ao Surf a sincronia do atributo nome do Model cliente:

1: presenter.getDataTransferer().updateModel(“cliente”, “nome”);

Listagem 38: Indicando o nome do Model que deve ser utilizado na sincronia

A diferença entre informar ou omitir o nome do Model só pode ser notada caso existam atributos com nomes iguais para diferentes Models. Por exemplo: suponha que você tenha dois Models declarados no seu Presenter: cliente e fornecedor. Ambos os Models possuem um atributo nome. Então, quando se desejar sincronizar a propriedade nome do cliente, devemos informar a String “cliente” no parâmetro que representa o nome do Model que deve ser usado. Caso se deseja trabalhar com o atributo nome do fornecedor, então devemos fornecer a String “fornecedor” no parâmetro que representa o nome do Model que deve ser usado. Ou, ainda, caso se deseja sincronizar o atributo nome, tanto de cliente quanto de fornecedor, basta informar null no lugar do nome do Model. Assim, todos os atributos nome encontrados serão sincronizados, independente do Model em que estão declarados.

O recurso de nested properties pode ser utilizado no nome do atributo que se deseja sincronizar. Por exemplo, podemos atualizar o atributo rua que está situado dentro do atributo endereco:

1: presenter.getDataTransferer().updateModel(null, “endereco.rua”);

Listagem 39: Sincronizando sub-atributos

3.9.2. Trabalhando com enums

O Surf possui a capacidade de trabalhar com a nova estrutura de dados definida na especificação 5.0 da linguagem JavaTM: Enums.

Os enums, ou enumeradores, são classes especiais que são utilizadas para representação de tipos enumerados. Um exemplo clássico pode ser visto abaixo:

public enum Sexo { MASCULINO, FEMININO}

Listagem 40: Exemplo de uma construção Enum

Para utilizar o enumerador Sexo, segue o exemplo de uma classe Pessoa:

Page 52: tcc - surf

51

public class Pessoa {

private String nome; private Sexo sexo;

// Gets e Sets // ...}

Listagem 41: Exemplo de uso de uma construção Enum

O Surf consegue tratar conversões de dados entre valores enumerados, Strings e inteiros. Portanto, existe a possibilidade de ligar quaisquer componentes visuais que representem números ou Strings a propriedades no Model que sejam do tipo Enum, sem que seja necessário fazer nenhuma configuração adicional.

Caso o componente represente um valor do tipo inteiro, então, quando o valor desse componente for atualizado com o valor da Enum, o valor setado nesse componente é o índice do valor enumerado. Por exemplo, se o Enum em questão fosse o enumerador Sexo, mostrado a pouco, e o valor da propriedade sexo do objeto Pessoa fosse FEMININO, então o valor assumido pelo componente da View seria o inteiro 1, que corresponde ao índice do elemento FEMININO na Enum Sexo.

Caso o componente represente um valor do tipo String, então, quando o valor desse componente for atualizado com o valor da Enum, o valor setado nesse componente é o nome do valor numerado. Por exemplo, se o Enum em questão fosse o enumerador Sexo, mostrado a pouco, e o valor da propriedade sexo do objeto Pessoa fosse FEMININO, então o valor assumido pelo componente da View seria a String “FEMININO”, que corresponde ao nome do elemento da Enum Sexo.

3.10. Operações comuns

Caso o desenvolvedor precise apenas recuperar um valor de um componente da View, o seguinte código pode ser utilizado:

1: presenter.getDataTransferer().getViewProperty("propriedade");

Listagem 42: Setando valores na View

Essa abstração permite que trabalhemos com diferentes tipos de componentes sem a preocupação de qual componente se trata, permitindo a troca desse componente futuramente, sem precisar alterar o código que o manipula. Uma observação importante: podemos representar propriedades aninhadas no parâmetro deste método, permitindo que seja possível obter o valor de componentes contidos dentro de subviews.

Page 53: tcc - surf

52

3.10.1. Obtendo uma referência a um componente da View

Caso seja preciso obter uma referência de um determinado componente da View, o seguinte código deve ser utilizado:

1: presenter.getWidget("property.subproperty").getComponent();

Listagem 43: Obtendo referência a um componente da View

Este método retorna uma referência a um componente Swing, caso o componente que está sendo indicado no parâmetro for um JTextField, por exemplo. Apesar de não ser aconselhável o uso do método getComponent(), ele se torna necessário em determinados momentos, quando é preciso fazer alguma manipulação mais “baixo nível”.

3.10.2. Habilitando e desabilitando componentes

Para habilitar e desabilitar um componente na View, o seguinte código deve ser utilizado:

1: // Habilita2: presenter.getWidget(“property.subproperty”).setEnabled(true);3:4: // Desabilita5: presenter.getWidget(“property.subproperty”).setEnabled(false);

Listagem 44: Habilitando e desabilitando componentes

3.11. Componentes especiais

O Surf consegue trabalhar com a maioria dos componentes sem que haja nenhum tipo de configuração extra. Mas existem determinados componentes que são, por natureza, mais complexos de manipular e, portanto, dão um pouco mais de trabalho para tê-los funcionando da forma adequada. Dois dos componentes mais complexos existentes no Swing podem ser utilizados com o Surf: JTable e JList.

Para facilitar o uso destes componentes, o Surf possui implementações simplificadas de AbstractTableModel e AbstractListModel, que são classes que representam o conteúdo dos componentes JTable e JList, respectivamente. As classes em questão são GenericTableModel e GenericListModel.

A seguir será mostrado, em detalhes, como trabalhar com componentes menos triviais.

3.11.1. Componente JList

Para setar um componente JList, basta criar uma instância de GenericListModel (ou

Page 54: tcc - surf

53

uma subclasse desta, customizada pelo desenvolvedor) e adicionar no JList como sendo um Model:

1: JList list = new JList();2: list.setModel(new GenericListModel());

Listagem 45: Utilização da classe GenericListModel

Isso já é o suficiente para que o Surf consiga manipular o componente, adicionando e removendo objetos da lista, além de tratar do gerenciamento dos objetos selecionados na lista.

3.11.2. Componente JTable

O componente JTable é ainda mais complexo, em termos de utilização, do que o componente JList e precisa de mais informações que devem ser fornecidas pelo desenvolvedor. Por exemplo: número de colunas mostradas na tabela, quais linhas/colunas são editáveis, entre outras. Se o desenvolvedor já trabalhou com a classe AbstractTableModel, fornecida pelo Swing, não vai sentir nenhuma dificuldade em utilizar a classe GenericTableModel. Abaixo, segue um exemplo de TableModel implementado com a classe GenericTableModel, fornecida pelo Surf:

Page 55: tcc - surf

54

public class TaskTableModel extends GenericTableModel<Task> { private DateFormat dateFormat = SimpleDateFormat.getDateTimeInstance(); public int getColumnCount() { return 5; } public Object getValue(Task task, int columnIndex) { switch (columnIndex) { case 0: return new Byte(task.getPriority()); case 1: return task.getDescription(); case 2: return task.getDueDate() != null ? dateFormat.format(task.getDueDate().getTime()) : ""; case 3: return task.getFinishTime() != null ? dateFormat.format(task.getFinishTime().getTime()) : ""; case 4: return new Boolean(task.isAlert()); } return null; } public void setValue(Task entity, Object newValue, int columnIndex) { switch (columnIndex) { case 0: entity.setPriority((Byte)newValue); break; case 1: entity.setDescription((String)newValue); break; case 4: entity.setAlert(((Boolean)newValue).booleanValue()); break; }

if (getPresenter() instanceof SimpleTaskService) { ((SimpleTaskService)getPresenter()).getTaskManager() .storeTask(entity); } }

Listagem 46: Criação de um TableModel no Surf

Algumas considerações sobre o código da classe TaskTableModel.

Na declaração da classe, utilizamos Gennerics para indicar qual é o tipo de objeto manipulado no Table Model. No caso, são objetos Task.

Podemos notar também que, no método getValue(), não é necessário criarmos código para tratamento de valores de linha que ultrapassem o intervalo dos objetos incluídos no TableModel, coisa que é necessária quando se trabalha diretamente com um TableModel fornecido pelo Swing. Além disso, o método getValue() já recebe uma instância do objeto

Page 56: tcc - surf

55

sendo renderizado pela tabela via parâmetro, ficando mais fácil de obtermos os dados para exibição na tabela. Algo semelhante ocorre no método setValue(), onde o objeto sendo modificado também é passado no parâmetro, simplificando a criação de tabelas editáveis.

A classe TaskTableModel, assim como todas as classes que estendem a classe GenericTableModel, possuem uma referência ao Presenter correspondente à View onde a tabela está situada, facilitando a codificação de funcionalidades que exigem informações que não são pertinentes ao TableModel. No caso do código acima, tal funcionalidade é atualizar o objeto no banco de dados quando ocorre alguma alteração nos dados da tabela.

3.11.3. Componente JRadioButton

Um outro componente que precisa de algumas configurações extras é o JRadioButton. Por exemplo, suponha que a aplicação tenha um campo sexo, no Cadastro de Pessoas, e o desenvolvedor queira que esse campo seja escolhido através de dois radio buttons, onde o radio button selecionado corresponda ao sexo escolhido.

Então, além de dois componentes do tipo JRadioButton, o desenvolvedor precisará criar um objeto ButtonGroup e adicionar os dois JRadioButtons no ButtonGroup. Um ButtonGroup é uma classe fornecida pelo Swing que serve para controlar grupos de botões, sendo que um formulário pode possuir vários grupos de botões para diferentes propósitos.

Além da criação e configuração do ButtonGroup, cada componente JRadioButton deve ter sua propriedade actionCommand alterada para indicar qual é o valor assumido pelo componente selecionado:

@Presenter(“MyPresenter”) @View(MyView.class)public class MyPresenter extends SwingPresenter {

// ...

/* Inicializa os componentes da View */ public void init() {

radioSexoMasc = new JRadioButton(“Masculino”); radioSexoMasc.setActionCommand(“M”);

radioSexoFem = new JRadioButton(“Feminino”); radioSexoFem.setActionCommand(“F”);

groupSexo = new ButtonGroup(); groupSexo.add(radioSexoMasc); groupSexo.add(radioSexoFem); }

// ...}

Listagem 47: Usando JRadioButtons

Page 57: tcc - surf

56

Finalizando a configuração, devemos agora criar um método get para o objeto ButtonGroup e anotá-lo com @Bind, de modo a ligar o valor do botão selecionado a um atributo do Model:

// ...

@Bind(field=”sexo”)public ButtonGroup getGroupSexo() { return groupSexo;}

// ...

Listagem 48: Binding de um grupo de componentes JRadioButton

Esta abordagem funciona da mesma forma para outros componentes semelhantes ao JRadioButton, como, por exemplo, os JToggleButton e os JRadioButtonMenuItem.

3.12. Trabalhando com seleções

Além de facilitar a passagem dos dados entre o Model e a View, o Surf também implementa um outro conceito extremamente fundamental em aplicações Swing: as Seleções.

Cada componente possui um tipo diferente de seleção, que varia de acordo com a forma com que o componente pode ser utilizado. Por exemplo, a seleção de um JTable pode ser uma lista de objetos Cliente – que correspondem às linhas selecionadas – enquanto que a seleção de um JTextField é uma String – que corresponde ao texto selecionado.

O código abaixo mostra como obtemos os dados de seleção de um componente da View que, no caso, é um JTable:

@Presenter(“MainPresenter”) @View(MainWindow.class)public class MainPresenter extends SwingPresenter {

private List<Task> selectedTasks;

public void getSelectedTasks() { selectedTasks = (List<Task>) getWidget("taskTable") .getSelection().getSelected(); }

// ...}

Listagem 49: Obtendo dados de seleção de um componente

O método getSelection() retorna um objeto qualquer que implementa a interface Selection. O tipo do objeto retornado depende do componente em questão. Neste caso, como

Page 58: tcc - surf

57

o componente em questão é o JTable, a classe de seleção correspondente é a JTableSelection. O método getSelected() retorna uma coleção de objetos do tipo Task que estão atualmente selecionados no JTable.

Se o componente em questão fosse um JList, o resultado seria o mesmo, já que a forma de seleção implementada nos dois componentes também são parecidas. A diferença é que, o método getSelection() retorna um objeto JListSelection em vez do JTableSelection. Da mesma forma, podemos utilizar o método getSelected() para obter uma coleção contendo os objetos Task atualmente selecionados no JList.

A forma de se trabalhar com seleções em componentes de entrada de texto, como o JTextField ou o JTextArea por exemplo, é um pouco diferente da forma mostrada anteriormente, pelo fato de que são tipos de seleções diferentes, onde, no caso de componentes de entrada de texto, a seleção é uma String, e não uma coleção de Objects:

@Presenter("SomePresenter") @View(SomwView.class)public class SomePresenter extends SwingPresenter {

public void getSelectedText() {

TextSelection sel = (TextSelection) getWidget("textField") .getSelection().getSingleSelection(); System.out.println(sel.getSelectedText()); }}

Listagem 50: Trabalhando com seleções de texto

Ao contrário do método getSelected() (que retorna uma coleção), o método getSingleSelection() retorna um objeto, sendo então o método apropriado para seleções que retornam apenas um objeto, como é o caso. Então, através do objeto TextSelection, podemos obter o texto selecionado e as posições inicial e final da seleção em relação ao conteúdo do componente.

Page 59: tcc - surf

58

4 SEGUNDA APLICAÇÃO: GERENCIADOR DE TAREFAS

Esta aplicação serve para mostrar alguns recursos mais avançados que não foram mostrados na primeira aplicação de exemplo, além de mostrar a integração do Surf Framework com outros frameworks (como o Hibernate e o Pico). Com isso, a idéia é mostrar que o Surf Framework pode ser aplicado em softwares mais complexos.

A ilustração 9 mostra a janela principal do aplicativo, que é responsável por exibir a lista de tarefas cadastradas. Através do menu Options, o usuário pode classificar a lista de acordo com a prioridade, data de finalização e data de finalização prevista. O usuário ainda conta com filtros onde pode-se apenas exibir as tarefas marcadas como alerta e as tarefas já concluídas.

Para permitir a inclusão de uma nova tarefa e a manutenção de uma tarefa previamente cadastrada, o usuário utiliza a seguinte janela:

Ilustração 9: Janela principal da aplicação

Page 60: tcc - surf

59

O restante deste documento irá detalhar a construção deste aplicativo, cujo objetivo principal é demonstrar como o Surf Framework pode ajudar a agilizar o desenvolvimento de aplicações Swing mais modulares e fáceis de manter.

4.1. Criação do model

O Model da aplicação é bastante simples, conforme podemos visualizar na imagem que segue:

Como foi dito anteriormente, para que o Surf Framework possa interagir com o Model, não é necessária nenhuma modificação no mesmo. Esta é a primeira grande vantagem em se utilizar o Surf Framework.

Ilustração 11: Modelo da aplicação

Ilustração 10: Janela de manutenção de tarefas

Page 61: tcc - surf

60

O código do Model é bem simples e não será necessário listá-lo neste documento, pois trata-se de uma classe que somente armazena dados e gerencia o acesso a eles através de métodos acessores (get's e set's).

4.2. Interfaces dos presenters

De modo a sintetizar a lógica de negócio que deve ser executada pelo aplicativo, foram criadas duas interfaces: TaskService e ExtendedTaskService. Essas interfaces definem as funcionalidades principais da aplicação:

public interface TaskService extends UIPresenter { void saveTask(); void removeTask(); void setTaskManager(TaskManager manager); TaskManager getTaskManager(); void setTask(Task task); Task getTask();

void refreshTasks();}

Listagem 51: Lógica de apresentação

public interface ExtendedTaskService extends TaskService { void clearTasks(); void showCompletedTasks(); void showAlertTasks();}

Listagem 52: Extenção da lógica de apresentação

Na listagem 51, a interface TaskService estende a interface UIPresenter, definida pelo Surf Framework. A listagem 52 mostra a interface ExtendedTaskService que, como o nome sugere, é uma extenção da interface TaskService, provendo algumas operações extras.

Para completar as interfaces listadas acima, devemos criar as interfaces dos Presenters propriamente ditos, que agrupam, além dos métodos de negócio, métodos responsáveis por gerenciar o estados das respectivas Views.

Page 62: tcc - surf

61

public interface MainPresenter extends ExtendedTaskService { void enableInterfaceButtons(); void showTaskDetails(Task t, boolean newTask); void showAbouDialog(); void setTasks(List tasks); List getTasks();}

Listagem 53: Interface do Presenter da janela principal da aplicação

public interface TaskDetailsPresenter extends TaskService { void enableShowAlertWidgets(boolean b); boolean isTaskValid();}

Listagem 54: Interface do Presenter da janela de edição de tarefas

Depois de definidas as interfaces dos Presenters partimos para a implementação das mesmas.

4.3. Implementação do presenter da janela principal

O código a seguir mostra a definição do Presenter da janela principal da aplicação:

@Presenter("MainPresenter") @View(MainWindow.class)public class MainPresenterImpl extends SwingPresenter implements MainPresenter { private List<Task> tasks; private List<Task> selectedTasks; private AboutPresenter aboutPresenter; private TaskDetailsPresenter taskDetailsPresenter; private TaskManager taskManager;

@Model public List<Task> getTasks() { return tasks; }

public void setTasks(List<Task> tasks) { this.tasks = tasks; }}

Listagem 55: Definição do Presenter da janela principal

Page 63: tcc - surf

62

Para definir uma classe como sendo um Presenter capaz de gerenciar Views Swing, essa classe deve estender SwingPresenter.

De modo a tornar a configuração mais simples, o Surf Framework implementa um esquema de configuração via anotações.

A seguir estão dispostos trechos de código que mostram algumas das principais funções desempenhadas pela janela principal. No método que segue, capturamos quais são as tarefas selecionadas na JTable e modificamos o estado dos componentes da janela de acordo com a seleção, habilitando e desabilitando tais componentes:

public void enableInterfaceButtons() { Collection<Task> c = getWidget("taskTable").getSelection().getSelected(); boolean hasSelection = c.size() > 0; getWidget("editTaskButton").setEnabled(hasSelection); getWidget("editTaskItem").setEnabled(hasSelection); getWidget("removeTasksButton").setEnabled(hasSelection); getWidget("removeTasksItem").setEnabled(hasSelection); getWidget("markAsCompletedButton").setEnabled(hasSelection); getWidget("markAsCompletedItem").setEnabled(hasSelection); if (hasSelection) { selectedTask = c.iterator().next(); getWidget("markAsCompletedButton") .setValue(selectedTask.isCompleted()); getWidget("markAsCompletedItem") .setValue(selectedTask.isCompleted()); }}

Listagem 56: Método do Presenter para manipulação da View

O método getWidget() serve para obtermos uma referência a um componente da View. Para que seja possível obter os dados de seleção do componente, utilizamos o objeto Selection, obtido através do método getSelection(). Note que trabalhar com seleções desta forma é muito mais simples e intuitivo do que acessar diretamente o TableSelectionModel do Swing, onde deveríamos buscar os objetos manualmente com base nos índices das linhas atualmente selecionadas no componente.

O código que segue é responsável por mostrar as tarefas na grid. Ele verifica quais foram os filtros selecionados pelo usuário e traz as tarefas correspondentes:

Page 64: tcc - surf

63

public void refreshTasks() { tasks = taskManager.getAllTasks(); if (getWidget("showAlertsItem").getValue().equals(true)) { tasks = taskManager.getAlertedTasks(tasks); } if (getWidget("showCompletedItem").getValue().equals(true)) { tasks = taskManager.getCompletedTasks(tasks); } if (getWidget("sortByDueDateItem").getValue().equals(true)) { taskManager.sortTasksByDueDate(tasks); } if (getWidget("sortByFinishTimeItem") .getValue().equals(true)) { taskManager.sortTasksByFinishDate(tasks); } if (getWidget("sortByPriorityItem") .getValue().equals(true)) { taskManager.sortTasksByPriority(tasks); } getDataTransferer().updateView();}

Listagem 57: Método para filtragem de tarefas

O código que segue mostra a implementação dos métodos de negócio, que utilizam a classe TaskManager para fazer a integração do sistema com o banco de dados:

public void saveTask() { taskManager.storeTask(selectedTask);}

public void removeTask() { taskManager.removeTask(selectedTask);}

public void clearTasks() { taskManager.clearTasks();}

Listagem 58: Interação com o banco de dados

Isso mostra como a integração do Surf Framework com as soluções ORM16 existentes

16 Object Relational Mapping, ou Mapeamento Objeto-Relacional. São soluções criadas com o objetivo de fazer com que linguagens orientadas a objetos possam interagir com bancos de dados relacionais.

Page 65: tcc - surf

64

no mercado ocorre facilmente. Nesta aplicação foi utilizado o EJB 3.0, implementado pelo Hibernate, para persistência dos dados.

4.4. Implementação do presenter da janela de manutenção

Veja a listagem de definição do Presenter:

@Presenter("TaskDetailsPresenter")@View(TaskDetailsDialog.class)public class TaskDetailsPresenterImpl extends SwingPresenter implements TaskDetailsPresenter { private Task task; private TaskManager taskManager;

// ...

Listagem 59: Definição do Presenter da janela de manutenção

O código da listagem 59 é bem parecido com o código do Presenter mostrado anteriormente, portanto as mesmas regras explicadas anteriormente são válidas.

Segue o próximo trecho de código:

Atualmente, a ferramenta ORM mais conhecida para JavaTM é o Hibernate.

Page 66: tcc - surf

65

public void enableShowAlertWidgets(boolean b) { getWidget("daysBefore").setEnabled(b); getWidget("daysBeforeLabel").setEnabled(b);}

public boolean isTaskValid() { boolean ret = true; BindableComponent statusLabel = getWidget("statusLabel"); if ("".equals(task.getDescription())) { statusLabel.setValue( "The field 'Description' is mandatory." ); ret = false; } else if (task.getDueDate() == null) { statusLabel.setValue( "The field 'Due Date' is mandatory." ); ret = false; } if (ret == false) { statusLabel.setIcon( new ImageIcon(getClass().getResource( "/icons/16x16/dialog-error.png" ))); } return ret;}

Listagem 60: Manipulação dos componentes da View

Depois de analisar alguns trechos de código da listagem 60 podemos ver outra grande vantagem do Surf Framework: o Presenter não é dependente dos componentes utilizados na View. Dessa forma, caso seja necessário trocar alguns componentes da View, o Presenter não precisa ser modificado.

4.5. Criação dos commands

Para fazer com que a aplicação consiga responder à interação do usuário, precisamos lidar com os eventos disparados por ele na View da nossa aplicação. Para isso, existem os Commands.

Um bom exemplo de Command que existe no programa é listado abaixo:

Page 67: tcc - surf

66

1: public class SaveTaskCommand extends AbstractCommand<TaskService> {2: 3: /** Creates a new instance of SaveTaskCommand */4: public SaveTaskCommand() {5: }6: 7: 8: public String execute() {9: 10: presenter.saveTask();11: return CONTINUE;12: }13: }

Listagem 61: Exemplo de Command

Podemos notar na listagem 61 que utilizamos Generics nesta classe: o Presenter é tratado como sendo uma instância de TaskService e, portanto, pode acessar todos os métodos definidos nesta interface sem que seja necessário especificar o tipo do Presenter através de casting. Podemos, então, utilizar este Command em qualquer Presenter que implemente a interface TaskService.

Ainda na listagem 61, um outro ponto que merece uma explicação é a instrução situada na linha 11. O método execute() retorna um objeto String qualquer. Esta String é utilizada pelo Surf Framework para indicar se o Command foi executado com sucesso ou não. Para efeitos de padronização, o Surf Framework já define algumas constantes indicativas de status, sendo as mais importantes as constantes CONTINUE e STOP.

Quando um evento é disparado, podemos fazer com que vários Commands sejam executados. Então, Surf Framework executa os Commands um a um, na mesma ordem em que são declarados. Caso um Command retorne CONTINUE, o próximo Command é executado. Mas, caso um Command retorne STOP, a execução dos Commands subseqüentes é interrompida.

Existe ainda uma outra forma de responder a eventos do usuário, sendo esta bem simples e prática, bastante útil quando se deseja tratar um evento mais simples.

@Interactionpublic javax.swing.JMenuItem getShowAboutDialog() { return aboutItem;}

Listagem 62: Criação simplificada de Commands

O método get do componente aboutItem está anotado com @Interaction, sendo que a anotação não possui nenhum parâmetro. Isso indica que, quando o evento de ação for disparado no componente aboutItem, o Surf irá invocar um método chamado showAboutDialog(), sendo que tal método está situado dentro do Presenter. A listagem abaixo mostra como fica esse método de forma que, quando o usuário clicar nesse item de

Page 68: tcc - surf

67

menu, a janela “Sobre...” seja mostrada:

public void showAboutDialog() { PicoPresenterManager.getInstance().getAboutPresenter() .showView(true);}

Listagem 63: Método executado quando o evento é disparado

4.6. Criação das views

4.6.1. Criação da view principal

O design da janela foi feito no NetBeans 5.5 beta, utilizando o Matisse, ferramenta esta que vem ganhando bastante popularidade entre os desenvolvedores de aplicações Desktop em JavaTM.

Depois de desenhada a janela, devemos criar métodos get para cada componente que queremos disponibilizar para o Surf Framework. Depois de criados os métodos, devemos utilizar as anotações nesses métodos get de modo a ligar os controles da janela com o Model e prover a funcionalidade da aplicação através da instalação de Commands nos componentes.

O trecho de código abaixo mostra como deve ser feito para adicionar comportamento a um componente visual, além de permitir que um componente seja sincronizado com o Model:

Page 69: tcc - surf

68

1: @Interaction(methodName=”addNewTask”)2: public javax.swing.JButton getAddTaskButton() {3: return addTaskButton;4: }5: 6: @Interaction(methodName=”editTask”)7: public javax.swing.JButton getEditTaskButton() {8: return editTaskButton;9: }10: 11: @Interaction(command={12: MarkAsCompletedCommand.class,13: SaveTaskCommand.class14: })15: public javax.swing.JToggleButton getMarkAsCompletedButton() {16: return markAsCompletedButton;17: }18: 19: @Interaction(command={20: ShowAlertsCommand.class,21: ListTasksCommand.class22: })23: public javax.swing.JToggleButton getShowAlertsButton() {24: return showAlertsButton;25: }26: 27: @Interaction(command={28: ShowCompletedTasksCommand.class,29: ListTasksCommand.class30: })31: public javax.swing.JToggleButton getShowCompletedButton() {32: return showCompletedButton;33: }34: 35: @Bind(model="tasks")36: @InteractionList({37: @Interaction(methodName="taskSelectionChange",38: event=EventType.LIST_SELECTION_CHANGE),39: @Interaction(copyFrom="editTaskItem",40: event=EventType.MOUSE_DOUBLE_CLICKED)41: })42: public javax.swing.JTable getTaskTable() {43: return taskTable;44: }

Listagem 64: Configuração da View da janela principal

Para adicionar um ou mais Commands para responder à interação do usuário, utilizamos a anotação @Interaction e @InteractionList. Nelas, informamos quais são os Commands que devem ser executados e qual evento irá disparar sua execução. Se não definirmos o tipo de evento que dispara os Commands, o Surf Framework utiliza o evento de ação por padrão.

Ainda sobre listagem 64, linha 35, para que possamos ligar um componente visual a

Page 70: tcc - surf

69

um objeto de negócio, utilizamos a anotação @Bind. Nela, definimos qual é nome do Model correspondente e qual é o nome da sub-propriedade do Model, caso exista. Também podemos adicionar uma anotação @Interaction neste componente para fazê-lo responder aos eventos disparados pelo usuário.

Caso o Presenter possua apenas uma propriedade anotada com @Model, não precisamos fornecer o nome do Model na anotação @Bind.

4.6.2. Criação da view de manutenção

A criação da View da janela de manutenção se assemelha bastante à criação da View da janela principal. Segue um trecho de código onde configuramos a View com as anotações do Surf Framework:

1: @Interaction(command=CloseDialogCommand.class)2: public javax.swing.JButton getCancelButton() {3: return cancelButton;4: }5: 6: @Interaction(command={7: ValidateTaskCommand.class,8: SaveTaskCommand.class,9: CloseDialogCommand.class,10: ListTasksCommand.class11: })12: public javax.swing.JButton getSaveButton() {13: return saveButton;14: }15: 16: @Bind17: public javax.swing.JCheckBox getCompleted() {18: return completed;19: }20: 21: @Bind22: public javax.swing.JSpinner getDaysBefore() {23: return daysBefore;24: }25: 26: @Bind @Formatter(type=SimpleDateFormat.class)27: public javax.swing.JFormattedTextField getDueDate() {28: return dueDate;29: }

Listagem 65: Configuração da View da janela de manutenção

Podemos observar alguns pontos interessantes no código da listagem 65.

Na linha 1 estamos reaproveitando a classe CloseDialogCommand, que é um Command fornecido pelo Surf, utilizado quando se deseja que a View seja fechada.

Page 71: tcc - surf

70

Na linha 6 utilizamos a anotação @Interaction com diversos Commands. Então, quando o evento de ação for disparado no componente saveButton, o Surf Framework executará os Commands em seqüência, conforme explicado anteriormente. Isso também melhora bastante o nível de reúso de código, pois podemos decompor uma tarefa em várias tarefas menores e então reutiliza-las em vários locais diferentes.

Na linha 26 temos a anotação @Formatter, cujo objetivo é formatar o valor na View. Neste caso, estamos utilizando a classe SimpleDateFormat para formatar a data de vencimento da tarefa. Podemos fornecer na anotação @Formatter uma String que representa o formato a ser utilizado pela classe. No exemplo de formatação de data, esse formato poderia ser uma String parecida com “dd/MM/yyyy”, indicando que a data deve ser exibida no padrão dia/mês/ano.

4.7. Configuração da camada intermediária

O Surf Framework fornece suporte aos frameworks Spring e Pico, dois dos mais conhecidos frameworks de Injeção de Dependências em JavaTM. Dessa forma podemos configurar as dependências da aplicação em um local separado do restante do código da aplicação, conseqüentemente diminuindo os custos de manutenção.

O software de demonstração utiliza o framework Pico, por este ser mais simples e rápido em relação ao Spring. Mas, para fins de demonstração, também será mostrado neste documento como ficaria a integração do Surf Framework com o Spring.

4.7.1. Utilizando o Spring

Começando pela integração com o Spring, a listagem abaixo mostra o arquivo ApplicationContext.xml, cuja função é indicar as dependências da aplicação. Este arquivo é utilizado pelo framework Spring para determinar quais objetos podem ser criados pelo BeanFactory:

Page 72: tcc - surf

71

<beans> <bean id="taskManager" class="br.com.surf.todomanager.model.manager.DaoTaskManager"> <property name="taskDao"> <bean class="br.com.surf.todomanager.dao.task.HSQLDBTaskDao" /> </property> </bean> <bean id="mainPresenter" class="br.com.surf.todomanager.presenter.MainPresenterImpl"> <property name="taskManager" ref="taskManager" /> </bean> <bean id="taskDetailsPresenter" class="br.com.surf.todomanager.presenter.TaskDetailsPresenterImpl"> <property name="taskManager" ref="taskManager" /> <property name="parentPresenter" ref="mainPresenter" /> </bean> <bean id="presenterSetup" class="br.com.surf.integration.spring.SwingSpringPresenterSetup"> <property name="configFactory" value="br.com.surf.annotation.parser.AnnotationPresenterConfigFactory" /> <property name="presenterList"> <list> <ref bean="mainPresenter" /> <ref bean="taskDetailsPresenter" /> </list> </property> </bean></beans>

Listagem 66: Arquivo de configuração do Spring

Na listagem 66, o bean taskManager é a classe responsável por manipular o banco de dados. No arquivo de configuração indicamos que os beans mainPresenter e taskDetailsPresenter devem receber uma instância do bean taskManager, sem que precisemos fazer a instanciação do objeto dentro do código, o que iria gerar uma dependência direta entre as classes relacionadas. Por fim, o bean presenterSetup é utilizado para configurar os Presenters criados pelo Spring.

Para obter um bean criado pelo Spring, foram criadas as seguintes classes:

public interface PresenterManager { MainPresenter getMainPresenter(); TaskDetailsPresenter getTaskDetailsPresenter(); AboutPresenter getAboutPresenter();}

Listagem 67: Interface de gerenciamento dos Presenters da aplicação

Page 73: tcc - surf

72

public class SpringPresenterManager implements PresenterManager { private BeanFactory beanFactory; private static SpringPresenterManager _instance; static { /* Padrão de projeto Singleton */ _instance = new SpringPresenterManager(); } private SpringPresenterManager() { /* Factory de beans declarados no arquivo XML */ beanFactory = new ClassPathXmlApplicationContext("ApplicationContext.xml"); } public static PresenterManager getInstance() { return _instance; } public MainPresenter getMainPresenter() { return (MainPresenter) beanFactory.getBean("mainPresenter"); } public TaskDetailsPresenter getTaskDetailsPresenter() { return (TaskDetailsPresenter) beanFactory.getBean("taskDetailsPresenter"); } public AboutPresenter getAboutPresenter() { return (AboutPresenter) beanFactory.getBean("aboutPresenter"); }}

Listagem 68: Classe de obtenção de Presenters via Spring

Na listagem 68 definimos a classe SpringPresenterManager, cuja responsabilidade é obter instâncias dos Presenters da aplicação através do uso do objeto BeanFactory do Spring.

Ao instanciar o BeanFactory, o Spring também instancia os beans declarados no arquivo XML e configura as dependências indicadas através das tags property, passando os objetos para os respectivos métodos set uns dos outros.

4.7.2. Utilizando o Pico

Na listagem que segue, foi feita uma outra implementação da interface PresenterManager, responsável por obter instâncias dos Presenters através do framework Pico:

Page 74: tcc - surf

73

public class PicoPresenterManager implements PresenterManager { private static PresenterManager _instance; private static MutablePicoContainer pico; static { _instance = new PicoPresenterManager(); }

private PicoPresenterManager() { pico = new DefaultPicoContainer(); /* Classes necessárias para ativar a integração com o Pico */ pico.registerComponentImplementation(SwingSurfConfig.class); pico.registerComponentImplementation( SwingPresenterFactory.class); pico.registerComponentImplementation( AnnotationPresenterConfigFactory.class); pico.registerComponentImplementation(PicoPresenterSetup.class); /* Dependências da aplicação */ pico.registerComponentImplementation( TaskDetailsPresenterImpl.class); pico.registerComponentImplementation(MainPresenterImpl.class); pico.registerComponentImplementation(AboutPresenterImpl.class); /* Camada de persistência */ pico.registerComponentImplementation(HSQLDBTaskDao.class); pico.registerComponentImplementation(DaoTaskManager.class); pico.start(); } public static PresenterManager getInstance() { return _instance; } public TaskDetailsPresenter getTaskDetailsPresenter() { return (TaskDetailsPresenter) pico.getComponentInstanceOfType(TaskDetailsPresenter.class); }

public MainPresenter getMainPresenter() { return (MainPresenter) pico.getComponentInstanceOfType(MainPresenter.class); }

public AboutPresenterImpl getAboutPresenter() { return (AboutPresenterImpl) pico.getComponentInstanceOfType(AboutPresenterImpl.class); }}

Listagem 69: Classe de obtenção de Presenters via Pico

Page 75: tcc - surf

74

Diferentemente do Spring, o Pico não exige nenhum arquivo de configuração para que este funcione. Durante a invocação do método start(), o Pico analiza os construtores dos objetos registrados anteriormente através do método registerComponentImplementation() e, automaticamente, cria os objetos na ordem correta, passando as referências dos objetos através de seus construtores.

Então, para que possamos obter uma referência a algum Presenter, basta utilizarmos os métodos definidos nas classes SpringPresenterManager ou PicoPresenterManager.

Uma vez que as dependências da aplicação foram agrupadas em um único lugar, a tarefa de se adicionar novos comportamentos ou realizar manutenção em serviços de “infraestrutura” torna-se mais simples.

4.8. Iniciando a aplicação

Uma vez que os Presenters estão devidamente configurados e são acessíveis através da classe PicoPresenterManager, então a classe que inicia a aplicação é bem simples:

public class Main { public Main() {

/* Inicia a aplicação, mostrando a View principal */ PicoPresenterManager.getInstance().getMainPresenter() .showView(true); } public static void main(String[] args) { new Main(); }}

Listagem 70: Classe principal da aplicação

O código desta classe apenas obtém uma referência para o Presenter principal da aplicação já criado pelo Pico e solicita a exibição de sua View. O parâmetro boolean indica se a View deve ser exibida (true) ou escondida (false).

Page 76: tcc - surf

75

5 CONSIDERAÇÕES FINAIS

O objetivo deste trabalho foi mostrar, de uma forma breve, dois padrões de projeto que podem ser aplicados para tornar o desenvolvimento de aplicações Swing mais simples, dando uma atenção especial em como tais padrões ajudam a tornar o código das aplicações melhor estruturados e organizados.

Como destacado anteriormente no texto, são poucas as diferenças entre o Model-View-Controller (MVC) e o Model-View-Presenter (MVP), mas tais diferenças podem influenciar positiva ou negativamente em um projeto de software, dependendo da natureza deste, tornando então a escolha entre um ou outro padrão de projeto uma escolha de extrema importância.

Depois de abordar os padrões de projeto MVC e MVP, o restante do trabalho se resume à especificação e documentação do Surf, um framework que implementa, além dos conceitos do padrão MVP, algumas funcionalidades com o objetivo de tornar mais simples o desenvolvimento de aplicações Swing.

Apesar de a proposta inicial do trabalho ter sido a implementação pura e simples de um framework MVP, essa proposta inicial foi se modificando com o passar do tempo e o framework foi agregando algumas funcionalidades que não são particulares ao MVP ou a qualquer outro padrão de projeto, fazendo com que o Surf deixasse de ser um simples framework MVP e se tornasse um framework cujo objetivo fosse facilitar ao máximo a vida do desenvolvedor Swing.

Page 77: tcc - surf

76

6 TRABALHOS FUTUROS

Existem duas coisas extremamente importantes e que precisam ser feitas com uma certa urgência:

1. Escrever testes para o código já implementado no Surf Framework; e2. Desenvolver site para o Surf Framework, este contendo informações mais detalhadas

sobre o projeto, documentação do framework e listas de discussão.

Os testes não foram escritos para o Surf Framework devido ao pouco tempo disponível para o desenvolvimento do trabalho, em razão das funcionalidades planejadas para o framework.

A atividade relacionada ao site do framework já foi iniciada. O site contém, atualmente, algumas informações pertinentes ao processo de build do framework, como a lista das dependências de compilação e execução, pessoas envolvidas no projeto e dados do servidor SubVersion17, a partir do qual o código do framework pode ser baixado.

Uma outra questão que poderá ser trabalhada no futuro é a possibilidade da utilização do Surf Framework com outras toolkits de desenvolvimento de interfaces visuais, como SWT [1] e Thinlets [2], além de melhorar o suporte ao Swing. O Surf Framework foi cuidadosamente projetado para que tais customizações sejam fáceis de serem incorporadas ao framework.

Da mesma forma, o Surf poderá também suportar outros métodos de configuração, sendo que, atualmente, a configuração é feita através do uso de anotações. Os métodos mais indicados são a utilização de arquivos de configuração em XML ou linguagens de script disponíveis para a plataforma JavaTM, como, por exemplo, o Groovy [3].

Em relação às funcionalidades do framework, algumas coisas serão feitas em breve, tanto para melhorar as funcionalidades já implementadas quanto para incluir novas funcionalidades. Uma coisa que já está sendo estudada é a utilização de AOP18 para automatizar completamente a passagem de dados entre a View e o Model, fazendo com que os métodos updateModel() e updateView() sejam chamados sob demanda. Assim, pode-se definir diferentes estratégias de sincronização entre a View e o Model, permitindo que o desenvolvedor escolha a estratégia que melhor se adapta às suas necessidades.

Uma funcionalidade importante que será adicionada é o suporte a validação de dados digitados pelo usuário na View, através do uso de frameworks como Commons-Validator [5] ou Hibernate Validator [6]. A escolha mais indicada para o Surf seria utilizar o Hibernate Validator pelo fato de que este trabalha com anotações para definir as regras de validação.

17 O SubVersion é um sistema de controle de versões, cuja função é gerenciar a modificação de arquivos compartilhados a diversos usuários simultaneamente, evitando que modificações conflitantes sejam efetuadas.

18 AOP ou Programação Orientada a Aspectos é uma técnica que propõe a decomposição funcional e sistêmica do problema, permitindo que a implementação de um sistema seja separada em requisitos funcionais e não-funcionais [WINK, 2006].

Page 78: tcc - surf

77

7 REFERÊNCIAS BIBLIOGRÁFICAS

[WINK, 2006] WINK, D. V.; JUNIOR, V. G. AspectJ: Programação Orientada a Aspectos com Java. São Paulo: Novatec, 2006. 229 p.

[GAMMA, 2000] GAMMA, E. et al. Padrões de Projeto: Soluções reutilizáveis de software orientado a objetos. Porto Alegre: Bookman, 2000. 364 p.

BAUER, C.; KING, G. Hibernate em Ação: O guia definitivo para o Hibernate. Rio de Janeiro: Ciência Moderna, 2005. 529 p.

WALLS, C.; BREIDENBACH, R. Spring em Ação. Rio de Janeiro: Ciência Moderna, 2006. 445 p.

HARROP, R.; MACHACEK, J. Pro Spring. Apress, 2005. 806 p.

TATE, B. A.; GEHTLAND, J. Better, Faster, Lighter Java. O'Reilly, 2004. 243 p.

FREEMAN, E.; FREEMAN, E. Use a Cabeça! Padrões de Projetos. Rio de Janeiro: Alta Books, 2005. 496 p.

HORSTMANN, C. S.; CORNELL, G. Core Java: Volume 1 – Fundamentos. São Paulo: Pearson Makron Books, 2003. 654 p.

HORSTMANN, C. S.; CORNELL, G. Core Java: Volume 2 – Recursos Avançados. São Paulo: Pearson Makron Books, 2003. 824 p.

WASLAWICK, R. S. Análise e Projeto de Sistemas de Informação Orientados a Objetos. Rio de Janeiro: Elsevier, 2004. 298 p.

FOWLER, M. et al. Refatoração: Aperfeiçoando o projeto de código existente. Porto Alegre: Bookman, 2004. 365 p.

FOWLER, M. Model-View-Presenter. Disponível em: <http://www.martinfowler.com/eaaDev/ModelViewPresenter.html>. Acesso em: 28 fev. 2006.

FOWLER, M. GUI Architectures. Disponível em: <http://martinfowler.com/eaaDev/uiArchs.html>. Acesso em: 27 jul. 2006.

MARTINS, D. F. Model-View-Presenter: O MVC focado na lógica de apresentação.Disponível em: <http://www.javafree.org/content/view.jf?idContent=91>. Acesso em: 3 mar. 2006.

MILLER, J. D. More thoughts on Model View Presenter. Disponível em: <http://codebetter.com/blogs/jeremy.miller/archive/2006/02/16/138382.aspx>. Acesso em: 25 mar. 2006.

Page 79: tcc - surf

78

MILLER, J. D. Test Driven Development with ASP.Net and the Model View Presenter Pattern. Disponível em: <http://codebetter.com/blogs/jeremy.miller/archive/2006/02/01/137457.aspx>. Acesso em: 25 mar. 2006.

MICHALIK, D. MVCMediator: Joy of Java Client Programming. Disponível em: <http://www.danmich.com/mvcmediator/1.0/wp/white_paper.html>. Acesso em: 24 mar. 2006.

DAMOC, P. Model View Presenter. Disponível em: <http://wiki.wxpython.org/index.cgi/ModelViewPresenter>. Acesso em: 24 mar. 2006.

HUNTER, J; MCLAUGHLIN, B. Easy Java/XML integration wih JDOM, Part 1. Disponível em: <http://www.javaworld.com/javaworld/jw-05-2000/jw-0518-jdom.html>. Acesso em: 21 mar. 2006.

JAMAE, J. Learn to Use the New Annotation Feature of Java 5.0. Disponível em: <http://www.devx.com/Java/Article/27235>. Acesso em: 17 mar. 2006.

HOLMGREN, A. Using Annotations to add Validity Constraints to JavaBeans Properties. Disponível em: <http://java.sun.com/developer/technicalArticles/J2SE/constraints/annotations.html>. Acesso em: 17 mar. 2006.

TALIGENT. Presentation Frameworks. Disponível em: <http://pcroot.cern.ch/TaligentDocs/TaligentOnline/DocumentRoot/1.0/Docs/books/PF/PF_2.html>. Acesso em: 24 mar. 2006.

Model-View-Presenter. Disponível em: <http://c2.com/cgi/wiki?ModelViewPresenter>. Acesso em: 25 mar. 2006.

Model-View-Presenter Framework. Disponível em: <http://www.mimuw.edu.pl/~sl/teaching/00_01/Delfin_EC/Overviews/ModelViewPresenter.htm>. Acesso em: 24 mar. 2006.

Pattern: Model-View-Presenter. Disponível em: <http://www.mimuw.edu.pl/~sl/teaching/00_01/Delfin_EC/Patterns/MVP.htm>. Acesso em: 28 fev. 2006.

OGNL: Object Graph Navigation Language. Disponível em: <http://www.ognl.com>. Acesso em: 20 nov. 2006.

[1] SWT.

Page 80: tcc - surf

79

Disponível em: <http://www.eclipse.org/swt>. Acesso em: 10 dez. 2006.

[2] Thinlets. Disponível em: <http://thinlet.sourceforge.net/home.html>. Acesso em: 10 dez. 2006.

[3] Groovy. Disponível em: <http://groovy.codehaus.org>. Acesso em: 10 dez. 2006.

[4] Surf Framework. Disponível em: <http://surfframework.sourceforge.net>. Acesso em: 30 nov. 2006.

[5] Commons-Validator. Disponível em: <http://jakarta.apache.org/commons/validator>. Acesso em: 10 dez. 2006.

[6] Hibernate Validator. Disponível em: <http://www.hibernate.org/hib_docs/annotations/reference/en/html/validator.html>. Acesso em: 10 dez. 2006.

[7] Java SDK. Disponível em: <http://java.sun.com>. Acesso em: 16 maio 2006.

[8] Commons-Logging. Disponível em: <http://jakarta.apache.org/commons/logging>. Acesso em: 21 mar. 2006.

[9] Eclipse. Disponível em: <http://www.eclipse.org>. Acesso em: 20 mar. 2006.

[10] NetBeans. Disponível em: <http://www.netbeans.org>. Acesso em: 20 mar. 2006.

[11] Spring Framework. Disponível em: <http://www.springframework.org>. Acesso em: 14 jul. 2006.

[12] Pico Container. Disponível em: <http://www.picocontainer.org>. Acesso em: 05 ago. 2006.

[13] Documentação JavaDoc – Surf Framework. Disponível em: <http://surfframework.sourceforge.net/apidocs/index.html>.