7. Versione 3: Porting dell'applicazione PAM su un server applicativo GlassFish
Proponiamo di collocare gli EJB dei livelli [business] e [DAO] dell'architettura OpenEJB/EclipseLink nel container di un server applicativo GlassFish.
L'attuale implementazione con OpenEJB / EclipseLink
![]() |
Come illustrato sopra, il livello [ui] utilizza l'interfaccia remota del livello [business].
Abbiamo testato due contesti di esecuzione: locale e remoto. In quest'ultima modalità, il livello [ui] ha agito come client del livello [business], implementato da EJB. Per operare in modalità client/server, in cui client e server girano su due JVM separate, distribuiremo i livelli [business, DAO, JPA] sul server Java EE GlassFish. Questo server è incluso in NetBeans.
L'implementazione da realizzare con il server GlassFish
![]() |
- il livello [ui] girerà in un ambiente Java SE (Standard Edition)
- I livelli [logica di business, DAO, JPA] gireranno in un ambiente Java EE (Enterprise Edition) su un server GlassFish v3
- Il client comunicherà con il server tramite una rete TCP/IP. La comunicazione di rete è trasparente per lo sviluppatore, sebbene questi debba comunque essere consapevole del fatto che il client e il server scambiano oggetti serializzati per comunicare, non riferimenti a oggetti. Il protocollo di rete utilizzato per questa comunicazione è denominato RMI (Remote Method Invocation), un protocollo utilizzabile solo tra due applicazioni Java.
- L'implementazione JPA utilizzata sul server GlassFish sarà EclipseLink.
7.1. La parte server- e dell'applicazione client/server PAM
7.1.1. L'architettura dell'applicazione
Qui esaminiamo il componente lato server che sarà ospitato dal contenitore EJB3 del server GlassFish:
![]() |
L'obiettivo è quello di trasferire sul server GlassFish ciò che è già stato sviluppato e testato con il contenitore OpenEJB. Questo è il vantaggio di OpenEJB e, più in generale, dei contenitori EJB integrati: ci consentono di testare l'applicazione in un ambiente di runtime semplificato. Una volta che l'applicazione è stata testata, 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], selezionare la categoria Maven e in [3] selezionare il tipo di modulo EJB. L'obiettivo è quello di creare un progetto che verrà ospitato ed eseguito da un contenitore EJB, in particolare dal server GlassFish.
![]() |
- Utilizzando il pulsante [4a], selezionare la cartella principale per la cartella del progetto oppure digitare direttamente il suo nome in [4b].
- In [5], assegnare un nome al progetto
- In [6], seleziona 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 Java EE.
![]() |
- In [1], il nuovo progetto. Si differenzia da un progetto Java standard per alcuni aspetti:
- viene creato automaticamente un ramo [Altre fonti] [2]. Esso conterrà, in particolare, il file [persistence.xml] che configura il livello JPA,
- Se si compila il progetto (Build), compare una dipendenza [javaee-api-6.0] [3]. È di tipo "provided" perché viene fornita in fase di esecuzione dal contenitore EJB Glassfish.
7.1.1.2. Configurazione del livello di persistenza
Per "configurazione del livello di persistenza" si intende la scrittura 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.
![]() |
Possiamo procedere come segue. Innanzitutto, nella scheda [Runtime / Databases], creeremo [1] una connessione al database MySQL5 / dbpam_eclipselink:
![]() |
Una volta fatto ciò, possiamo passare alla creazione della risorsa 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], selezionare il progetto EJB
- In [3], selezionare la categoria [Glassfish]
- in [4], seleziona "Crea una risorsa JDBC"
![]() |
- in [5], specificare che la risorsa JDBC utilizzerà un nuovo pool di connessioni. Si noti che un pool di connessioni è un insieme di connessioni aperte utilizzato per velocizzare le interazioni dell’applicazione con il database.
- in [6], assegnare un nome JNDI alla risorsa JDBC creata. Questo nome può essere qualsiasi cosa, ma spesso assume la forma jdbc/nome. Questo nome JNDI verrà utilizzato nel file [persistence.xml] per designare l'origine dati che l'implementazione JPA deve utilizzare.
- In [7], assegnare un nome qualsiasi al pool di connessioni che verrà creato
- Nell'elenco a discesa [8], selezionare la connessione JDBC precedentemente creata per il database MySQL / dbpam_eclipselink.
- In [9], viene visualizzato un riepilogo delle proprietà del pool di connessioni: lasciare tutto com'è
![]() |
- In [10], è possibile specificare diverse proprietà del pool di connessioni: lasciare i valori predefiniti
- In [11], dopo aver completato la procedura guidata per la 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:
Il file [glassfish-resources.xml] è un file XML che contiene tutti i dati raccolti dalla procedura guidata. Verrà utilizzato da NetBeans per richiedere la creazione della risorsa JDBC richiesta da questo modulo durante la distribuzione del modulo EJB sul server GlassFish.
Ora puoi creare il file [persistence.xml], che servirà a configurare 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], selezionare il progetto EJB
- in [3], selezionare la categoria [Persistence]
- in [4], creare un'unità di persistenza
![]() |
- in [5], assegnare un nome all'unità di persistenza
- In [6], vengono offerte diverse implementazioni JPA. Qui, selezionare [EclipseLink]. È possibile utilizzare altre implementazioni a condizione che si includano le librerie che le implementano insieme a quelle del server GlassFish.
- Nell'elenco a discesa [7], selezionare l'origine dati JDBC [jdbc/dbpam_eclipselink] appena creata.
- In [8], specificare che le transazioni sono gestite dal contenitore EJB
- In [9], specificare che non devono essere eseguite operazioni sull'origine dati durante la distribuzione del modulo EJB sul server. Questo perché 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"?>
<!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>
- riga 3: il nome dell'unità di persistenza [mv-pam-ejb-metier-dao-eclipselinkPU] e il tipo di transazione (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 cercate nel classpath del modulo EJB.
- Il nome dell'implementazione JPA (Hibernate, EclipseLink, ecc.) utilizzata non è specificato. In questo caso, GlassFish v3 utilizza EclipseLink per impostazione predefinita.
7.1.1.3. Inserimento dei livelli [JPA, DAO, Business]
Ora che il file [persistence.xml] è stato definito, possiamo procedere all'inserimento dei livelli [business, DAO, JPA] dell'applicazione enterprise [pam] nel progetto:
![]() |
Questi tre livelli sono identici a quelli che erano con OpenEJB. Possiamo semplicemente copiare e incollare tra i due progetti. È quello che stiamo facendo ora:
![]() |
- in [1], il risultato della copia dei pacchetti [jpa, dao, business, exception] dal progetto [mv-pam-openejb-eclipselink] nel modulo EJB [mv-pam-ejb-business-dao-jpa-eclipselink]
7.1.1.4. Configurazione del server GlassFish
Dobbiamo ancora configurare il server GlassFish in due aree:
- Il livello JPA è implementato da EclipseLink. Dobbiamo assicurarci che il server GlassFish disponga delle librerie necessarie per questa implementazione JPA.
- L'origine dati è un database MySQL. Dobbiamo assicurarci che il server GlassFish disponga del driver JDBC per questo sistema di gestione del database.
Potresti scoprire che queste librerie mancano durante la distribuzione del modulo EJB. Ecco uno dei diversi modi per aggiungere le librerie mancanti al server GlassFish:
![]() |
- In [1], visualizza le proprietà del server GlassFish
- In [2], prendere nota della cartella dei domini del server. La chiameremo <domains>
- Nella cartella <domains>\domain1\lib, inserisci le librerie mancanti. Nell'esempio sono state aggiunte le librerie Hibernate (lib/hibernate-tools) e il driver JDBC di MySQL (lib/misc). Per impostazione predefinita, il server GlassFish include le librerie EclipseLink. Aggiungeremo 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 distribuiremo il modulo EJB sul server GlassFish:
![]() |
- In [1], il modulo EJB viene distribuito
- In [2], l'albero del server GlassFish viene aggiornato
- in [3], dopo la distribuzione, il modulo EJB appare nel ramo [Applications] del server GlassFish
- in [4], la risorsa JDBC [jdbc / dbpam_eclipselink] è stata creata sul server GlassFish. Ricordiamo che l'abbiamo definita nella Sezione 7.1.1.2.
Durante la distribuzione, il server GlassFish registra le seguenti informazioni nella console:
<?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>
Si noti che le righe
- 3, 6, 8 e 11: i nomi JNDI portabili degli EJB distribuiti. Java EE 6 ha introdotto il concetto di nomi JNDI portabili. Questo indica un nome JNDI riconosciuto da tutti i server Java EE 6. Con Java EE 5, i nomi JNDI sono specifici del server in uso.
- 4, 7, 9, 12: i nomi JNDI degli EJB distribuiti in un formato specifico per GlassFish v3.
Questi nomi saranno utili per l'applicazione console che scriveremo per utilizzare il modulo EJB distribuito.
7.2. Client console - Versione 1
Ora che abbiamo distribuito il lato server della nostra applicazione client/server, esamineremo il lato 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 client
Nel file [pom.xml], aggiungiamo le seguenti dipendenze:
- righe 31–35: la dipendenza dalla libreria [gf-client], che consente a un client Glassfish di comunicare con un server remoto,
- righe 36–41: la dipendenza dal progetto Maven del modulo EJB. Qui, vogliamo recuperare le definizioni delle entità JPA e delle varie interfacce, così come quella della classe di eccezione [PamException],
Dal progetto [mv-pam-openejb-eclipselink], copiamo la classe [MainRemote]:
![]() |
La classe [MainRemote] deve ottenere un riferimento all'EJB nel livello [business]. Il codice della classe [MainRemote] cambia come segue:
<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>
- Riga 6: Inizializzazione del contesto JNDI del server GlassFish.
- Riga 8: questo contesto JNDI viene interrogato per ottenere un riferimento all'interfaccia remota del livello [business]. In base ai log di GlassFish, sappiamo che l'interfaccia remota del livello [business] ha due possibili nomi:
// it's OK - we can ask for the payslip
FeuilleSalaire feuilleSalaire = null;
IMetierRemote metier = null;
try {
// context JNDI of Glassfish server
InitialContext initialContext = new InitialContext();
// business layer instantiation
metier = (IMetierRemote) initialContext.lookup("java:global/istia.st_mv-pam-ejb-metier-dao-eclipselink_ejb_1.0-SNAPSHOT/Metier!metier.IMetierRemote");
// wage sheet calculation
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 1: il nome JNDI utilizzabile con qualsiasi server di applicazioni Java EE 6. Riga 2: il nome JNDI specifico per GlassFish. Nel codice, alla riga 9, utilizziamo il nome JNDI portatile.
- Il resto del codice rimane invariato
![]() |
In [1], configuriamo il progetto per eseguire la classe [MainRemote] con degli argomenti. Se tutto va bene, l'esecuzione del progetto produce il seguente risultato:
Se nelle proprietà viene inserito un numero di previdenza sociale errato, si ottiene il seguente risultato:
7.3. Console client - versione 2
Nelle versioni precedenti, l'ambiente JNDI del server Glassfish veniva configurato utilizzando un file [jndi.properties] situato da qualche parte negli archivi del progetto. Il suo contenuto predefinito è il seguente:
Le righe 7 e 8 specificano il computer del servizio JNDI e la sua porta di ascolto. Questo file non consente di interrogare un server JNDI diverso da localhost o uno in esecuzione su una porta diversa dalla porta 3700. Se si desidera modificare queste due impostazioni, è possibile creare un proprio file [jndi.properties] o utilizzare una configurazione Spring. Dimostreremo quest'ultima tecnica.
Iniziamo creando un nuovo progetto basato sul 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 Spring è il seguente:
# accès JNDI à Sun Application Server
java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory
java.naming.factory.url.pkgs=com.sun.enterprise.naming
# Required to add a javax.naming.spi.StateFactory for CosNaming that
# supports dynamic RMI-IIOP.
java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl
org.omg.CORBA.ORBInitialHost=localhost
org.omg.CORBA.ORBInitialPort=3700
Qui stiamo utilizzando un tag <jee> (riga 14) introdotto in 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> viene utilizzato per ottenere un riferimento a un oggetto da un servizio JNDI. Qui, associamo il bean denominato "metier" alla risorsa JNDI associata all'EJB [Metier]. Il nome JNDI utilizzato qui è il nome portatile (Java EE 6) dell'EJB.
- Il contenuto del file [jndi.properties] diventa il contenuto del tag <jee:environment> (riga 15), utilizzato per definire i parametri di connessione per il servizio JNDI.
La classe principale [MainRemote] cambia come segue:
<?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">
<!-- business -->
<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>
Righe 7–8: A Spring viene richiesto il riferimento al tipo [IMetierRemote] nel livello [business]. Questa soluzione conferisce flessibilità alla nostra architettura. Infatti, se l’EJB nel livello [business] diventasse locale — ovvero, se venisse eseguito nella stessa JVM del nostro client [MainRemote] — il codice del client rimarrebbe invariato. Cambierebbe solo il contenuto del file [spring-config-client.xml]. Avremmo quindi una configurazione simile all'architettura Spring/JPA discussa nella Sezione 5.11.
I lettori sono invitati a provare questa nuova versione.
7.4. Il client Swing
Ora creeremo il client Swing per la nostra applicazione client/server EJB.
![]() |
Il file [pom.xml] deve includere le dipendenze necessarie per le applicazioni Swing:
Sopra, la classe [PamJFrame] era stata originariamente scritta per funzionare in un ambiente Spring/JPA:
![]() |
Ora questa classe deve diventare il client remoto di un EJB distribuito sul server Glassfish.
![]() |
Esercizio pratico: seguendo l'esempio del client console [ui.console.MainRemote] nel progetto, modificare il modo in cui il metodo [doMyInit] (vedere la Sezione 5.12.4) nella classe [PamJFrame] viene utilizzato per acquisire un riferimento al livello [business], che ora è remoto.

























