Die Firma Sun Microsystems definiert ein Bean wie folgt: „Ein Java-Bean ist eine wiederverwendbare Software-Komponente, die in einer Entwicklungsumgebung visuell bearbeitet werden kann." Mit dieser Definition führt Sun mit JavaBeans ein Application Programming Interface (API) für eine Komponentenarchitektur in Java ein. Mittels des JavaBeans-API können unabhängige Komponenten erstellt werden, die in den gängigen WWW-Browsern und in anderen Umgebungen ausgeführt werden können. Die JavaBeans-Technologie basiert vollständig auf der Programmiersprache Java und ist somit plattformunabhängig. Weiterhin übernimmt jedes Bean den hohen Sicherheitsstandard von Java in Bezug auf verteilte Anwendungen und Inter-/Intranetkommunikation. Bei der JavaBeans-Technologie handelt es sich daher nicht um einen vollständig neuen Software-Ansatz. Alle zur Programmierung von JavaBeans notwendigen Elemente sind bereits im JDK enthalten. Das Konzept der JavaBeans ist damit voll und ganz in die Programmiersprache Java integriert. Bei der JavaBeans-Technologie handelt es sich um bindende Vereinbarungen, die jeder Programmierer einhalten muss, um ein Bean programmieren zu können. Diese Vereinbarungen (von der Firma Sun auch Design Pattern genannt, siehe Kapitel 9.2), sind nicht zu verwechseln mit den Design Patterns von Gamma [Gamma95], die in Kapitel 2 beschrieben wurden. Sie sind in verpflichtend, als dass Sun ein Software-Paket zum schnellen Entwickeln, Testen und Veröffentlichen von Beans anbietet, das eben diese Vereinbarungen benötigt und überprüft (das sog. Bean Development Kit, siehe Kapitel 9.8). Von Seiten der Entwickler stellen diese Vereinbarungen keine Einschränkung dar, da sie eher als Leitfaden dienen. Die Vereinbarungen betreffen bspw. Methodennamen von JavaBeans. In Standard-Java müsste eine Komponenteneigenschaft bspw. folgendermaßen gesetzt werden: aStringProperty = "hallo"; In einem JavaBean wird eine derartige Eigenschaft hingegen folgendermaßen gesetzt: setStringProperty("hallo"); Der Zugriff auf Objekte erfolgt also nicht direkt, sondern über sog. Setter- und Getter-Methoden, die in Kapitel 9.2 ausführlich behandelt werden. Komponentenmodell Beans liegen immer in Form von Black-Box-Komponenten vor. Dies bedeutet, dass ein Bean nicht erweitert werden kann, es sei denn, der Entwickler ist im Besitz des Quellcodes. Beans müssen weiterhin nicht explizit visuell dargestellt werden. Ein Beispiel für ein nichtvisuelles Bean ist bspw. das Timer-Bean. Abb. 9-1 zeigt ein Bean aus Sicht des Programmierers. Ein Bean kann hierbei aus Klassen oder auch aus anderen Beans bestehen. Es stellt seine Methoden, Eigenschaften und Events nach außen hin zur Verfügung, so dass diese durch ein anderes Bean oder von einer Entwicklungsumgebung erkannt werden können. Ein Bean speichert seinen internen Zustand in einer Datei mit der Endung .ser, die zusammen mit den anderen Dateien und Klassen in einem Package abgelegt werden kann (in einer JAR-Datei). Ein Bean reflektiert interne Daten (Introspektion) mit Hilfe der BeanInfo-Klasse. Die Eigenschaften eines Beans werden durch den Eigenschaften-Editor zugänglich gemacht. Diese Eigenschaften werden erkannt, da Beans ein bestimmtes Design Pattern verwenden, das im weiteren Verlauf dieses Kapitels erklärt wird. Abb. 9.1: Black-Box-Sicht eines Beans Im Folgenden wird die Grundstruktur eines JavaBeans (siehe Abb. 9-1) erläutert: Eine Entwicklungsumgebung erkennt die Eigenschaften eines Beans mit Hilfe der Introspektion (Introspection). Diese definiert, wie die interne Struktur eines Beans, die als public deklariert ist, der Außenwelt bekannt gemacht werden kann. Die Erkennung dieser Schnittstelle wird auf zwei verschiedene Arten unterstützt: Reflexion Die Reflexion stellt einen Mechanismus zur Abfrage der als public deklarierten Schnittstellen dar, damit eine Entwicklungsumgebung diese Schnittstelle zum Zugriff auf eine Komponente nutzen kann. Das Konzept der Reflexion wird dadurch unterstützt, dass Methoden, Eigenschaften und Events aufgrund von Namenskonventionen unterschieden werden (Design Pattern). BeanInfo-Klasse Sollen weitere Informationen über eine Klasse zur Verfügung gestellt werden, als die Reflection-Schnittstelle liefern kann, so muss der Entwickler eine eigene BeanInfo-Klasse implementieren. Die Entwicklungsumgebung, in der eine JavaBean-Komponente bearbeitet wird, verwendet dann nicht mehr das einfache Reflection-Interface, sondern fragt die nötigen Informationen bei der BeanInfo-Klasse ab. Eigenschaften (Properties) Eigenschaften beschreiben das Aussehen und Verhalten eines Beans und können verändert werden. Zur externen Änderung des Status einer Komponente müssen deren Eigenschaften anderen Komponenten bekannt sein. Eigenschaften werden dementsprechend durch sog. Setter- und Getter-Methoden nach außen weitergegeben. Unterstützung für Entwicklungsumgebungen (Customization) Entwicklungsumgebungen benutzen das Konzept der Introspektion, um die Eigenschaften von Beans einlesen zu können. Durch die Methoden des Customization-Interfaces können diese Eigenschaften bearbeitet werden. Event-Verarbeitung Ein Bean kommuniziert mit der Außenwelt auch durch Ereignisse (Events), die bei internen Zustandsänderungen, aber auch bspw. durch Betätigung einer Taste oder durch Bewegen des Mauszeigers, erzeugt werden. Events werden von registrierten externen Programmteilen (Event Listener) verarbeitet. Ein Bean, das Events sendet, wird auch als Source-Bean bezeichnet. Persistenz Das Persistenzkonzept legt fest, wie ein Bean gespeichert und wieder hergestellt werden kann. Durch Persistenz wird der aktuelle Zustand einer Komponente in Bezug auf die Umgebung und auf andere Komponenten in einer permanenten Datei mit der Endung .ser gespeichert. Zum gespeicherten Zustand gehören üblicherweise alle als public deklarierten Eigenschaften. Verweise auf externe Beans einschließlich der Ereignisregistrierung werden im Gegenzug dazu nicht durch die Persistenz gespeichert. JavaBeans benutzen die Interfaces java.io.Serializable und java.io.Externalizable, um die Persistenz zu unterstützen. Schutzmechanismen Wie eine reguläre Java-Klasse kann auch eine JavaBean-Komponente verschiedene Zugriffsrechte für Methoden beinhalten. Als private gekennzeichnete Methoden sind bspw. nur innerhalb eines Beans zugänglich, während als protected deklarierte Methoden sowohl innerhalb des Beans als auch in abgeleiteten Beans zugänglich sind. Die Methoden mit der weitestgehenden Verfügbarkeit sind die als public deklarierten Methoden. Sie sind intern für abgeleitete Beans und extern für Anwendungen und andere Komponenten zugänglich. Dies impliziert, dass eine Anwendung jede als public deklarierte Methode aufrufen kann. Packaging Durch das Packaging können Teilkomponenten eines JavaBeans in einem Package zusammengefasst und komprimiert werden, wodurch die Datenmenge eines Beans verringert wird. Hieraus resultiert eine schnellere Übertragung der Daten über Netze. Verteilungsaspekt JavaBeans unterstützt die Kommunikation verteilt ablaufender Programme. Es ist dabei nicht von Belang, welcher Mechanismus für eine derartige Kommunikation verwendet wird (bspw. RMI oder CORBA). Ziele von JavaBeans Die JavaBeans-Technologie verfolgt die Ziele: Komponenten genau einmal zu implementieren Komponenten unabhängig von einer Umgebung ausführen zu können Komponenten so oft wie möglich wiederzuverwenden. Implementierung Das Ziel, Komponenten genau einmal zu implementieren, spart Entwicklungsressourcen, indem ein praktikables Mittel dafür angeboten wird, einen bereits existierenden Code funktionell zu erweitern oder zu verbessern, ohne den ursprünglichen Code neu bearbeiten zu müssen. Lauffähigkeit JavaBeans-Komponenten sollten in jeder beliebigen Umgebung ausgeführt werden können. Die JavaBeans-Technologie baut auf Java auf und weist somit auch die Eigenschaft auf, plattformunabhängig zu sein. Aspekte der Lauffähigkeit beziehen sich hierbei nicht nur darauf, dass JavaBeans-Komponenten auf verschiedenen Plattformen lauffähig sind, sondern auch darauf, dass sie in verteilten Netzwerkumgebungen ausgeführt werden können. Wiederverwendbarkeit Eigenschaften von JavaBeans-Komponenten sollten in vielen verschiedenen Szenarien verwendet werden können, bspw. in Anwendungen, Webseiten und Entwicklungsumgebungen. Dieses Ziel stimmt mit dem allgemeinen Entwurfsziel von Software-Komponenten überein, der Wiederverwendbarkeit von Code (siehe Kapitel 2). Umsetzung der Ziele Die oben erwähnten Ziele von JavaBeans werden durch folgende Eigenschaften realisiert: Ausnutzung der Stärken der Programmiersprache Java Portabilität Einfache und kompakte Erzeugung von Komponenten Unterstützung von Entwicklungsumgebungen Unterstützung verteilten Arbeitens Stärken der Programmiersprache Java Java bietet eine Reihe von Eigenschaften, die leicht auf Komponenten übertragen werden können. Eine dieser Eigenschaften ist die dynamische Klassenerkennung, die es ermöglicht, Objekte dynamisch während der Laufzeit miteinander interagieren zu lassen. Nutzt man diese Eigenschaft aus, so kann ein System entwickelt werden, in dem Objekte unabhängig von Ihrer Herkunft und Entwicklung integriert werden können. Ein Beispiel hierfür ist das dynamische Laden einer Sprachklasse, das im Folgenden angegeben ist. if (ladeNeueKlasseZurLaufzeit){ try { // Laden der gewuenschten Klasse durch Class.forName mit // newInstance, wird die geladene Klasse zur Laufzeit // instantiiert. gewuenschteInstance = Class.forName("KlassenName").newInstance(); } catch (ClassNotFoundException cnfe1){ System.out.println("KlassenName.java: nicht gefunden");} catch (InstantiationException ie1) {System.out.println("Fehler bei der Instantiierung:" + ie1);} catch (IllegalAccessException iae1) {System.out.println("Zugriffsfehler: " + iae1);} } Die Persistenz, die es ermöglichst, den internen Zustand von Objekten zu speichern und zu einem späteren Zeitpunkt wieder herstellen zu können, ist eine der Eigenschaften, die JavaBeans von Java übernimmt und speziell ausnutzt. Die Persistenz wird von JavaBeans durch die Interfaces java.io.Serializable und java.io.Externalizable realisiert. Portabilität Die Portabilität von Programmen ist eines der wichtigsten Prinzipien der Sprache Java, um Software-Entwickler von der Notwendigkeit zu entbinden, die Verwendung plattformspezifischer Bibliotheken im Detail zu kennen. JavaBeans sind wiederverwendbare Komponenten, die auf einer Vielzahl von Plattformen lauffähig sind. Kompaktheit Kompaktheit ist ein Konzept, das speziell in verteilten Anwendungen sehr wichtig ist, da hierdurch der Transport von Daten in Netzwerken mit beschränkter Bandbreite unterstützt wird, eine unabdingbare Voraussetzung für akzeptable Übertragungszeiten. Diese Eigenschaft wird dadurch realisiert, dass Dateien in JAR-Archiven gepackt werden können. Unterstützung von Entwicklungsumgebungen Die Entwicklung von JavaBeans besteht in der Komponentenarchitektur von JavaBeans aus zwei Phasen: Der Designphase bzw. der Phase, in der Entwickler Anwendungen aufbauen, die aus bereits fertigen JavaBeans bestehen. Die JavaBeans-Technologie beinhaltet daher die Spezifikation der Designphase und Editiermechanismen, die das visuelle Bearbeiten von Beans erleichtern. Unterstützung verteilten Arbeitens Die JavaBeans-Technologie unterstützt verteilte Anwendungen durch die Einbindung externer Technologien. JavaBeans stellen dem Entwickler Mechanismen zum verteilten Arbeiten zur Verfügung, die je nach Bedarf eingesetzt werden können. Somit bleiben die JavaBeans-Komponenten kompakt und die Verteilung offen. Entwickler von JavaBeans-Komponenten haben die Möglichkeit, für ein verteiltes Arbeiten ein Verfahren ihrer Wahl zu wählen. Mit der Remote Method Invocation (RMI) bietet Java hierzu eine Möglichkeit. Andere Varianten sind CORBA und DCOM. In Kapitel 11 wird näher auf Aspekte des verteilten Arbeitens in Java eingegangen. JavaBeans und Applets Bevor der Unterschied zwischen einem Applet und einem Bean erklärt werden kann, muss zunächst der Unterschied zwischen einem Bean und einer Java-Klasse erläutert werden. Beide unterscheiden sich dadurch, dass ein Bean: eines der Interfaces java.io.Serializable- oder java.io.Externalizable- implementiert: public class SimpleBean extends Canvas implements Serializable{ // Code } einen Null-Konstruktor hat (Konstruktor ohne Argument). Der Grund hierfür liegt in der Verwendung von Beans in Entwicklungsumgebungen. Hierbei wählt der Benutzer eine Komponente und instantiiert sie in einer Entwicklungsumgebung. Zu diesem Zeitpunkt kann die Entwicklungsumgebung keine Vorhersage über den Zustand dieses Beans geben, weshalb ein Null-Konstruktor eingesetzt werden muss. public class SimpleBean extends Canvas implements Serializable{ // Null-Konstruktor public SimpleBean() { // Konstruktor-Code } // weiterer Code } keine als public deklarierten Variablen verwendet. Um den Wert einer Variablen zu ändern sind die sog. Setter- bzw. Getter- Methoden zu verwenden. das Konzept der Introspektion durch die Namenskonventionen (Design Pattern), durch die BeanInfo-Klasse oder durch beide unterstützt. public class SimpleBeanBeanInfo extends SimpleBeanInfo { // BeanInfo-Rumpf } Applets sind visuelle Komponenten, die innerhalb eines Browsers ausgeführt werden. Beans können aber auch nichtvisuell vorliegen und als Server-Anwendungen, bzw. als Applets arbeiten. Beans können weiterhin mit anderen Beans interagieren, aber auch mit deren Container. Applets sind dahingegen eher Container-zentriert. Ein Bean ist wesentlich flexibler konfigurierbar als ein Applet, ohne dass dem Programmierer der Quellcode oder eine exakte Beschreibung der Methoden der verwendeten JavaBean-Komponenten vorliegen muss. Durch die als public deklarierten Schnittstellen einer Komponente kann eine Java-VM während der Laufzeit feststellen, welche Eigenschaften ein Bean hat und wie diese genutzt werden können. Bei der Programmierung (oder auch später) können so während der Programmausführung neue Komponenten, die dem Programm völlig unbekannt sind, mittels Drag and Drop hinzugefügt und sofort genutzt werden. Diese Leistung ist nicht nur auf die Spezifikation einiger Schnittstellen zurückzuführen, sondern auch konkret auf Eigenschaften der Programmiersprache Java und der Laufzeitumgebung. Programmierung von JavaBeans Die Entwicklung einer Anwendung mit JavaBeans kann durch die Nutzung vorhandener Software-Bausteine (Beans) verkürzt werden. Ist eine bestimmte Funktionalität bereits als Bean realisiert, so wird dieses übernommen, angepasst und in die Anwendung an der gewünschten Stelle integriert. Deckt kein Baustein die gewünschte Funktionalität ab, so wird eine Beschreibung für die benötigte Funktionalität erstellt. Das gewünschte Bean wird dann anschließend programmiert. Die so entwikkelten Beans können in einem Repository abgelegt werden und stehen damit zur allgemeinen Nutzung zur Verfügung (siehe Abb. 9-2). Hierdurch lassen sich die folgenden beiden Typen von Bean-Programmierern unterscheiden: Programmierer, die JavaBeans-Komponenten in einer Entwicklungsumgebung zusammenfügen und Programmierer, die JavaBeans-Komponenten von Grund auf implementieren. Komponentenprogrammierung JavaBeans-Komponenten können auf zwei Arten zu Applikationen zusammengesetzt werden: Entweder in einer visuellen Entwicklungsumgebung (bspw. Visual Café, Visual Age, JBuilder oder Bean Development Kit) oder manuell. Hierbei werden lediglich vorgefertigte Komponenten zusammengesetzt, was den Entwicklungsprozess maßgeblich verkürzt. Die Verwendung von Komponenten-Software ist in Abb. 9-2 dargestellt. Entwicklungsumgebungen stellen Editoren zur Bearbeitung von Eigenschaften bereit und erlauben weiterhin, Events verschiedener Komponenten miteinander zu verknüpfen. Ist eine Menge vorgefertigter Komponenten vorhanden, so ist es auch für Anwender ohne Programmierkenntnisse möglich, leistungsfähige Anwendungen aus einer Komponentenmenge in kurzer Zeit zusammenzustellen. Dieser Ansatz ermöglicht eine effiziente Arbeitsteilung bei der Entwicklung von Anwendungen. Während sich Programmierer mit der Erstellung von Komponenten beschäftigen, können branchenspezifische Anwendungen von Branchenexperten zusammengesetzt werden, die keine Programmierer sind. Nachdem eine Anwendung in einer Entwicklungsumgebung fertig gestellt wurde, wird der Code zur Verbindung der Komponenten automatisch erzeugt und alle Komponenten werden zu einer Datei zusammengefasst (JAR-Datei, siehe Kapitel 9.7), die dann betriebssystemunabhängig ausgeführt werden kann. Abb. 9.2: Verwendung von Komponenten Bei der Programmierung einer JavaBeans-Komponente wird wie folgt vorgegangen: Erstellung der Komponentenklassen unter Berücksichtigung der entsprechenden Design Patterns. Erstellung der Design-Time-Klassen, die zur Anpassung der Komponente in Entwicklungsumgebungen benötigt werden. Hierzu zählen vor allem die BeanInfo-Klasse sowie Property-Editoren, falls komplexe Eigenschaften verwendet werden. Diese Klassen werden nicht mehr benötigt, sobald eine Komponente angepasst ist und werden deswegen bei einer fertig gestellten Anwendung nicht mitgeliefert (siehe dazu Abb. 9-16 auf Seite 572). Zusammenstellung aller benötigten Ressourcen, wie z. B. Bilder oder Audio. Erstellung einer Dokumentation im HTML-Format. Erstellung internationalisierter Ressourcen, falls die Komponente international genutzt werden soll. Zusammenfassung aller Dateien in einem JAR-Archiv. Hierbei müssen nicht immer alle Schritte durchgeführt werden. Zur Erstellung einfacher Komponenten genügen oft die Schritte 1 und 6. Bevor die Programmierung von JavaBeans-Komponenten im weiteren Verlauf dieses Kapitels näher betrachtet werden kann, muss zunächst auf das Komponentenmodell von JavaBeans und dessen Ziele eingegangen werden. Package JavaBeans Um die Funktionalität der JavaBeans zu realisieren, wurde das JDK um das Package java.beans erweitert. Dieses Package stellt eine Menge von Schnittstellen (Interfaces), Klassen und Exceptions zur Verfügung. Lediglich ein kleiner Teil dieser Klassen wird während der Laufzeit eines Beans benutzt. So wird bspw. die Event-Klasse von denjenigen Beans verwendet, die Instanzen der Klassen PropertyChangeEvent oder VetoableChangeEvent erzeugen. Der größte Teil des Packages wird allerdings von Entwicklungsumgebungen benutzt, um Beans zu analysieren und sie zusammenzubinden. Diese Klassen haben daher vor allem im Rahmen der Entstehung eines Customization-Interfaces unterstützende Funktion. So kann bspw. eine bestimmte Eigenschaft eines Beans durch das Interface PropertyEditor bearbeitet werden. |
Interface | Bedeutung
AppletInitializer | Diese Schnittstelle stellt einen Mechanismus zur Verfügung, mit dem eine ordnungsgemäße Initialisierung von JavaBeans, die auch als Applets fungieren, während der Instantiierung mit Hilfe der Methode java.beans.Beans.instantiate() erfolgt.
BeanInfo | Allgemeine Schnittstelle für die Beschreibung eines Beans; die unten angegebene Klasse SimpleBeanInfo wird von diesem Interface abgeleitet.
DesignMode | Schnittstelle zur Abfrage des Status designTime eines Beans.
PropertyChangeListener | Listener-Interface für Events, die über die Änderungen einer Eigenschaft informieren (PropertyChangeEvent).
PropertyEditor | Schnittstelle für einfache Eingabemöglichkeiten zur Manipulation einer Eigenschaft in einem Property-Fenster.
VetoableChangeListener | Listener für beabsichtigte Änderungen von Constrained-Properties. Der Listener empfängt VetoableChangeEvents und kann eine Property-Änderung erlauben oder verbieten.
Visibility | Interface für Beans, die eine grafische Oberfläche besitzen; reine Funktions-Beans benötigen kein GUI (Graphical User Interface).
Tab. 9.1: Interfaces des JavaBeans-Packages |
Klasse | Bedeutung
BeanDescriptor | Ein BeanDescriptor-Objekt stellt allgemeine Informationen über ein Bean bereit, z. B. den Klassennamen oder den dargestellten Namen in einer Entwicklungsumgebung.
Beans | Beinhaltet allgemeine Methoden zur Instantiierung und zur Verarbeitung von Beans.
EventSetDescriptor | Beschreibt eine Gruppe von Events, die ein Bean auslösen kann.
IndexedPropertyDescript or | Beschreibt indizierte Eigenschaften.
Introspector | Stellt wichtige Methoden für die Introspektion von Objekten zur Verfügung.
MethodDescriptor | Beschreibt die Methoden eines Beans.
ParameterDescriptor | Beschreibt die Parameter eines Beans.
PropertyChangeEvent | Beans können diesen Event-Typ an registrierte PropertyChangeListener-Objekte senden, um über die Änderung einer Property zu informieren.
PropertyChangeSupport | Hilfsklasse für die Verwaltung von Änderungen bei Bound-Properties.
PropertyDescriptor | Beschreibt eine Eigenschaft und das zugehörige Zugriffsmethodenpaar von Lese- und Schreibfunktionen.
PropertyEditorManager | Verwaltet die Property-Editoren.
PropertyEditorSupport | Hilfsklasse für die Implementierung eines Property-Editors.
SimpleBeanInfo | Hilfsklasse mit einer einfachen Implementierung des Interfaces BeanInfo.
VetoableChangeSupport | Hilfsklasse für die Verwaltung von Änderungen bei Constrained-Properties.
| Tab. 9.2: Klassen des JavaBeans-Packages

