Skip to content

7. Versione 3: Porting dell’applicazione PAM su un server applicativo Glassfish

Si propone di collocare i EJB dei livelli [metier] e [DAO] dell’architettura OpenEJB / EclipseLink nel contenitore di un server di applicazioni Glassfish.

L'implementazione attuale con OpenEJB / EclipseLink

Come illustrato sopra, il livello [ui] utilizza l'interfaccia remota del livello [metier].

Abbiamo testato due contesti di esecuzione: local e distant. In quest’ultimo caso, il livello [ui] era client del livello [metier], livello implementato da EJB. Per operare in modalità client/server, in cui il client e il server vengono eseguiti in due JVM distinti, collocheremo i livelli [metier, DAO, jpa] sul server Java Glassfish EE. Questo server è fornito con NetBeans.

L'implementazione da realizzare con il server Glassfish

  • il livello [ui] verrà eseguito in un ambiente Java SE (Standard Edition)
  • I layer [metier, DAO, JPA] verranno eseguiti in un ambiente Java EE (Enterprise Edition) su un server Glassfish v3
  • il client comunicherà con il server tramite una rete TCP/IP. Gli scambi di rete sono trasparenti per lo sviluppatore, ma è comunque necessario che questi sia consapevole del fatto che il client e il server si scambiano oggetti serializzati per comunicare, e non riferimenti agli oggetti. Il protocollo di rete utilizzato per questi scambi si chiama RMI (Remote Method Invocation), un protocollo utilizzabile esclusivamente tra due applicazioni Java.
  • L’implementazione JPA utilizzata sul server Glassfish sarà EclipseLink.

7.1. La parte server dell’applicazione client/server PAM

7.1.1. L’architettura dell’applicazione

Qui esaminiamo la parte server che sarà ospitata dal contenitore EJB3 del server Glassfish:

Si tratta di effettuare un porting sul server Glassfish di ciò che è già stato realizzato e testato con il contenitore OpenEJB. È proprio questo il vantaggio di OpenEJB e, in generale, dei contenitori EJB integrati: ci consentono di testare l’applicazione in un ambiente di esecuzione semplificato. Una volta testata l’applicazione, non resta che trasferirla su un server di destinazione, in questo caso il server Glassfish.

7.1.1.1. Il progetto NetBeans

Iniziamo creando un nuovo progetto NetBeans:

  • in [1], nuovo progetto
  • in [2], scegliere la categoria Maven e in [3] il tipo EJB Modulo. Si tratta infatti di creare un progetto che sarà ospitato ed eseguito da un contenitore EJB, quello del server Glassfish.
  • utilizzando il pulsante [4a], selezionare la cartella principale della cartella del progetto oppure digitarne direttamente il nome in [4b].
  • in [5], assegnare un nome al progetto
  • in [6], selezionare il server delle applicazioni su cui verrà eseguito. Quello selezionato qui è uno di quelli visibili nella scheda [Runtime / Servers], in questo caso Glassfish v3.
  • in [7], selezionare la versione di Java EE.
  • in [1], il nuovo progetto. Si differenzia da un progetto Java classico per alcuni aspetti:
    • viene creato automaticamente un ramo [Other Sources] [2]. Esso conterrà in particolare il file [persistence.xml] che configura il livello JPA,
    • se si esegue la compilazione (Build) del progetto, compare una dipendenza [javaee-api-6.0] da [3]. È di tipo provided poiché viene fornita in fase di esecuzione dal contenitore EJB di Glassfish.

7.1.1.2. Configurazione del livello di persistenza

Per configurazione del livello di persistenza si intende la creazione del file [persistence.xml] che definisce:

  • l’implementazione JPA da utilizzare
  • la definizione della fonte dati utilizzata dal livello JPA. Si tratterà di una fonte JDBC gestita dal server Glassfish.

Si potrà procedere come segue. Innanzitutto, nella scheda [Runtime / Databases], si creerà una connessione alla base dati MySQL5 / dbpam_eclipselink:

