4. Il servizio web J2EE per gli appuntamenti
Torniamo all'architettura dell'applicazione da realizzare:
![]() |
In questa sezione ci concentreremo sulla realizzazione del servizio web J2EE [1] in esecuzione 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: il numero identificativo del medico — la chiave primaria della tabella
- VERSIONE: un numero che identifica la versione della riga nella tabella. Questo numero viene incrementato di 1 ogni volta che viene apportata una modifica alla riga.
- LAST_NAME: il cognome del medico
- FIRST_NAME: il nome del medico
- TITOLO: il titolo (Sig.ra, Sig.ra, Sig.)
4.1.2. La tabella [CLIENTI]
I clienti dei vari medici sono memorizzati 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.
- COGNOME: il cognome del cliente
- NOME: il nome del cliente
- TITOLO: il titolo (Sig.ra, Sig.ra, Sig.)
4.1.3. La tabella [SLOTS]
Elenca le fasce orarie in cui sono disponibili gli appuntamenti:
![]() |
![]() |
- ID: numero identificativo della fascia oraria - chiave primaria della tabella (riga 8)
- VERSION: Un numero che identifica la versione della riga nella tabella. Questo numero viene incrementato di 1 ogni volta che viene apportata una modifica alla riga.
- DOC_ID: numero ID che identifica il medico a cui appartiene questa fascia oraria – chiave esterna sulla colonna DOCTORS(ID).
- START_TIME: Ora di inizio della fascia oraria
- MSTART: 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 [SLOTS] (vedi [1] sopra) indica, ad esempio, che la fascia oraria 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 gli appuntamenti prenotati per ciascun medico:
![]() |
- ID: identificatore univoco dell'appuntamento – chiave primaria
- GIORNO: giorno dell'appuntamento
- SLOT_ID: fascia oraria dell'appuntamento – chiave esterna sul campo [ID] della tabella [SLOTS] – determina sia la fascia oraria che il medico coinvolto.
- CLIENT_ID: ID del cliente per il quale è stata effettuata la prenotazione – chiave esterna sul campo [ID] della tabella [CLIENTS]
Questa tabella ha un vincolo di unicità sui valori delle colonne unite (GIORNO, SLOT_ID):
Se una riga nella tabella [RV] ha il valore (DAY1, SLOT_ID1) per le colonne (DAY, SLOT_ID), questo valore non può comparire in nessun altro punto. In caso contrario, ciò significherebbe che sono stati prenotati due appuntamenti contemporaneamente per lo stesso medico. Dal punto di vista della programmazione Java, il driver JDBC del database genera un'eccezione SQLException quando ciò si verifica.
La riga con ID pari a 3 (vedi [1] sopra) indica che è stato prenotato un appuntamento per lo slot n. 20 e il cliente n. 4 il 23/08/2006. La tabella [SLOTS] ci dice che lo slot n. 20 corrisponde alla fascia oraria 16:20 – 16:40 e appartiene al medico n. 1 (Sig.ra Marie PELISSIER). La tabella [CLIENTS] ci dice che il cliente n. 4 è la sig.ra Brigitte BISTROU.
4.2. Creazione del database
Crea il database MySQL [dbrdvmedecins] utilizzando lo strumento che preferisci. Per creare le tabelle e popolarle, puoi utilizzare lo script [createbd.sql] fornito. Il suo contenuto è il seguente:
4.3. Componenti dell'architettura lato server
Torniamo all'architettura dell'applicazione da realizzare:
![]() |
Sul lato server, l'applicazione sarà composta da:
- un livello JPA che consente l'interazione con il database tramite oggetti
- un EJB responsabile della gestione delle operazioni con il livello JPA
- un servizio web responsabile dell'esposizione dell'interfaccia EJB ai client remoti sotto forma di servizio web.
Gli elementi (b) e (c) implementano il livello [DAO] mostrato nel diagramma precedente. Sappiamo che un'applicazione può accedere a un EJB remoto tramite i protocolli RMI e JNDI. In pratica, questo limita i client a quelli Java. Un servizio web utilizza un protocollo di comunicazione standardizzato che vari linguaggi implementano: .NET, PHP, C++, ... Questo è ciò che vogliamo dimostrare qui utilizzando un client .NET.
Per una breve introduzione ai servizi web, consultare il corso [rif1], 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
![]() |
- da un EJB contrassegnato con l'annotazione @WebService che viene eseguito in un contenitore EJB
![]() |
![]() |
Qui useremo la prima soluzione:
Nel corso [rif. 1], paragrafo 14, pagina 109, troverete un esempio che utilizza la seconda soluzione.
4.4. e la configurazione di Hibernate per il server GlassFish
A seconda della versione, il server GlassFish V2 incluso in NetBeans potrebbe non disporre delle librerie Hibernate richieste dal livello JPA/Hibernate. Se, mentre procedi con il tutorial, ti accorgi che GlassFish non fornisce un'implementazione JPA/Hibernate, o se durante la distribuzione del servizio si verifica un'eccezione che indica che le librerie Hibernate non sono state trovate, devi aggiungere le librerie alla cartella [<glassfish>/domains/domain1/lib/ext] e quindi riavviare il server GlassFish:
![]() |
|
Le librerie Hibernate sono incluse nel file ZIP allegato al tutorial.
4.5. 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. È utile acquisire familiarità con questi metodi di generazione automatica perché il codice generato fornisce preziose indicazioni su come scrivere entità JPA o il codice EJB che le utilizza.
Descriveremo ora alcuni di questi strumenti di generazione automatica. Per comprendere il codice generato, è necessaria una solida conoscenza delle entità JPA [rif. 1] e degli EJB [rif. 2].
Creazione di una connessione NetBeans al database
- Avviare il DBMS MySQL 5 in modo che il database sia disponibile
- Creare una connessione NetBeans al database [dbrdvmedecins]
![]() |
- Nella scheda [File], nella sezione [Database] [1], selezionare il driver JDBC di MySQL [2]
- Quindi seleziona l'opzione [3] "Connetti utilizzando" per creare una connessione a un database MySQL
- In [4], inserisci le informazioni richieste
- quindi confermare in [5]
![]() |
- In [6], la connessione viene creata. È possibile visualizzare le quattro tabelle nel database collegato.
![]() |
- In [1], creare una nuova applicazione, un modulo EJB
- In [2], selezionare la categoria [Java EE] e in [3], selezionare il tipo [Modulo EJB]
![]() |
- In [4], scegli una cartella per il progetto e in [5], assegnagli un nome, quindi completa 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 [Servizi], avvia il server GlassFish [2, 3]
- Nella scheda [Progetti], fare clic con il tasto destro del mouse sul progetto EJB e in [5] selezionare l'opzione [Nuovo / Altro] per 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 [Risorsa JDBC]
- 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], definire 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 al passaggio successivo
- In [15], normalmente non c'è nulla da modificare in questa pagina. Le proprietà della connessione al database MySQL [dbrdvmedecins] sono state prese da quelle della connessione NetBeans [dbrdvmedecins] creata in precedenza
- In [16], passare al passaggio successivo
![]() |
- in [17], mantenere i valori predefiniti forniti
- in [18], completare la procedura guidata. In questo modo viene creato il file [sun-resources.xml] [19] con il seguente contenuto:
Il file sopra riportato contiene tutte le informazioni inserite nella procedura guidata in formato XML. Verrà utilizzato dall'IDE NetBeans per indicare 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: specifica l'implementazione JPA utilizzata (TopLink, Hibernate, ecc.) e la configura.
![]() |
![]() |
- In [1], fare clic con il tasto destro del mouse sul progetto EJB e selezionare [Nuovo / Altro] in [2]
- In [3], selezionare la categoria [Persistenza], quindi in [4], indicare che si desidera creare un'unità di persistenza JPA
![]() |
- In [5], assegnare un nome all'unità di persistenza creata
- In [6], scegli [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, converte le informazioni fornite nella procedura guidata in formato XML. Questo file non è sufficiente per lavorare con il database MySQL5 "dbrdvmedecins". Dovremmo specificare a Hibernate il tipo di DBMS da gestire. Lo faremo in seguito.
![]() |
![]() |
![]() |
- In [1], fare clic con il tasto destro del mouse sul progetto e in [2] selezionare l'opzione [Nuovo / Altro]
- In [3], selezionare la categoria [Persistenza], quindi in [4] indicare che si desidera creare entità JPA da un database esistente.
![]() |
- In [5], selezionare la sorgente JDBC "jdbc/dbrdvmedecins" che abbiamo creato
- In [6], selezionare le quattro tabelle dal 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 per l'entità [Rv], che rappresenta una riga nella tabella [rv] del database [dbrdvmedecins].
Creazione del livello EJB per l'accesso alle entità JPA
![]() |
![]() |
- In [1], fare clic con il tasto destro del mouse sul progetto e in [2] selezionare l'opzione [Nuovo / Altro]
- in [3], selezionare la categoria [Persistenza], quindi in [4] selezionare il tipo [Session Bean per classi di entità]
![]() |
- in [5] vengono visualizzate le entità JPA create in precedenza
- In [6], selezionarle tutte
- In [7], sono state selezionate
- In [8], prosegui con la procedura guidata
![]() |
- In [9], assegnare un nome al pacchetto per gli EJB che verranno generati
- In [10], specificare che gli EJB devono implementare sia un'interfaccia locale che una remota
- Completa la procedura guidata
- in [11], gli EJB generati
Ecco, ad esempio, il codice EJB che gestisce l'accesso all'entità [Rv] e, quindi, alla tabella [rv] nel database [dbrdvmedecins]:
Come accennato, la generazione automatica del codice può essere molto utile per avviare un progetto e familiarizzare con le entità JPA e gli EJB. Nelle sezioni seguenti riscriveremo i livelli JPA ed EJB con il nostro codice, ma il lettore riconoscerà le informazioni che abbiamo appena trattato nella generazione automatica dei livelli.
4.6. Il progetto NetBeans per il modulo EJB
Creiamo un nuovo modulo EJB vuoto (vedere la sezione 4.5):
![]() |
- Il pacchetto [rdvmedecins.entities] contiene le entità del livello JPA
- il pacchetto [rdvmedecins.dao] implementa l'EJB per il livello [dao]
- il pacchetto [rdvmedecins.exceptions] implementa una classe di eccezioni specifica dell'applicazione
Di seguito, si presume che il lettore abbia seguito tutti i passaggi della sezione 4.5. Sarà necessario ripeterne alcuni.
4.6.1. Configurazione del livello JPA
Rivediamo 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 dalle procedure guidate che abbiamo già incontrato:
- La generazione del file [sun-resources.xml] è stata descritta nella Sezione 4.5.
- La generazione del file [persistence.xml] è stata descritta nella sezione 4.5.
Il file [persistence.xml] generato deve essere modificato come segue:
- Riga 3: Il tipo di transazione è 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 (vedere la sezione 4.4).
- Riga 5: l'origine 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 DBMS utilizzato è MySQL5.
L'origine dati "jdbc/dbrdvmedecins" è configurata nel seguente file [sun-resources.xml]:
- Righe 8–10: Le proprietà JDBC dell'origine dati (URL del database, nome utente e password). Il database MySQL `dbrdvmedecins` è quello descritto nella Sezione 4.1.
- Riga 7: le caratteristiche del pool di connessioni associato a questa origine dati
4.6.2. Le entità del livello JPA
Rivediamo l'architettura della nostra applicazione client/server:
![]() |
Il progetto NetBeans:
![]() |
Il pacchetto [rdvmedecins.entites] implementa il livello [Jpa].
Nella Sezione 4.5 abbiamo visto come generare automaticamente entità JPA per un'applicazione. Qui non useremo questa tecnica, ma definiremo le entità noi stessi. Tuttavia, queste incorporeranno gran parte del codice generato nella Sezione 4.5. In questo caso, vogliamo che le entità [Medecin] e [Client] siano classi figlie di una classe [Personne].
La classe Person viene utilizzata per rappresentare medici e clienti:
- Riga 3: Si noti che la classe [Person] non è di per sé 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 [Person]:
- Riga 3: la classe [Client] è un'entità JPA
- riga 4: è associata alla tabella [clients]
- riga 5: deriva dalla classe [Person]
L'entità [Doctor], che incapsula le righe della tabella [doctors], segue lo stesso schema:
L'entità [Creneau] incapsula le righe della tabella [creneaux]:
- Le righe 15–17 modellano la relazione "uno-a-molti" tra la tabella [slots] e la tabella [doctors] nel database.
L'entità [Rv] incapsula le righe della tabella [rv]:
- Le righe 15–17 modellano la relazione "uno-a-molti" tra la tabella [rv] e la tabella [clients] nel database, mentre le righe 18–20 modellano la relazione "uno-a-molti" tra la tabella [rv] e la tabella [slots]
4.6.3. La classe di eccezione
![]() |
La classe di eccezione dell'applicazione [ RdvMedecinsException] è la seguente:
- Riga 6: La classe estende la classe [RuntimeException]. Pertanto, il compilatore non richiede che venga gestita con blocchi try/catch.
- Riga 5: l'annotazione @ApplicationException garantisce che l'eccezione non venga "assorbita" da un'[EjbException].
Per comprendere l'annotazione @ApplicationException, rivediamo l'architettura lato server:
![]() |
L'eccezione [RdvMedecinsException] verrà generata dai metodi EJB nel livello [dao] all'interno del contenitore EJB3 e da esso intercettata. Senza l'annotazione @ApplicationException, il contenitore EJB3 incapsula l'eccezione verificatasi all'interno di una [EjbException] e la rigenera. Potresti non volere questo incapsulamento e preferire che un'eccezione di tipo [RdvMedecinsException] fuoriesca dal contenitore EJB3. Questo è ciò che consente l'annotazione @ApplicationException. Inoltre, l'attributo (rollback=true) di questa annotazione indica al contenitore EJB3 che, se si verifica un'eccezione di tipo [RdvMedecinsException] all'interno di un metodo eseguito come parte di una transazione con un DBMS, la transazione deve essere annullata. In termini tecnici, questo processo è chiamato rollback della transazione.
4.6.4. L'EJB del livello [dao]
![]() |
![]() |
L'interfaccia Java [ IDao] del livello [dao] è la seguente:
L'interfaccia locale dell'EJB [IDaoLocal] estende semplicemente la precedente interfaccia [IDao]:
Lo stesso vale per l'interfaccia remota [IDaoRemote]:
L'EJB [DaoJpa] implementa sia l'interfaccia locale che quella remota:
- La riga 3 indica che l'EJB remoto è denominato "rdvmedecins.dao"
- La riga 4 indica che tutti i metodi dell'EJB vengono eseguiti all'interno di una transazione gestita dal contenitore EJB3.
- La riga 5 mostra che l'EJB implementa le interfacce locale e remota.
Il codice EJB completo è 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. Quando la classe viene istanziata, questo campo verrà inizializzato dal contenitore EJB utilizzando l'annotazione @PersistenceContext alla riga 7.
- riga 15: query JPQL che restituisce tutte le righe della tabella [clients] come un elenco di oggetti [Client].
- riga 22: una query simile per i medici
- Riga 32: una query JPQL che esegue un join tra le tabelle [slots] e [doctors]. È parametrizzata dall’ID del medico.
- Riga 43: una query JPQL che esegue un join tra le tabelle [appointments], [slots] e [doctors] e che ha due parametri: l'ID del medico e la data dell'appuntamento.
- Righe 55–57: creazione di un appuntamento e sua successiva persistenza nel database.
- Riga 67: Elimina un appuntamento dal database.
- Riga 76: esegue una query SELECT sul database per trovare un cliente specifico
- Riga 85: Lo stesso per un medico
- Riga 94: lo stesso per un appuntamento
- Riga 103: lo stesso per una fascia oraria
- Tutte le operazioni che coinvolgono il contesto di persistenza della riga 9 potrebbero incontrare un problema con il database. Pertanto, sono tutte racchiuse in un blocco try/catch. Qualsiasi eccezione è incapsulata nell'eccezione personalizzata 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 l'EJB creato in precedenza sul server GlassFish.
![]() |
- Nelle proprietà del progetto EJB, selezionare le opzioni di runtime [1].
- In [2], il nome del server su cui verrà distribuito l'EJB
- Nella scheda [Servizi] [3], avvialo [4].
![]() |
- In [5], il server GlassFish una volta avviato. Non dispone ancora di un modulo EJB.
- Avviare il server MySQL e assicurarsi che il database [dbrdvmedecins] sia online. A tal fine, è possibile utilizzare la connessione NetBeans creata nella sezione 4.5.
- Nella scheda [Progetti] [6], distribuire il modulo EJB [7]: il DBMS MySQL5 deve essere 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], rimuovere l'EJB distribuito
- In [10], l'EJB non compare più nella struttura ad albero del server GlassFish.
4.8. Distribuzione dell'EJB dal livello [DAO] con GlassFish
Qui mostriamo come distribuire un EJB sul server GlassFish 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 nella Sezione 4.5.
Esaminiamo la configurazione JPA del modulo EJB da distribuire. Questa configurazione è definita nel file [persistence.xml]:
La riga 5 indica che il livello JPA utilizza un'origine dati JTA, ovvero una gestita dal contenitore EJB3, denominata "jdbc/dbrdvmedecins".
Abbiamo visto nella Sezione 4.5 come creare questa risorsa JDBC utilizzando NetBeans. Qui mostriamo come farlo direttamente con GlassFish. Seguiamo la procedura descritta nella Sezione 13.1.2, pagina 79 di [rif1].
Iniziamo eliminando la risorsa in modo da 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 per questa risorsa JDBC
![]() |
- in [4], eliminiamo il pool di connessioni. Ciò comporterà l'eliminazione di tutte le risorse JDBC che lo utilizzano, inclusa 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 [Servizi] [1] di NetBeans, avviare il server GlassFish [2] e quindi accedere [3] alla sua console di amministrazione
- In [4], accedi come amministratore (password: adminadmin se non l'hai modificata durante l'installazione o in seguito).
![]() |
- In [5], seleziona il ramo [Connection Pools] delle risorse di GlassFish
- In [6], creare un nuovo pool di connessioni. Si noti che un pool di connessioni è una tecnica per limitare il numero di connessioni aperte e chiuse con un DBMS. All'avvio del server, vengono aperte N connessioni (un numero definito dalla configurazione) al DBMS. Queste connessioni aperte vengono quindi rese disponibili agli EJB che le richiedono per eseguire un'operazione con il DBMS. Non appena l'operazione è completata, l'EJB restituisce la connessione al pool. La connessione non viene mai chiusa; viene condivisa tra i vari thread che accedono al DBMS
- in [7], assegnare un nome al pool
- in [8], la classe che modella l'origine dati è la classe [javax.sql.DataSource]
- in [9], il DBMS contenente l'origine dati è MySQL in questo caso.
- in [10], procedere al passo successivo
![]() |
- in [11], l'attributo "Connection Validation Required" garantisce che, prima di concedere una connessione, il pool verifichi che sia operativa. In caso contrario, ne crea una nuova. Ciò consente a un'applicazione di continuare a funzionare dopo un'interruzione temporanea del DBMS. Durante l'interruzione, nessuna connessione è utilizzabile e vengono generate delle eccezioni per il client. Al termine dell'interruzione, i client che continuano a richiedere connessioni le ottengono nuovamente: grazie all'attributo "Convalida connessione richiesta", tutte le connessioni nel pool verranno ricreate. Senza questo attributo, il pool rileverebbe che le connessioni iniziali sono andate perse, ma non tenterebbe di crearne di nuove.
- In [12], per le transazioni è specificato il livello di isolamento "Read Committed". Questo livello garantisce che una transazione T2 non possa leggere i dati modificati da una transazione T1 fino a quando quest'ultima non sia completamente completata.
- In [13], specifichiamo che tutte le transazioni devono utilizzare il livello di isolamento specificato in [12]
![]() |
- In [14] e [15], specificare l'URL del database le cui connessioni sono gestite dal pool
- In [16], l'utente sarà root
- In [17], aggiungere una proprietà
- In [18], aggiungere la proprietà "Password" con il valore () in [19]. Sebbene la schermata [19] non lo mostri, non inserire una stringa vuota; inserire invece () (parentesi aperta, parentesi chiusa) per indicare una password vuota. Se l'utente root del DBMS MySQL ha una password non vuota, inserire quella password.
- In [20], completare la procedura guidata di creazione del pool di connessioni per il database MySQL [dbrdvmedecins].
![]() |
- In [21], il pool è stato creato. Fare clic sul relativo collegamento.
- In [22], il pulsante [Ping] consente di stabilire 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], selezionare il ramo [Risorse JDBC] dall'albero degli oggetti del server
- In [2], creare una nuova risorsa JDBC
- In [3], assegnare un nome alla risorsa JDBC. Questo deve corrispondere al nome utilizzato nel file [persistence.xml]:
- In [4], specifica il pool di connessioni che la nuova risorsa JDBC deve utilizzare: quello che hai appena creato
- In [5], completiamo la procedura guidata di creazione
![]() |
- In [6], la nuova risorsa JDBC
Ora che la risorsa JDBC è stata creata, è possibile distribuire il file JAR dell'EJB:
![]() |
- In [1], selezionare il ramo [Enterprise Applications]
- In [2], fare clic sul pulsante [Deploy] per indicare che si desidera distribuire una nuova applicazione
- In [3], specificare che l'applicazione è un modulo EJB
- In [4], selezionare il file JAR EJB [serveur-ejb-dao-jpa-hibernate.jar] fornito per l'esercitazione.
- In [5], è possibile modificare il nome del modulo EJB, se lo si desidera
- In [6], completare la procedura guidata di distribuzione del modulo EJB
![]() |
- In [7], il modulo EJB è stato distribuito. Ora è possibile utilizzarlo.
4.9. Test dell'EJB del livello [DAO]
Ora che l'EJB per il livello [DAO] della nostra applicazione è stato implementato, possiamo testarlo. Lo faremo utilizzando il seguente client Java:
![]() |
La classe [MainTestsDaoRemote] [1] è una classe di test JUnit 4. Le librerie in [2] consistono in:
- il file JAR EJB del livello [DAO] [3] (vedere la sezione 4.6.4).
- le librerie GlassFish [4] necessarie per i client EJB remoti.
La classe di test è la seguente:
- Riga 13: Si noti l'istanziazione del proxy EJB remoto. Utilizziamo il suo nome JNDI "rdvmedecins.dao".
- I metodi di test utilizzano i metodi esposti dall'EJB (vedere la sezione 4.6.4).
Se tutto va bene, i test dovrebbero superare:
![]() |
Ora che l'EJB del livello [dao] è operativo, possiamo procedere a renderlo pubblico tramite un servizio web.
4.10. Il servizio web del livello [dao]
Per una breve introduzione al concetto di servizio web, consultare la sezione 14, pagina 111 di [rif1].
Torniamo all'architettura server della nostra applicazione client/server:
![]() |
Qui ci concentriamo sul servizio web del livello [DAO]. L'unico scopo di questo servizio è rendere l'interfaccia EJB del livello [DAO] disponibile ai client multipiattaforma in grado di comunicare con un servizio web.
Ricordiamo che esistono due modi per implementare un servizio web:
- utilizzando una classe annotata con @WebService che viene eseguita in un contenitore web
![]() |
- utilizzando un EJB annotato con @WebService che viene eseguito in un contenitore EJB
![]() |
In questo caso, utilizziamo la prima soluzione. Nell'IDE NetBeans, dobbiamo creare un progetto enterprise 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 attualmente sviluppando.
Realizzeremo questo progetto enterprise in due modi.
4.10.1. Progetto NetBeans - Versione 1
Per prima cosa, creiamo un progetto NetBeans di tipo "Applicazione Web":
![]() |
- In [1], creare un nuovo progetto nella categoria "Java Web" [2] del tipo "Applicazione Web" [3].
![]() |
- In [4] si assegna un nome al progetto, mentre in [5] si specifica la cartella in cui deve essere generato
- In [6], specifichiamo il server delle applicazioni che eseguirà l'applicazione web
- In [7], impostare il contesto dell'applicazione
- In [8], convalidare la configurazione del progetto.
![]() |
- In [9], il progetto generato. Il servizio web che stiamo realizzando utilizzerà l'EJB del progetto precedente [10]. Pertanto, deve fare riferimento al file .jar del modulo EJB [10].
- In [11], aggiungere un progetto NetBeans alle librerie del progetto web [12]
![]() |
- In [13], selezionare la cartella del modulo EJB nel file system e confermare.
![]() |
- In [14], il modulo EJB è stato aggiunto alle librerie del progetto web.
In [15], implementiamo il servizio web con la seguente classe [WsDaoJpa]:
- Riga 4: La classe [WsdaoJpa] implementa l'interfaccia [IDao]. Ricordiamo che questa interfaccia è definita nell'archivio EJB del livello [dao] come segue:
- Riga 3: L'annotazione @WebService rende la classe [WsDaoJpa] un servizio web.
- Righe 6–7: Il riferimento all'EJB nel livello [DAO] verrà iniettato dal server dell'applicazione nel campo alla riga 7. Si noti che viene sempre iniettata l'implementazione locale (IDaoLocal in questo caso). Questa iniezione è possibile perché 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 chiama semplicemente il metodo M corrispondente dell'EJB iniettato alla riga 7.
La creazione di questo servizio web si riflette in un nuovo ramo nel progetto NetBeans:
![]() |
In [1] vediamo il servizio web WsDaoJpa e in [2] i metodi che esso espone ai client remoti.
Esaminiamo 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 creato
- [2]: il modulo EJB che abbiamo creato in un passaggio precedente, da cui dipende il servizio web
Per distribuirli insieme, dobbiamo combinare i due moduli in un progetto "enterprise" di NetBeans:
![]() |
In [1], creare un nuovo progetto enterprise [2, 3].
![]() |
- In [4,5], assegniamo un nome al progetto e specifichiamo la directory di creazione
- In [6], selezionare il server delle applicazioni su cui verrà distribuita l'applicazione aziendale
- In [7], un progetto aziendale può avere tre componenti: applicazione web, modulo EJB e applicazione client. Qui, il progetto viene creato senza alcun componente. Questi verranno aggiunti in seguito.
![]() |
- 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 nell'IDE. Qui, selezioniamo il modulo web [web-service-server-1-ejb-dao-jpa-hibernate] e il modulo EJB [ejb-server-dao-jpa-hibernate] che abbiamo creato.
- In [11], i due moduli aggiunti al progetto enterprise.
Ora dobbiamo distribuire questa applicazione enterprise sul server GlassFish. Successivamente, è necessario avviare il DBMS MySQL in modo che sia accessibile l'origine dati JDBC "jdbc/dbrdvmedecins" utilizzata dal modulo EJB.
![]() |
- In [1], avviamo il server GlassFish
- Se il modulo EJB [ejb-server-dao-jpa-hibernate] è distribuito, lo scarichiamo [2]
- In [3], distribuire l'applicazione enterprise
![]() |
- In [4], è distribuita. Possiamo vedere che contiene entrambi i moduli: Web ed EJB.
4.10.2. Progetto NetBeans - Versione 2
Ora mostreremo 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 per il 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], che abbiamo già studiato
- [3]: l'archivio EJB per il livello [DAO], che consente alla classe [WsDaoJpa] di accedere alle definizioni delle varie classi, interfacce ed entità nei livelli [DAO] e [JPA].
Quindi creiamo il progetto enterprise necessario per distribuire il servizio web:
![]() |
- [1] Creiamo un'applicazione aziendale [ea-rdvmedecins], inizialmente priva di moduli.
- In [2], aggiungiamo il precedente modulo web [webservice-ejb-dao-jpa-hibernate]
- in [3], il risultato.
Allo stato attuale, 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] in NetBeans.
- In questo archivio [3] si trovano i due componenti dell'applicazione enterprise:
- l'archivio EJB [ejb-server-dao-jpa-hibernate]. Questo archivio è presente perché faceva parte delle librerie a cui fa riferimento il servizio web.
- l'archivio del servizio web [webservice-server-ejb-dao-jpa-hibernate].
- L'archivio [ea-rdvmedecins.ear] viene creato da una semplice compilazione [4] dell'applicazione enterprise.
- In [5], l'operazione di distribuzione fallisce.
Per distribuire l'archivio dell'applicazione aziendale [ea-rdvmedecins.ear], procediamo come illustrato nella distribuzione dell'archivio EJB [ejb-server-dao-jpa-hibernate.jar] nella sezione 4.2. Utilizziamo nuovamente il client di amministrazione web del server GlassFish. Non ripeteremo i passaggi già descritti.
Per prima cosa, inizieremo "scaricando" l'applicazione aziendale distribuita nella sezione 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], selezionare il ramo [Enterprise Applications] del server GlassFish
- in [2], distribuisci una nuova applicazione enterprise
- In [3], selezionare il tipo [Enterprise Application]
- In [4], specificare il file .ear per il progetto NetBeans [ea-rdvmedecins]
- In [5], distribuire questo archivio
![]() |
- In [6], l'applicazione è stata distribuita
- in [7], il servizio web [WsDaoJpa] appare nel ramo [Web Services] del server GlassFish. Selezionarlo.
- In [8] sono disponibili vari dettagli sul servizio web. L'informazione più rilevante per un client è [9]: l'URI del servizio web.
- In [10], è possibile testare il servizio web
![]() |
- In [11], l'URI del servizio web a cui è stato aggiunto il parametro ?test. Questo URI visualizza una pagina di test. Tutti i metodi (@WebMethod) esposti dal servizio web vengono visualizzati e possono essere testati. Qui, testiamo il metodo [13], che recupera l'elenco dei client.
![]() |
- In [14], mostriamo solo una vista parziale della pagina di risposta. Tuttavia, possiamo vedere che il metodo getAllClients ha effettivamente restituito l'elenco dei clienti. Lo screenshot mostra che invia la sua risposta in formato XML.
Un servizio web è descritto in modo completo da un file XML chiamato file WSDL:
![]() |
- In [1] nello strumento web di amministrazione del server GlassFish, selezionare il servizio web [WsDaoJpa]
- In [2], seguire il link [Visualizza WSDL]
![]() |
- In [3]: l'URI del file WSDL. Si tratta di un'informazione importante da conoscere. È necessaria per configurare i client per questo servizio web.
- In [4], la descrizione XML del servizio web. Non commenteremo questo contenuto complesso.
4.10.3. Test JUnit per il servizio web
Creiamo un progetto NetBeans per "eseguire" i test precedentemente effettuati con un client EJB, questa volta utilizzando un client per il servizio web appena implementato. Qui seguiamo una procedura simile a quella descritta nella sezione 14.2.1, pagina 115 di [rif1].
![]() |
- in [1], un classico progetto Java
- In [2], la classe di test
- in [3], il client utilizza l'archivio EJB per accedere alle definizioni dell'interfaccia del livello [DAO] e alle entità JPA. Si noti che questo archivio si trova nella sottocartella [dist] della cartella del modulo EJB.
Per accedere al servizio web remoto, è necessario generare le classi proxy:
![]() |
Nel diagramma sopra, il livello [2] [C=Client] comunica con il livello [1] [S=Server]. Per interagire con il livello [S], il client [C] deve stabilire una connessione di rete con il livello [S] e comunicare con esso utilizzando un protocollo specifico. Le connessioni di rete sono connessioni TCP e il protocollo di trasporto è HTTP. Il livello [S], che rappresenta il servizio web, è implementato da un servlet Java in esecuzione sul server GlassFish. Non abbiamo scritto questo servlet. La sua generazione è automatizzata da GlassFish sulla base delle annotazioni @WebService e @WebMethod nella classe [WsDaoJpa] che abbiamo scritto. Allo stesso modo, automatizzeremo la generazione del livello client [C]. Il livello [C] è talvolta chiamato livello proxy per il servizio web remoto, dove il termine "proxy" si riferisce a un elemento intermediario in una catena software. In questo caso, il proxy C funge da intermediario tra il client che stiamo per scrivere e il servizio web che abbiamo distribuito.
Con NetBeans 6.5, il proxy C può essere generato come segue (per il resto del processo, il servizio web deve essere in esecuzione sul server GlassFish):
![]() |
- In [1], aggiungere un nuovo elemento al progetto Java
- in [2], selezionare il ramo [Servizi Web]
- in [3], selezionare [Web Service Client]
![]() |
- in [4], fornire l'URI del file WSDL del servizio web. Questo URI è stato presentato nella sezione 4.10.2.
- In [5], lasciare il valore predefinito [JAX-WS]. L'altro valore possibile è [JAX-RPC]
- Dopo aver confermato la procedura guidata di creazione del proxy del servizio web, il progetto NetBeans è stato espanso per includere un ramo [Riferimenti ai servizi web] [6]. Questo ramo mostra i metodi esposti dal servizio web remoto.
![]() |
- Nella scheda [Files] [7], è stato aggiunto il codice sorgente Java [8]. Esso corrisponde al proxy C generato.
- In [9] è riportato il codice di una delle classi. Possiamo vedere [10] che sono state inserite in un pacchetto [rdvmedecins.ws]. Non commenteremo il codice di queste classi, che è ancora una volta 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 quindi metodi locali (eseguiti nella stessa JVM) e, in modo trasparente per esso, queste chiamate locali vengono tradotte in chiamate remote.
Dobbiamo ancora 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 per testare l'EJB del livello [dao]:
- riga [13], il test test1 rimane invariato.
- riga [9], il contenuto del metodo [init] è stato eliminato.
A questo punto, il progetto contiene degli errori perché il metodo di test [test1] utilizza le entità [Client], [Medecin], [Creneau] e [Rv], che non si trovano più negli stessi pacchetti di prima. Ora si trovano nel pacchetto proxy C generato. Rimuoviamo le istruzioni di importazione pertinenti e le rigeneriamo utilizzando 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 sapere come utilizzare il proxy C generato nel nostro codice. NetBeans ci aiuta in questo processo.
![]() |
- Selezionare con il mouse il metodo [getAllClients] del servizio web in [1], quindi trascinare questo metodo e rilasciarlo nel metodo [init] della classe di test.
Otteniamo il risultato [2]. Questo scheletro di codice ci mostra come utilizzare il proxy C generato:
- La riga [5] mostra che il metodo [getAllClients] è un metodo dell'oggetto [WsDaoJpa] definito alla riga 3. Il tipo [WsDaoJpa] è un'interfaccia che espone gli stessi metodi esposti dal servizio web remoto.
- Nella riga [3], l'oggetto [WsDaoJpaPort] viene ottenuto da un altro oggetto di tipo [WsDaoJpaService] definito nella riga 2. Il tipo [WsDaoJpaService] rappresenta il proxy C generato localmente.
- L'accesso al servizio web remoto potrebbe non andare a buon fine, pertanto l'intero blocco di codice è racchiuso in un blocco try/catch.
- Gli oggetti proxy C si trovano nel pacchetto [rdvmedecins.ws]
Una volta compreso questo codice, si vede che il riferimento locale al servizio web remoto può essere ottenuto utilizzando il seguente codice:
Il codice per la classe di test JUnit diventa quindi il seguente:
Ora siamo pronti per il test:
![]() |
In [1] viene eseguito il test JUnit. In [2] il test viene superato. Se osserviamo l'output sulla console di NetBeans, vediamo 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 vari campi di un oggetto [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. Questo spiega la visualizzazione precedente. Ciò non sminuisce il test JUnit: è stato superato. Considereremo ora di avere un servizio web operativo.






























































































