4. Il servizio web J2EE degli appuntamenti
Torniamo all'architettura dell'applicazione da realizzare:
![]() |
In questa sezione ci occuperemo della realizzazione del servizio web J2EE [1] eseguito su un server Sun / Glassfish.
4.1. Il database
Il database, che chiameremo [dbrdvmedecins] , è un database MySQL5 con quattro tabelle:

4.1.1. La tabella [MEDECINS]
Contiene informazioni sui medici gestiti dall’applicazione [RdvMedecins].
![]() | ![]() |
- ID: numero identificativo del medico - chiave primaria della tabella
- VERSION: numero che identifica la versione della riga nella tabella. Questo numero viene incrementato di 1 ogni volta che viene apportata una modifica alla riga.
- NOM: il cognome del medico
- PRENOM: il suo nome
- TITRE: il suo titolo (Sig.na, Sig.ra, Sig.)
4.1.2. La tabella [CLIENTS]
I clienti dei diversi medici sono registrati nella tabella [CLIENTS]:
![]() | ![]() |
- ID: numero identificativo del cliente - chiave primaria della tabella
- VERSION: numero che identifica la versione della riga nella tabella. Questo numero viene incrementato di 1 ogni volta che viene apportata una modifica alla riga.
- NOM: il nome del cliente
- PRENOM: il suo nome
- TITRE: il suo titolo (Sig.na, Sig.ra, Sig.)
4.1.3. La tabella [CRENEAUX]
Elenca le fasce orarie in cui sono possibili i RV:
![]() |
![]() |
- ID: numero identificativo della fascia oraria - chiave primaria della tabella (riga 8)
- VERSION: numero che identifica la versione della riga nella tabella. Questo numero viene incrementato di 1 ogni volta che viene apportata una modifica alla riga.
- ID_MEDECIN: numero identificativo del medico a cui appartiene questa fascia oraria – chiave esterna sulla colonna MEDECINS (ID).
- HDEBUT: ora di inizio della fascia oraria
- MDEBUT: minuti di inizio della fascia oraria
- HFIN: ora di fine della fascia oraria
- MFIN: minuti di fine della fascia oraria
La seconda riga della tabella [CRENEAUX] (cfr. [1] sopra) indica, ad esempio, che la fascia n. 2 inizia alle 8:20 e termina alle 8:40 e appartiene al medico n. 1 (dott.ssa Marie PELISSIER).
4.1.4. La tabella [RV]
Elenca i RV assegnati a ciascun medico:
![]() |
- ID: numero che identifica in modo univoco il RV – chiave primaria
- JOUR: giorno del RV
- ID_CRENEAU: fascia oraria del RV – chiave esterna sul campo [ID] della tabella [CRENEAUX] – determina sia la fascia oraria che il medico interessato.
- ID_CLIENT: numero del cliente per il quale è stata effettuata la prenotazione – chiave esterna sul campo [ID] della tabella [CLIENTS]
Questa tabella presenta un e vincolo di unicità sui valori delle colonne collegate (JOUR, ID_CRENEAU):
Se una riga della tabella [RV] presenta il valore (JOUR1, ID_CRENEAU1) per le colonne (JOUR, ID_CRENEAU), tale valore non può comparire in nessun altro punto. Altrimenti, ciò significherebbe che due RV sono stati registrati contemporaneamente per lo stesso medico. Dal punto di vista della programmazione Java, il driver JDBC del database avvia un SQLException quando si verifica questo caso.
La riga di id pari a 3 (cfr. [1] sopra) indica che un RV è stato prenotato per la fascia oraria n. 20 e il cliente n. 4 il 23/08/2006. La tabella [CRENEAUX] ci indica che la fascia n. 20 corrisponde alla fascia oraria 16:20 - 16:40 e appartiene al medico n. 1 (la signora Marie PELISSIER). La tabella [CLIENTS] ci indica che il cliente n. 4 è la signorina Brigitte BISTROU.
4.2. Generazione del database
Create il database MySql [dbrdvmedecins] con lo strumento che preferite. Per creare le tabelle e inserirvi i dati, potrete utilizzare lo script [createbd.sql] che vi verrà fornito. Il suo contenuto è il seguente:
4.3. Gli elementi dell’architettura lato server
Torniamo all’architettura dell’applicazione da realizzare:
![]() |
Sul lato server, l’applicazione sarà costituita da:
- da un livello JPA che consente di lavorare con il BD tramite oggetti
- da un EJB incaricato di gestire le operazioni con il livello JPA
- da un servizio web incaricato di esporre ai client remoti l’interfaccia dell’EJB sotto forma di servizio web.
Gli elementi (b) e (c) implementano il livello [dao] rappresentato nello schema precedente. È noto che un’applicazione può accedere a un EJB remoto tramite i protocolli RMI e JNDI. In pratica, ciò limita i client a quelli Java. Un servizio web utilizza un protocollo di comunicazione standardizzato implementato da diversi linguaggi: .NET, PHP, C++, ... È proprio questo che vogliamo dimostrare qui utilizzando un client .NET.
Per una breve introduzione ai servizi web, si può consultare il corso [ref1], paragrafo 14, pagina 109.
Un servizio web può essere implementato in due modi:
- tramite una classe annotata con @WebService che viene eseguita in un contenitore web
![]() |
- tramite un EJB annotato con @WebService che viene eseguito in un contenitore EJB
![]() |
![]() |
In questo caso utilizzeremo la prima soluzione:
Nel corso [ref1], paragrafo 14, pagina 109, si trova un esempio che utilizza la seconda soluzione.
4.4. Configurazione di Hibernate e del server GlassFish
A seconda della versione, il server Glassfish V2 fornito con NetBeans potrebbe non disporre delle librerie Hibernate necessarie al livello JPA/Hibernate. Se nel prosieguo del tutorial vi accorgete che Glassfish non offre un’implementazione JPA/Hibernate o che, durante la distribuzione dei servizi, un’eccezione segnala che le librerie Hibernate non sono state trovate, dovete aggiungere le librerie nella cartella [<glassfish>/domains/domain1/lib/ext] e quindi riavviare il server Glassfish:
![]() |
|
Le librerie Hibernate sono contenute nel file zip allegato al tutorial.
4.5. Gli strumenti di generazione automatica di NetBeans
Torniamo all’architettura che dobbiamo realizzare:
![]() |
Con NetBeans è possibile generare automaticamente il livello [JPA] e il livello [Ejb] che controlla l’accesso alle entità JPA generate. È interessante conoscere questi metodi di generazione automatica poiché il codice generato fornisce preziose indicazioni su come scrivere le entità JPA o il codice EJB che le utilizza.
Descriviamo ora alcuni di questi strumenti di generazione automatica. Per comprendere il codice generato, è necessario avere una buona conoscenza delle entità JPA, [ref1], EJB e [ref2].
Creazione di una connessione NetBeans al database
- avviare SGBD e MySQL 5 affinché BD sia disponibile
- creare una connessione NetBeans al database [dbrdvmedecins]
![]() |
- nella scheda [Files], nel ramo [Databases] [1], selezionare il driver JDBC MySQL [2]
- quindi selezionare l'opzione [3] "Connect Using" che consente di creare una connessione con un database MySQL
- in [4], inserire le informazioni richieste
- quindi confermare in [5]
![]() |
- in [6], la connessione è stata creata. Sono visibili le quattro tabelle del database collegato.
Creazione di un progetto EJB
![]() |
- in [1], creare una nuova applicazione, un modulo EJB
- in [2], selezionare la categoria [Java EE] e in [3] il tipo [EJB Module]
![]() |
- in [4] scegliere una cartella per il progetto e in [5] assegnargli un nome - quindi completare la procedura guidata
- in [6] il progetto generato
Aggiunta di una risorsa JDBC al server Glassfish
Aggiungeremo una risorsa JDBC al server Glassfish.
![]() |
![]() |
- nella scheda [Services], avviare il server Glassfish [2, 3]
- nella scheda [Projects], fare clic con il tasto destro del mouse sul progetto EJB e in [5] selezionare l’opzione [New / Other] che consente di aggiungere un elemento al progetto.

