![]() |
|||||||||||||||||||||||||||||||||
|
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:
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 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. 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. 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. 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. 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. 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. 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:
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:
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 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:
public class SimpleBean extends Canvas implements Serializable{ // Code }
public class SimpleBean extends Canvas implements Serializable{ // Null-Konstruktor // Konstruktor-Code } }
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:
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:
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. |
|||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||
|
Tab. 9.1: Interfaces des JavaBeans-Packages |
|||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||
|
Tab. 9.2: Klassen des JavaBeans-Packages |
|||||||||||||||||||||||||||||||||
|
|
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 |
|
|