Fatto ciò, si può procedere alla creazione della ris e JDBC utilizzata dal modulo EJB:

  • in [1], creare un nuovo file – assicurarsi che il progetto EJB sia selezionato prima di eseguire questa operazione
  • in [2], il progetto EJB
  • in [3], selezionare la categoria [Glassfish]
  • in [4], si desidera creare una risorsa JDBC
  • in [5], indicare che la risorsa JDBC utilizzerà un nuovo pool di connessioni. Si ricorda che un pool di connessioni è un insieme di connessioni aperte che serve ad accelerare gli scambi dell’applicazione con il database.
  • in [6], assegnare il nome JNDI alla risorsa JDBC appena creata. Questo nome può essere qualsiasi, ma spesso assume la forma jdbc/nom. Questo nome JNDI verrà utilizzato nel file [persistence.xml] per indicare la fonte di dati che l’implementazione JPA deve utilizzare.
  • In [7], assegnare un nome a scelta al pool di connessioni che verrà creato
  • nell'elenco a discesa [8], selezionare la connessione JDBC creata in precedenza sulla base di MySQL / dbpam_eclipselink.
  • In [9], viene visualizzato un riepilogo delle proprietà del pool di connessioni: non modificare nulla
  • in [10], è possibile specificare diverse proprietà del pool di connessioni - si mantengono i valori predefiniti
  • in [11], al termine della procedura guidata di creazione di una risorsa JDBC per il modulo EJB, è stato creato un file [glassfish-resources.xml] nel ramo [Other Sources]. Il contenuto di questo file è il seguente:

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

Il file [glassfish-resources.xml] è un file XML che riporta tutti i dati raccolti dall'assistente. Verrà utilizzato da NetBeans per richiedere, durante la distribuzione del modulo EJB sul server GlassFish, la creazione della risorsa JDBC necessaria a tale modulo.

È ora possibile creare il file [persistence.xml] che configurerà il livello JPA del modulo EJB:

  • in [1], creare un nuovo file – assicurarsi che il progetto EJB sia selezionato prima di eseguire questa operazione
  • in [2], il progetto EJB
  • in [3], si seleziona la categoria [Persistence]
  • in [4], si desidera creare un'unità di persistenza
  • in [5], si assegna un nome all’unità di persistenza
  • in [6], vengono proposte diverse implementazioni JPA. In questo caso si sceglierà [EclipseLink]. È possibile utilizzare altre implementazioni a condizione di integrare le librerie che le implementano con quelle del server Glassfish.
  • Nel menu a tendina [7], selezionare la fonte dati JDBC [jdbc/dbpam_eclipselink] appena creata.
  • In [8], specificare che le transazioni sono gestite dal contenitore EJB
  • in [9], specificare che non deve essere eseguita alcuna operazione sulla fonte dati durante la distribuzione del modulo EJB sul server. Infatti, il modulo EJB utilizzerà un database [dbpam_eclipselink] già creato.
  • Al termine della procedura guidata, è stato creato un file [persistence.xml] [10]. Il suo contenuto è il seguente:

<?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>
  • riga 3: il nome dell’unità di persistenza [mv-pam-ejb-metier-dao-eclipselinkPU] e il tipo di transazioni (JTA per un contenitore EJB)
  • riga 5: il nome JNDI della fonte dati utilizzata dal livello di persistenza: jdbc/dbpam_eclipselink
  • riga 6: le entità JPA non sono specificate. Verranno ricercate nel Classpath del modulo EJB.
  • Il nome dell'implementazione JPA (Hibernate, EclipseLink, ...) utilizzata non è specificato. In questo caso, Glassfish v3 utilizza per impostazione predefinita EclipseLink.

7.1.1.3. Inserimento dei livelli [jpa, DAO, metier]

Ora che il file [persistence.xml] è stato definito, possiamo procedere all’inserimento nel progetto dei livelli [metier, dao, jpa] dell’applicazione aziendale [pam]:

Questi tre livelli sono identici a quelli presenti in OpenEJB. È possibile procedere con un semplice copia/incolla tra i due progetti. È proprio quello che faremo ora:

  • in [1], il risultato della copia dei pacchetti [jpa, dao, metier, exception] dal progetto [mv-pam-openejb-eclipselink] nel modulo EJB [mv-pam-ejb-metier-dao-jpa-eclipselink]

7.1.1.4. Configurazione del server Glassfish

Resta da configurare il server Glassfish su due punti:

  • il livello JPA è implementato da EclipseLink. Dobbiamo assicurarci che il server Glassfish disponga delle librerie relative a tale implementazione JPA.
  • la fonte dati è un database MySQL. Dobbiamo assicurarci che il server Glassfish disponga del driver JDBC per questo SGBD.