Exception | Bedeutung
IntrospectionException | Tritt bei Fehlern während der Introspektion eines Beans auf.
PropertyVetoException | Mit dieser Exception kann ein PropertyChangeListener-Objekt die beabsichtigte Änderung einer Constrained-Property verbieten.

| Tab. 9.3: Exceptions des JavaBeans-Packages Zusammenhängende Beans Das Package java.beans.beancontext beinhaltet Klassen und Interfaces zur Umsetzung des Prinzips des Kontextes von JavaBeans. Der Komponentenkontext von JavaBeans stellt einen Container dar und definiert eine einheitliche, abgeschlossene Umgebung für die in ihm enthaltenen Beans. Mehrere Beans können in einem derartigen Beancontext enthalten sein. Java erlaubt die mehrstufige Verschachtelung von Containern und realisiert damit, dass ein Komponentenkontext einen anderen Komponentenkontext beinhalten kann. Das Package beinhaltet auch die Definition von Events und Event-Listenern, um Beans beim Zufügen oder Entfernen in einen bzw. aus einem Komponentenkontext zu registrieren bzw. deregistrieren. Ein Container ist nicht nur dafür verantwortlich, die Hierarchie bzw. die logische Struktur der Beans festzuhalten, sondern stellt den JavaBeans-Komponenten, die in ihm enthalten sind, auch Dienste zur Verfügung. Diese Dienste können unter anderem Komponenten zur Bearbeitung bestimmter Datenstrukturen oder bspw. ein Druck-dienst sein. Dienste sind in der Regel außerhalb des Komponentenkontextes realisiert und sind mit dem Kontext über Referenzen verbunden. Abb. 9-3 zeigt die Struktur einer Anwendung, die auf dem JavaBeans-Komponentenkontext basiert. Kap. 9.3: JavaBeans-Komponentenkontext