Você está na página 1de 10

CAPÍTULO 1

Introdução ao Seam

A primeira coisa a entender sobre o Seam é que ele é um framework. Na verdade


é um framework que está acima do framework (Java EE), que por sua vez também fica
acima de outro framework (Java). Mas não se distraia com isso agora.
A palavra framework tem um amplo significado, podendo ter várias interpretações
dependendo de como é usada (e de quem a está usando). No caso do Seam, interpre-
tamos palavra framework sob o ponto de vista da tecnologia de sistemas: Ele molda
um conjunto de APIs e serviços em um ambiente que facilita (ou simplifica) escrever
aplicações web Java EE.
Um framework geralmente “facilita” fazer algo, simplificando atividades rotinei-
ras e comuns, fornecendo utilitários nativos que em outro caso você mesmo teria que
escrever. Seam não é diferente. Seam está baseado em Java EE, logo ele atende aos seus
deveres de framework de duas maneiras fundamentais:
• Seam simplifica Java EE: Seam fornece um conjunto de atalhos e simplifica-
ções do framework padrão Java EE, tornando fácil e eficaz o uso de compo-
nentes web e de negócios Java EE.
• Seam extende Java EE: Seam integra um conjunto de conceitos e ferramentas
ao framework Java EE. Estas extensões trazem novas funcionalidades para
dentro do framework Java EE.
Você se familiarizará com o Seam neste capítulo, examinando rapidamente cada
uma de suas características. No final deste capítulo, são listados vários serviços e
utilitários que o Seam fornece. Nos capítulos que se seguem, você verá estes serviços
em ação, com exemplos de desenvolvimento de aplicações.
2 PROJETOS PRÁTICOS COM JBOSS SEAM

SEAM SIMPLIFICA JAVA EE


O ambiente padrão Java EE é formado pelo Java Standard Edition (Java SE) com
todas as suas APIs (JDBC para acesso a banco de dados, JAXP para processamento de
XML etc.) que suportam todos os recursos da camada enterprise do Java EE (JSF/JSP/
servlets para desenvolvimento de componentes web, JAX-WS para web services etc).
Seus componentes de aplicação são construídos diretamente sobre o topo de todo este
framework, conforme a Figura 1-1.

Application Components

JSF JSP/ JAX-WS EJB3/JPA ...


Servlets

Java Enterprise Edition (Java EE)

JNDI RMI JAXP JDBC ...

Figura 1-1 – Framework padrão Java EE.

Além das APIs e dos diversos componentes descritos na figura 1-1, Java EE também
fornece serviços de deployment, serviço de segurança em tempo de execução, e outros
que você precisa para criar aplicações eficazes. E Java EE fornece um conjunto de
melhorias em relação ao framework predecessor, o J2EE, por exemplo:
• As anotações do Java 5.0 estão integradas por toda a API no Java EE,
oferecendo a você a opção de utilizar as anotações tanto como informação
externa para deployment no formato XML ou embutidas no código.
• O Java Server Faces (JSF) 1.2, o Java API para XML baseados em Web Services
(JAX-WS) 2.0, as APIs Enterprise JavaBeans (EJB) 3.0 oferecem modelos de
programação mais fáceis em relação ao predecessor J2EE, permitindo a você
implementar boa parte dos componentes web, web service e de negócios
usando simples JavaBeans.
• EJB 3.0 elimina a necessidade por muitas das interfaces e outros artefatos
exigidos na maioria dos casos, pelas versões anteriores do EJB .
Mesmo com as melhorias apresentadas pelo Java EE, o time do JBOSS Seam
visualizou espaço para simplificar as coisas ainda mais. A Figura 1-2 descreve o
framework Seam entre duas camadas, a camada do código de sua aplicação e a camada
do framework Java EE.
CAPÍTULO 1 – INTRODUÇÃO AO SEAM 3

Application Components

Seam Framework
jBPM Conversação Regras JBoss

Modelo de Componente