È possibile rilevare la mancanza di queste librerie durante la distribuzione del modulo EJB. Ecco uno dei modi per aggiungere le librerie mancanti al server Glassfish:

  • in [1], visualizzare le proprietà del server Glassfish
  • in [2], prendere nota della cartella dei domini del server. La indicheremo in seguito come <domains>
  • nella cartella <domains>\domain1\lib, inserire le librerie mancanti. Nell’esempio, sono state aggiunte le librerie di Hibernate (lib / hibernate-tools) e il driver JDBC di MySQL (lib / vari). Per impostazione predefinita, il server Glassfish dispone delle librerie di EclipseLink. Si aggiungerà quindi solo il driver JDBC di MySQL.
  • in [1], nella scheda [Services], avviamo il server Glassfish v3
  • in [2], è attivo

7.1.1.5. Distribuzione del modulo EJB

Ora distribuiamo il modulo EJB sul server Glassfish:

  • in [1], il modulo EJB è stato distribuito
  • in [2], la struttura del server Glassfish viene aggiornata
  • in [3], dopo la distribuzione, il modulo EJB compare nel ramo [Applications] del server Glassfish
  • in [4], la risorsa JDBC [jdbc / dbpam_eclipselink] è stata creata sul server Glassfish. Ricordiamo che l’avevamo definita nel paragrafo 7.1.1.2.

Durante la distribuzione, il server Glassfish registra nella console alcune informazioni interessanti:

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.

Si noti che alle righe

  • 3, 6, 8 e 11 i nomi portabili JNDI delle istanze EJB distribuite. Java EE 6 ha introdotto il concetto di nome portabile JNDI. Ciò indica un nome JNDI riconosciuto da tutti i server Java EE 6. Con Java EE 5, i nomi JNDI sono specifici del server utilizzato.
  • 4, 7, 9, 12: i nomi JNDI dei EJB distribuiti in una forma specifica per Glassfish v3.

Questi nomi saranno utili all’applicazione console che scriveremo per utilizzare il modulo EJB distribuito.

7.2. Console client - versione 1

Ora che abbiamo distribuito la parte server della nostra applicazione client/server, passiamo ad analizzare la parte client [1]:

7.2.1. Il progetto client

Creiamo un nuovo progetto Maven di tipo [Java Application] denominato [mv-pam-client-ejb-metier-dao-eclipselink]:

  • in [1], il progetto del cliente

Nel file [pom.xml], aggiungiamo le seguenti dipendenze:


<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>
  • righe 31-35: la dipendenza dalla libreria [gf-client], che consente a un client Classfish di comunicare con un server remoto,
  • righe 36-41: la dipendenza dal progetto Maven del modulo EJB. In questo caso vogliamo recuperare le definizioni delle entità JPA e quelle delle diverse interfacce, nonché quella della classe di eccezione [PamException],

Dal progetto [mv-pam-openejb-eclipselink], copiamo la classe [MainRemote]:

La classe [MainRemote] deve ottenere un riferimento alla classe EJB del livello [metier]. Il codice della classe [MainRemote] viene modificato come segue:


// Va bene, possiamo richiedere la busta paga
    FeuilleSalaire feuilleSalaire = null;
    IMetierRemote metier = null;
    try {
      // contesto JNDI del server Glassfish
      InitialContext initialContext = new InitialContext();
      // istanziazione del livello business
      metier = (IMetierRemote) initialContext.lookup("java:global/istia.st_mv-pam-ejb-metier-dao-eclipselink_ejb_1.0-SNAPSHOT/Metier!metier.IMetierRemote");
      // calcolo della busta paga
      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;
    }
  • riga 6: inizializzazione del contesto JNDI del server Glassfish.
  • riga 8: a questo contesto JNDI viene richiesto un riferimento all’interfaccia remota del livello [metier]. Dai log di Glassfish si evince che l’interfaccia remota del livello [metier] ha due possibili nomi:
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]

Riga 1: il nome JNDI, utilizzabile con qualsiasi server di applicazioni JAVA, EE, ecc. Riga 2: il nome JNDI, specifico per GlassFish. Nel codice, alla riga 9, utilizziamo il nome portabile JNDI.

  • Il resto del codice rimane invariato