- in [6], selezionare la categoria [Glassfish] e in [7] specificare che si desidera creare una risorsa JDBC selezionando il tipo [JDBC Resource]
- in [8], specificare che questa risorsa JDBC utilizzerà il proprio pool di connessioni
- in [9], assegnare un nome alla risorsa JDBC
- in [10], passare alla fase successiva
![]() |
- in [11], si definiscono le caratteristiche del pool di connessioni della risorsa JDBC
- in [12], assegnare un nome al pool di connessioni
- in [13], selezionare la connessione NetBeans [dbrdvmedecins] creata in precedenza
- in [14], passare alla fase successiva
- in [15], normalmente non c'è nulla da modificare in questa pagina. Le proprietà della connessione al database MySQL [dbrdvmedecins] sono state ricavate da quelle della connessione NetBeans [dbrdvmedecins] creata in precedenza
- in [16], passare alla fase successiva
![]() |
- in [17], mantenere i valori predefiniti proposti
- in [18], completare la procedura guidata. Questa crea il file [sun-resources.xml] [19] il cui contenuto è il seguente:
Il file sopra riportato riporta tutte le informazioni inserite nella procedura guidata in formato XML. Verrà utilizzato da IDE NetBeans per richiedere al server GlassFish di creare la risorsa "jdbc/dbrdvmedecins" definita alla riga 4.
Creazione di un'unità di persistenza
L'unità di persistenza [persistence.xml] configura il livello JPA: indica l'implementazione JPA utilizzata (Toplink, Hibernate, ...) e la configura.
![]() |
![]() |
- in [1], fare clic con il tasto destro del mouse sul progetto EJB e selezionare [New / Other] in [2]
- in [3], selezionare la categoria [Persistence], quindi in [4], specificare che si desidera creare un'unità di persistenza JPA
![]() |
- in [5], assegnare un nome all’unità di persistenza creata
- in [6], scegliere [Hibernate] come implementazione JPA
- in [7], selezionare la risorsa Glassfish "jdbc/dbrdvmedecins" appena creata
- in [8], specificare che non deve essere eseguita alcuna azione sul database durante l’istanziazione del livello JPA
- completare la procedura guidata
- in [9], il file [persistence.xml] creato dalla procedura guidata
Il suo contenuto è il seguente:
Ancora una volta, riprende in un formato XML le informazioni fornite nella procedura guidata. Questo file non è sufficiente per lavorare con il database MySQL5 "dbrdvmedecins". Dovremmo indicare a Hibernate il tipo di SGBD da gestire. Ciò verrà fatto in un secondo momento.
Creazione delle entità JPA
![]() |
![]() |
![]() |
- in [1], fare clic con il tasto destro del mouse sul progetto e in [2] selezionare l’opzione [New / Other]
- in [3], selezionare la categoria [Persistence], quindi in [4], specificare che si desidera creare entità JPA a partire da un database esistente.
![]() |
- in [5], selezionare la fonte JDBC "jdbc/dbrdvmedecins" che abbiamo creato
- in [6], le quattro tabelle del database associato
- in [7,8], includerle tutte nella generazione delle entità JPA
- in [9], proseguire con la procedura guidata
![]() |
- in [10], le entità JPA che verranno generate
- in [11], assegnare un nome al pacchetto delle entità JPA
- in [12], scegliere il tipo Java che incapsulerà gli elenchi di oggetti restituiti dal livello JPA
- completare la procedura guidata
- in [13], le quattro entità JPA generate, una per ogni tabella del database.
Ecco, ad esempio, il codice dell’entità [Rv] che rappresenta una riga della tabella [rv] del database [dbrdvmedecins].
Creazione del livello EJB di accesso alle entità JPA
![]() |
![]() |
- in [1], fare clic con il tasto destro del mouse sul progetto e in [2], selezionare l'opzione [New / Other]
- in [3], selezionare la categoria [Persistence], quindi in [4] il tipo [Session Beans for Entity Classes]
![]() |
- in [5], le entità JPA create in precedenza vengono visualizzate
- in [6], selezionarle tutte
- in [7], sono state selezionate
- in [8], proseguire con la procedura guidata
![]() |
- in [9], assegnare un nome al pacchetto degli EJB che verranno generati
- in [10], specificare che gli EJB devono implementare sia un'interfaccia locale che una remota
- chiudere la procedura guidata
- in [11], gli EJB generati
Ecco, ad esempio, il codice dell'EJB che gestisce l'accesso all'entità [Rv], ovvero alla tabella [rv] del database [dbrdvmedecins]:
Come già detto, la generazione automatica del codice può essere molto utile per avviare un progetto e familiarizzare con le entità JPA e EJB. Di seguito riscriveremo i livelli JPA e EJB con il nostro codice, ma il lettore vi ritroverà le informazioni che abbiamo appena visto nella generazione automatica dei livelli.
4.6. Il progetto NetBeans del modulo EJB
Creiamo un nuovo modulo EJB vuoto (cfr. paragrafo 4.5):
![]() |
- il pacchetto [rdvmedecins.entites] raggruppa le entità del livello JPA
- il pacchetto [rdvmedecins.dao] implementa l’EJB del livello [dao]
- il pacchetto [rdvmedecins.exceptions] implementa una classe di eccezione specifica dell’applicazione
Di seguito, diamo per scontato che il lettore abbia seguito tutti i passaggi descritti nel paragrafo 4.5. Alcuni di essi dovranno essere ripetuti.
4.6.1. Configurazione del livello JPA
Ricordiamo l’architettura della nostra applicazione client/server:
![]() |
Il progetto NetBeans:
![]() |
Il livello [JPA] è configurato dai file [persistence.xml] e [sun-resources.xml] sopra riportati. Questi due file sono generati da procedure guidate già illustrate:
- la generazione del file [sun-resources.xml] è stata descritta nel paragrafo 4.5.
- la generazione del file [persistence.xml] è stata descritta nel paragrafo 4.5.
Il file [persistence.xml] generato deve essere modificato come segue:
- riga 3: il tipo di transazioni è JTA: le transazioni saranno gestite dal contenitore EJB3 di GlassFish
- riga 4: viene utilizzata un’implementazione JPA/Hibernate. A tal fine, la libreria Hibernate è stata aggiunta al server GlassFish (cfr. paragrafo 4.4).
- riga 5: la fonte dati JTA utilizzata dal livello JPA ha il nome JNDI «jdbc/dbrdvmedecins».
- riga 8: questa riga non viene generata automaticamente. Deve essere aggiunta manualmente. Indica a Hibernate che il SGBD utilizzato è MySQL5.
La fonte dati "jdbc/dbrdvmedecins" è configurata nel seguente file [sun-resources.xml]:
- righe 8-10: le caratteristiche JDBC della fonte dati (URL del database, nome utente e password). Il database MySQL dbrdvmedecins è quello descritto al paragrafo 4.1.
- riga 7: le caratteristiche del pool di connessioni associato a questa fonte di dati
4.6.2. Le entità del livello JPA
Ricordiamo l’architettura della nostra applicazione client/server:
![]() |
Il progetto NetBeans:
![]() |
Il pacchetto [rdvmedecins.entites] implementa il livello [Jpa].
Nel paragrafo 4.5 abbiamo visto come generare automaticamente le entità JPA di un'applicazione. In questa sede non utilizzeremo tale tecnica, ma definiremo noi stessi le entità. Queste riprenderanno tuttavia gran parte del codice generato nel paragrafo 4.5. In questo caso, vogliamo che le entità [Medecin] e [Client] siano classi figlie di una classe [Personne].
La classe Personne viene utilizzata per rappresentare medici e clienti:
- riga 3: si noti che la classe [Personne] non è essa stessa un’entità (@Entity). Sarà la classe padre delle entità. L’annotazione @MappedSuperClass indica questa situazione.
L’entità [Client] incapsula le righe della tabella [clients]. Deriva dalla precedente classe [Personne]:
- riga 3: la classe [Client] è un'entità JPA
- riga 4: è associata alla tabella [clients]
- riga 5: deriva dalla classe [Personne]
L’entità [Medecin], che incapsula le righe della tabella [medecins], segue lo stesso modello:
L'entità [Creneau] incapsula le righe della tabella [creneaux]:
- le righe 15-17 modellano la relazione «uno a molti» esistente tra la tabella [creneaux] e la tabella [medecins] del database.
L’entità [Rv] incapsula le righe della tabella [rv]:
- le righe 15-17 modellano la relazione «uno a molti» esistente tra la tabella [rv] e la tabella [clients] del database, mentre le righe 18-20 modellano la relazione "uno a molti" che esiste tra la tabella [rv] e la tabella [creneaux]
4.6.3. La classe di eccezione
![]() |
La classe di eccezione [RdvMedecinsException] dell’applicazione è la seguente:
- riga 6: la classe deriva dalla classe [RuntimeException]. Il compilatore non impone quindi di gestirla con try / catch.
- riga 5: l'annotazione @ApplicationException fa sì che l'eccezione non venga "trascurata" da un'eccezione di tipo [EjbException].
Per comprendere l’annotazione @ApplicationException torniamo all’architettura utilizzata sul lato server:
![]() |
L'eccezione di tipo [RdvMedecinsException] verrà generata dai metodi dell'EJB del livello [dao] all'interno del contenitore EJB3 e intercettata da quest'ultimo. Senza l'annotazione @ApplicationException, il contenitore EJB3 incapsula l'eccezione verificatasi in un'eccezione di tipo [EjbException] e la rilancia. Si potrebbe non volere tale incapsulamento e lasciare che dal contenitore Ejb3 fuoriesca un'eccezione di tipo [RdvMedecinsException]. È ciò che consente l'annotazione @ApplicationException. Inoltre, l’attributo (rollback=true) di questa annotazione indica al contenitore EJB3 che, se l’eccezione di tipo [RdvMedecinsException] si verifica all’interno di un metodo eseguito in una transazione con un SGBD, quest’ultima deve essere annullata. In termini tecnici, questa operazione è denominata «rollback» della transazione.
4.6.4. L'EJB del livello [dao]
![]() |
![]() |
L'interfaccia Java [IDao] del livello [dao] è la seguente:
L'interfaccia locale [IDaoLocal] dell'EJB si limita a derivare dalla precedente interfaccia [IDao]:
Lo stesso vale per l’interfaccia remota [IDaoRemote]:
L'EJB [DaoJpa] implementa entrambe le interfacce, locale e remota:
- la riga 3 indica che l'EJB remoto ha il nome "rdvmedecins.dao"
- la riga 4 indica che tutti i metodi dell'EJB si svolgono all'interno di una transazione gestita dal contenitore EJB3.
- la riga 5 mostra che l'EJB implementa le interfacce locale e remota.
Il codice completo dell'EJB è il seguente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | |
- riga 8: l'oggetto EntityManager che gestisce l'accesso al contesto di persistenza. All'istanziazione della classe, questo campo verrà inizializzato dal contenitore EJB grazie all'annotazione @PersistenceContext della riga 7.
- riga 15: query JPQL che restituisce tutte le righe della tabella [clients] sotto forma di un elenco di oggetti [Client].
- riga 22: query analoga per i medici
- riga 32: una query JPQL che esegue un join tra le tabelle [creneaux] e [medecins]. È configurata in base all’ID del medico.
- riga 43: una query JPQL che esegue un join tra le tabelle [rv], [creneaux] e [medecins] e che ha due parametri: l'ID del medico e il giorno dell'appuntamento.
- righe 55-57: creazione di un appuntamento e successivo salvataggio dello stesso nel database.
- riga 67: eliminazione di un appuntamento dal database.
- riga 76: esegue una query SELECT sul database per trovare un determinato cliente
- riga 85: idem per un medico
- riga 94: lo stesso per un appuntamento
- riga 103: idem per una fascia oraria
- tutte le operazioni che utilizzano il contesto di persistenza em della riga 9 potrebbero incontrare un problema con il database. Pertanto, sono tutte racchiuse in un blocco try/catch. L'eventuale eccezione è incapsulata nell'eccezione "interna" RdvMedecinsException.
Una volta compilato, il modulo EJB genera un file .jar denominato :
![]() |
4.7. Distribuzione dell’EJB del livello [dao] con NetBeans
NetBeans consente di distribuire facilmente sul server GlassFish l’EJB creato in precedenza.
![]() |
- Nelle proprietà del progetto EJB, verificare le opzioni di esecuzione [1].
- In [2], il nome del server su cui verrà distribuito l'EJB
- nella scheda [Services] [3], si avvia [4].
![]() |
- in [5], il server Glassfish una volta avviato. Non dispone ancora di alcun modulo EJB.
- Avviare il server MySQL e assicurarsi che il database [dbrdvmedecins] sia online. A tal fine, è possibile utilizzare la connessione NetBeans creata al paragrafo 4.5.
- Nella scheda [Projects] [6], si distribuisce il modulo EJB [7]: è necessario che SGBD MySQL5 sia in esecuzione affinché la risorsa JDBC "jdbc/dbrdvmedecins" utilizzata dall’EJB sia accessibile.
- In [8], l’EJB distribuito appare nella struttura ad albero del server GlassFish
![]() |
- In [9], si rimuove l'EJB distribuito
- in [10], l'EJB non compare più nella struttura ad albero del server GlassFish.
4.8. Distribuzione dell'EJB del livello [dao] con GlassFish
Qui mostriamo come distribuire sul server GlassFish un EJB a partire dal suo archivio .jar.
- Avviare il server MySQL e assicurarsi che il database [dbrdvmedecins] sia online. A tal fine, è possibile utilizzare la connessione NetBeans creata al paragrafo 4.5.
Ricordiamo la configurazione JPA del modulo EJB che verrà distribuito. Tale configurazione è definita nel file [persistence.xml]:
La riga 5 indica che il livello JPA utilizza una fonte di dati JTA, c.a.d gestita dal contenitore EJB3, denominata "jdbc/dbrdvmedecins".
Nel paragrafo 4.5 abbiamo visto come creare questa risorsa JDBC da NetBeans. Qui mostriamo come farlo direttamente con GlassFish. Seguiamo la procedura descritta nel paragrafo 13.1.2, a pagina 79 di [ref1].
Iniziamo eliminando la risorsa per poterla ricreare. Lo facciamo da NetBeans:
![]() |
- in [1], le risorse JDBC del server GlassFish
- in [2], la risorsa "jdbc/dbrdvmedecins" del nostro EJB
- in [3], il pool di connessioni di questa risorsa JDBC
![]() |
- in [4], si elimina il pool di connessioni. Ciò comporterà l’eliminazione di tutte le risorse JDBC che lo utilizzano, quindi la risorsa "jdbc/dbrdvmedecins".
- In [5] e [6], la risorsa JDBC e il pool di connessioni sono stati eliminati.
Ora utilizziamo la console di amministrazione del server GlassFish per creare la risorsa JDBC e distribuire l'EJB.
![]() |
- nella scheda [services] [1] di NetBeans, avviare il server GlassFish [2], quindi accedere alla sua console di amministrazione
- all'indirizzo [4], effettuare l'accesso come amministratore (password: adminadmin se non è stata modificata durante l'installazione o successivamente).
![]() |
- in [5], selezionare il ramo [Connection Pools] delle risorse di Glassfish
- in [6], creare un nuovo pool di connessioni. Si ricorda che un pool di connessioni è una tecnica per limitare il numero di aperture/chiusure di connessioni con un SGBD. All’avvio del server, N (un numero definito dalla configurazione) connessioni vengono aperte con il SGBD. Queste connessioni aperte vengono poi messe a disposizione degli EJB che le richiedono per eseguire un’operazione con il SGBD. Non appena l’operazione è terminata, l’EJB restituisce la connessione al pool. La connessione non viene mai chiusa. Viene condivisa tra i diversi thread che accedono al SGBD
- in [7]; assegnate un nome al pool
- in [8]; la classe che modella la fonte dati è la classe [javax.sql.DataSource]
- in [9], il SGBD che contiene la fonte dati è qui MySQl.
- in [10], passare alla fase successiva
![]() |
- In [11], l'attributo "Connection Validation Required" fa sì che, prima di fornire una connessione, il pool verifichi che sia operativa. Se così non fosse, ne crea una nuova. Ciò consente a un'applicazione di continuare a funzionare dopo un'interruzione momentanea con SGBD. Durante l’interruzione, nessuna connessione è utilizzabile e vengono segnalate delle eccezioni al client. Una volta terminata l’interruzione, i client che continuano a richiedere connessioni le ottengono nuovamente: grazie all’attributo "Connection Validation Required", tutte le connessioni del pool verranno ricreate. Senza questo attributo, il pool rileverebbe che le connessioni iniziali sono state interrotte ma non tenterebbe di crearne di nuove.
- In [12], si richiede il livello di isolamento “Read Committed” per le transazioni. Questo livello garantisce che una transazione T2 non possa leggere i dati modificati da una transazione T1 finché quest’ultima non sia completamente terminata.
- In [13], si richiede che tutte le transazioni utilizzino il livello di isolamento specificato in [12]
![]() |
- in [14] e [15], specificare l’URL di BD il cui pool gestisce le connessioni
- in [16], l'utente sarà root
- in [17], aggiungere una proprietà
- in [18], aggiungere la proprietà "Password" con il valore () in [19]. Sebbene lo screenshot [19] non lo mostri, non bisogna inserire la stringa vuota, ma () (parentesi aperta, parentesi chiusa) per indicare una password vuota. Se l’utente root del vostro SGBD MySQL ha una password non vuota, inserite tale password.
- in [20], completate la procedura guidata di creazione del pool di connessioni per il database MySQL [dbrdvmedecins].
![]() |
- in [21], il pool è stato creato. Fare clic sul relativo link.
- in [22], il pulsante [Ping] consente di creare una connessione con il database [dbrdvmedecins]
- in [23], se tutto va bene, un messaggio indica che la connessione è stata stabilita con successo
Una volta creato il pool di connessioni, è possibile creare una risorsa JDBC:
![]() |
- in [1], si seleziona il ramo [JDBC Resources] dall’albero degli oggetti del server
- in [2], si crea una nuova risorsa JDBC
- in [3], si assegna un nome alla risorsa JDBC. Il nome deve corrispondere a quello utilizzato nel file [persistence.xml]:
- in [4], si specifica il pool di connessioni che la nuova risorsa JDBC deve utilizzare: quello appena creato
- in [5], si completa la procedura guidata di creazione
![]() |
- in [6] la nuova risorsa JDBC
Ora che la risorsa JDBC è stata creata, è possibile distribuire l'archivio jar dell'EJB:
![]() |
- in [1], selezionate il ramo [Enterprise Applications]
- in [2], utilizzando il pulsante [Deploy], specificare che si desidera distribuire una nuova applicazione
- in [3], specificare che l’applicazione è un modulo EJB
- in [4], selezionate il file JAR dell’EJB [serveur-ejb-dao-jpa-hibernate.jar] che vi è stato fornito per il TP.
- in [5], è possibile modificare il nome del modulo EJB, se lo si desidera
- in [6], completate la procedura guidata di distribuzione del modulo EJB
![]() |
- Nel [7], il modulo EJB è stato implementato. Ora è possibile utilizzarlo.
4.9. Test dell'EJB del livello [dao]
Ora che l’EJB del livello [dao] della nostra applicazione è stato distribuito, possiamo testarlo. Lo faremo utilizzando il seguente client Java:
![]() |
La classe [MainTestsDaoRemote] [1] è una classe di test JUnit 4. Le librerie in [2] sono costituite, da un lato, da:
- dal file JAR dell'EJB del livello [dao] [3] (cfr. paragrafo 4.6.4).
- dalle librerie GlassFish [4] necessarie ai client remoti degli EJB.
La classe di test è la seguente:
- riga 13: si noti l’istanziazione del proxy dell’EJB remoto. Si utilizza il suo nome JNDI "rdvmedecins.dao".
- I metodi di test utilizzano i metodi esposti dall'EJB (cfr. paragrafo 4.6.4).
Se tutto va bene, i test dovrebbero superare:
![]() |
Ora che l’EJB del livello [dao] è operativo, è possibile procedere alla sua esposizione pubblica tramite un servizio web.
4.10. Il servizio web del livello [dao]
Per una breve introduzione al concetto di servizio web, si rimanda al paragrafo 14, pagina 111 di [ref1].
Torniamo all’architettura del server della nostra applicazione client/server:
![]() |
Ci interessiamo qui di seguito al servizio web del livello [dao]. L’unico ruolo di questo servizio è quello di rendere disponibile l’interfaccia dell’EJB del livello [dao] a client multipiattaforma in grado di dialogare con un servizio web.
Ricordiamo che esistono due modi per implementare un servizio web:
- tramite una classe annotata con @WebService che viene eseguita in un contenitore web
![]() |
- tramite un EJB annotato con @WebService che viene eseguito in un contenitore EJB
![]() |
Qui utilizziamo la prima soluzione. In NetBeans, dobbiamo creare un progetto aziendale con due moduli:
- il modulo EJB che verrà eseguito nel contenitore EJB: l’EJB del livello [dao].
- il modulo web che verrà eseguito nel contenitore web: il servizio web che stiamo realizzando.
Realizzeremo questo progetto aziendale in due modi.
4.10.1. Progetto NetBeans - Versione 1
Per prima cosa creiamo un progetto NetBeans di tipo «Web Application»:
![]() |
- in [1], creiamo un nuovo progetto nella categoria “Java Web” [2] di tipo “Web Application” [3].
![]() |
- in [4], si assegna un nome al progetto e in [5] si specifica la cartella in cui deve essere generato
- in [6], si imposta il server dell’applicazione che eseguirà l’applicazione web
- in [7], si imposta il contesto dell'applicazione
- in [8], si convalida la configurazione del progetto.
![]() |
- in [9], il progetto generato. Il servizio web che stiamo realizzando utilizzerà il EJB del progetto precedente [10]. Pertanto, deve fare riferimento al file .jar del modulo EJB [10].
- In [11], si aggiunge un progetto NetBeans alle librerie del progetto web [12]
![]() |
- in [13], si seleziona la cartella del modulo EJB nel file system e si conferma.
![]() |
- in [14], il modulo EJB è stato aggiunto alle librerie del progetto web.
In [15], implementiamo il servizio web con la seguente classe [WsDaoJpa]:
- alla riga 4, la classe [WsdaoJpa] implementa l'interfaccia [IDao]. Ricordiamo che questa interfaccia è definita nell'archivio dell'EJB del livello [dao] nella forma seguente:
- riga 3: l’annotazione @WebService rende la classe [WsDaoJpa] un servizio web.
- righe 6-7: il riferimento all'EJB del livello [dao] verrà iniettato dal server dell'applicazione nel campo della riga 7. Ricordiamo che è sempre l’implementazione locale (in questo caso IDaoLocal) a essere così iniettata. Tale iniezione è possibile poiché il servizio web viene eseguito nella stessa JVM dell’EJB.
- Tutti i metodi del servizio web sono contrassegnati con l’annotazione @WebMethod per renderli visibili ai client remoti. Un metodo non contrassegnato con l’annotazione @WebMethod sarebbe interno al servizio web e non visibile ai client remoti. Ogni metodo M del servizio web si limita a chiamare il metodo M corrispondente dell'EJB iniettato alla riga 7.
La creazione di questo servizio web è rappresentata da un nuovo ramo nel progetto NetBeans:
![]() |
In [1] si vede il servizio web WsDaoJpa e in [2] i metodi che esso espone ai clienti remoti.
Ricordiamo l’architettura del servizio web in fase di sviluppo:
![]() |
I componenti del servizio web che stiamo per implementare sono:
- [1]: il modulo web che abbiamo appena realizzato
- [2]: il modulo EJB che abbiamo creato in una fase precedente e dal quale dipende il servizio web
Per distribuirli insieme, è necessario riunire i due moduli in un progetto NetBeans denominato “aziendale”:
![]() |
In [1] si crea un nuovo progetto aziendale [2, 3].
![]() |
- in [4,5], si assegna un nome al progetto e si specifica la cartella di creazione
- in [6], si sceglie il server applicativo su cui verrà distribuita l’applicazione aziendale
- in [7], un progetto aziendale può avere tre componenti: applicazione web, modulo EJB, applicazione client. In questo caso, il progetto viene creato senza alcuna componente. Queste verranno aggiunte in un secondo momento.
![]() |
- in [8], l’applicazione aziendale appena creata.
![]() |
- in [9], fare clic con il tasto destro su [Java EE Modules] e aggiungere un nuovo modulo
- in [10], vengono visualizzati solo i moduli NetBeans attualmente aperti in IDE. Qui selezioniamo il modulo web [serveur-webservice-1-ejb-dao-jpa-hibernate] e il modulo EJB [serveur-ejb-dao-jpa-hibernate] che abbiamo creato.
- In [11], i due moduli aggiunti al progetto aziendale.
Non resta che distribuire questa applicazione aziendale sul server GlassFish. Successivamente, è necessario avviare SGBD e MySQL affinché la fonte dati JDBC "jdbc/dbrdvmedecins" utilizzata dal modulo EJB sia accessibile.
![]() |
- in [1], si avvia il server Glassfish
- se il modulo EJB [serveur-ejb-dao-jpa-hibernate] è distribuito, lo si rimuove [2]
- in [3], si distribuisce l'applicazione aziendale
![]() |
- in [4], l'applicazione è distribuita. Si nota che contiene entrambi i moduli: Web ed EJB.
4.10.2. Progetto NetBeans - versione 2
Mostriamo ora come distribuire il servizio web quando non si dispone del codice sorgente del modulo EJB, ma solo del suo archivio .jar.
Il nuovo progetto NetBeans del servizio web sarà il seguente:
![]() |
Gli elementi salienti del progetto sono i seguenti:
- [1]: il servizio web è implementato da un progetto NetBeans di tipo [Web Application].
- [2]: il servizio web è implementato dalla classe [WsDaoJpa] già esaminata
- [3]: l'archivio EJB del livello [dao] che consente alla classe [WsDaoJpa] di accedere alle definizioni delle diverse classi, interfacce ed entità dei livelli [dao] e [jpa].
Successivamente, realizziamo il progetto aziendale necessario per l’implementazione del servizio web:
![]() |
- [1], creiamo un'applicazione aziendale [ea-rdvmedecins], inizialmente priva di qualsiasi modulo.
- in [2], si aggiunge il modulo web [serveur-webservice-ejb-dao-jpa-hibernate] precedente
- in [3], il risultato.
Così com’è, l’applicazione aziendale [ea-rdvmedecins] non può essere distribuita sul server Glassfish da NetBeans. Si verifica un errore. È quindi necessario distribuire manualmente l’archivio EAR dell’applicazione [ea-rdvmedecins]:
![]() |
- l'archivio [ea-rdvmedecins.ear] si trova nella cartella [dist] [2] della scheda [Files] di NetBeans.
- In questo archivio [3] si trovano i due elementi dell’applicazione aziendale:
- l'archivio dell'EJB [serveur-ejb-dao-jpa-hibernate]. Questo archivio è presente perché faceva parte delle librerie a cui faceva riferimento il servizio web.
- l'archivio del servizio web [serveur-webservice- ejb-dao-jpa-hibernate].
- L'archivio [ea-rdvmedecins.ear] è costituito da un semplice Build [4] dell'applicazione aziendale.
- In [5], l’operazione di distribuzione non va a buon fine.
Per distribuire l’archivio [ea-rdvmedecins.ear] dell’applicazione aziendale, procediamo come illustrato durante la distribuzione dell’archivio EJB [serveur-ejb-dao-jpa-hibernate.jar] al paragrafo 4.2. Utilizziamo nuovamente il client web di amministrazione del server GlassFish. Non ripeteremo i passaggi già descritti.
Per prima cosa, inizieremo con lo «scaricare» l’applicazione aziendale distribuita al paragrafo 4.10.1:
![]() |
- [1]: selezionare il ramo [Enterprise Applications] del server Glassfish
- in [2] selezionare l’applicazione aziendale da scaricare, quindi in [3] scaricarla
- in [4] l’applicazione aziendale è stata scaricata
![]() |
- in [1], scegliere il ramo [Enterprise Applications] del server Glassfish
- in [2], distribuire una nuova applicazione aziendale
- in [3], selezionare il tipo [Enterprise Application]
- in [4], specificare il file .ear del progetto NetBeans [ea-rdvmedecins]
- in [5], distribuite questo archivio
![]() |
- in [6]; l'applicazione è stata distribuita
- in [7], il servizio web [WsDaoJpa] appare nel ramo [Web Services] del server Glassfish. Lo si seleziona.
- In [8] sono disponibili diverse informazioni sul servizio web. La più interessante per un cliente è l’informazione [9]: l’URI del servizio web.
- In [10] è possibile testare il servizio web
![]() |
- In [11], l' , l'URI del servizio web a cui è stato aggiunto il parametro ?tester. Questo URI mostra una pagina di test. Tutti i metodi (@WebMethod) esposti dal servizio web vengono visualizzati e possono essere testati. In questo caso, si testa il metodo [13] che richiede l'elenco dei clienti.
![]() |
- In [14], presentiamo solo una vista parziale della pagina di risposta. Tuttavia, si può notare che il metodo getAllClients ha effettivamente restituito l'elenco dei clienti. Lo screenshot ci mostra che invia la risposta in formato XML.
Un servizio web è interamente descritto da un file XML denominato file WSDL:
![]() |
- in [1] nello strumento di amministrazione web del server Glassfish, selezionate il servizio web [WsDaoJpa]
- in [2], seguire il link [View WSDL]
![]() |
- in [3]: l'URI del file WSDL. Si tratta di un'informazione importante da conoscere. È necessaria per configurare i client di questo servizio web.
- in [4], la descrizione XML del servizio web. Non commenteremo questo contenuto complesso.
4.10.3. Test JUnit del servizio web
Creiamo un progetto NetBeans per «ripetere» i test già eseguiti con un client EJB, utilizzando questa volta un client per il servizio web recentemente implementato. Seguiamo qui una procedura analoga a quella descritta al paragrafo 14.2.1, pagina 115 di [ref1].
![]() |
- in [1], un progetto Java classico
- in [2], la classe di test
- in [3], il client utilizza l'archivio dell'EJB per accedere alle definizioni dell'interfaccia del livello [dao] e delle entità JPA. Si ricorda che questo archivio si trova nella sottocartella [dist] della cartella del modulo EJB.
Per accedere al servizio web remoto, è necessario generare delle classi proxy:
![]() |
Nello schema sopra riportato, il livello [2] [C=Client] comunica con il livello [1] [S=Serveur]. Per comunicare con il livello [S], il client [C] deve creare una connessione di rete con il livello [S] e comunicare con esso secondo un protocollo specifico. Le connessioni di rete sono di tipo TCP e il protocollo di trasporto è HTTP. Il livello [S], che rappresenta il servizio web, è implementato da una servlet Java eseguita dal server Glassfish. Non abbiamo scritto questa servlet. La sua generazione è automatizzata da Glassfish a partire dalle annotazioni @Webservice e @WebMethod della classe [WsDaoJpa] che abbiamo scritto. Allo stesso modo, automatizzeremo la generazione del livello [C] del client. Il livello [C] viene talvolta definito livello proxy del servizio web remoto, poiché il termine proxy indica un elemento intermedio in una catena software. In questo caso, il proxy C funge da intermediario tra il client che scriveremo e il servizio web che abbiamo distribuito.
Con NetBeans 6.5, il proxy C può essere generato nel modo seguente (per il seguito, è necessario che il servizio web sia attivo sul server GlassFish):
![]() |
- in [1], aggiungere un nuovo elemento al progetto Java
- in [2], selezionare il ramo [Web services]
- in [3], selezionare [Web Service Client]
![]() |
- in [4], specificare l'URI del file WSDL del servizio web. Questo URI è stato illustrato nel paragrafo 4.10.2.
- in [5], lasciare il valore predefinito [JAX-WS]. L'altro valore possibile è [JAX-RPC]
- Dopo aver confermato la procedura guidata per la creazione del proxy del servizio web, il progetto NetBeans è stato arricchito con un ramo [Web Service References] [6]. Questo ramo mostra i metodi esposti dal servizio web remoto.
![]() |
- nella scheda [Files] [7], sono stati aggiunti codici sorgente Java [8]. Essi corrispondono al proxy C generato.
- In [9] è riportato il codice di una delle classi. Si nota [10] che sono state inserite in un pacchetto [rdvmedecins.ws]. Non commenteremo il codice di queste classi, che risulta nuovamente piuttosto complesso.
Per il client Java che stiamo realizzando, il proxy C generato funge da intermediario. Per accedere al metodo M del servizio web remoto, il client Java chiama il metodo M del proxy C. Il client Java chiama così metodi locali (eseguiti nella stessa JVM) e, in modo trasparente per lui, queste chiamate locali vengono tradotte in chiamate remote.
Resta da capire come chiamare i metodi M del proxy C. Torniamo alla nostra classe di test JUnit:
![]() |
In [1], la classe di test [MainTestsDaoRemote] è quella già utilizzata durante il test dell’EJB del livello [dao]:
- riga [13], il test test1 è stato mantenuto invariato.
- riga [9], il contenuto del metodo [init] è stato eliminato.
A questo punto, il progetto presenta degli errori poiché il metodo di test [test1] utilizza le entità [Client], [Medecin], [Creneau], [Rv], che non si trovano più negli stessi pacchetti di prima. Si trovano nel pacchetto del proxy C generato. Si eliminano le istruzioni import interessate e le si rigenerano tramite l'operazione «Fix Imports».
![]() |
Torniamo al codice della classe di test [MainTestsDaoRemote]:
Il metodo [init] alla riga 10 deve inizializzare il riferimento al livello [dao] alla riga 7. Dobbiamo capire come utilizzare il proxy C generato nel nostro codice. NetBeans ci aiuta in questo processo.
![]() |
- Selezionare in [1] il metodo [getAllClients] del servizio web con il mouse, quindi trascinare tale metodo e rilasciarlo all’interno del metodo [init] della classe di test.
Si ottiene il risultato [2]. Questo scheletro di codice ci mostra come utilizzare il proxy C generato:
- la riga [5] ci mostra che il metodo [getAllClients] è un metodo dell’oggetto di tipo [WsDaoJpa] definito alla riga 3. Il tipo [WsDaoJpa] è un'interfaccia che presenta gli stessi metodi di quelli esposti dal servizio web remoto.
- Alla riga [3], l’oggetto [WsDaoJpa port] viene ottenuto da un altro oggetto di tipo [WsDaoJpaService] definito alla riga 2. Il tipo [WsDaoJpaService] rappresenta il proxy C generato localmente.
- L'accesso al servizio web remoto potrebbe non riuscire, pertanto l'intero codice è racchiuso in un blocco try/catch.
- Gli oggetti del proxy C si trovano nel pacchetto [rdvmedecins.ws]
Una volta compreso questo codice, si vede che il riferimento locale del servizio web remoto può essere ottenuto tramite il codice:
Il codice della classe di test JUnit diventa quindi il seguente:
Ora siamo pronti per i test:
![]() |
In [1] viene eseguito il test JUnit. In [2] il test ha esito positivo. Osservando i messaggi visualizzati sulla console di NetBeans, si trovano righe come le seguenti:
Liste des clients :
rdvmedecins.ws.Client@1982fc1
rdvmedecins.ws.Client@676437
rdvmedecins.ws.Client@1e4853f
rdvmedecins.ws.Client@1e808ca
Sul lato server, l'entità [Client] dispone di un metodo toString che visualizza i diversi campi di un oggetto di tipo [Client]. Durante la generazione automatica del proxy C, le entità vengono create nel proxy C ma solo con i campi privati accompagnati dai relativi metodi get / set. Pertanto, il metodo toString non è stato generato nell'entità [Client] del proxy C. Ciò spiega la visualizzazione precedente. Ciò non toglie nulla al test JUnit: è stato superato. D'ora in poi considereremo il servizio web operativo.






























































