JSP/
JSF EJB3/JPA JAX-WS ...
Servlets

Java Enterprise Edition (Java EE)

JNDI RMI JDBC JAXP ...

Java Standard Edition (Java SE)

Figura 1-2 – Seam Framework.

O Modelo de Componentes do Seam


As simplificações fornecidas pelo Seam derivam principalmente do seu modelo ou
arquitetura de componentes – este modelo de componente pode ser considerado, em
essência, como uma extensão do modelo de componente utilizado pelos managed
beans do JSF, mas também pode ser usado para outras finalidades, além de somente
a camada de componentes web, como você verá nos capítulos finais.
Um benefício fundamental fornecido pelo modelo de componente do Seam é o uso
direto de componentes EJB como beans acoplados as páginas JSF. O modelo padrão
do JSF permite que Javabeans regulares ou comuns sejam utilizados como managed
beans, conforme a configuração do arquivo JSF faces-config.xml.Componentes EJB
podem ser invocados a partir de métodos callback de managed beans, servindo como
uma “fachada” (façade) para o componente EJB. Seam fornece uma ponte entre o
modelo de componente do JSF e o modelo de componente do EJB, permitindo que você
utilize um EJB diretamente como um managed bean JSF. Isto elimina a necessidade
por fachadas extras de beans quando tudo que você necessita é um único EJB.
Outra simplificação oferecida pelo Seam é a habilidade de usar código de anotações
para ligar diretamente beans aos nomes de componentes JSF ao invés de escrever
referências do managed-bean no arquivo faces-config.xml.
O modelo de componente do Seam inclui anotações que podem ser usadas para
conectar diretamente uma instância de um bean com o nome do managed-bean JSF.
Quando o nome é utilizado no JSF (uma de suas propriedades é usada como valor de
um campo HTML por exemplo), a instância do bean será automaticamente inicializada,
se necessário, e usada como um bean acoplado no JSF. Não existe a necessidade de
4 PROJETOS PRÁTICOS COM JBOSS SEAM

conectar o bean com o nome do managed bean JSF através do arquivo faces-
config.xml.
O modelo de componente do Seam também suporta uma visão mais abrangente de
dependência por injeção, chamada de bijeção. A dependência por injeção padrão
envolve uma única inicialização da referência do bean dentro do componente,
geralmente feito por um tipo de container ou outro serviço runtime. A bijeção no Seam
estende este conceito para suportar o seguinte:
• Propagação das referências em dois sentidos: Um componente pode ter uma
injeção à referência feita pelo container, e o componente também pode realizar
uma injeção ao contexto.
• Atualizações dinâmicas: Ao invés de realizar a injeção das referências de uma
única vez, a bijeção é realizada a cada invocação do componente. Este ponto
é chave no modelo de componente do Seam, já que os componentes possuem
estados, logo estes componentes e seus beans dependentes podem ser invo-
cados livremente.
• Múltiplos contextos: Dependências (de entrada e saída) podem ser estabelecidas
através de múltiplos contextos Seam em vez de serem obrigados a existir
dentro de um único contexto. Então um componente em escopo de sessão pode
efetuar uma injeção a um bean em escopo de requisição e também realizar uma
injeção-externa para beans com escopo de aplicação, por exemplo.
Tudo isto pode parecer um pouco esotérico neste ponto, mas o valor desses recursos
no modelo do Seam ficará claro quando eu mostrar alguns exemplos de código.

Rodando um Exemplo: Um Catálogo de Dispositivos


