Entwurfsmuster bei der Implementierung von OpenUSS, Teil 3

Divide et impera!

Von Frank Bensberg und Lofi Dewanto

Nachdem die Techniken für die Dokumenten-Speicherung im Teil 2 dieser Artikelreihe vorgestellt wurden, soll nun auf die Vererbungsproblematik bei EJB eingegangen werden. Ein allgemeines Konzept zur Vererbung und Komposition soll ebenfalls berücksichtigt werden, da es in einer komponentenorientierten und objektorientierten Softwarearchitektur eine wesentliche Grundlage darstellt. Anschließend wird der Zusammenhang dieses Konzeptes mit einer EJB-basierten Diskussionsforums-Komponente in OpenUSS erklärt.

Das Konzept der Vererbung ist eine der wichtigsten Eigenschaften bei objektorientierten Programmiersprachen. In Java wird derzeit ausschließlich die einfache Klassenvererbung unterstützt, da die mehrfache Vererbung – wie beispielsweise in C++ – einige Probleme mit sich bringen kann. Dank des Schnittstellen-Konzeptes in Java kann eine mehrfache Klassenvererbung jedoch simuliert werden. Anders sieht es bei der Schnittstellenvererbung aus, die das Konzept der mehrfachen Vererbung ermöglicht. Die EJB-Architektur nutzt die bereits vorhandenen Vererbungseigenschaften (Klassen- und Schnittstellenvererbung) in Java und bringt keine eigene Erweiterung mit sich. Dies bedeutet, dass der EJB-Entwickler die Vererbung für die EJB-Klassen und -Schnittstellen einzeln und nicht als eine Gesamtheit betrachten muss. Selbstständig muss entschieden werden, welche Klassen bzw. Schnittstellen mit Hilfe der Vererbung implementiert werden sollen.

Lohnt es sich beispielsweise die für die Superklasse bereits geschriebene EJBHome-Schnittstelle zu vererben? Die EJBHome-Schnittstelle muss leider ständig neu geschrieben bzw. erzeugt werden, da in dieser Schnittstelle die Methoden create und find das richtige EJBObject zurückgeben müssen. Hier reicht es nicht aus die Superklasse zurückzuliefern. Dadurch bringt in den meisten Fällen eine Vererbung für die Schnittstelle EJBHome nichts. Als Abhilfe wird die Verwendung von XDoclet [1] empfohlen, um diese EJBHome-Schnittstelle automatisch – und nicht jedesmal manuell – erzeugen zu können. Die EJBObject-Schnittstelle stellt bei der Vererbung kein Problem dar. Diese Schnittstelle kann je nach Bedarf einfach oder mehrfach erweitert werden. Die Bean-Implementierungsklassen EntityBean, SessionBean und MessageDrivenBean sind die wichtigsten Klassen, die bei der Vererbung von Bedeutung sind.

Für die Geschäftsobjekte werden meistens die Entity-Beans verwendet. Die Vererbung der Entity-Beans ist in vielen Fällen sinnvoll, da die Wiederverwendung der Geschäftsobjekte damit gut möglich ist. Bei der Vererbung eines bereits implementierten CMP EntityBean muss darauf geachtet werden, dass bei der Methode ejbCreate die erweiterten Attribute initialisiert werden. Der richtige Primärschlüssel – wenn vorhanden – muss ebenfalls zurückgegeben werden. Für die Implementierung des BMP EntityBean müssen die dazugehörenden Methoden findA, findB usw. das richtige Objekt zurückgeben. Dies bedeutet, dass Entity-Beans und auch ganz allgemein die EJB-Technologie im eigentlichen Sinne keine echte Vererbung unterstützen. Ein Beispiel soll diesen Sachverhalt verdeutlichen. Das Person-Entity-Bean wurde bereits in einem EJB-Container installiert. Das Student-Entity-Bean soll das Person-Entity-Bean anschließend erweitern. Dies stellt zunächst kein Problem dar, wie oben bereits erklärt wurde. Bei der Installation des Student-Entity-Beans müssen jedoch alle Attribute des Person-Entity-Beans im Student-XML-Deskriptor noch einmal geschrieben werden (keine echte Vererbung!). Das heißt, um das Student-Entity-Bean benutzen zu können, muss das Person-Entity-Bean nicht im Container installiert sein. Es reicht vollkommen aus, wenn das Student-Entity-Bean auf die Klasse Person-Entity-Bean zugreifen kann (beispielsweise durch die Classpath-Eintragungen). Das Person-Entity-Bean wird bei der Verwendung des Student-Entity-Beans komplett ignoriert. Dies ist damit zu begründen, dass die EJB-Technologie stark an die relationale Datenbank angelehnt ist.

Zusammengefasst stellt die Vererbung der Entity-Beans (Geschäftsobjekte) – auch wenn keine echte Vererbung möglich ist – kein Problem dar. Wie sieht es nun für die Workflowobjekte aus? Lohnt es sich hierbei Gedanken über die Vererbung zu machen?

