4. De webservice J2EE voor afspraken
Laten we terugkeren naar de architectuur van de te bouwen applicatie:
![]() |
In dit deel richten we ons op de ontwikkeling van de webservice J2EE [1] die wordt uitgevoerd op een Sun/Glassfish-server.
4.1. De database
De database, die we [dbrdvmedecins] zullen noemen, is een MySQL5-database met vier tabellen:

4.1.1. De tabel [MEDECINS]
Deze bevat informatie over de artsen die worden beheerd door de applicatie [RdvMedecins].
![]() | ![]() |
- ID: identificatienummer van de arts – primaire sleutel van de tabel
- VERSION: identificatienummer van de versie van de rij in de tabel. Dit nummer wordt telkens met 1 verhoogd wanneer er een wijziging in de rij wordt aangebracht.
- NOM: de achternaam van de arts
- PRENOM: zijn of haar voornaam
- TITRE: zijn/haar aanspreektitel (mevrouw, meisje, meneer)
4.1.2. De tabel [CLIENTS]
De cliënten van de verschillende artsen worden opgeslagen in de tabel [CLIENTS]:
![]() | ![]() |
- ID: identificatienummer van de klant – primaire sleutel van de tabel
- VERSION: nummer dat de versie van de rij in de tabel identificeert. Dit nummer wordt met 1 verhoogd telkens wanneer er een wijziging in de rij wordt aangebracht.
- NOM: de naam van de klant
- PRENOM: de voornaam
- TITRE: zijn/haar aanspreektitel (mevrouw, meisje, heer)
4.1.3. De tabel [CRENEAUX]
Deze tabel geeft een overzicht van de tijdvakken waarin de RV mogelijk zijn:
![]() |
![]() |
- ID: nummer dat het tijdvak identificeert – primaire sleutel van de tabel (regel 8)
- VERSION: nummer dat de versie van de rij in de tabel identificeert. Dit nummer wordt met 1 verhoogd telkens wanneer er een wijziging in de rij wordt aangebracht.
- ID_MEDECIN: nummer dat de arts identificeert aan wie dit tijdslot toebehoort – vreemde sleutel op de kolom MEDECINS (ID).
- HDEBUT: starttijd van het tijdvak
- MDEBUT: minuten begin van het tijdvak
- HFIN: einduur van het tijdvak
- MFIN: minuten einde tijdslot
De tweede regel van de tabel [CRENEAUX] (zie [1] hierboven) geeft bijvoorbeeld aan dat tijdvak nr. 2 om 8.20 uur begint en om 8.40 uur eindigt en toebehoort aan arts nr. 1 (mevrouw Marie PELISSIER).
4.1.4. De tabel [RV]
Deze tabel geeft een overzicht van de RV die voor elke arts zijn vastgelegd:
![]() |
- ID: nummer dat de RV op unieke wijze identificeert – primaire sleutel
- JOUR: dag van de RV
- ID_CRENEAU: tijdvak van RV – externe sleutel op het veld [ID] van de tabel [CRENEAUX] – bepaalt zowel het tijdvak als de betreffende arts.
- ID_CLIENT: nummer van de klant voor wie de reservering is gemaakt – externe sleutel op het veld [ID] van de tabel [CLIENTS]
Deze tabel heeft een uniekheids -beperking op de waarden van de gekoppelde kolommen (JOUR, ID_CRENEAU):
Als een rij in de tabel [RV] de waarde (JOUR1, ID_CRENEAU1) voor de kolommen (JOUR, ID_CRENEAU), dan mag deze waarde nergens anders voorkomen. Anders zou dit betekenen dat er twee RV’en tegelijkertijd voor dezelfde arts zijn vastgelegd. Vanuit het oogpunt van Java-programmering start de JDBC-driver van de database een SQLException wanneer dit zich voordoet.
De regel met id gelijk aan 3 (zie [1] hierboven) betekent dat er op 23/08/2006 een RV is geboekt voor tijdvak nr. 20 en klant nr. 4. Uit de tabel [CRENEAUX] blijkt dat tijdvak nr. 20 overeenkomt met het tijdvak 16.20 - 16.40 uur en toebehoort aan arts nr. 1 (mevrouw Marie PELISSIER). Uit de tabel [CLIENTS] blijkt dat klant nr. 4 mevrouw Brigitte BISTROU is.
4.2. Aanmaken van de database
Maak de database MySql [dbrdvmedecins] aan met een tool naar keuze. Om de tabellen aan te maken en te vullen, kunt u het script [createbd.sql] gebruiken dat u wordt verstrekt. De inhoud ervan is als volgt:
4.3. De elementen van de serverzijde-architectuur
Laten we terugkeren naar de architectuur van de te bouwen applicatie:
![]() |
Aan de serverzijde zal de applicatie bestaan uit:
- een JPA-laag waarmee met de BD kan worden gewerkt door middel van objecten
- een EJB die verantwoordelijk is voor het beheer van de bewerkingen met de JPA-laag
- een webservice die de interface van de EJB in de vorm van een webservice beschikbaar stelt aan externe clients.
De elementen (b) en (c) implementeren de [dao]-laag die in het vorige schema is weergegeven. Het is bekend dat een applicatie toegang kan krijgen tot een externe EJB via de protocollen RMI en JNDI. In de praktijk beperkt dit de clients tot Java-clients. Een webservice maakt gebruik van een gestandaardiseerd communicatieprotocol dat door verschillende talen wordt geïmplementeerd: .NET, PHP, C++, ... Dit willen we hier laten zien aan de hand van een .NET-client.
Voor een korte inleiding tot webservices kunt u de cursus [ref1] raadplegen, paragraaf 14, pagina 109.
Een webservice kan op twee manieren worden geïmplementeerd:
- door een klasse met de annotatie @WebService die in een webcontainer wordt uitgevoerd
![]() |
- door een EJB met de annotatie @WebService die wordt uitgevoerd in een EJB-container
![]() |
![]() |
We gaan hier de eerste oplossing gebruiken:
In de cursus [ref1], paragraaf 14, pagina 109, staat een voorbeeld waarin de tweede oplossing wordt gebruikt.
4.4. Hibernate- configuratie van de GlassFish-server
Afhankelijk van de versie beschikt de Glassfish-server V2 die bij NetBeans wordt geleverd mogelijk niet over de Hibernate-bibliotheken die de JPA/Hibernate-laag nodig heeft. Als u tijdens het doorlopen van de tutorial ontdekt dat Glassfish geen JPA/Hibernate-implementatie aanbiedt of dat er bij het implementeren van de services een uitzondering wordt gemeld dat de Hibernate-bibliotheken niet worden gevonden, moet u de bibliotheken toevoegen aan de map [<glassfish>/domains/domain1/lib/ext] en vervolgens de Glassfish-server opnieuw opstarten:
![]() |
|
De Hibernate-bibliotheken zitten in de zip-bestand dat bij de tutorial hoort.
4.5. De tools voor automatische generatie van NetBeans
Laten we teruggaan naar de architectuur die we moeten bouwen:
![]() |
Met NetBeans is het mogelijk om automatisch de laag [JPA] en de laag [Ejb] te genereren, die de toegang tot de gegenereerde entiteiten JPA regelen. Het is interessant om deze methoden voor automatische generatie te kennen, omdat de gegenereerde code waardevolle aanwijzingen geeft over hoe JPA-entiteiten of de EJB-code die deze gebruikt, moeten worden geschreven.
We beschrijven nu enkele van deze automatische generatietools. Om de gegenereerde code te begrijpen, moet men een goede kennis hebben van de entiteiten JPA, [ref1] en de EJB, [ref2].
Een NetBeans-verbinding met de database maken
- Start de entiteiten SGBD en MySQL 5 op, zodat de entiteit BD beschikbaar is
- Maak een NetBeans-verbinding met de database [dbrdvmedecins]
![]() |
- in het tabblad [Files], in de tak [Databases] [1], selecteer de JDBC-driver MySQL [2]
- en selecteer vervolgens de optie [3] "Connect Using" waarmee u een verbinding kunt maken met een database MySQL
- in [4], voer de gevraagde gegevens in
- en bevestig vervolgens in [5]
![]() |
- in [6] is de verbinding tot stand gebracht. Hier ziet u de vier tabellen van de database waarmee verbinding is gemaakt.
Een EJB-project aanmaken
![]() |
- in [1], maak een nieuwe applicatie aan, een EJB-module
- in [2], de categorie [Java EE] selecteren en in [3] het type [EJB Module]
![]() |
- in [4] een map voor het project kiezen en in [5] het een naam geven – en vervolgens de wizard afsluiten
- in [6] het gegenereerde project
Een resource JDBC toevoegen aan de Glassfish-server
We gaan een bron JDBC toevoegen aan de Glassfish-server.
![]() |
![]() |
- in het tabblad [Services] de Glassfish-server [2, 3] starten
- klik in het tabblad [Projects] met de rechtermuisknop op het EJB-project en selecteer in [5] de optie [New / Other] waarmee u een element aan het project kunt toevoegen.