O exemplo que é utilizado em boa parte do livro é um catálogo online de
dispositivos de alta tecnologia (telefones celulares, computadores portáteis, media
players etc.). Nos próximos capítulos, esta aplicação será construida a partir de uma
ferramenta simples de entrada de dados, e em seguida em algo um pouco mais
interessante; será construido também soluções para outros casos do mundo real,
usando os potenciais do framework Seam. Mas agora, será apresentado inicialmente
uma aplicação bem simples que pode fazer somente duas coisas :
• Mostrar uma lista de dispositivos eletrônicos contidos no catálogo.
• Permitir o usuário entrar com um novo dispositivo no catálogo.
Neste ponto, o modelo de aplicação será dolorosamente simples; um dispositivo
irá consistir de uma descrição (Ex: “Acme Powertop X1 Laptop”) e o tipo (Ex:
“laptop”). A informação sobre esses dispositivos será armazenada e gerenciada em um
banco de dados relacional. O fluxo das páginas da interface de usuário também será
igualmente simples: a página principal mostrará uma lista de dispositivos do banco
de dados e oferecerá uma única opção de adicionar um novo dispositivo no banco de
CAPÍTULO 1 – INTRODUÇÃO AO SEAM 5

dados. Esta opção dará ao usuário um formulário de entrada de dados que apresenta
os atributos necessários, e durante a submissão de um novo dispositivo, o mesmo será
armazenado no banco de dados e atualizado na lista de dispositivos que serão
apresentados novamente.
Podemos representar o “desenho da solução” neste ponto com um “diagrama de
fluxo de página” e um diagrama de banco relacional. O fluxo de página para a primeira
interação do Catálogo de Dispositivos é apresentado na Figura 1-3 e a estrutura do
banco de dados na Figura 1-4:

Salvar

Adicionar
Dispositivo

Lista de
Dispositivos Formulário
de Entrada

Figura 1-3 – Fluxo de página do Catálogo de Dispositivos.

Dispositivos
Tipo Char(3)
Desc Varchar(100)

Figura 1-4 – Banco do Catálogo de Dispositivo.

Agora tudo o que temos que fazer é construir. Como referência, vamos primeiro ver
como o Catálogo de Dispositivos é no framework Vanilla Java EE.

O Catálogo de Dispositivos sem o Seam


O código para este exemplo pode ser encontrado no pacote de códigos para este
livro, em baixo do subdiretório intro-JavaEE. No framework Java EE, sem o JBoss
Seam, a abordagem normal para a implementação de um Catalogo de Dispositivos é
usar o JSF como um UI em conjunto com os EJBs trabalhando a persistência e a lógica.
Para começar, vamos implementar um entity bean EJB 3.0 para representar o
dispositivo a ser armazenado na tabela de dispositivos. A Listagem 1-1 mostra o bean
de dispositivo. Este é um entity bean que é mapeado com a tabela de dispositivo através
da anotação EJB@Table. O bean tem duas propriedades persistentes: A propriedade
descrição que é mapeada na coluna DESCR, e a propriedade tipo que é mapeado na
coluna TYPE.
6 PROJETOS PRÁTICOS COM JBOSS SEAM

Listagem 1-1 – Entity EJB Dispositivo (GADGET no código)

