Anda di halaman 1dari 80

FGP-FACULDADE GENNARI & PEARTREE

Sistemas de Informação

SURF FRAMEWORK – UM FRAMEWORK MVP EM JAVATM

Daniel Fernandes Martins

PEDERNEIRAS – SP
2006
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 – SP
2006
FOLHA DE APROVAÇÃO

Pederneiras, 01 de Dezembro de 2006.

Orientadora:

Examinador:

Examinador:
LISTA DE ILUSTRAÇÕES

Ilustração 1: Modelo MVC...................................................................................................................8


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

Listagem 1: Código da View..............................................................................................................19


Listagem 2: Presenter da aplicação....................................................................................................20
Listagem 3: Classe principal da aplicação..........................................................................................21
Listagem 4: Configuração manual......................................................................................................23
Listagem 5: Arquivo XML de configuração do Spring......................................................................25
Listagem 6: Utilização do BeanFactory do Spring.............................................................................26
Listagem 7: Configuração do Framework usando o Pico..................................................................26
Listagem 8: Obtendo referência de um Presenter criado pelo framework Pico.................................27
Listagem 9: Utilizando a anotação @Bind.........................................................................................29
Listagem 10: Utilizando a anotação @Formatter...............................................................................30
Listagem 11: Executando um evento mapeado com @Interaction....................................................30
Listagem 12: Reutilizando configuração através do atributo copyFrom............................................31
Listagem 13: Reutilização parcial dos parâmetros de interação.........................................................32
Listagem 14: Command que fecha a janela ao clicar no botão..........................................................32
Listagem 15: Adicionando Commands em mais de um tipo de evento.............................................33
Listagem 16: Usando a anotação @Property.....................................................................................34
Listagem 17: Recuperando uma propriedade informada na anotação @Interaction..........................34
Listagem 18: Utilização de subviews com @SubView......................................................................35
Listagem 19: Aplicando Commands a componentes de uma subview..............................................36
Listagem 20: Informando o tipo de um componente com a anotação @Type...................................37
Listagem 21: Definindo um atributo do Presenter como Model........................................................38
Listagem 22: Evento de fechamento da View....................................................................................39
Listagem 23: Declarando um Presenter..............................................................................................41
Listagem 24: Exemplo de Presenter...................................................................................................43
Listagem 25: Definindo um atributo como Model.............................................................................43
Listagem 26: Exemplo de Command.................................................................................................44
Listagem 27: Exemplo de Command, utilizando Generics................................................................44
Listagem 28: Comparando um Command com e sem Generics........................................................45
Listagem 29: Uso do atributo methodName da anotação @Interaction.............................................45
Listagem 30: Método que será executado pelo Surf ao disparar o evento.........................................46
Listagem 31: Omissão do parâmetro methodName na anotação @Interaction.................................46
Listagem 32: Método a ser executado pelo Surf ao disparar o evento...............................................46
Listagem 33: Configurando um evento com dois Commands...........................................................47
Listagem 34: Setando um parâmetro no contexto de Commands......................................................48
Listagem 35: Obtendo um parâmetro do contexto de Commands.....................................................48
Listagem 36: Passagem de dados entre a View e o Model.................................................................49
Listagem 37: Sincronizando atributos individuais.............................................................................49
Listagem 38: Indicando o nome do Model que deve ser utilizado na sincronia................................50
Listagem 39: Sincronizando sub-atributos.........................................................................................50
Listagem 40: Exemplo de uma construção Enum..............................................................................50
Listagem 41: Exemplo de uso de uma construção Enum...................................................................51
Listagem 42: Setando valores na View..............................................................................................51
Listagem 43: Obtendo referência a um componente da View...........................................................52
Listagem 44: Habilitando e desabilitando componentes....................................................................52
Listagem 45: Utilização da classe GenericListModel........................................................................53
Listagem 46: Criação de um TableModel no Surf.............................................................................54
Listagem 47: Usando JRadioButtons.................................................................................................55
Listagem 48: Binding de um grupo de componentes JRadioButton..................................................56
Listagem 49: Obtendo dados de seleção de um componente.............................................................56
Listagem 50: Trabalhando com seleções de texto..............................................................................57
Listagem 51: Lógica de apresentação.................................................................................................60
Listagem 52: Extenção da lógica de apresentação.............................................................................60
Listagem 53: Interface do Presenter da janela principal da aplicação................................................61
Listagem 54: Interface do Presenter da janela de edição de tarefas...................................................61
Listagem 55: Definição do Presenter da janela principal...................................................................61
Listagem 56: Método do Presenter para manipulação da View.........................................................62
Listagem 57: Método para filtragem de tarefas..................................................................................63
Listagem 58: Interação com o banco de dados...................................................................................63
Listagem 59: Definição do Presenter da janela de manutenção.........................................................64
Listagem 60: Manipulação dos componentes da View......................................................................65
Listagem 61: Exemplo de Command.................................................................................................66
Listagem 62: Criação simplificada de Commands.............................................................................66
Listagem 63: Método executado quando o evento é disparado..........................................................67
Listagem 64: Configuração da View da janela principal...................................................................68
Listagem 65: Configuração da View da janela de manutenção.........................................................69
Listagem 66: Arquivo de configuração do Spring.............................................................................71
Listagem 67: Interface de gerenciamento dos Presenters da aplicação..............................................71
Listagem 68: Classe de obtenção de Presenters via Spring................................................................72
Listagem 69: Classe de obtenção de Presenters via Pico...................................................................73
Listagem 70: Classe principal da aplicação........................................................................................74
SUMÁRIO