- in [6], selecteer de categorie [Glassfish] en geef in [7] aan dat je een resource JDBC wilt aanmaken door het type [JDBC Resource] te selecteren
- in [8] aangeven dat deze resource JDBC zijn eigen verbindingspool gaat gebruiken
- in [9], geef de resource JDBC een naam
- in [10], ga naar de volgende stap
![]() |
- in [11] worden de kenmerken van de verbindingspool van de resource JDBC gedefinieerd
- in [12], geef de verbindingspool een naam
- in [13], kies de eerder aangemaakte NetBeans-verbinding [dbrdvmedecins]
- in [14], ga naar de volgende stap
- in [15] hoeft er normaal gesproken niets te worden gewijzigd op deze pagina. De eigenschappen van de databaseverbinding MySQL [dbrdvmedecins] zijn overgenomen van die van de eerder aangemaakte NetBeans-verbinding [dbrdvmedecins]
- in [16], ga naar de volgende stap
![]() |
- naar [17], behoud de voorgestelde standaardwaarden
- naar [18], sluit de wizard af. Deze maakt het bestand [sun-resources.xml] [19] aan met de volgende inhoud:
Het bovenstaande bestand bevat alle informatie die in de wizard is ingevoerd in het formaat XML. Het wordt door NetBeans gebruikt om de GlassFish-server te vragen de in regel 4 gedefinieerde bron "jdbc/dbrdvmedecins" aan te maken.
Een persistentie-eenheid aanmaken
De persistentie-eenheid [persistence.xml] configureert de laag JPA: deze geeft de gebruikte implementatie JPA aan (Toplink, Hibernate, ...) en configureert deze.
![]() |
![]() |
- in [1], klik met de rechtermuisknop op het EJB-project en selecteer [New / Other] in [2]
- in [3], selecteer de categorie [Persistence] en vervolgens in [4], geef aan dat u een persistentie-eenheid wilt aanmaken JPA
![]() |
- in [5], geef de aangemaakte persistentie-eenheid een naam
- in [6], kies [Hibernate] als implementatie JPA
- in [7], selecteer de zojuist aangemaakte Glassfish-resource "jdbc/dbrdvmedecins"
- in [8], geef aan dat er geen actie op de database moet worden uitgevoerd bij het instantiëren van de laag JPA
- sluit de wizard af
- in [9]: het door de wizard aangemaakte bestand [persistence.xml]
De inhoud ervan is als volgt:
Ook hier worden de in de wizard opgegeven gegevens weergegeven in het formaat XML. Dit bestand volstaat niet om te werken met de database MySQL5 "dbrdvmedecins". We zouden aan Hibernate moeten aangeven welk type SGBD moet worden beheerd. Dit zal later worden gedaan.
Aanmaken van de entiteiten JPA
![]() |
![]() |
![]() |
- in [1], klik met de rechtermuisknop op het project en in [2] kies de optie [New / Other]
- in [3], selecteer de categorie [Persistence] en geef vervolgens in [4] aan dat u entiteiten JPA wilt aanmaken op basis van een bestaande database.
![]() |
- in [5] de bron JDBC "jdbc/dbrdvmedecins" selecteren die we hebben aangemaakt
- in [6], de vier tabellen van de bijbehorende database
- in [7,8]: neem ze allemaal op in de generatie van entiteiten in JPA
- in [9], de wizard voortzetten
![]() |
- in [10]: de entiteiten JPA die zullen worden gegenereerd
- in [11], geef het pakket van de entiteiten JPA een naam
- in [12], kies het Java-type dat de lijsten met objecten van de laag JPA zal inkapselen
- sluit de wizard af
- in [13], de vier gegenereerde entiteiten JPA, één voor elke tabel in de database.
Hieronder staat bijvoorbeeld de code van de entiteit [Rv], die een rij van de tabel [rv] uit de database [dbrdvmedecins] vertegenwoordigt.
Aanmaken van de EJB-toegangslaag voor de entiteiten JPA
![]() |
![]() |
- in [1], klik met de rechtermuisknop op het project en in [2], selecteer de optie [New / Other]
- in [3], selecteer de categorie [Persistence] en vervolgens in [4] het type [Session Beans for Entity Classes]
![]() |
- in [5] worden de eerder aangemaakte entiteiten JPA weergegeven
- in [6], selecteer ze allemaal
- in [7] zijn ze geselecteerd
- in [8], ga verder met de wizard
![]() |
- in [9], geef een naam aan het pakket met de EJB’s die zullen worden gegenereerd
- in [10], geef aan dat de EJB’s zowel een lokale als een externe interface moeten implementeren
- de wizard afsluiten
- in [11], de gegenereerde EJB's
Hier is bijvoorbeeld de code van de EJB die de toegang tot de entiteit [Rv] beheert, dus tot de tabel [rv] in de database [dbrdvmedecins]:
Zoals gezegd kan het automatisch genereren van code erg nuttig zijn om een project op te starten en vertrouwd te raken met de entiteiten JPA en EJB. Verderop herschrijven we de lagen JPA en EJB met onze eigen code, maar de lezer zal daar informatie terugvinden die we zojuist hebben besproken bij het automatisch genereren van de lagen.
4.6. Het NetBeans-project van de EJB-module
We maken een nieuwe, lege EJB-module aan (zie paragraaf 4.5):
![]() |
- het pakket [rdvmedecins.entites] bevat de entiteiten van de JPA-laag
- het pakket [rdvmedecins.dao] implementeert de EJB van de laag [dao]
- het pakket [rdvmedecins.exceptions] implementeert een toepassingsspecifieke uitzonderingsklasse
Hierna gaan we ervan uit dat de lezer alle stappen uit paragraaf 4.5 heeft gevolgd. Sommige daarvan zal hij moeten herhalen.
4.6.1. Configuratie van de laag JPA
Laten we nog eens de architectuur van onze client/server-toepassing in herinnering brengen:
![]() |
Het NetBeans-project:
![]() |
De laag [JPA] wordt geconfigureerd door de hierboven genoemde bestanden [persistence.xml] en [sun-resources.xml]. Deze twee bestanden worden gegenereerd door wizards die we al eerder hebben gezien:
- het genereren van het bestand [sun-resources.xml] is beschreven in paragraaf 4.5.
- het genereren van het bestand [persistence.xml] is beschreven in paragraaf 4.5.
Het gegenereerde bestand [persistence.xml] moet als volgt worden aangepast:
- regel 3: het transactietype is JTA: de transacties worden beheerd door de EJB3-container van Glassfish
- regel 4: er wordt een JPA/Hibernate-implementatie gebruikt. Hiervoor is de Hibernate-bibliotheek toegevoegd aan de GlassFish-server (zie paragraaf 4.4).
- regel 5: de gegevensbron JTA die door de JPA-laag wordt gebruikt, heeft de naam JNDI „jdbc/dbrdvmedecins”.
- regel 8: deze regel wordt niet automatisch gegenereerd. Deze moet handmatig worden toegevoegd. Deze geeft aan Hibernate door dat de gebruikte SGBD de MySQL5 is.
De gegevensbron "jdbc/dbrdvmedecins" is geconfigureerd in het volgende bestand [sun-resources.xml]:
- regels 8-10: de JDBC-kenmerken van de gegevensbron (database-URL, gebruikersnaam en wachtwoord). De database MySQL dbrdvmedecins is de database die in paragraaf 4.1 wordt beschreven.
- regel 7: de kenmerken van de verbindingspool die aan deze gegevensbron is gekoppeld
4.6.2. De entiteiten van de laag JPA
Laten we nog eens de architectuur van onze client/server-toepassing in herinnering brengen:
![]() |
Het NetBeans-project:
![]() |
Het pakket [rdvmedecins.entites] implementeert de laag [Jpa].
In paragraaf 4.5 hebben we gezien hoe we automatisch JPA-entiteiten voor een applicatie kunnen genereren. We zullen deze techniek hier niet gebruiken, maar de entiteiten zelf definiëren. Deze zullen echter een groot deel van de in paragraaf 4.5 gegenereerde code overnemen. Hier willen we dat de entiteiten [Medecin] en [Client] dochterklassen zijn van de klasse [Personne].
De klasse Personne wordt gebruikt om artsen en klanten weer te geven:
- regel 3: merk op dat de klasse [Personne] zelf geen entiteit (@Entity) is. Deze klasse zal de bovenliggende klasse van entiteiten zijn. De annotatie @MappedSuperClass duidt deze situatie aan.
De entiteit [Client] omvat de rijen van de tabel [clients]. Deze is afgeleid van de voorgaande klasse [Personne]:
- regel 3: de klasse [Client] is een JPA-entiteit
- regel 4: deze is gekoppeld aan de tabel [clients]
- regel 5: deze is afgeleid van de klasse [Personne]
De entiteit [Medecin], die de rijen van de tabel [medecins] omvat, volgt hetzelfde patroon:
De entiteit [Creneau] omvat de rijen van de tabel [creneaux]:
- de rijen 15-17 modelleren de "één-op-veel"-relatie die bestaat tussen de tabel [creneaux] en de tabel [medecins] in de database.
De entiteit [Rv] omvat de rijen van de tabel [rv]:
- de rijen 15-17 modelleren de „één-op-veel”-relatie die bestaat tussen de tabel [rv] en de tabel [clients] in de database, en de rijen 18-20 de "één-op-veel"-relatie die bestaat tussen de tabel [rv] en de tabel [creneaux]
4.6.3. De uitzonderingsklasse
![]() |
De uitzonderingsklasse [RdvMedecinsException] van de applicatie is als volgt:
- regel 6: de klasse is afgeleid van de klasse [RuntimeException]. De compiler dwingt dus niet om deze met try/catch te behandelen.
- regel 5: de annotatie @ApplicationException zorgt ervoor dat de uitzondering niet wordt ‘opgeslokt’ door een uitzondering van het type [EjbException].
Om de annotatie @ApplicationException te begrijpen, gaan we terug naar de architectuur die aan de serverzijde wordt gebruikt:
![]() |
De uitzondering van het type [RdvMedecinsException] wordt gegenereerd door de EJB-methoden van de laag [dao] binnen de EJB3-container en door deze opgevangen. Zonder de annotatie @ApplicationException kapselt de EJB3-container de opgetreden uitzondering in een uitzondering van het type [EjbException] in en gooit deze opnieuw. Het kan zijn dat men deze inkapseling niet wenst en een uitzondering van het type [RdvMedecinsException] uit de Ejb3-container wil laten ontsnappen. Dit wordt mogelijk gemaakt door de annotatie @ApplicationException. Bovendien geeft het attribuut (rollback=true) van deze annotatie aan de EJB3-container aan dat, als de uitzondering van het type [RdvMedecinsException] optreedt binnen een methode die wordt uitgevoerd in een transactie met een SGBD, deze transactie moet worden teruggedraaid. In technische termen wordt dit een rollback van de transactie uitvoeren genoemd.
4.6.4. De EJB van de laag [dao]
![]() |
![]() |
De Java-interface [IDao] van de laag [dao] is als volgt:
De lokale interface [IDaoLocal] van de EJB is slechts een afgeleide van de voorgaande interface [IDao]:
Hetzelfde geldt voor de externe interface [IDaoRemote]:
De EJB [DaoJpa] implementeert beide interfaces, zowel de lokale als de externe:
- regel 3 geeft aan dat de remote EJB de naam "rdvmedecins.dao" draagt
- regel 4 geeft aan dat alle methoden van de EJB plaatsvinden binnen een transactie die wordt beheerd door de EJB3-container.
- regel 5 laat zien dat de EJB de lokale en de remote-interface implementeert.
De volledige code van de EJB is als volgt:
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 | |
- regel 8: het object EntityManager dat de toegang tot de persistentiecontext beheert. Bij het instantiëren van de klasse wordt dit veld door de EJB-container geïnitialiseerd dankzij de annotatie @PersistenceContext op regel 7.
- regel 15: query JPQL die alle rijen van de tabel [clients] retourneert in de vorm van een lijst met objecten [Client].
- regel 22: soortgelijke query voor artsen
- regel 32: een query JPQL die een join uitvoert tussen de tabellen [creneaux] en [medecins]. Deze wordt ingesteld op basis van de id van de arts.
- regel 43: een query JPQL die een join uitvoert tussen de tabellen [rv], [creneaux] en [medecins] en twee parameters heeft: de id van de arts en de dag van de afspraak.
- regels 55-57: aanmaken van een afspraak en deze vervolgens opslaan in de database.
- regel 67: verwijdering van een afspraak uit de database.
- regel 76: voert een SELECT-query uit op de database om een bepaalde klant te vinden
- regel 85: idem voor een arts
- regel 94: idem voor een afspraak
- regel 103: idem voor een tijdslot
- Alle bewerkingen met de persistentie-context em uit regel 9 kunnen een probleem met de database veroorzaken. Daarom zijn ze allemaal omgeven door een try/catch-blok. De eventuele uitzondering wordt ingekapseld in de "huis"-uitzondering RdvMedecinsException.
De EJB-module levert na compilatie een .jar-bestand op met de :
![]() |
4.7. Implementatie van de EJB van de laag [dao] met NetBeans
Met NetBeans kun je de eerder gemaakte EJB eenvoudig op de GlassFish-server implementeren.
![]() |
- Controleer in de eigenschappen van het EJB-project de uitvoeringsopties [1].
- In [2]: de naam van de server waarop de EJB wordt geïmplementeerd
- in het tabblad [Services] [3] start u het op [4].
![]() |
- in [5], de Glassfish-server zodra deze is gestart. Deze heeft nog geen EJB-module.
- Start de server MySQL en controleer of de database [dbrdvmedecins] online is. Hiervoor kunt u de NetBeans-verbinding gebruiken die in paragraaf 4.5 is aangemaakt.
- In het tabblad [Projects] [6] wordt de EJB-module [7] geïmplementeerd: SGBD MySQL5 moet gestart zijn, zodat de door de EJB gebruikte bron JDBC "jdbc/dbrdvmedecins" toegankelijk is.
- In [8] verschijnt de geïmplementeerde EJB in de boomstructuur van de GlassFish-server
![]() |
- In [9] wordt de geïmplementeerde EJB verwijderd
- in [10] verschijnt de EJB niet meer in de boomstructuur van de GlassFish-server.
4.8. Implementatie van de EJB van de laag [dao] met GlassFish
Hier laten we zien hoe je een EJB vanuit het bijbehorende .jar-archief op de GlassFish-server implementeert.
- Start de MySQL-server en controleer of de database [dbrdvmedecins] online is. Hiervoor kunt u de NetBeans-verbinding gebruiken die in paragraaf 4.5 is aangemaakt.
Laten we nog even de JPA-configuratie van de EJB-module die geïmplementeerd gaat worden, in herinnering brengen. Deze configuratie is vastgelegd in het bestand [persistence.xml]:
Regel 5 geeft aan dat de JPA-laag gebruikmaakt van een gegevensbron JTA, c.a.d, die wordt beheerd door de EJB3-container met de naam "jdbc/dbrdvmedecins".
In paragraaf 4.5 hebben we gezien hoe we deze bron JDBC vanuit NetBeans kunnen aanmaken. Hier laten we zien hoe dit rechtstreeks met GlassFish kan worden gedaan. We volgen hierbij een procedure die wordt beschreven in paragraaf 13.1.2, pagina 79 van [ref1].
We beginnen met het verwijderen van de resource, zodat we deze opnieuw kunnen aanmaken. Dit doen we vanuit NetBeans:
![]() |
- in [1], de resources JDBC van de GlassFish-server
- in [2], de resource "jdbc/dbrdvmedecins" van onze EJB
- in [3], de verbindingspool van deze resource JDBC
![]() |
- in [4], verwijderen we de verbindingspool. Dit heeft tot gevolg dat alle bronnen JDBC die hiervan gebruikmaken, worden verwijderd, dus ook de bron "jdbc/dbrdvmedecins".
- In [5] en [6] zijn de resource JDBC en de verbindingspool verwijderd.
Nu gebruiken we de beheerconsole van de Glassfish-server om de resource JDBC aan te maken en de EJB te implementeren.
![]() |
- in het tabblad [services] [1] van NetBeans, start de GlassFish-server [2] en ga vervolgens naar [3] de beheerconsole
- in [4], log in als beheerder (wachtwoord: adminadmin als u dit tijdens de installatie of daarna niet hebt gewijzigd).
![]() |
- in [5], selecteer de tak [Connection Pools] van de GlassFish-bronnen
- in [6], maak een nieuwe verbindingspool aan. Ter herinnering: een verbindingspool is een techniek om het aantal keer dat verbindingen met een SGBD worden geopend en gesloten te beperken. Bij het opstarten van de server N worden er, een aantal dat per configuratie wordt bepaald, verbindingen geopend met de SGBD. Deze geopende verbindingen worden vervolgens ter beschikking gesteld aan de EJB’s die erom vragen om een bewerking uit te voeren met de SGBD. Zodra deze is voltooid, geeft de EJB de verbinding terug aan de pool. De verbinding wordt nooit gesloten. Deze wordt gedeeld door de verschillende threads die toegang hebben tot de SGBD
- in [7], geef de pool een naam
- in [8]; de klasse die de gegevensbron modelleert is de klasse [javax.sql.DataSource]
- in [9], de SGBD die de gegevensbron bevat, is hier MySQl.
- in [10], ga dan naar de volgende stap
![]() |
- In [11] zorgt het attribuut "Connection Validation Required" ervoor dat de pool, voordat een verbinding wordt toegewezen, controleert of deze operationeel is. Als dat niet het geval is, maakt de pool een nieuwe verbinding aan. Hierdoor kan een applicatie blijven functioneren na een tijdelijke onderbreking met de SGBD. Tijdens de onderbreking is er geen enkele verbinding bruikbaar en worden er uitzonderingen doorgegeven aan de client. Zodra de onderbreking voorbij is, krijgen de clients die nog steeds verbindingen aanvragen deze weer toegewezen: dankzij het attribuut "Connection Validation Required" worden alle verbindingen in de pool opnieuw aangemaakt. Zonder dit attribuut zou de pool weliswaar vaststellen dat de oorspronkelijke verbindingen zijn verbroken, maar zou hij niet proberen nieuwe aan te maken.
- In [12] wordt het isolatieniveau „Read Committed“ voor transacties gevraagd. Dit niveau zorgt ervoor dat een transactie T2 geen gegevens kan lezen die zijn gewijzigd door een transactie T1, zolang deze laatste niet volledig is voltooid.
- In [13] wordt gevraagd dat alle transacties het isolatieniveau gebruiken dat is opgegeven in [12]
![]() |
- in [14] en [15] moet u de URL specificeren van de BD waarvan de pool de verbindingen beheert
- in [16], de gebruiker is dan root
- in [17], voeg een eigenschap toe
- in [18]: voeg de eigenschap "Password" toe met de waarde () in [19]. Hoewel dit niet te zien is op de schermafbeelding van [19], mag je geen lege tekenreeks invoeren, maar wel () (open haakje, sluitend haakje) om een leeg wachtwoord aan te duiden. Als de gebruiker root van uw SGBD MySQL een niet-leeg wachtwoord heeft, voer dan dit wachtwoord in.
- in [20], voltooi dan de wizard voor het aanmaken van de verbindingspool voor de database MySQL [dbrdvmedecins].
![]() |
- in [21] is de pool aangemaakt. Klik op de link.
- in [22] kunt u met de knop [Ping] een verbinding tot stand brengen met de database [dbrdvmedecins]
- in [23]: als alles goed gaat, verschijnt er een bericht dat de verbinding tot stand is gebracht
Zodra de verbindingspool is aangemaakt, kun je een JDBC-bron aanmaken:
![]() |
- in [1]. Selecteer de tak [JDBC Resources] in de objectboom van de server
- in [2] maakt u een nieuwe bron aan: JDBC
- in [3], geef je de bron JDBC een naam. Deze moet overeenkomen met de naam die in het bestand [persistence.xml] wordt gebruikt:
- in [4] wordt de verbindingspool gespecificeerd die de nieuwe resource JDBC moet gebruiken: de pool die zojuist is aangemaakt
- In [5] voltooit u de aanmaakwizard
![]() |
- in [6] de nieuwe resource JDBC
Nu de resource JDBC is aangemaakt, kunnen we het JAR-archief van de EJB implementeren:
![]() |
- naar [1], selecteer de branch [Enterprise Applications]
- naar [2], met de knop [Deploy], geef aan dat u een nieuwe applicatie wilt implementeren
- in [3], geef aan dat de applicatie een EJB-module is
- in [4] selecteert u de EJB-jar [serveur-ejb-dao-jpa-hibernate.jar] die u voor TP hebt ontvangen.
- in [5] kunt u de naam van de EJB-module desgewenst wijzigen
- in [6]: voltooi de implementatiewizard voor de EJB-module
![]() |
- In [7] is de EJB-module geïmplementeerd. Deze kan nu worden gebruikt.
4.9. Testen van de EJB van de laag [dao]
Nu de EJB van de laag [dao] van onze applicatie is geïmplementeerd, kunnen we deze testen. We doen dit met behulp van de volgende Java-client:
![]() |
De klasse [MainTestsDaoRemote] [1] is een testklasse JUnit 4. De bibliotheken in [2] bestaan enerzijds uit:
- de JAR-bestanden van de EJB van de laag [dao] [3] (zie paragraaf 4.6.4).
- de GlassFish-bibliotheken [4] die nodig zijn voor de externe clients van de EJB's.
De testklasse is als volgt:
- regel 13: let op de instantiëring van de proxy van de externe EJB. We gebruiken de naam JNDI "rdvmedecins.dao".
- De testmethoden maken gebruik van de methoden die door de EJB worden blootgesteld (zie paragraaf 4.6.4).
Als alles goed gaat, moeten de tests slagen:
![]() |
Nu de EJB van de laag [dao] operationeel is, kunnen we overgaan tot de openbare beschikbaarstelling ervan via een webservice.
4.10. De webservice van de laag [dao]
Voor een korte inleiding tot het begrip webservice verwijzen we naar paragraaf 14, pagina 111 van [ref1].
Laten we terugkeren naar de serverarchitectuur van onze client/server-toepassing:
![]() |
Hierboven richten we ons op de webservice van de laag [dao]. Deze service heeft als enige taak de interface van de EJB van de laag [dao] beschikbaar te maken voor clients op verschillende platforms die in staat zijn om met een webservice te communiceren.
Ter herinnering: er zijn twee manieren om een webservice te implementeren:
- via een klasse met de annotatie @WebService die in een webcontainer wordt uitgevoerd
![]() |
- via een EJB met de annotatie @WebService die wordt uitgevoerd in een EJB-container
![]() |
We gebruiken hier de eerste oplossing. In NetBeans moeten we een bedrijfsproject opzetten met twee modules:
- de EJB-module die in de EJB-container wordt uitgevoerd: de EJB van de [dao]-laag.
- de webmodule die in de webcontainer zal draaien: de webservice die we momenteel aan het bouwen zijn.
We gaan dit bedrijfsproject op twee manieren opzetten.
4.10.1. NetBeans-project – Versie 1
We bouwen eerst een NetBeans-project van het type „Web Application“:
![]() |
- in [1] maken we een nieuw project aan in de categorie "Java Web" [2] van het type "Web Application" [3].
![]() |
- in [4], geef je het project een naam en in [5] geef je de map aan waarin het moet worden gegenereerd
- in [6] stel je de applicatieserver in die de webapplicatie gaat uitvoeren
- in [7] wordt de context van de applicatie ingesteld
- in [8] wordt de projectconfiguratie gevalideerd.
![]() |
- in [9] wordt het gegenereerde project weergegeven. De webservice die we bouwen, zal gebruikmaken van de EJB van het vorige project [10]. Daarom moet er worden verwezen naar de .jar van de EJB-module [10].
- In [11] voegen we een NetBeans-project toe aan de bibliotheken van het webproject [12]
![]() |
- in [13] selecteert men de map van de EJB-module in het bestandssysteem en bevestigt men.
![]() |
- in [14] is de EJB-module toegevoegd aan de bibliotheken van het webproject.
In [15] implementeren we de webservice met de volgende klasse [WsDaoJpa]:
- In regel 4 implementeert de klasse [WsdaoJpa] de interface [IDao]. Ter herinnering: deze interface is gedefinieerd in het EJB-archief van de laag [dao] in de volgende vorm:
- regel 3: de annotatie @WebService maakt van de klasse [WsDaoJpa] een webservice.
- regels 6-7: de EJB-referentie van de laag [dao] wordt door de applicatieserver in het veld van regel 7 geïnjecteerd. Ter herinnering: het is altijd de lokale implementatie (hier IDaoLocal) die op deze manier wordt geïnjecteerd. Deze injectie is mogelijk omdat de webservice in dezelfde JVM draait als de EJB.
- Alle methoden van de webservice zijn gemarkeerd met de annotatie @WebMethod om ze zichtbaar te maken voor externe clients. Een methode die niet is gemarkeerd met de annotatie @WebMethod zou intern zijn voor de webservice en niet zichtbaar voor externe clients. Elke methode M van de webservice roept gewoon de overeenkomstige methode M aan van de EJB die op regel 7 is geïnjecteerd.
Het aanmaken van deze webservice wordt weerspiegeld door een nieuwe tak in het NetBeans-project:
![]() |
In [1] zien we de webservice WsDaoJpa en in [2] de methoden die deze aan externe clients blootstelt.
Laten we nog eens de architectuur van de webdienst in ontwikkeling bekijken:
![]() |
De componenten van de webservice die we gaan implementeren zijn:
- [1]: de webmodule die we zojuist hebben gebouwd
- [2]: de EJB-module die we in een eerdere stap hebben gebouwd en waarvan de webservice afhankelijk is
Om ze samen te implementeren, moeten de twee modules worden samengebracht in een zogenaamd "bedrijfs"-project in NetBeans:
![]() |
In [1] maken we een nieuw bedrijfsproject aan: [2, 3].
![]() |
- In [4,5] geef je het project een naam en stel je de map in waarin het wordt aangemaakt
- in [6] kiest men de applicatieserver waarop de bedrijfsapplicatie zal worden geïmplementeerd
- in [7]: een bedrijfsproject kan drie componenten hebben: webapplicatie, EJB-module, clientapplicatie. Hier wordt het project zonder componenten aangemaakt. Deze worden later toegevoegd.
![]() |
- in [8], de zojuist aangemaakte bedrijfsapplicatie.
![]() |
- in [9], klik met de rechtermuisknop op [Java EE Modules] en voeg een nieuwe module toe
- in [10] worden alleen de NetBeans-modules weergegeven die momenteel geopend zijn in IDE. Hier selecteren we de webmodule [serveur-webservice-1-ejb-dao-jpa-hibernate] en de EJB-module [serveur-ejb-dao-jpa-hibernate] die we hebben gebouwd.
- In [11] zijn de twee modules toegevoegd aan het bedrijfsproject.
Nu moeten we deze bedrijfsapplicatie nog op de GlassFish-server implementeren. Vervolgens moet SGBD MySQL worden gestart, zodat de gegevensbron JDBC "jdbc/dbrdvmedecins" die door de EJB-module wordt gebruikt, toegankelijk is.
![]() |
- in [1] wordt de Glassfish-server gestart
- als de EJB-module [serveur-ejb-dao-jpa-hibernate] is geïmplementeerd, wordt deze ontkoppeld [2]
- naar [3], wordt de bedrijfsapplicatie geïmplementeerd
![]() |
- in [4] is deze geïmplementeerd. We zien dat deze de twee modules bevat: Web en EJB.
4.10.2. NetBeans-project – versie 2
We laten nu zien hoe de webservice geïmplementeerd kan worden wanneer men niet over de broncode van de EJB-module beschikt, maar alleen over het bijbehorende .jar-archief.
Het nieuwe NetBeans-project voor de webservice ziet er als volgt uit:
![]() |
De opvallende elementen van het project zijn de volgende:
- [1]: de webservice wordt geïmplementeerd door een NetBeans-project van het type [Web Application].
- [2]: de webservice wordt geïmplementeerd door de klasse [WsDaoJpa] die we al hebben besproken
- [3]: het EJB-archief van de laag [dao], waardoor de klasse [WsDaoJpa] toegang heeft tot de definities van de verschillende klassen, interfaces en entiteiten van de lagen [dao] en [jpa].
Vervolgens bouwen we het bedrijfsproject dat nodig is voor de implementatie van de webservice:
![]() |
- [1], we maken een bedrijfsapplicatie [ea-rdvmedecins], in eerste instantie zonder modules.
- In [2] voegen we de eerdere webmodule [serveur-webservice-ejb-dao-jpa-hibernate] toe
- in [3], het resultaat.
In deze vorm kan de bedrijfsapplicatie [ea-rdvmedecins] niet vanuit NetBeans op de GlassFish-server worden geïmplementeerd. Er treedt een fout op. Het ear-archief van de applicatie [ea-rdvmedecins] moet dan handmatig worden geïmplementeerd:
![]() |
- Het archief [ea-rdvmedecins.ear] is te vinden in de map [dist] [2] op het tabblad [Files] van NetBeans.
- In dit archief [3] bevinden zich de twee onderdelen van de bedrijfsapplicatie:
- het EJB-archief [serveur-ejb-dao-jpa-hibernate]. Dit archief is aanwezig omdat het deel uitmaakte van de bibliotheken waarnaar de webservice verwijst.
- het archief van de webservice [serveur-webservice- ejb-dao-jpa-hibernate].
- Het archief [ea-rdvmedecins.ear] is samengesteld uit een eenvoudig Build en [4] van de bedrijfsapplicatie.
- In [5] mislukt de implementatiebewerking.
Om het archief [ea-rdvmedecins.ear] van de bedrijfsapplicatie te implementeren, gaan we te werk zoals beschreven bij de implementatie van het EJB-archief [serveur-ejb-dao-jpa-hibernate.jar] in paragraaf 4.2. We gebruiken opnieuw de webclient voor het beheer van de GlassFish-server. We herhalen de reeds beschreven stappen niet.
Allereerst beginnen we met het „uitpakken“ van de bedrijfsapplicatie die in paragraaf 4.10.1 is geïmplementeerd:
![]() |
- [1]: selecteer de branch [Enterprise Applications] van de GlassFish-server
- selecteer in [2] de bedrijfsapplicatie die moet worden verwijderd en verwijder deze vervolgens in [3]
- in [4] is de bedrijfsapplicatie verwijderd
![]() |
- in [1], kies de branch [Enterprise Applications] van de Glassfish-server
- in [2], implementeer een nieuwe bedrijfsapplicatie
- in [3], selecteer het type [Enterprise Application]
- in [4], wijs het .ear-bestand van het NetBeans-project aan [ea-rdvmedecins]
- in [5], implementeer dit archief
![]() |
- in [6], de applicatie is geïmplementeerd
- in [7], de webservice [WsDaoJpa] verschijnt in de branch [Web Services] van de GlassFish-server. We selecteren deze.
- In [8] is diverse informatie over de webservice beschikbaar. Het meest interessant voor een klant is de informatie [9]: de URI van de webservice.
- In [10] kun je de webservice testen
![]() |
- In [11] is de -URI van de webservice waaraan de parameter ?test is toegevoegd. Deze URI toont een testpagina. Alle methoden (@WebMethod) die door de webservice worden aangeboden, worden weergegeven en kunnen worden getest. Hier testen we de methode [13], die de lijst met klanten opvraagt.
![]() |
- In [14] tonen we slechts een gedeeltelijk overzicht van de antwoordpagina. Maar we kunnen zien dat de methode getAllClients de lijst met klanten inderdaad heeft teruggestuurd. De schermafbeelding laat zien dat de methode haar antwoord in het formaat XML verstuurt.
Een webservice wordt volledig beschreven door een bestand met de naam XML, ook wel het WSDL-bestand genoemd:
![]() |
- in [1] in de webbeheertool van de Glassfish-server, selecteer de webservice [WsDaoJpa]
- naar [2], volg de link [View WSDL]
![]() |
- naar [3]: de URI van het bestand WSDL. Dit is belangrijke informatie om te weten. Deze is nodig om de clients van deze webservice te configureren.
- in [4], de beschrijving XML van de webservice. We zullen geen toelichting geven op deze complexe inhoud.
4.10.3. Tests JUnit van de webservice
We maken een NetBeans-project aan om de tests die al met een EJB-client zijn uitgevoerd, nu te „herhalen” met een client voor de onlangs geïmplementeerde webservice. We volgen hierbij een aanpak die vergelijkbaar is met die beschreven in paragraaf 14.2.1, pagina 115 van [ref1].
![]() |
- in [1], een klassiek Java-project
- in [2], de testklasse
- in [3] gebruikt de client het EJB-archief om toegang te krijgen tot de definities van de interface van de laag [dao] en de JPA-entiteiten. Ter herinnering: dit archief bevindt zich in de submap [dist] van de EJB-modulemap.
Om toegang te krijgen tot de externe webservice, moeten er proxyklassen worden gegenereerd:
![]() |
In het bovenstaande schema communiceert de laag [2] [C=Client] met de laag [1] [S=Serveur]. Om te communiceren met de laag [S] moet de client [C] een netwerkverbinding tot stand brengen met de laag [S] en met deze laag communiceren volgens een specifiek protocol. De netwerkverbindingen zijn van het type TCP en het transportprotocol is HTTP. De laag [S], die de webservice vertegenwoordigt, wordt geïmplementeerd door een Java-servlet die wordt uitgevoerd door de Glassfish-server. We hebben deze servlet niet zelf geschreven. De generatie ervan wordt door Glassfish geautomatiseerd op basis van de annotaties @Webservice en @WebMethod van de klasse [WsDaoJpa] die we hebben geschreven. Op dezelfde manier gaan we de generatie van de [C]-laag van de client automatiseren. De laag [C] wordt soms een proxylaag van de externe webservice genoemd, waarbij de term proxy verwijst naar een tussenelement in een softwareketen. Hier fungeert de C-proxy als tussenpersoon tussen de client die we gaan schrijven en de webservice die we hebben geïmplementeerd.
Met NetBeans 6.5 kan de C-proxy als volgt worden gegenereerd (hiervoor moet de webservice actief zijn op de GlassFish-server):
![]() |
- in [1], voeg een nieuw element toe aan het Java-project
- in [2], selecteer de branch [Web services]
- in [3], selecteer [Web Service Client]
![]() |
- in [4], de URI van het bestand WSDL van de webservice opgeven. Deze URI is beschreven in paragraaf 4.10.2.
- in [5], laat de standaardwaarde [JAX-WS] staan. De andere mogelijke waarde is [JAX-RPC]
- Nadat de wizard voor het aanmaken van de webservice-proxy was bevestigd, werd het NetBeans-project uitgebreid met een tak [Web Service References] [6]. Deze tak toont de methoden die door de externe webservice worden aangeboden.
![]() |
- Op het tabblad [Files] [7] is Java-broncode toegevoegd [8]. Deze komt overeen met de gegenereerde C-proxy.
- In [9] staat de code van een van de klassen. Daaruit blijkt [10] dat ze in een pakket [rdvmedecins.ws] zijn geplaatst. We zullen geen commentaar geven op de code van deze klassen, die opnieuw vrij complex is.
Voor de Java-client die we aan het bouwen zijn, fungeert de gegenereerde C-proxy als tussenpersoon. Om toegang te krijgen tot de methode M van de externe webservice, roept de Java-client de methode M van de C-proxy aan. De Java-client roept dus lokale methoden aan (die in dezelfde JVM worden uitgevoerd) en op een voor hem transparante manier worden deze lokale aanroepen omgezet in externe aanroepen.
Nu moeten we nog leren hoe we de methoden M van de C-proxy kunnen aanroepen. Laten we teruggaan naar onze testklasse JUnit:
![]() |
In [1] is de testklasse [MainTestsDaoRemote] dezelfde die al werd gebruikt bij het testen van de EJB van de laag [dao]:
- regel [13]: de test test1 blijft ongewijzigd.
- regel [9]: de inhoud van de methode [init] is verwijderd.
Op dit moment bevat het project fouten, omdat de testmethode [test1] gebruikmaakt van de entiteiten [Client], [Medecin], [Creneau], [Rv], die zich niet meer in dezelfde pakketten bevinden als voorheen. Ze bevinden zich nu in het pakket van de gegenereerde C-proxy. De betreffende instructies import worden verwijderd en vervolgens opnieuw gegenereerd met de bewerking ‘Fix Imports’.
![]() |
Laten we teruggaan naar de code van de testklasse [MainTestsDaoRemote]:
De methode [init] op regel 10 moet de referentie van de laag [dao] op regel 7 initialiseren. We moeten weten hoe we de gegenereerde C-proxy in onze code kunnen gebruiken. NetBeans helpt ons hierbij.
![]() |
- Selecteer in [1] de methode [getAllClients] van de webservice met de muis en sleep deze methode vervolgens naar de methode [init] van de testklasse.
Het resultaat is [2]. Dit codekader laat zien hoe de gegenereerde C-proxy moet worden gebruikt:
- De regel [5] laat zien dat de methode [getAllClients] een methode is van het object van het type [WsDaoJpa], gedefinieerd op regel 3. Het type [WsDaoJpa] is een interface met dezelfde methoden als die welke door de externe webservice worden blootgesteld.
- In regel [3] wordt het object [WsDaoJpa port] verkregen uit een ander object van het type [WsDaoJpaService], gedefinieerd in regel 2. Het type [WsDaoJpaService] vertegenwoordigt de lokaal gegenereerde C-proxy.
- De toegang tot de externe webservice kan mislukken, daarom is de volledige code omgeven door een try/catch-blok.
- De objecten van de C-proxy bevinden zich in het pakket [rdvmedecins.ws]
Als je deze code eenmaal begrijpt, zie je dat de lokale referentie van de externe webservice kan worden verkregen met de volgende code:
De code van de testklasse JUnit wordt dan als volgt:
We zijn nu klaar om te testen:
![]() |
In [1] wordt de test JUnit uitgevoerd. In [2] is deze geslaagd. Als we de uitvoer op de NetBeans-console bekijken, zien we regels zoals de volgende:
Liste des clients :
rdvmedecins.ws.Client@1982fc1
rdvmedecins.ws.Client@676437
rdvmedecins.ws.Client@1e4853f
rdvmedecins.ws.Client@1e808ca
Aan de serverzijde heeft de entiteit [Client] een methode toString die de verschillende velden van een object van het type [Client] weergeeft. Bij het automatisch genereren van de C-proxy worden de entiteiten in de C-proxy aangemaakt, maar dan alleen met de privévelden en de bijbehorende get-/set-methoden. De methode toString is dus niet gegenereerd in de entiteit [Client] van de C-proxy. Dit verklaart de eerder getoonde weergave. Dit doet niets af aan de test JUnit: deze is geslaagd. We gaan er nu vanuit dat we een operationele webservice hebben.






























































