@Entity
@Table(name=”GADGET”)
public class GadgetBean implements Serializable {
private String mDescription = “”;
private String mType = “”;

public GadgetBean() { }

@Id
@Column(name=”DESCR”)
public String getDescription() {
return mDescription;
}

public void setDescription(String desc) {


mDescription = desc;
}

@Id
@Column(name=”TYPE”)
public String getType() {
return mType;
}

public void setType(String t) {


mType = t;
}

Dica Prática Tenha cuidado com as palavras reservadas do SQL usadas como classe
entity bean EJB ou como nomes de propriedades. Mecanismos de
Persistência podem tentar mapeá-los diretamente para automaticamente
gerar as colunas/tabelas, resultando em uma Exceção SQL inesperada.
Observe que nomeou-se a propriedade do bean de dispositivo (GadgetBean)
como “descrição” ao invés de “desc”. É um nome maior para o tipo, mas
“desc” é uma palavra reservada em alguns bancos de dados. Se você decidir
auto-gerar o esquema, a propriedade chamada “desc” poderia ser mapeada
em uma coluna chamada “DESC”, e poderia gerar problemas. Estamos
sendo muito cuidadosos ao usar explicitamente anotações EJB3 @Column
para mapear as propriedades em colunas em nosso modelo de banco de
dados, logo mesmo se nós auto gerássemos o esquema (como fazemos nos
códigos fornecidos como exemplo no pacote de código do livro), estarí-
amos seguros de não gerarmos o problema citado.
CAPÍTULO 1 – INTRODUÇÃO AO SEAM 7

Com o fim de implementar a funcionalidade que foi apresentada para o catálogo


de dispositivos, é preciso estar apto a obter uma lista de todos os dispositivos
atualmente dentro do banco de dados, e é preciso adicionar um novo dispositivo ao
banco de dados. Usando um padrão típico “Session Façade” para o EJB, foi criado o
EJB de sessão GadgetAdminBean para prover estas funções. O código para isto, é
apresentado na listagem 1-2:

Listagem 1-2 – Sessão EJB GadgetAdminBean

@Stateless
public class GadgetAdminBean implements IGadgetAdminBean {
@PersistenceContext(unitName=”gadgetDatabase”)
private EntityManager mEntityManager;

/** Retrieve all gadgets from the catalog, ordered by description */


public List<GadgetBean> getAllGadgets() {
List<GadgetBean> gadgets = new ArrayList<GadgetBean>();
try {
Query q =
mEntityManager.createQuery( “select g from GadgetBean “ +
“g order by g.description”);
List gList = q.getResultList();
Iterator i = gList.iterator();
while (i.hasNext()) {
gadgets.add((GadgetBean)i.next());
}
}
catch (Exception e) {
e.printStackTrace();
}
return gadgets;
}

/** Insert a new gadget into the catalog */


public void newGadget(GadgetBean g) {
try {
mEntityManager.persist(g);
}
catch (Exception e) {
e.printStackTrace();
}
}
}

Esta sessão EJB usa o padrão EJB 3.0 e chamadas Java Persistence API (JPA) para
implementar as funções exigidas. Nós as marcamos como session bean sem estado
usando a anotação @Stateless do EJB 3.0 na declaração da classe. Também usamos
8 PROJETOS PRÁTICOS COM JBOSS SEAM

a anotação JPA @Persistence-Context para introduzir o EntityManager JPA em um


session bean, nos permitindo executar as operações de persistência necessárias para
consultar e inserir no banco de dados de dispositivos. Estamos referenciando uma
unidade de persistência chamada de “gadgetDatabase”, logo precisaremos definir uma
unidade de persistência com esse nome no arquivo de deployment persistence.xml
quando empacotarmos os EJBs.
O método getAllGadgets() carrega um catálogo inteiro de dispositivos usando
uma consulta JPA criada a partir do EntityManager. O método newGadget() persiste
um novo dispositivo usando o EntityManager. (na forma do bean de dispositivo –
GadgetBean).
Estes dois EJBs parecem tomar conta de nossas atuais necessidades em termos de
operações de persistência, então agora podemos mudar a nossa atenção para a UI. Para
implementar a UI que especificamos no fluxo de página desenhado anteriormente,
criamos duas páginas JSF, uma para cada uma das páginas especificadas. A primeira
mostra uma lista de dispositivos em um banco de dados junto com um link para criar
um novo dispositivo. Durante a construção destas páginas, vamos assumir que
podemos acessar a funcionalidade de persistência que construímos anteriormente
através do managed bean JSF chamado “gadgetAdmin”. Nossa lista de Dispositivos
JSF é apresentada na Listagem 1-3. Ela simplesmente utiliza um componente “data
table” JSF para interagir através dos dispositivos retornados da operação getAllGadgets()
no bean gadgetAdmin, mostrando cada dispositivo na linha do componente “data
table”. Então, no pé do “data table” nós geramos um link que invoca uma ação JSF
chamada “addGadget”.

Listagem 1-3 – Página JSF de listagem de dispositivos

<%@ taglib uri=”http://java.sun.com/jsf/html” prefix=”h”%>


<%@ taglib uri=”http://java.sun.com/jsf/core” prefix=”f”%>

<html>
<head>
<title>Gadget List</title>
</head>

<body>
<f:view>
<h:messages/>
<!— Show the current gadget catalog —>
<h:dataTable value=”#{gadgetAdmin.allGadgets}” var=”g”>
<h:column>
<f:facet name=”header”>
<h:outputText value=”Type” />
</f:facet>
<h:outputText value=”#{g.type}” />
CAPÍTULO 1 – INTRODUÇÃO AO SEAM 9

</h:column>
<h:column>
<f:facet name=”header”>
<h:outputText value=”Description” />
</f:facet>
<h:outputText value=”#{g.description}” />
</h:column>
</h:dataTable>
<h:form>
<!— Link to add a new gadget —>
<h:commandLink action=”addGadget”>
<h:outputText value=”Add a new gadget” />
</h:commandLink>
</h:form>
</f:view>
</body>
</html>

A ação addGadget deve nos trazer a segunda página no nosso fluxo, a página com
o formulário de entrada de dispositivos. A página JSF que implementa isto, a
addGadget.jsp, é apresentada na Listagem 1-4.

Listagem 1-4 – Página JSF de entrada de dispositivos.

<%@ taglib uri=”http://java.sun.com/jsf/html” prefix=”h”%>


<%@ taglib uri=”http://java.sun.com/jsf/core” prefix=”f”%>

<html>
<head>
<title>Add a Gadget</title>
</head>

<body>
<f:view>
<h:form>
<table border=”0">
<tr>
<td>Description:</td>
<td>
<h:inputText value=”#{gadget.description}”
required=”true” />
</td>
</tr>
<tr>
<td>Type:</td>
<td>
<h:selectOneMenu value=”#{gadget.type}”
required=”true”>
<f:selectItems value=”#{gadgetAdmin.gadgetTypes}” />
10 PROJETOS PRÁTICOS COM JBOSS SEAM

</h:selectOneMenu>
</td>
</tr>
</table>
<h:commandButton type=”submit” value=”Create”
action=”#{gadgetAdmin.newGadget}” />
</h:form>
</f:view>
</body>
</html>

Esta página gera um simples formulário de entrada que questiona o usuário a


informar o tipo e a descrição de um novo dispositivo para o catalogo. O campo
descrição é um simples campo de entrada de texto, enquanto o tipo é um campo select-
list que será preenchido com os valores permitidos vindos da enumeração GadgetTypes.
Ambos campos são limitados com as propriedades do novo managed bean chamado
“gadget”. Ao final de cada formulário há o botão de submit que invoca a operação
newGadGet() no gadgetAdmin managed bean.
Neste ponto, como em qualquer aplicação JSF, precisaremos ligar os managed
beans JSF com as classes em nosso modelo. Podemos tentar associar o bean gadgetAdmin
com uma instância de nossa sessão EJB GadgetAdminBean e o bean gadget com nossa
entity EJB GadgetBean, usando entradas em nosso faces-config.xml, como mostra a
listagem abaixo:

<faces-config>
<managed-bean>
<managed-bean-name>gadget</managed-bean-name>
<managed-bean-class>GadgetBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>

<managed-bean>
<managed-bean-name>gadgetAdmin</managed-bean-name>
<managed-bean-class>GadgetAdminBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>

Mas o que você descobrirá é que isto não irá funcionar, pelo menos não do jeito
que você esperava. Em JSF, espera-se que os managed beans sejam simples JavaBeans,
e eles serão tratados assim em runtime pelo container JSF. Quando o bean gadget ou
gadgetAdmin, são criados e usados em tempo de execução, para estes beans o container
JSF não segue as regras dos componentes EJB. Ele não irá, por exemplo, usar o
container EJB para obter uma instância do GadgetAdminBean, como deveria para
qualquer bean de sessão. Ao contrário, ele tentará construir instâncias do
GadgetAdminBean diretamente, fora do container EJB e de todos os seus serviços. E