Skip to content

7. Versão 3: Portabilidade da aplicação PAM para um servidor de aplicações Glassfish

Propõe-se colocar os EJB das camadas [metier] e [DAO] da arquitetura OpenEJB / EclipseLink no contentor de um servidor de aplicações Glassfish.

A implementação atual com OpenEJB / EclipseLink

Acima, a camada [ui] utiliza a interface remota da camada [metier].

Testámos dois contextos de execução: local e distant. Neste último modo, a camada [ui] era cliente da camada [metier], camada implementada por EJB. Para funcionar 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. Este servidor é fornecido com o NetBeans.

A implementação a construir com o servidor Glassfish

  • a camada [ui] será executada num ambiente Java SE (Standard Edition)
  • As camadas [metier, DAO, JPA] serão executadas num ambiente Java EE (Enterprise Edition) num servidor Glassfish v3
  • o cliente comunicará com o servidor através de uma rede TCP/IP. As trocas de dados em rede são transparentes para o programador, embora este deva estar ciente de que o cliente e o servidor trocam objetos serializados para comunicar, e não referências a objetos. O protocolo de rede utilizado para estas trocas denomina-se RMI (Remote Method Invocation), um protocolo que só pode ser utilizado 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á alojada pelo contentor EJB3 do servidor Glassfish:

Trata-se de fazer uma migração para o servidor Glassfish do que já foi feito e testado com o contentor OpenEJB. É aí que reside o interesse do OpenEJB e, em geral, dos contentores EJB incorporados: permitem-nos testar a aplicação num ambiente de execução simplificado. Quando a aplicação tiver sido testada, basta portá-la para um servidor de destino, neste caso, o servidor Glassfish.

7.1.1.1. O projeto NetBeans

Comecemos por criar um novo projeto NetBeans:

  • em [1], novo projeto
  • em [2], selecionar a categoria Maven e, em [3], o tipo EJB Módulo. Trata-se, de facto, de criar um projeto que será alojado e executado por um contentor EJB, o do servidor Glassfish.
  • com o botão [4a], selecione a pasta pai da pasta do projeto ou digite o seu nome diretamente em [4b].
  • em [5], atribua um nome ao projeto
  • em [6], selecione o servidor de aplicações no qual será executado. O selecionado aqui é um dos que aparecem no separador [Runtime / Servers], neste caso o Glassfish v3.
  • em [7], selecione a versão do Java EE.
  • em [1], o novo projeto. Este difere de um projeto Java clássico em alguns aspetos:
    • é criada automaticamente uma ramificação [Other Sources] [2]. Esta irá conter, nomeadamente, o ficheiro [persistence.xml] que configura a camada JPA,
    • se compilarmos o projeto (Build), surge uma dependência [javaee-api-6.0] do [3]. É do tipo provided, uma vez que é fornecida em tempo de execução pelo contentor 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 ficheiro [persistence.xml], que define:

  • a implementação JPA a utilizar
  • a definição da fonte de dados utilizada pela camada JPA. Esta será uma fonte JDBC gerida pelo servidor Glassfish.

Pode-se proceder da seguinte forma. Em primeiro lugar, no separador [Runtime / Databases], irá criar-se uma ligação à base de dados MySQL5 / dbpam_eclipselink:

Feito isto, podemos passar à criação do recurso JDBC utilizado pelo módulo EJB:

  • no [1], criar um novo ficheiro – certifique-se de que o projeto EJB está selecionado antes de realizar esta operação
  • em [2], o projeto EJB
  • em [3], selecione a categoria [Glassfish]
  • em [4], pretende-se criar um recurso JDBC
  • em [5], indicar que o recurso JDBC irá utilizar um novo conjunto de ligações. Recorde-se que um conjunto de ligações é um conjunto de ligações abertas que serve para acelerar as trocas de dados entre a aplicação e a base de dados.
  • em [6], atribuir o nome JNDI ao recurso JDBC criado. Este nome pode ser qualquer um, mas tem frequentemente o formato jdbc/nom. Este nome, JNDI, será utilizado no ficheiro [persistence.xml] para designar a fonte de dados que a implementação JPA deve utilizar.
  • No [7], atribua um nome (que pode ser qualquer um) ao conjunto de ligações que vai ser criado
  • na lista suspensa [8], selecione a ligação JDBC criada anteriormente com base em MySQL / dbpam_eclipselink.
  • Em [9], é apresentado um resumo das propriedades do conjunto de ligações — não é necessário alterar nada
  • em [10], é possível especificar várias propriedades do conjunto de ligações — mantêm-se os valores predefinidos
  • em [11], após a conclusão do assistente de criação de um recurso JDBC para o módulo EJB, foi criado um ficheiro [glassfish-resources.xml] no ramo [Other Sources]. O conteúdo deste ficheiro é 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 ficheiro [glassfish-resources.xml] é um ficheiro XML que contém todos os dados recolhidos pelo assistente. Será utilizado pelo NetBeans para, aquando da implementação do módulo EJB no servidor GlassFish, solicitar a criação do recurso JDBC de que este módulo necessita.

