Beispiel: Container Managed N:M Relationship zweier Entity Beans (IBM WebSphere)


Beispiel für zwei Container Managed Entity Bean, auf die per Webclient zugegriffen wird. Zwischen den beiden Beans besteht eine Container Managed N:M Relationship.
Dieses Beispiel entspricht (mit Modifikationen) dem Beispiel "NM" für den SunAppServer. Die Deployanleitung bezieht sich auf IBM WebSphere.
Hier gibt es das WebSphere-Projekt zum Download (dies ist ein Projektaustausch-Export, die Importanleitung findet man im Stateless-Beispiel): NMExport.zip

Aufbau des Beispieles

a) Entity Bean-Klasse für ein Wort mit Local-Interfaces.
b) Entity Bean-Klasse für einen Buchstaben mit Local-Interfaces. Beide Beans sind mit einer N-zu-M-Beziehung verbunden.
c) Webclient


Anlegen der Application

Ein Unternehmensanwendungsprojekt mit dem Namen "NM" erstellen.
Zu erzeugende Module definieren. Dieses Beispiel benötigt ein EJB-Projekt und ein Anwendungsclientprojekt.


Anlegen der Entity Bean "Wort"

Es wird eine neue Entity Bean angelegt. Dazu in der J2EE-Hierarchie "EJB-Module" -> "NMEJB" -> "Entity Beans" wählen und im Contextmenü den Punkt "Neu" -> "CMP-Bean" auswählen.
Im ersten Schritt wird das EJB-Projekt gewählt, in dem die Bean erstellt werden soll.
In Schritt 2 wird der Typ der Bean festgelegt: Es handelt sich um eine Bean mit Container Managed Felder, und zwar nach CMP-Version 2. Bean-Name und Package-Name müssen angegeben werden.
Kuchen Bean, Step 1
In Schritt 3 wird festgelegt, dass wir hier ein Local Interface haben wollen. In der unteren Liste fügen wir die Container Managed Attribute zu.
Da IBM WebSphere keine automatisch generierten Primary Keys kennt, müssen wir den Primary Key manuell erzeugen. Wir fügen also ein Feld "id" von Typ "java.lang.Integer" zu.
Wort Bean, Felder (1)
Das einzige Datenfeld unserer Bean ist "Wort". Dieses wird ebenfalls zugefügt.
Kuchen Bean, Felder (2)
Das Ergebnis von Schritt 3 sollte so aussehen:
Wort Bean, Step 2
Damit haben wir das Erstellen der Bean abgeschlossen. Die weiteren Schritte erfolgen, sobald wir die zweite Bean "Buchstabe" angelegt haben.


Anlegen der Entity Bean "Buchstabe"

Es wird eine neue Entity Bean namens "Buchstabe" angelegt.
In Schritt 2 wird der Typ der Bean festgelegt: Es handelt sich um eine Bean mit Container Managed Felder, und zwar nach CMP-Version 2. Bean-Name und Package-Name müssen angegeben werden.
Buchstabe Bean, Step 1
In Schritt 3 wird festgelegt, dass wir hier ein Local Interface haben wollen.
In der unteren Liste fügen wir die Container Managed Attribute zu.
Da IBM WebSphere keine automatisch generierten Primary Keys kennt, müssen wir den Primary Key manuell erzeugen. Wir fügen also ein Feld "id" von Typ "java.lang.Integer" zu.
Buchstabe Bean, Felder (1)
Das einzige Datenfeld unserer Bean ist "Buchstabe". Dieses wird ebenfalls zugefügt.
Buchstabe Bean, Felder (2)
Das Ergebnis von Schritt 3 sollte so aussehen:
Buchstabe Bean, Step 2
Damit haben wir das Erstellen der Bean abgeschlossen. Jetzt können wir uns an die Nachbearbeitung der Beans machen.

Nachbearbeitung der WortBean

Die Methode "findAll" muss implementiert werden. Dazu zum EJB-Implementierungsdeskriptor unter "Abfragen" eine neue Find-Methode namens "findAll" mit dem Rückgabetyp "java.util.Collection" hinzufügen.
Die Query lautet
select object(o) from Wort o order by o.wort

Die Logik für das Verwalten des Primary Keys muss implementiert werden (manuell zu erzeugen !):
Wir definieren eine finder-Methode, die den Datensatz mit der Maximalen Id zurückliefert (mittels einem Subselect). Dies geschieht an der gleichen Stelle im "EJB-Implementierungsdeskriptor" wie die findAll-Methode. Die Finder-Methode hat den Namen "findByMaxId", sie steckt im Local-Interface, und hat als Rückgabewert eine einzelne Wort-Bean.
Die Query sieht so aus:
select object(o) from Wort o where o.id in (select max (oInner.id) from Wort oInner)
Es wird also in einer inneren Abfrage die maximale ID geholt, dann wird der Datensatz zu dieser ID geholt. (Dies führt zu FinderExceptions, wenn noch keine Beans in der Datenbank vorhanden sind).

Weitere Nachbearbeitung:
In der Methode "ejbCreate" entfernen wir den Parameter "id" (im Home-Interface nachziehen !) sowie den Aufruf von "setId(id)". Stattdessen wird die ID mittels einer einzufügenden Methode "getNextId" abgerufen (diese wiederum greift auf "findByMaxId" zu) und in der Bean gesetzt: "this.setId (this.getNextId() )".

Die Methode "ejbCreateByWort" (Rückgabewert: Integer) muss zugefügt werden. Natürlich muss auch "ejbPostCreateByWort" implementiert werden. Diese neue Create-Methode muss auf das LocalHome-Interface hochgestuft werden.