In [1], si configura il progetto in modo che esegua la classe [MainRemote] con degli argomenti. Se tutto va bene, l’esecuzione del progetto produce il seguente risultato:

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 nelle proprietà si inserisce un numero di previdenza sociale errato, si ottiene il seguente risultato:

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. Console client - versione 2

Nelle versioni precedenti, l’ambiente JNDI del server Glassfish veniva configurato a partire da un file [jndi.properties] presente da qualche parte negli archivi del progetto. Il suo contenuto predefinito è il seguente:


# accesso a Sun Application Server tramite JNDI
java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory
java.naming.factory.url.pkgs=com.sun.enterprise.naming
# È necessario aggiungere un javax.naming.spi.StateFactory per CosNaming che
# supporti il RMI-IIOP dinamico.
java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl
org.omg.CORBA.ORBInitialHost=localhost
org.omg.CORBA.ORBInitialPort=3700

Le righe 7 e 8 indicano il computer su cui è in esecuzione il servizio JNDI e la porta di ascolto dello stesso. Questo file non consente di interrogare un server JNDI diverso da localhost o che operi su una porta diversa dalla porta 3700. Se si desidera modificare questi due parametri, è possibile creare un proprio file [jndi.properties] oppure utilizzare una configurazione Spring. Illustreremo questa seconda tecnica.

Iniziamo creando un nuovo progetto a partire dal progetto iniziale [pam-client-metier-dao-jpa-eclipselink].

  • in [1], il nuovo progetto
  • in [2], il file di configurazione Spring [spring-config-client.xml]. Il suo contenuto è il seguente:

Il file di configurazione di Spring è il seguente:


<?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">

  <!-- professione -->
  <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>

Qui utilizziamo un tag <jee> (riga 14) introdotto con Spring 2.0. L'uso di questo tag richiede la definizione dello schema a cui appartiene, righe 4, 10 e 11.

  • riga 14: il tag <jee:jndi-lookup> consente di ottenere il riferimento a un oggetto da un servizio JNDI. Qui si associa il bean denominato "metier" alla risorsa JNDI associata a EJB e [Metier]. Il nome JNDI qui utilizzato è il nome portabile (Java EE 6) di EJB.
  • Il contenuto del file [jndi.properties] diventa il contenuto del tag <jee:environment> (riga 15), che serve a definire i parametri di connessione al servizio JNDI.

La classe principale [MainRemote] si evolve come segue:

...
     // Va bene - si può richiedere la busta paga
    FeuilleSalaire feuilleSalaire = null;
    IMetierRemote metier=null;
    try {
       // istanza del livello [metier]
      ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config-client.xml");
      metier = (IMetierRemote) ctx.getBean("metier");
       // calcolo della busta paga
      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;
    }
    ...

Righe 7-8: viene richiesto a Spring il riferimento di tipo [IMetierRemote] sul livello [metier]. Questa soluzione apporta flessibilità alla nostra architettura. Infatti, se l'EJB del livello [metier] diventasse locale, c.a.d. verrebbe eseguito nello stesso JVM del nostro client [MainRemote], il codice di quest’ultimo non cambierebbe. Cambierebbe solo il contenuto del file [spring-config-client.xml]. Si otterrebbe quindi una configurazione analoga all'architettura Spring / JPA esaminata nel paragrafo 5.11.

Il lettore è invitato a provare questa nuova versione.

7.4. Il client Swing

Ora realizziamo il client swing della nostra applicazione client/server EJB.

Il file [pom.xml] deve avere le dipendenze necessarie per le applicazioni Swing:


    <dependency>
      <groupId>org.swinglabs</groupId>
      <artifactId>swing-layout</artifactId>
      <version>1.0.3</version>
</dependency>

In precedenza, la classe [PamJFrame] era stata inizialmente scritta per essere eseguita in un ambiente Spring / JPA:

Ora questa classe deve diventare il client remoto di un EJB distribuito sul server Glassfish.


Esercitazione pratica: seguendo l’esempio del client console [ui.console.MainRemote] del progetto, modificare il modo in cui il metodo [doMyInit] (cfr. paragrafo 5.12.4) della classe [PamJFrame] per acquisire un riferimento al livello [metier], che ora è remoto.