Agora já é possível criar o ficheiro [persistence.xml], que irá configurar a camada JPA do módulo EJB:

  • em [1], criar um novo ficheiro – certifique-se de que o projeto EJB está selecionado antes de realizar esta operação
  • no [2], o projeto EJB
  • em [3], seleciona-se a categoria [Persistence]
  • em [4], pretende-se criar uma unidade de persistência
  • em [5], atribuir 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 colocadas juntamente 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], indicar que as transações são geridas pelo contentor EJB
  • em [9], indicar que não deve ser realizada nenhuma operação na fonte de dados durante a implementação do módulo EJB no servidor. Com efeito, o módulo EJB irá utilizar uma base de dados [dbpam_eclipselink] já criada.
  • No final do assistente, foi criado um ficheiro [persistence.xml] [10]. O 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 contentor 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. Serão procuradas no Classpath do módulo EJB.
  • O nome da implementação JPA (Hibernate, EclipseLink, ...) utilizada não está indicado. Neste caso, o Glassfish v3 utiliza, por predefinição, EclipseLink.

7.1.1.3. Inserção das camadas [jpa, DAO, metier]

Agora que o ficheiro [persistence.xml] foi definido, podemos passar à inserção no projeto das camadas [metier, dao, jpa] da aplicação empresarial [pam]:

Estas três camadas são idênticas às que existiam no OpenEJB. É possível efetuar uma simples operação de copiar/colar entre os dois projetos. É isso que vamos fazer 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 aspetos:

  • a camada JPA é implementada por EclipseLink. Temos de garantir que o servidor Glassfish dispõe das bibliotecas desta implementação JPA.
  • a fonte de dados é uma base de dados MySQL. Temos de garantir que o servidor Glassfish dispõe do controlador JDBC para esta base de dados SGBD.

É possível detetar a ausência destas bibliotecas durante a implementação do módulo EJB. Aqui está uma das várias formas de proceder para adicionar as bibliotecas em falta ao servidor Glassfish:

  • em [1], visualize as propriedades do servidor Glassfish
  • em [2], anote a pasta dos domínios do servidor. Anotamos-a a seguir como <domains>
  • na pasta <domains>\domain1\lib, coloque as bibliotecas em falta. No exemplo, foram adicionadas as bibliotecas do Hibernate (lib / hibernate-tools) e o controlador JDBC de MySQL (lib / divers). Por predefinição, o servidor Glassfish já possui as bibliotecas de EclipseLink. Por isso, apenas será adicionado o controlador JDBC de MySQL.
  • em [1], no separador [Services], iniciamos o servidor Glassfish v3
  • em [2], que está ativo

7.1.1.5. Implantação do módulo EJB

Implantamos agora o módulo EJB no servidor Glassfish:

  • em [1], o módulo EJB é implementado
  • em [2], a árvore de diretórios do servidor Glassfish é atualizada
  • em [3], após a implementaçã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. Recorde-se que o tínhamos definido no parágrafo 7.1.1.2.

Durante a implementação, o servidor Glassfish regista na consola algumas informações interessantes:

INFO: Realm admin-realm of classtype com.sun.enterprise.security.auth.realm.file.FileRealm successfully created.
....
INFO: Portable JNDI names for EJB IndemniteDao : [java:global/pam-serveur-metier-dao-jpa-eclipselink/IndemniteDao!DAO.IIndemniteDaoLocal, java:global/pam-serveur-metier-dao-jpa-eclipselink/IndemniteDao!DAO.IIndemniteDaoRemote]
INFO: Glassfish-specific (Non-portable) JNDI names for EJB IndemniteDao : [DAO.IIndemniteDaoRemote#DAO.IIndemniteDaoRemote, DAO.IIndemniteDaoRemote]
...
INFO: Portable JNDI names for EJB CotisationDao : [java:global/pam-serveur-metier-dao-jpa-eclipselink/CotisationDao!DAO.ICotisationDaoLocal, java:global/pam-serveur-metier-dao-jpa-eclipselink/CotisationDao!DAO.ICotisationDaoRemote]
INFO: Glassfish-specific (Non-portable) JNDI names for EJB CotisationDao : [DAO.ICotisationDaoRemote, DAO.ICotisationDaoRemote#DAO.ICotisationDaoRemote]
INFO: Portable JNDI names for EJB Metier : [java:global/pam-serveur-metier-dao-jpa-eclipselink/Metier!metier.IMetierRemote, java:global/pam-serveur-metier-dao-jpa-eclipselink/Metier!metier.IMetierLocal]
INFO: Glassfish-specific (Non-portable) JNDI names for EJB Metier : [metier.IMetierRemote#metier.IMetierRemote, metier.IMetierRemote]
...
INFO: Portable JNDI names for EJB EmployeDao : [java:global/pam-serveur-metier-dao-jpa-eclipselink/EmployeDao!DAO.IEmployeDaoLocal, java:global/pam-serveur-metier-dao-jpa-eclipselink/EmployeDao!DAO.IEmployeDaoRemote]
INFO: Glassfish-specific (Non-portable) JNDI names for EJB EmployeDao : [DAO.IEmployeDaoRemote#DAO.IEmployeDaoRemote, DAO.IEmployeDaoRemote]
INFO: pam-serveur-metier-dao-jpa-eclipselink was successfully deployed in 12 891 milliseconds.

Repare-se nas linhas

  • 3, 6, 8 e 11 os nomes portáteis JNDI dos EJB implementados. O Java EE 6 introduziu o conceito de nome portátil JNDI. Isto significa que um nome JNDI é reconhecido por todos os servidores Java EE 6. Com o Java EE 5, os nomes JNDI são específicos do servidor utilizado.
  • 4, 7, 9, 12: os nomes JNDI dos EJB implementados de uma forma específica para o Glassfish v3.

Estes nomes serão úteis para a aplicação de consola que vamos escrever para utilizar o módulo EJB implementado.

7.2. Consola do cliente - versão 1

Agora que implementámos a parte do servidor da nossa aplicação cliente/servidor, passamos a analisar a parte do cliente [1]:

7.2.1. O projeto do cliente

Criamos um novo projeto Maven do tipo [Java Application] denominado [mv-pam-client-ejb-metier-dao-eclipselink]:

  • no [1], o projeto do cliente

No ficheiro [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 comunique com um servidor remoto,
  • linhas 36-41: a dependência do projeto Maven do módulo EJB. Pretendemos aqui recuperar as definições das entidades JPA e das várias 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] é alterado da seguinte forma:


// Está tudo bem — já podemos pedir a folha de vencimento
    FeuilleSalaire feuilleSalaire = null;
    IMetierRemote metier = null;
    try {
      // contexto JNDI do servidor Glassfish
      InitialContext initialContext = new InitialContext();
      // instanciação da camada de negócio
      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 este contexto JNDI uma referência à interface remota da camada [metier]. De acordo com os registos do Glassfish, sabe-se que a interface remota da camada [metier] tem dois nomes possíveis:
Infos: EJB5181:Portable JNDI names for EJB Metier: [java:global/istia.st_mv-pam-ejb-metier-dao-eclipselink_ejb_1.0-SNAPSHOT/Metier!metier.IMetierLocal, java:global/istia.st_mv-pam-ejb-metier-dao-eclipselink_ejb_1.0-SNAPSHOT/Metier!metier.IMetierRemote]
Infos: EJB5182:Glassfish-specific (Non-portable) JNDI names for EJB Metier: [metier.IMetierRemote#metier.IMetierRemote, metier.IMetierRemote]

Linha 1: o nome JNDI, utilizável com qualquer servidor de aplicações JAVA, EE, 6. Linha 2: o nome JNDI, específico do Glassfish. No código, na linha 9, utilizamos o nome JNDI, que é portátil.

  • O resto do código não sofre alterações

Em [1], configuramos o projeto para que execute a classe [MainRemote] com argumentos. Se tudo correr bem, a execução do projeto produz o seguinte resultado:

run:
Valeurs saisies :
N° de sécurité sociale de l'employé : 254104940426058
Nombre d'heures travaillées : 150
Nombre de jours travaillés : 20

Informations Employé : 
Nom : Jouveinal
Prénom : Marie
Adresse : 5 rue des oiseaux
Ville : St Corentin
Code Postal : 49203
Indice : 2

Informations Cotisations : 
CSGRDS : 3.49 %
CSGD : 6.15 %
Retraite : 7.88 %
Sécurité sociale : 9.39 %

Informations Indemnités : 
Salaire horaire : 2.1 euro
Entretien/jour : 2.1 euro
Repas/jour : 3.1 euro
Congés Payés : 15.0 %

Informations Salaire : 
Salaire de base : 362.25 euro
Cotisations sociales : 97.48 euro
Indemnités d'entretien : 42.0 euro
Indemnités de repas : 62.0 euro
Salaire net : 368.77 euro

BUILD SUCCESSFUL (total time: 2 seconds)

Se, nas propriedades, for introduzido um número de segurança social incorreto, obtém-se o seguinte resultado:

1
2
3
run:
L'erreur suivante s'est produite : L'employé de n°[254104940426058x] est introuvable
BUILD SUCCESSFUL (total time: 2 seconds)

7.3. Consola do cliente - versão 2

Nas versões anteriores, o ambiente JNDI do servidor Glassfish era configurado a partir de um ficheiro [jndi.properties] que se encontrava algures nos arquivos do projeto. O seu conteúdo por predefiniçã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 o servidor do serviço JNDI e a porta de escuta do mesmo. Este ficheiro não permite consultar um servidor JNDI que não seja o localhost ou que funcione numa porta diferente da porta 3700. Se pretender alterar estes dois parâmetros, pode criar o seu próprio ficheiro [jndi.properties] ou utilizar uma configuração Spring. Apresentamos esta segunda técnica.

Começamos por criar um novo projeto a partir do projeto inicial [pam-client-metier-dao-jpa-eclipselink].

  • em [1], o novo projeto
  • em [2], o ficheiro de configuração do Spring [spring-config-client.xml]. O seu conteúdo é o seguinte:

O ficheiro 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 baliza <jee> (linha 14) introduzida com o Spring 2.0. A utilização desta baliza requer a definição do esquema ao qual pertence, nas linhas 4, 10 e 11.

  • linha 14: a baliza <jee:jndi-lookup> permite obter a referência de um objeto junto de um serviço JNDI. Aqui, associamos o bean denominado «metier» ao recurso JNDI associado ao EJB [Metier]. O nome JNDI utilizado aqui é o nome portátil (Java EE 6) do EJB.
  • O conteúdo do ficheiro [jndi.properties] passa a ser o conteúdo da baliza <jee:environment> (linha 15), que serve para definir os parâmetros de ligação ao serviço JNDI.

A classe principal [MainRemote] evolui da seguinte forma:

...
     // Está tudo bem — já podemos pedir a folha de vencimento
    FeuilleSalaire feuilleSalaire = null;
    IMetierRemote metier=null;
    try {
       // instanciação da camada [metier]
      ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config-client.xml");
      metier = (IMetierRemote) ctx.getBean("metier");
       // 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;
    }
    ...

Nas linhas 7-8, é solicitada ao Spring a referência de tipo [IMetierRemote] na camada [metier]. Esta solução confere flexibilidade à nossa arquitetura. Com efeito, se o EJB da camada [metier] se tornasse local, c.a.d. executado na mesma JVM que o nosso cliente [MainRemote], o código deste último não se alteraria. Apenas o conteúdo do ficheiro [spring-config-client.xml] mudaria. Encontraríamos então uma configuração análoga à arquitetura Spring / JPA analisada no parágrafo 5.11.

Convidamos o leitor a testar esta nova versão.

7.4. O cliente Swing

Vamos agora construir o cliente swing da nossa aplicação cliente/servidor EJB.

O ficheiro [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] tinha sido inicialmente escrita para ser executada num ambiente Spring / JPA:

Agora, esta classe deve tornar-se o cliente remoto de um EJB implementado no servidor Glassfish.


Exercício prático: seguindo o exemplo do cliente de consola [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 se encontra remota.