Nachbearbeitung der BuchstabeBean

Die Methode "findAll" muss implementiert werden. Dazu zum EJB-Implementierungsdeskriptor unter "Abfragen" eine neue Find-Methode namens "findAll" mit dem Rückgabetyp "java.util.Collection" hinzufügen.
Die Query lautet
select object(o) from Buchstabe o order by o.buchstabe

Die Methode "findByBuchstabe" (Laden eines Buchstabens anhand des eindeutigen Werts des Felds "Buchstabe") muss implementiert werden. Dazu zum EJB-Implementierungsdeskriptor unter "Abfragen" eine neue Find-Methode namens "findByBuchstabe" mit dem Rückgabetyp "com.knauf.ejb.nm.BuchstabeLocal" hinzufügen. Wichtig ist hier, dass ein Parameter "buchstabe" vom Typ "java.lang.String" zugefügt werden muss.
BuchstabeBean: findByBuchstabe, Schritt 1
Die Query sieht so aus:
select object(o) from Buchstabe o where o.buchstabe = ?1
BuchstabeBean: findByBuchstabe, Schritt 2

Die Logik für das Verwalten des Primary Keys muss implementiert werden (manuell zu erzeugen !):
Wir definieren eine finder-Methode, die den Datensatz mit der Maximalen Id zurückliefert (mittels einem Subselect). Dies geschieht an der gleichen Stelle im "EJB-Implementierungsdeskriptor" wie die findAll-Methode. Die Finder-Methode hat den Namen "findByMaxId", sie steckt im Local-Interface, und hat als Rückgabewert eine einzelne Buchstabe-Bean.
Die Query sieht so aus:
select object(o) from Buchstabe o where o.id in (select max (oInner.id) from Buchstabe oInner)
Es wird also in einer inneren Abfrage die maximale ID geholt, dann wird der Datensatz zu dieser ID geholt. (Dies führt zu FinderExceptions, wenn noch keine Beans in der Datenbank vorhanden sind).

Weitere Nachbearbeitung:
In der Methode "ejbCreate" entfernen wir den Parameter "id" (im Home-Interface nachziehen !) sowie den Aufruf von "setId(id)". Stattdessen wird die ID mittels einer einzufügenden Methode "getNextId" abgerufen (diese wiederum greift auf "findByMaxId" zu) und in der Bean gesetzt: "this.setId (this.getNextId() )".

Die Methode "ejbCreateByBuchstabe" (Rückgabewert: Integer) muss zugefügt werden. Natürlich muss auch "ejbPostCreateByBuchstabe" implementiert werden. Diese neue Create-Methode muss auf das LocalHome-Interface hochgestuft werden.

Erstellen der n:m-Relationship

Im EJB-Implementierungsdeskriptor wählt man die Wort-Bean und geht zu "Beziehungen".
Man klickt auf "Hinzufügen". Im ersten Schritt des Assistenten wählt man die beiden zu verknüpfenden Beans aus.
Wort: Relationship, Schritt 1
Im nächsten Schritt gibt man die Kardinalität der Beziehung an und definiert die Feldnamen der Properties. Als Änderungen sind hier vorzunehmen:
Den Namen der Property "buchstabe" ändern wir in "buchstaben", da ein Wort eine Liste von Buchstaben zurückliefert.
Den Namen der Property "wort" ändern wir in "worte", da ein Buchstabe aus einer Liste von Worten besteht.
Auf beiden Seiten wird als Multiplizität "Many" gewählt.
Wort: Relationship, Schritt 2
Es werden automatisch in der Wort-Bean die Methoden "getBuchstaben" und "setBuchstaben" angelegt. In der BuchstabeBean wird "getWorte" und "setWorte" angelegt. Die Properties erkennt man auch in der J2EE-Hierarchie.

Nachbearbeitung:
In der WortBean werden die drei Methoden "addBuchstabe", "removeBuchstabe" und "getBuchstabenListe" (umwandeln der Buchstaben-Collection aus "getBuchstaben" in eine ArrayList, damit Clients sie verwenden können) zugefügt. Alle drei Methoden müssen auf das Local Interface hochgestuft werden.

In der BuchstabeBean werden die beiden Methoden "addWort" und "getWortListe" (umwandeln der Wort-Collection aus "getWorte" in eine ArrayList, damit Clients sie verwenden können) zugefügt. Die beiden Methoden müssen auf das Local Interface hochgestuft werden.

Anlegen des Webclients

Der Webclient muss die EJB-JARs referenzieren. Dazu in die Eigenschaften des Webmoduls "NMWeb" wechseln und unter "Java-JAR-Abhängigkeiten" das EJB-JAR wählen.
EJB-Verweise festlegen:
Im Webimplementierungsdeskriptor auf die Registerkarte "Verweise" wechseln und lokale Verweise "ejb/Wort" und "ejb/Buchstabe" auf Wort bzw. Buchstabe zufügen. Das Ergebnis sieht so aus:
EJB-Referenzen
Es müssen zwei JSP-Seiten "index.jsp" und "wortedit.jsp" zugefügt werden (Rechtsklick auf "Webmodule" \ "NMWeb", im Contextmenü "Neu" -> "Andere..." wählen und in der Auswahlliste links auf "Web" gehen. Dann rechts "JSP-Seite" auswählen.).

Ausführen des Clients

Die Anwendung ist unter http://localhost:9080/NM/index.jsp zu erreichen.