Die Session-Beans (stateless und stateful) werden primär für Workflowobjekte (Entwurfsmuster: Session Facade) verwendet. Die Vererbung der Workflowobjekte ist zum Teil problematisch, da die verwendeten Geschäftsobjekte – meistens Entity-Beans – innerhalb der Workflowmethoden direkt angesprochen werden müssen. Als Beispiel kann die Workflowmethode Update von Person genannt werden. In dieser Methode muss das Objekt Person (Entity-Bean) direkt mit allen vorhandenen Attributen angesprochen werden. Bei der Vererbung dieses Workflowobjektes muss die abgeleitete Workflowmethode Update von Student (das Entity-Bean Student erweitert Person) komplett neu geschrieben werden, da das Objekt Student einige neue Attribute mit sich bringt. Die Vererbung der Workflowobjekte ist in bestimmten Fällen jedoch durchaus sinnvoll, so dass in diesem Fall keine allgemeine Aussage getroffen werden kann.

Die Vererbung von MessageDriven-Beans bringt in den meisten Fällen nichts, da die oben aufgezeigte Problematik der Session-Beans ebenfalls vorhanden ist.

Abb. 1: Vererbung in EJB

Für die Wiederverwendung ist es nicht zu empfehlen, nur das Konzept der Vererbung zu verwenden. Das Konzept Vererbung sollte ausschließlich in einer is-a-Beziehung genutzt werden. Im obigen Beispiel stellt die Beziehung zwischen Person und Student eine is-a-Beziehung dar (Ein Student ist eine Person). In vielen Fällen ist die Verwendung des Kompositionskonzeptes für die Wiederverwendung einfacher [3]. In OpenUSS wird sowohl Komposition als auch Vererbung für den Integrationscode in EJB genutzt.

Um ein Geschäftsobjekt dynamisch in der Laufzeit mit neuen Attributen zu erweitern, können die oben genannte Komposition und Vererbung nicht weiterhelfen. Die einfache Komposition und Vererbung müssen in der Compilierungszeit – und nicht erst in der Laufzeit – bereits bekannt sein. Das Entwurfsmuster Property Container ist eine Abhilfe zu dieser Problematik [4]. Dieses Entwurfsmuster wird in die erweiterte bzw. dynamische Komposition kategorisiert. Abpictureung 2 zeigt die Struktur dieses Entwurfsmusters.

Abb. 2: Entwurfsmuster Property Container

Das Objekt BusinessObject implementiert die Schnittstelle PropertyContainer, die die Sammlung von Schlüssel und die dazugehörenden Property-Objekte beinhaltet. Folgender Quellcode-Abschnitt verdeutlicht die Verwendung des Entwurfsmusters Property Container (die Klasse Student implementiert die Schnittstelle PropertyContainer):

Abb. 3: Discussion Extension Component

Die Entwicklung der Diskussionsforums-Komponente beginnt mit der Erstellung des Pakets org.openuss.business.extension.discussion, in dem sich die Schnittstellen DiscussionItemBase, DiscussionFileDescription und DiscussionFileBase befinden. In diesem Paket werden anschließend die Implementierungen der EJBs (EJBHome, EJBObject, EntityBean und SessionBean) ebenfalls durchgeführt. Die Schnittstelle DiscussionItemBase stellt die Hauptschnittstelle für den Beitrag einer Diskussion dar. Alle Pakete, Schnittstellen und Klassen, die hier liegen, werden vollständig unabhängig vom restlichen System bzw. Stand alone entworfen und implementiert. Nachdem die Funktionalitäten eines Diskussionsforums fertig implementiert werden, müssen nur noch die Beziehungen dieser Diskussions-Komponente mit den Foundation Components definiert werden.

Da für jede Veranstaltung in OpenUSS (Foundation Component: Enrollment), die aus Organisation (Faculty), Zeitraum (Semester) und Subjekt (Subject) besteht, ein Diskussionsforum mit mehreren Diskussionsbeiträgen angelegt werden kann, muss eine Beziehung mit der Foundation Component Enrollment aufgebaut werden. Für jede Veranstaltung können mehrere Diskussionsbeiträge angelegt und bearbeitet werden. Die Foundation Component Enrollment dient hier als Extension Point für die Diskussionsforums-Komponente. Um die Eigenschaften der Schnittstelle DiscussionItemBase beizubehalten, muss diese erweitert werden.

Für die Beziehung zwischen den Schnittstellen Enrollment und DiscussionItemBase wird ein neues Paket namens org.openuss.business.extension.discussionfoundation definiert. Innerhalb dieses Pakets wird die Schnittstelle DiscussionItem implementiert, die die Schnittstelle DiscussionItemBase erweitert (Vererbung). Gleichzeitig wird die Beziehung mit dem Foundation Component Enrollment definiert (Komposition). Dieses Paket wird in OpenUSS als Glue Code bzw. Integrationscode bezeichnet. Dank dieses Integrationscodes kann jede Funktionalität zunächst getrennt entwickelt und anschließend an die Foundation Components hinzugefügt werden. Listing 1 zeigt die EJB-Implementierung der Schnittstelle DiscussionItem in der Klasse DiscussionItemBean.