1 INTRODUÇÃO.................................................................................................................................8
1.1. Nome do framework.................................................................................................................8
1.2. Descrição do problema.............................................................................................................8
1.2.1. Limitações do MVC..........................................................................................................9
1.2.2. Origem do MVP..............................................................................................................10
1.3. Objetivos do Surf Framework.................................................................................................10
1.4. Procedimentos de instalação...................................................................................................11
1.4.1. Requisitos básicos...........................................................................................................11
1.4.1.1. Requisitos de hardware...........................................................................................11
1.4.1.2. Requisitos de software.............................................................................................11
1.4.2. Procedimento para instalação..........................................................................................11
1.4.3. Procedimento para configuração.....................................................................................11
1.4.3.1. Eclipse 3.2...............................................................................................................12
1.4.3.2. NetBeans 5.5...........................................................................................................12
1.4.4. Aplicativo de demonstração............................................................................................12
2 DESCRIÇÃO DO FUNCIONAMENTO........................................................................................13
2.1. Arquitetura do framework......................................................................................................13
2.1.1. Models e View................................................................................................................13
2.1.2. Swing..............................................................................................................................13
2.1.3. Configurações do Surf....................................................................................................14
2.1.3.1. Adaptadores de componentes..................................................................................14
2.1.3.2. Conversores.............................................................................................................14
2.1.3.3. Formatadores...........................................................................................................14
2.1.4. Configurações do Presenter............................................................................................14
2.1.5. Binding............................................................................................................................14
2.1.6. Commands......................................................................................................................15
2.1.7. Presenter..........................................................................................................................16
2.2. Desenvolvendo a primeira aplicação......................................................................................16
2.2.1. Construindo a aplicação..................................................................................................18
2.2.1.1. Criando o model......................................................................................................18
2.2.1.2. Criando a view.........................................................................................................19
2.2.1.3. Criando o presenter.................................................................................................20
2.2.1.4. Criando a classe principal........................................................................................21
3 CONHECENDO O SURF FRAMEWORK....................................................................................23
3.1. Configurando o Surf...............................................................................................................23
3.1.1. Configuração manual......................................................................................................23
3.1.2. Configuração via Spring.................................................................................................24
3.1.3. Configuração via Pico.....................................................................................................26
3.2. Nested properties....................................................................................................................27
3.2.1. Referenciando um atributo aninhado..............................................................................27
3.3. Anotações do Surf...................................................................................................................28
3.3.1. Apresentando as anotações.............................................................................................28
3.3.1.1. Anotações de view...................................................................................................28
3.3.1.1.1. @Bind..............................................................................................................28
3.3.1.1.2. @Formatter......................................................................................................29
3.3.1.1.3. @Interaction....................................................................................................30
3.3.1.1.4. @InteractionList..............................................................................................32
3.3.1.1.5. @Property........................................................................................................33
3.3.1.1.6. @SubView.......................................................................................................34
3.3.1.1.7. @Type.............................................................................................................36
3.3.1.1.8. @Widget..........................................................................................................37
3.3.1.2. Anotações de presenter............................................................................................37
3.3.1.2.1. @Model...........................................................................................................37
3.3.1.2.2. @OnViewActivate..........................................................................................38
3.3.1.2.3. @OnViewClose...............................................................................................39
3.3.1.2.4. @OnViewClosed.............................................................................................39
3.3.1.2.5. @OnViewDeactivate.......................................................................................39
3.3.1.2.6. @OnViewDeiconify........................................................................................40
3.3.1.2.7. @OnViewGainFocus.......................................................................................40
3.3.1.2.8. @OnViewIconify............................................................................................40
3.3.1.2.9. @OnViewLostFocus.......................................................................................40
3.3.1.2.10. @OnViewOpened..........................................................................................41
3.3.1.2.11. @Presenter.....................................................................................................41
3.3.1.2.12. @View...........................................................................................................41
3.3.2. Mais exemplos de uso das anotações..............................................................................42
3.4. Criando os models..................................................................................................................42
3.5. Criando as views.....................................................................................................................42
3.6. Criando os presenters..............................................................................................................42
3.6.1. Definindo os models.......................................................................................................43
3.7. Criando commands.................................................................................................................43
3.7.1. Combinando generics com commands...........................................................................44
3.7.2. Criação simplificada de commands................................................................................45
3.8. Command Context..................................................................................................................46
3.9. Utilizando o recurso de data binding......................................................................................48
3.9.1. Sincronizando a view e o model.....................................................................................49
3.9.2. Trabalhando com enums.................................................................................................50
3.10. Operações comuns................................................................................................................51
3.10.1. Obtendo uma referência a um componente da View....................................................52
3.10.2. Habilitando e desabilitando componentes.....................................................................52
3.11. Componentes especiais.........................................................................................................52
3.11.1. Componente JList.........................................................................................................52
3.11.2. Componente JTable.......................................................................................................53
3.11.3. Componente JRadioButton...........................................................................................55
3.12. Trabalhando com seleções....................................................................................................56
4 SEGUNDA APLICAÇÃO: GERENCIADOR DE TAREFAS......................................................58
4.1. Criação do model....................................................................................................................59
4.2. Interfaces dos presenters.........................................................................................................60
4.3. Implementação do presenter da janela principal.....................................................................61
4.4. Implementação do presenter da janela de manutenção...........................................................64
4.5. Criação dos commands...........................................................................................................65
4.6. Criação das views...................................................................................................................67
4.6.1. Criação da view principal...............................................................................................67
4.6.2. Criação da view de manutenção......................................................................................69
4.7. Configuração da camada intermediária..................................................................................70
4.7.1. Utilizando o Spring.........................................................................................................70
4.7.2. Utilizando o Pico.............................................................................................................72
4.8. Iniciando a aplicação..............................................................................................................74
5 CONSIDERAÇÕES FINAIS..........................................................................................................75
6 TRABALHOS FUTUROS..............................................................................................................76
7 REFERÊNCIAS BIBLIOGRÁFICAS............................................................................................77
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:

Ilustração 1: Modelo MVC

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.
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]
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:

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

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-
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.
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.
13

2 DESCRIÇÃO DO FUNCIONAMENTO

2.1. Arquitetura do framework


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

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

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.
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
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.
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:
17

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

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:

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

Então, para mostrar que as informações foram transferidas, a seguinte mensagem é


exibida ao usuário:

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

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:
18

Ilustração 7: Obtendo os dados do Model

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;
}
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


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.
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
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.
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á


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.
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.AnnotationPresenterConfigFact
ory"
/>

<!-- 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.
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:
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:

Ilustração 8: Nested properties

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
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
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:
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 @Interaction


EventCallback 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.
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


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)
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:
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
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:
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:
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
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
}
}
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: @OnViewClose
6: 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
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()
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
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.
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: @Model
8: 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
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
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ário
3:
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.
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:

// ...
@Interaction
public 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


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:
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
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
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:


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.
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: // Habilita
2: presenter.getWidget(“property.subproperty”).setEnabled(true);
3:
4: // Desabilita
5: 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
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:
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
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


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
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.
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.

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

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:
59

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

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:

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

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.
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.
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


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:
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.
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.


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:


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.

@Interaction
public 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
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:
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.class
14: })
15: public javax.swing.JToggleButton getMarkAsCompletedButton() {
16: return markAsCompletedButton;
17: }
18:
19: @Interaction(command={
20: ShowAlertsCommand.class,
21: ListTasksCommand.class
22: })
23: public javax.swing.JToggleButton getShowAlertsButton() {
24: return showAlertsButton;
25: }
26:
27: @Interaction(command={
28: ShowCompletedTasksCommand.class,
29: ListTasksCommand.class
30: })
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
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.class
11: })
12: public javax.swing.JButton getSaveButton() {
13: return saveButton;
14: }
15:
16: @Bind
17: public javax.swing.JCheckBox getCompleted() {
18: return completed;
19: }
20:
21: @Bind
22: 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.
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:
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.AnnotationPresenterConfigFactor
y" />
<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


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:
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


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).
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.
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; e


2. 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 AOP 18 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].
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.
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.
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>.

Anda mungkin juga menyukai