7. Versão 3: Portabilidade do aplicativo PAM para um servidor de aplicativos Glassfish
Propõe-se colocar os EJB das camadas [metier] e [DAO] da arquitetura OpenEJB / EclipseLink no contêiner de um servidor de aplicativos Glassfish.
A implementação atual com OpenEJB / EclipseLink
![]() |
Acima, a camada [ui] utiliza a interface remota da camada [metier].
Testamos dois contextos de execução: local e distant. Neste último modo, a camada [ui] era cliente da camada [metier], camada implementada por EJB. Para operar no modo cliente/servidor, no qual o cliente e o servidor são executados em dois JVM diferentes, vamos colocar as camadas [metier, DAO, jpa] no servidor Java Glassfish EE. Esse servidor vem junto com o NetBeans.
A implementação a ser construída com o servidor Glassfish
![]() |
- a camada [ui] será executada em um ambiente Java SE (Standard Edition)
- As camadas [metier, DAO, JPA] serão executadas em um ambiente Java EE (Enterprise Edition) em um servidor GlassFish v3
- o cliente se comunicará com o servidor por meio de uma rede TCP/IP. As trocas de dados pela rede são transparentes para o desenvolvedor, exceto pelo fato de que ele deve estar ciente de que o cliente e o servidor trocam objetos serializados para se comunicarem, e não referências a objetos. O protocolo de rede utilizado para essas trocas é chamado RMI (Remote Method Invocation), um protocolo utilizável exclusivamente entre duas aplicações Java.
- A implementação JPA utilizada no servidor Glassfish será EclipseLink.
7.1. A parte do servidor da aplicação cliente/servidor PAM
7.1.1. A arquitetura da aplicação
Analisamos aqui a parte do servidor que será hospedada pelo contêiner EJB3 do servidor Glassfish:
![]() |
Trata-se de fazer uma migração para o servidor Glassfish do que já foi feito e testado com o contêiner OpenEJB. É aí que reside a vantagem do OpenEJB e, de modo geral, dos contêineres EJB integrados: eles nos permitem testar a aplicação em um ambiente de execução simplificado. Quando a aplicação for testada, basta portá-la para um servidor de destino, neste caso, o servidor Glassfish.
7.1.1.1. O projeto NetBeans
Vamos começar criando um novo projeto no NetBeans:
![]() |
- em [1], novo projeto
- em [2], selecione a categoria Maven e, em [3], o tipo EJB Módulo. Trata-se, de fato, de criar um projeto que será hospedado e executado por um contêiner EJB, o do servidor Glassfish.
![]() |
- usando o botão [4a], selecione a pasta pai da pasta do projeto ou digite seu nome diretamente em [4b].
- em [5], atribua um nome ao projeto
- em [6], selecione o servidor de aplicativos no qual ele será executado. O selecionado aqui é um dos visíveis na aba [Runtime / Servers], neste caso, o Glassfish v3.
- em [7], selecione a versão do Java EE.
![]() |
- em [1], o novo projeto. Ele difere de um projeto Java clássico em alguns pontos:
- um branch [Other Sources] [2] é criado automaticamente. Ele conterá, entre outros, o arquivo [persistence.xml], que configura a camada JPA;
- se compilarmos o projeto (Build), surge uma dependência [javaee-api-6.0] do [3]. Ela é do tipo provided, pois é fornecida na execução pelo contêiner EJB do GlassFish.
7.1.1.2. Configuração da camada de persistência
Por configuração da camada de persistência, entendemos a criação do arquivo [persistence.xml], que define:
- a implementação JPA a ser utilizada
- a definição da fonte de dados utilizada pela camada JPA. Essa fonte será uma fonte JDBC gerenciada pelo servidor Glassfish.
![]() |
Pode-se proceder da seguinte forma. Primeiramente, na guia [Runtime / Databases], criaremos uma conexão com o banco de dados MySQL5 / dbpam_eclipselink:
![]() |
Feito isso, podemos passar à criação do recurso JDBC utilizado pelo módulo EJB:
![]() |
- no [1], crie um novo arquivo – certifique-se de que o projeto EJB esteja selecionado antes de realizar essa operação
- em [2], o projeto EJB
- em [3], selecione a categoria [Glassfish]
- no [4], deseja-se criar um recurso JDBC
![]() |
- em [5], indique que o recurso JDBC utilizará um novo pool de conexões. Vale lembrar que um pool de conexões é um conjunto de conexões abertas que serve para acelerar as trocas entre o aplicativo e o banco de dados.
- em [6], atribua o nome JNDI ao recurso JDBC criado. Esse nome pode ser qualquer um, mas geralmente tem o formato jdbc/nom. Esse nome JNDI será utilizado no arquivo [persistence.xml] para indicar a fonte de dados que a implementação JPA deve utilizar.
- No [7], atribua um nome (que pode ser qualquer um) ao pool de conexões que será criado
- na lista suspensa [8], selecione a conexão JDBC criada anteriormente com base em MySQL / dbpam_eclipselink.
- No [9], um resumo das propriedades do pool de conexões — não altere nada
![]() |
- em [10], é possível definir várias propriedades do pool de conexões — mantemos os valores padrão
- em [11], ao final do assistente de criação de um recurso JDBC para o módulo EJB, foi criado um arquivo [glassfish-resources.xml] no ramo [Other Sources]. O conteúdo desse arquivo é o seguinte:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
<jdbc-resource enabled="true" jndi-name="jdbc/dbpam_eclipselink" object-type="user" pool-name="dbpamEclipselinkConnectionPool">
<description/>
</jdbc-resource>
<jdbc-connection-pool allow-non-component-callers="false" associate-with-thread="false" connection-creation-retry-attempts="0" connection-creation-retry-interval-in-seconds="10" connection-leak-reclaim="false" connection-leak-timeout-in-seconds="0" connection-validation-method="auto-commit" datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" fail-all-connections="false" idle-timeout-in-seconds="300" is-connection-validation-required="false" is-isolation-level-guaranteed="true" lazy-connection-association="false" lazy-connection-enlistment="false" match-connections="false" max-connection-usage-count="0" max-pool-size="32" max-wait-time-in-millis="60000" name="dbpamEclipselinkConnectionPool" non-transactional-connections="false" pool-resize-quantity="2" res-type="javax.sql.DataSource" statement-timeout-in-seconds="-1" steady-pool-size="8" validate-atmost-once-period-in-seconds="0" wrap-jdbc-objects="false">
<property name="URL" value="jdbc:mysql://localhost:3306/dbpam_eclipselink"/>
<property name="User" value="root"/>
<property name="Password" value=""/>
</jdbc-connection-pool>
</resources>
O arquivo [glassfish-resources.xml] é um arquivo XML que contém todos os dados coletados pelo assistente. Ele será utilizado pelo NetBeans para, durante a implantação do módulo EJB no servidor GlassFish, solicitar a criação do recurso JDBC necessário para esse módulo.
Agora é possível criar o arquivo [persistence.xml], que configurará a camada JPA do módulo EJB:
![]() |
- em [1], crie um novo arquivo – certifique-se de que o projeto EJB esteja selecionado antes de realizar essa operação
- no [2], o projeto EJB
- em [3], seleciona-se a categoria [Persistence]
- em [4], deseja-se criar uma unidade de persistência
![]() |
- em [5], atribua um nome à unidade de persistência
- em [6], são propostas várias implementações JPA. Aqui, escolheremos [EclipseLink]. Outras implementações podem ser utilizadas, desde que as bibliotecas que as implementam sejam incluídas junto com as do servidor Glassfish.
- Na lista suspensa [7], selecione a fonte de dados JDBC [jdbc/dbpam_eclipselink] que acabou de ser criada.
- em [8], indique que as transações são gerenciadas pelo contêiner EJB
- em [9], indicar que nenhuma operação deve ser realizada na fonte de dados durante a implantação do módulo EJB no servidor. De fato, o módulo EJB utilizará um banco de dados [dbpam_eclipselink] já criado.
- Ao final do assistente, foi criado um arquivo [persistence.xml] com o nome [10]. Seu conteúdo é o seguinte:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="mv-pam-ejb-metier-dao-eclipselinkPU" transaction-type="JTA">
<jta-data-source>jdbc/dbpam_eclipselink</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties/>
</persistence-unit>
</persistence>
- linha 3: o nome da unidade de persistência [mv-pam-ejb-metier-dao-eclipselinkPU] e o tipo de transações (JTA para um contêiner EJB)
- linha 5: o nome JNDI da fonte de dados utilizada pela camada de persistência: jdbc/dbpam_eclipselink
- linha 6: as entidades JPA não estão especificadas. Elas serão procuradas no Classpath do módulo EJB.
- O nome da implementação JPA (Hibernate, EclipseLink, ...) utilizada não está indicado. Nesse caso, o Glassfish v3 utiliza, por padrão, EclipseLink.
7.1.1.3. Inserção das camadas [jpa, DAO, metier]
Agora que o arquivo [persistence.xml] foi definido, podemos prosseguir com a inserção no projeto das camadas [metier, dao, jpa] do aplicativo corporativo [pam]:
![]() |
Essas três camadas são idênticas às que existiam no OpenEJB. É possível simplesmente copiar e colar entre os dois projetos. É isso que faremos agora:
![]() |
- no [1], o resultado da cópia dos pacotes [jpa, dao, metier, exception] do projeto [mv-pam-openejb-eclipselink] para o módulo EJB [mv-pam-ejb-metier-dao-jpa-eclipselink]
7.1.1.4. Configuração do servidor Glassfish
Resta-nos configurar o servidor Glassfish em dois pontos:
- a camada JPA é implementada por EclipseLink. É preciso garantir que o servidor Glassfish possua as bibliotecas dessa implementação JPA.
- a fonte de dados é um banco de dados MySQL. É preciso garantir que o servidor Glassfish possua o driver JDBC para esse SGBD.
É possível detectar a ausência dessas bibliotecas durante a implantação do módulo EJB. Aqui está uma das várias maneiras de adicionar as bibliotecas ausentes ao servidor GlassFish:
![]() |
- em [1], visualize as propriedades do servidor GlassFish
- em [2], anote a pasta dos domínios do servidor. A seguir, vamos chamá-la de <domains>
- na pasta <domains>\domain1\lib, coloque as bibliotecas que faltam. No exemplo, foram adicionadas as bibliotecas do Hibernate (lib / hibernate-tools) e o driver JDBC do MySQL (lib / divers). Por padrão, o servidor GlassFish já possui as bibliotecas de EclipseLink. Portanto, adicionaremos apenas o driver JDBC de MySQL.
![]() |
- em [1], na aba [Services], iniciamos o servidor Glassfish v3
- em [2], ele está ativo
7.1.1.5. Implantação do módulo EJB
Agora, implantamos o módulo EJB no servidor Glassfish:
![]() |
- em [1], o módulo EJB está implantado
- em [2], a árvore de diretórios do servidor Glassfish é atualizada
- em [3], após a implantação, o módulo EJB aparece no ramo [Applications] do servidor Glassfish
- em [4], o recurso JDBC [jdbc / dbpam_eclipselink] foi criado no servidor Glassfish. Vale lembrar que o definimos no parágrafo 7.1.1.2.
Durante a implantação, o servidor Glassfish registra informações interessantes no console:
Observe nas linhas
- 3, 6, 8 e 11 os nomes portáteis JNDI dos EJB implantados. O Java EE 6 introduziu o conceito de nome portátil JNDI. Isso indica um nome JNDI reconhecido por todos os servidores Java EE 6. No Java EE 5, os nomes JNDI são específicos do servidor utilizado.
- 4, 7, 9, 12: os nomes JNDI dos EJB implantados de uma forma específica para o Glassfish v3.
Esses nomes serão úteis para o aplicativo de console que vamos escrever para utilizar o módulo EJB implantado.
7.2. Console do cliente – versão 1
Agora que implantamos a parte do servidor de nossa aplicação cliente/servidor, passamos a estudar a parte do cliente [1]:
![]() |
7.2.1. O projeto do cliente
Criamos um novo projeto Maven do tipo [Java Application] chamado [mv-pam-client-ejb-metier-dao-eclipselink]:
![]() |
- no [1], o projeto do cliente
No arquivo [pom.xml], adicionamos as seguintes dependências:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>istia.st</groupId>
<artifactId>mv-pam-client-ejb-metier-dao-eclipselink</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>mv-pam-client-ejb-metier-dao-eclipselink</name>
<url>http://maven.apache.org</url>
<repositories>
<repository>
<url>http://download.eclipse.org/rt/eclipselink/maven.repo/</url>
<id>eclipselink</id>
<layout>default</layout>
<name>Repository for library Library[eclipselink]</name>
</repository>
<repository>
<url>http://repo1.maven.org/maven2/</url>
<id>swing-layout</id>
<layout>default</layout>
<name>Repository for library Library[swing-layout]</name>
</repository>
</repositories>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.glassfish.appclient</groupId>
<artifactId>gf-client</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mv-pam-ejb-metier-dao-eclipselink</artifactId>
<version>${project.version}</version>
<type>ejb</type>
</dependency>
<dependency>
<groupId>org.swinglabs</groupId>
<artifactId>swing-layout</artifactId>
<version>1.0.3</version>
</dependency>
</dependencies>
</project>
- linhas 31-35: a dependência da biblioteca [gf-client], que permite que um cliente Classfish se comunique com um servidor remoto,
- linhas 36-41: a dependência do projeto Maven do módulo EJB. Queremos recuperar aqui as definições das entidades JPA e das diversas interfaces, bem como a da classe de exceção [PamException],
A partir do projeto [mv-pam-openejb-eclipselink], copiamos a classe [MainRemote]:
![]() |
A classe [MainRemote] deve obter uma referência à classe EJB da camada [metier]. O código da classe [MainRemote] sofre as seguintes alterações:
// Tudo certo — já podemos solicitar o holerite
FeuilleSalaire feuilleSalaire = null;
IMetierRemote metier = null;
try {
// contexto JNDI do servidor Glassfish
InitialContext initialContext = new InitialContext();
// instanciação da camada de negócios
metier = (IMetierRemote) initialContext.lookup("java:global/istia.st_mv-pam-ejb-metier-dao-eclipselink_ejb_1.0-SNAPSHOT/Metier!metier.IMetierRemote");
// cálculo da folha de pagamento
feuilleSalaire = metier.calculerFeuilleSalaire(args[0], nbHeuresTravaillées, nbJoursTravaillés);
} catch (PamException ex) {
System.err.println("L'erreur suivante s'est produite : "
+ ex.getMessage());
return;
} catch (Exception ex) {
System.err.println("L'erreur suivante s'est produite : "
+ ex.toString());
return;
}
- linha 6: inicialização do contexto JNDI do servidor Glassfish.
- linha 8: solicita-se a esse contexto JNDI uma referência à interface remota da camada [metier]. De acordo com os logs do Glassfish, sabe-se que a interface remota da camada [metier] tem dois nomes possíveis:
Linha 1: o nome JNDI, utilizável com qualquer servidor de aplicativos JAVA, EE, etc. Linha 2: o nome JNDI, específico do Glassfish. No código, na linha 9, usamos o nome JNDI, que é portátil.
- O restante do código não sofre alterações
![]() |
Em [1], configuramos o projeto para que ele execute a classe [MainRemote] com argumentos. Se tudo correr bem, a execução do projeto produz o seguinte resultado:
Se, nas propriedades, for inserido um número de seguro social incorreto, obtém-se o seguinte resultado:
7.3. Console do cliente – versão 2
Nas versões anteriores, o ambiente JNDI do servidor Glassfish era configurado a partir de um arquivo [jndi.properties] localizado em algum lugar nos arquivos do projeto. Seu conteúdo padrão é o seguinte:
# acesso JNDI ao Sun Application Server
java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory
java.naming.factory.url.pkgs=com.sun.enterprise.naming
# É necessário adicionar um javax.naming.spi.StateFactory para o CosNaming que
# suporta o RMI-IIOP dinâmico.
java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl
org.omg.CORBA.ORBInitialHost=localhost
org.omg.CORBA.ORBInitialPort=3700
As linhas 7 e 8 indicam a máquina do serviço JNDI e a porta de escuta do mesmo. Esse arquivo não permite consultar um servidor JNDI que não seja o localhost ou que opere em uma porta diferente da 3700. Se quisermos alterar esses dois parâmetros, podemos criar nosso próprio arquivo [jndi.properties] ou utilizar uma configuração do Spring. Mostraremos essa segunda técnica.
Começamos criando um novo projeto a partir do projeto inicial [pam-client-metier-dao-jpa-eclipselink].
![]() |
- em [1], o novo projeto
- em [2], o arquivo de configuração do Spring [spring-config-client.xml]. Seu conteúdo é o seguinte:
O arquivo de configuração do Spring é o seguinte:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">
<!-- função -->
<jee:jndi-lookup id="metier" jndi-name="java:global/istia.st_mv-pam-ejb-metier-dao-eclipselink_ejb_1.0-SNAPSHOT/Metier!metier.IMetierRemote">
<jee:environment>
java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory
java.naming.factory.url.pkgs=com.sun.enterprise.naming
java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl
org.omg.CORBA.ORBInitialHost=localhost
org.omg.CORBA.ORBInitialPort=3700
</jee:environment>
</jee:jndi-lookup>
</beans>
Utilizamos aqui uma tag <jee> (linha 14) introduzida no Spring 2.0. O uso dessa tag requer a definição do esquema ao qual ela pertence, nas linhas 4, 10 e 11.
- linha 14: a tag <jee:jndi-lookup> permite obter a referência de um objeto junto a um serviço JNDI. Aqui, associamos o bean chamado “metier” ao recurso JNDI, associado ao EJB e ao [Metier]. O nome JNDI utilizado aqui é o nome portátil (Java EE 6) do EJB.
- O conteúdo do arquivo [jndi.properties] passa a ser o conteúdo da tag <jee:environment> (linha 15), que serve para definir os parâmetros de conexão com o serviço JNDI.
A classe principal [MainRemote] sofre as seguintes alterações:
Nas linhas 7-8, a referência do tipo [IMetierRemote] na camada [metier] é solicitada ao Spring. Essa solução traz flexibilidade à nossa arquitetura. De fato, se o EJB da camada [metier] se tornasse local, c.a.d. fosse executado na mesma JVM que nosso cliente [MainRemote], o código deste último não mudaria. Apenas o conteúdo do arquivo [spring-config-client.xml] seria alterado. Encontraríamos, então, uma configuração análoga à arquitetura Spring / JPA estudada no parágrafo 5.11.
Convidamos o leitor a testar essa nova versão.
7.4. O cliente Swing
Agora, vamos construir o cliente swing de nossa aplicação cliente/servidor EJB.
![]() |
O arquivo [pom.xml] deve ter a dependência necessária para as aplicações Swing:
<dependency>
<groupId>org.swinglabs</groupId>
<artifactId>swing-layout</artifactId>
<version>1.0.3</version>
</dependency>
Acima, a classe [PamJFrame] havia sido escrita inicialmente para ser executada em um ambiente Spring / JPA:
![]() |
Agora, essa classe deve se tornar o cliente remoto de um EJB implantado no servidor Glassfish.
![]() |
Exercício prático: seguindo o exemplo do cliente de console [ui.console.MainRemote] do projeto, altere a forma como o método [doMyInit] (ver parágrafo 5.12.4) da classe [PamJFrame] para obter uma referência à camada [metier], que agora está remota.

