...
package org.openuss.business.extension.discussionfoundation;
...
public class DiscussionItemBean extends DiscussionItemBaseBean implements DiscussionItem {

// Object state
public String enrollmentPK;

// Relationship
protected Enrollment enrollment;

public DiscussionItemPK ejbCreate(String id, String filename,
long size, DiscussionFileBase fileBase, String subject, String text,
java.util.Date date, java.util.Locale locale,
String submitter, String submitterType,
DiscussionItemBase parent, Enrollment enrollment)
throws CreateException {

// Init
super.ejbCreate(id, filename, size, fileBase, subject, text, date,
locale, submitter, submitterType, parent);

try {
// Init object state
this.enrollment = enrollment;
EnrollmentObject enrollmentObject = (EnrollmentObject)enrollment;
enrollmentPK = ((EnrollmentPK)enrollmentObject.getPrimaryKey()).id;
}
catch (Exception ex) {
throw new EJBException("Cannot create the discussion: " + ex);
}

return null;
}

public void ejbPostCreate(String id, String filename,
long size, DiscussionFileBase fileBase, String subject, String text,
java.util.Date date, java.util.Locale locale,
String submitter, String submitterType,
DiscussionItemBase parent, Enrollment enrollment)
throws CreateException {

// Init
super.ejbPostCreate(id, filename, size, fileBase, subject, text, date,
locale, submitter, submitterType, parent);
}

public Enrollment getEnrollment() {
// Lazy load...
try {
if (enrollment != null) {
return enrollment;
}
else {
EnrollmentHome enrollmentHome = (EnrollmentHome)HomeInterfaceFactory.create(
EnrollmentHome.class, EnrollmentHome.COMP_NAME);
enrollment = enrollmentHome.findByPrimaryKey(new EnrollmentPK(enrollmentPK));
return enrollment;
}
}
catch (Exception ex) {
throw new EJBException("Cannot get the enrollment: " + ex);
}
}
...

Die Verwendung des Vererbungskonzeptes in EJB ist leider noch aufwendig, da EJB eine Sammlung von Schnittstellen und keine Gesamtheit – wie es bei JavaBeans der Fall ist – darstellt. Wenn jedoch einmal damit gearbeitet wird, ist das Vererbungskonzept – auch wenn es keine echte Vererbung darstellt – nicht mehr wegzudenken. Für eine komponentenorientierte Softwarearchitektur stellt nicht nur die Vererbung, sondern auch die Komposition ein wichtiges Konzept dar. Die Nutzung beider Konzepte in EJB ist die Basis für die Implementierung eines solch komponentenorientierten Systems.

Die EJB-Artikelreihe über OpenUSS ist nun abgeschlossen. Zu Beginn haben wir den allgemeinen Aufbau des OpenUSS-Systems dargestellt. Dies umfasste u.a. die Vorstellung der Entwurfsmuster Facade, Value Objects und Interface Definition. Im zweiten Teil der Reihe wurde das Entwurfsmuster BLOB skizziert, wobei die Diskussionsforums-Komponente in OpenUSS erstmalig vorgeführt wurde. Bestandteil des letzten Teils der Artikelreihe war das Entwurfsmuster Extension (Komposition und Vererbung) im OpenUSS-System. Die Diskussionsforums-Komponente wurde mit Hilfe dieses Entwurfsmusters in die Foundation Components eingefügt. Tabelle 1 zeigt alle besprochenen Entwurfsmuster auf.

Die Nutzung von Entwurfsmustern ist für heutige komplexe Systemerstellung nicht mehr wegzudenken, wie diese Artikelreihe aufgezeigt hat. Die Entwicklung neuer Methoden und Instrumente zur Beherrschung solcher komplexen Systeme ist ein absolutes Muss. Entwurfsmuster und aspektorientierte Programmierung (für AOP wäre ein eigener Artikel notwendig) zeigen wie die neuen Wege auszusehen haben, um die erzeugten Codes zu beherrschen und wartbar zu machen.

  • [1] XDoclet-Projekt in SourceForge: xdoclet.sourceforge.net
  • [2] Bensberg, F.; Dewanto, L.: Mustergültig; In Javamagazin 12.01.
  • [3] Venners, B.: Composition versus Inheritance; A Comparative Look at Two Fundamental Ways to Relate Classes; In www.artima.com/designtechniques/compoinh.html [23.02.02].
  • [4] Carey, J.; Carlson, B.; Graser, T.: SanFransisco Design Patterns; Addison-Wesley; ISBN 0-201-61644-0.
  • [5] Bensberg, F.; Dewanto, L.: Open Business; In Javamagazin 01.02.
  • [6] Bensberg, F.; Dewanto, L.: BLOB: Big and Beautiful; In Javamagazin 02.02.
    Die aktuellsten Quellcodes können bei OpenUSS heruntergeladen werden: openuss.sourceforge.net
Geschrieben von
Von Frank Bensberg und Lofi Dewanto
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.