vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Woche 3

Tag 19

JavaBeans und andere fortgeschrittene Features

Von einer Sprache, die so schnell wie Java wächst, kann man sich schnell von der Menge der Klassen, die von JavaSoft angeboten werden, überrollt fühlen. Jedes neue Release der Sprache führt bemerkenswerte Features wie JavaBeans, Java Database Connectivity und 2D-Grafik, ein.

Glücklicher Weise müssen Sie nicht alle Teile der Standard-Klassenbibliothek meistern, bevor Sie nützliche Programme erstellen können. Sie können sich auf die Pakete und Klassen konzentrieren, die Sie in Ihrem Fachbereich benötigen und Ihre Kenntnisse in neuen Bereichen nach Bedarf erweitern.

Heute erhalten Sie eine Einführung in einige der fortgeschritteneren Features, die mit dem aktuellsten Release von Java angeboten werden, darunter auch die folgenden:

Für den größten Teil des heutigen Tages gilt die Direktive, Sie mit dem jeweiligen Thema vertraut zu machen als ersten Schritt, diese Klassen zu verwenden. Allerdings werden Sie auch einige konkrete Projekte zu den Themen Datentransfer und Applet- Browser-Kommunikation finden.

JavaBeans

Schon seit geraumer Zeit verfolgt die Gemeinde der Software-Entwicklung verstärkt den Gedanken wiederverwendbarer Komponenten. Eine Komponente - im allgemeinen Sinn, nicht im Sinne des AWT - ist ein wiederverwendbares Software-Teil, das leicht zur Erstellung von Anwendungen verwendet werden kann, und zwar mit weitaus größerer Entwicklungseffizienz. Dieser Gedanke der Wiederverwendung sorgfältig zusammengestellter Software wurde zu einem gewissen Maße dem Verfahren des Montagebandes entliehen, das während der industriellen Revolution in den Vereinigten Staaten, lange vor der Ära moderner Computer, so populär wurde. Auf Software angewandt bedeutet das, einmalig zu Beginn kleine, wiederverwendbare Komponenten zu bauen und sie dann in höchstmöglichem Maße wiederzuverwenden und damit den gesamten Entwicklungsprozeß zu rationalisieren.


Eine Software-Komponente ist ein Stück Software, das in eine diskrete, leicht wiederverwendbare Struktur gekapselt ist.

Obwohl Komponenten-Software ihre Vorteile bietet, muß sich die vollständig wiederverwendbare Software erst noch richtig etablieren. Dies aus einer Vielzahl von Gründen, nicht zuletzt der Tatsache, daß die Software-Industrie im Vergleich zu den Industrien, die sich während der industriellen Revolution etabliert haben, noch sehr jung ist. Es leuchtet ein, daß es einige Zeit dauert, die schwachen Punkte im gesamten Software-Produktionsprozeß auszumerzen. (Wenn Sie meine Einstellung teilen, nehmen Sie die rapiden, in der Welt der Software stattfindenden Veränderungen bereitwillig an und genießen die Tatsache, daß Sie ein Teil von so etwas ähnlichem wie einer Revolution sind - eine Informationsrevolution. Aber ich schweife ab!)

Das vielleicht größte Problem, dem sich Komponenten-Software stellen mußte, ist der große Bereich ungleichartiger Mikroprozessoren und heute eingesetzter Betriebssysteme. Es gab eine Reihe angemessener Versuche in der Komponenten-Software, die aber immer auf ein spezifisches Betriebssystem limitiert waren. Die VBX- und OCX- Komponentenarchitekturen von Microsoft verzeichneten große Erfolge in der Welt des PC, konnten aber wenig zum Schließen der Lücke zwischen anderen Betriebssystemtypen beitragen. Wirft man das Arbeitsvolumen in die Waagschale, das dazu benötigt wird, um eine inhärente, plattformabhängige Komponententechnologie auf einer Vielzahl von Betriebssystemen zum Laufen zu bringen, macht die ausschließliche Fokussierung auf den PC-Markt von Microsoft Sinn.


Tatsächlich zielt die auf ihrer OCX-Technologie basierte ActiveX-Technologie von Microsoft darauf ab, eine universelle Komponententechnologie bereitzustellen, die Kompatibilität für einen breiten Bereich von Plattformen bietet. Betrachtet man allerdings die Abhängigkeit des ActiveX von dem 32-Bit-Windows-Code, bleibt abzuwarten, wie Microsoft das Problem der Plattformabhängigkeit lösen wird. Vielleicht wartet man nur darauf, daß alle zu Windows 95/NT wechseln?

Bevor es zu der explosionsartigen Entwicklung im Internet-Bereich kam, stellte die Plattformabhängigkeit nicht so ein großes Problem dar. PC-Entwickler machten sich nicht unbedingt allzu viele Gedanken darüber, daß ihre Produkte nicht auf einem Solaris-System laufen konnten. Okay, einige PC-Entwickler gingen auf Nummer sicher und sorgten für Anschluß Ihrer Anwendungen an die Macintosh-Plattform, allerdings oftmals unter beträchtlichem Entwicklungsaufwand. Das gesamte Szenario änderte sich durch den vom Internet erzeugten Schmelztiegel der Betriebssysteme. Daraus resultierte ein erneutes Interesse, Software zu entwickeln, die von jedermann, unabhängig vom benutzten Betriebssystem, benutzt werden kann. Java trug in großem Maße dazu bei, echt plattformunabhängige Software-Entwicklung Wirklichkeit werden zu lassen. Allerdings hatte Java bis vor kurzem keine Antwort auf das Problem der Komponenten-Software - dazu kommen wir gleich.

Als ob das Problem der Plattformabhängigkeit noch nicht genug ist, leiden einige verfügbare Komponententechnologien darunter, in einer spezifischen Programmiersprache oder für eine spezielle Umgebung entwickelt werden zu müssen. So wie die Plattformabhängigkeit Komponenten zur Laufzeit verkrüppelt, führt Limitierung der Komponentenentwicklung auf eine spezifische Programmiersprache oder Entwicklungsumgebung gleichermaßen zur Verkrüppelung der Komponenten im Entwicklungsbereich. Software-Entwickler würden lieber selbst entscheiden, welche Sprache für eine bestimmte Aufgabe und welche Entwicklungsumgebung die am besten geeignete ist, als gezwungen zu sein, eine den Einschränkungen einer Komponententechnologie unterliegende zu verwenden. Demnach muß sich jede realistische, auf lange Sicht ausgerichtete Komponententechnologie dem Problem der Plattform- und Sprachabhängigkeit stellen. Und das bringt mich zu unserem Thema: JavaBeans. Die JavaBeans-Technologie von JavaSoft ist eine Komponententechnologie, die direkte Antworten auf beide Probleme bietet. Die JavaBeans-Technologie verspricht das Paradigma der Zusammenfügung von Komponenten-Software auf eine neue Ebene zu heben. Im Augenblick befindet sich die JavaBeans-Spezifikation in der Entwicklung und die vorläufige Freigabe soll im Anschluß daran erfolgen.

JavaBeans wird als architektur- und plattformunabhängiges API zur Erstellung und Verwendung dynamischer Java-Software-Komponenten realisiert. JavaBeans setzt an dem Punkt an, wo andere Komponententechnologien aufgehört haben, und verwendet die portable Java-Plattform als Basis zur Bereitstellung einer kompletten Lösung für Komponenten-Software, die in der Welt des Online ohne weiteres anwendbar ist.

Das Ziel von JavaBeans

Nach dem schnellen Erfolg des Laufzeitsystems und der Programmiersprache von Java, war JavaSoft die Bedeutung der Entwicklung einer kompletten Lösung für die Komponententechnologie klar. Man antwortete mit der JavaBeans-Technologie, deren Designziele in folgender Spezifikationsliste zusammengefaßt werden können:

Die erste Anforderung von JavaBeans - so kompakt zu sein - beruht auf der Tatsache, daß die JavaBeans-Komponenten häufig in verteilten Umgebungen verwendet werden, in denen komplette Komponenten eventuell über eine Internet-Verbindung mit geringer Bandbreite übertragen werden. Genauer gesagt müssen Komponenten so kompakt wie möglich sein, um eine angemessene Übertragungszeit zu ermöglichen. Der zweite Teil dieses Designziels bezieht sich auf die Leichtigkeit, mit der diese Komponenten erstellt und verwendet werden. Leicht verwendbare Komponenten kann man sich relativ leicht vorstellen, aber die Erzeugung einer Komponentenarchitektur, die das Erstellen von Komponenten leicht gestaltet, ist eine völlig andere Sache. Versuche auf der Ebene der Komponenten-Software werden dem Entwickler oftmals durch komplexes Programmieren von APIs erschwert. JavaBeans-Komponenten müssen also nicht nur leicht zu verwenden, sondern auch leicht zu entwickeln sein. Dies stellt für Sie und mich eine wesentliche Anforderung dar, da sie weniger Kopfschmerzen bereitet und uns mehr Zeit gibt, die Komponenten mit blumigen Eigenschaften auszuschmücken.

JavaBeans-Komponenten basieren größtenteils auf der bereits in der traditionellen Applet-Programmierung von Java verwendeten Klassenstruktur, was wiederum für diejenigen von uns, die viel Zeit und Energie darauf aufwenden, Java zu erlernen, einen enormen Vorteil bietet. JavaSoft hat versprochen, daß die rund um das AWT-Paket entworfenen Java-Applets sich leicht in neue JavaBeans-Komponenten verwandeln lassen. Auch dies leistet den positiven Nebeneffekt der ausgesprochenen Kompaktheit von JavaBeans-Komponenten, da Java-Applets hinsichtlich der Größe bereits sehr leistungsfähig sind.

Das zweite Hauptziel von JavaBeans ist vollständige Portabilität; darüber haben wir zu Beginn dieser Lektion gesprochen. Als Folge davon brauchen sich Entwickler keine Gedanken um die Einbeziehung plattformspezifischer Bibliotheken bei Ihren Java-Applets zu machen. Das Ergebnis sind wiederverwendbare Komponenten, die die Computerwelt glücklich und friedlich unter einem Dach vereinigen. (Okay, vielleicht ist das etwas zu viel verlangt - ich begnüge mich schon mit der Entwicklung einer Komponente, die ohne Anbringen von Modifizierungen auf einem Java-unterstützten System läuft.)

Die bestehende Java-Architektur bietet bereits eine große Anzahl von Vorteilen, die leicht auf Komponenten anwendbar ist. Eine der wesentlicheren Eigenschaften von Java ist ihr eingebauter Klassenerkennungsmechanismus, der dynamische Interaktionen zwischen Objekten ermöglicht. Daraus entsteht ein System, in dem sich Objekte unabhängig von ihrem Ursprung oder ihrer Entwicklungsgeschichte ineinander einbauen lassen. Dieser Mechanismus zur Klassenauffindung stellt nicht nur eine nette Eigenschaft von Java dar, sondern ist in jeder Komponentenarchitektur eine notwendige Voraussetzung und für JavaBeans ein Glücksfall, daß diese Funktionalität von Java bereits kostenlos geboten wird. Andere Komponentenarchitekturen mußten vertrackte Registriermechanismen implementieren, um zu dem gleichen Ergebnis zu kommen.

Darüber hinaus erhält JavaBeans aus der bestehenden Java-Funktionalität noch die Persistenz, d.h. die Fähigkeit eines Objektes, seinen internen Status zu speichern und wieder zu laden. Diese Persistenz erfolgt in JavaBeans automatisch einfach durch die Verwendung des in Java bereits vorhandenen Serialisations-Mechanismus. Falls erforderlich, können Entwickler alternativ speziell angepaßte Persistenz-Lösungen erstellen.


Persistenz ist die Fähigkeit eines Objektes, seinen internen Status zu speichern und wieder zu laden. Serialisation ist das Verfahren, Informationen über ein Standardprotokoll zu speichern oder zu laden.

Obwohl kein Schlüsselelement der JavaBeans-Architektur, stellt die Unterstützung für verteiltes Rechnen bei JavaBeans dennoch ein Hauptthema dar. Da verteiltes Rechnen, als ein Ergebnis der komplexen Natur der verteilten Systeme, relativ komplexe Lösungen erforderlich macht, hebt JavaBeans die Verwendung von externen verteilten, auf Bedarf basierten Methoden an. Anders ausgedrückt ermöglichen JavaBeans Entwicklern die Verwendung verteilter Rechenmechanismen, wann immer erforderlich, überladen sich aber auch nicht mit entsprechender Unterstützung für verteiltes Rechnen. Man könnte jetzt die JavaBeans-Architekten für faul halten, Tatsache ist aber, daß genau in diesem Designansatz der Schlüssel für die Kompaktheit der JavaBeans-Komponenten liegt, da verteilte Rechenlösungen unvermeidlich zu höherer Systemverwaltungszeit führen.

Entwickler von JavaBeans-Komponenten haben die Möglichkeit, die für ihre Bedürfnisse am besten geeignete Methode auszuwählen. Mit seiner Technologie der Remote Method Invocation (RMI, Methoden-Fernaufruf) bietet JavaSoft eine verteilte Rechenlösung, die aber den JavaBeans-Entwicklern keinesfalls die Hände bindet. Unter anderem beinhalten andere Lösungsmöglichkeiten CORBA (Common Object Request Broker Architecture) und von Microsoft DCOM (Distributed Component Object Model). Der Punkt ist, daß verteiltes Rechnen säuberlich von JavaBeans abgetrennt wurde, um die Struktur straff zu halten und gleichzeitig Entwicklern, die die entsprechende Unterstützung benötigen, einen breiten Bereich an Optionen zu bieten. Das letzte Designziel von JavaBeans behandelt Probleme der Entwurfszeit und die Art und Weise, wie Entwickler Anwendungen unter Verwendung von JavaBeans-Komponenten erstellen. Die Architektur von JavaBeans umfaßt Unterstützung für die Spezifizierung von Eigenschaften der Entwurfszeit und Bearbeitungsmechanismen zur weiteren Erleichterung visueller Bearbeitung von JavaBeans-Komponenten. Das hat zur Folge, daß Entwickler visuelle Werkzeuge zum nahtlosen Zusammenfügen und Modifizieren von JavaBeans-Komponenten einsetzen können, ganz ähnlich der Weise, in der bestehende visuelle PC-Werkzeuge mit Komponenten wie VBX- oder OCX-Steuerungen arbeiten. Komponentenentwickler spezifizieren so die Art und Weise, in der die Komponenten in einer Entwicklungsumgebung zu verwenden und zu manipulieren sind. Allein diese Eigenschaft wird offiziell die Verwendung von professionellen visuellen Editoren einleiten und der Produktivität von Anwendungsentwicklern in bedeutender Weise Auftrieb verleihen.

Wie JavaBeans in Beziehung zu Java steht

Für viele Entwickler, die nicht ganz mit dem Gedanken von Software-Komponenten vertraut sind, wird die Beziehung zwischen JavaBeans und Java etwas verwirrend sein. Wurde für Java nicht als eine objektorientierte Technologie mit der Fähigkeit, wiederverwendbare Objekte zu bedienen, die Werbetrommel gerührt? Ja und Nein. Ja, Java bietet eine Möglichkeit der Erstellung wiederverwendbarer Objekte, allerdings gibt es einige Regeln oder Standards, die für die Art und Weise, wie Objekte miteinander interagieren, maßgeblich sind. Durch Spezifizieren umfangreicher Gruppen von Mechanismen für die Interaktion zwischen Objekten, zusammen mit allgemeinen, von den meisten Objekten zu unterstützenden Aktionen wie Persistenz- und Ereignisbehandlung, baut JavaBeans auf dem bestehenden Design von Java auf.

Das aktuelle Java-Komponentenmodell ist, obgleich es nicht schlecht ist, relativ limitiert, wenn es darum geht, echte Wiederverwendung und Interoperabilität zu liefern. Auf der Objektebene gibt es definitiv keinen einfachen Mechanismus zur Erstellung wiederverwendbarer Java-Objekte, die mit anderen Objekten dynamisch in konsequenter Weise in Wechselwirkung treten können. Was Sie dem am nächsten kommend in Java durchführen können, ist, Applets zu erstellen und zu versuchen, diese auf einer Webseite miteinander kommunizieren zu lassen, was nicht gerade eine leichte Aufgabe ist. JavaBeans stellt den Rahmen, in dem diese Kommunikation stattfinden kann, mit Leichtigkeit zur Verfügung. Noch wichtiger ist die Tatsache, daß JavaBeans- Komponenten leicht über eine Standardgruppe von gut definierten Eigenschaften getriggert werden können. JavaBeans vereinigt die Leistungsstärke eines voll ausgereiften Java-Applet mit der Kompaktheit und Wiederverwendbarkeit von Java-AWT- Komponenten, wie beispielsweise Schaltflächen.

JavaBeans-Komponenten sind jedoch nicht auf visuelle Objekte wie Schaltflächen beschränkt. Sie können genauso einfach nicht visuelle JavaBeans-Komponenten entwikkeln, die zusammen mit anderen Komponenten einige Hintergrundfunktionen ausüben. Auf diese Weise vereinigt JavaBeans die Leistungsstärke visueller Java-Applets mit nicht visuellen Java-Anwendungen unter dem festen Dach eines Komponentengerüsts.


Eine nicht visuelle Komponente ist jede Komponente, deren Ausgabe nicht sichtbar ist. Wenn man sich eine Komponente im Hinblick auf AWT-Objekte wie Schaltflächen und Menüs betrachtet, mag das ein wenig fremd erscheinen. Vergessen Sie dabei aber nicht, daß eine Komponente einfach ein dicht gepacktes Programm ist und nicht unbedingt visuell sein muß. Ein gutes Beispiel für eine nicht visuelle Komponente ist eine Timer-Komponente, die in bestimmten Abständen Ereignisse sendet. Timer-Komponenten sind in anderen Entwicklungsumgebungen von Komponenten wie Microsoft Visual Basic sehr populär.

Sie können eine Vielzahl von JavaBeans-Komponenten gemeinsam benutzen, ohne daß Sie unter Verwendung visueller Werkzeuge einen Code schreiben müssen. Diese Möglichkeit der gleichzeitigen Benutzung einer Vielzahl von Komponenten, deren Ursprung dabei unwichtig ist, stellt eine Verbesserung des aktuellen Java-Modells dar. Sicherlich können Sie andere, in Java bereits integrierte Objekte benutzen, müssen aber über ausführliches Wissen, die Schnittstelle des Objektes betreffend, verfügen. Darüber hinaus müssen Sie das Objekt programmatisch in Ihren Code integrieren. JavaBeans-Komponenten legen ihre eigenen Schnittstellen visuell dar und stellen somit ein Mittel zur Bearbeitung ihrer Eigenschaften ohne Programmierung bereit. Des weiteren können Sie mit der Verwendung eines visuellen Editors eine JavaBeans-Komponente einfach in eine Anwendung einfügen, ohne daß Sie eine einzige Zeile Code schreiben müssen. Hier sehen wir eine vollständig neue Ebene der Flexibilität und Wiederverwendung, die mit Java allein bisher nicht möglich war.

Das JavaBeans-API

Okay, genug gesagt über JavaBeans und darüber, was es kann und warum es »cool« ist. Konzentrieren wir uns jetzt auf einige Einzelheiten, um festzustellen, wie das alles möglich ist. Behalten Sie dabei im Auge, daß JavaBeans letztendlich eine Programmierschnittstelle ist, was bedeutet, daß all seine Eigenschaften als Erweiterungen der Standard-Klassenbibliothek von Java realisiert werden. Somit wird die gesamte, von JavaBeans zur Verfügung gestellte Funktionalität tatsächlich in dem JavaBeans-API realisiert. Das JavaBeans-API selbst ist eine Reihe von kleineren APIs, die spezifischen Funktionen oder Services gewidmet sind. Die nachfolgende Liste zeigt wesentliche Komponentenservices in dem JavaBeans-API, die zur Erleichterung all der Eigenschaften, die Sie heute gelernt haben, notwendig sind:

Durch entsprechendes Verständnis dieser Services und wie sie arbeiten, bekommen Sie einen größeren Einblick in die Technologie von JavaBeans. Jeder dieser Services wird in Form von kleineren, in dem größeren API enthaltenen APIs realisiert. In den nächsten Abschnitten widmen wir uns jedem dieser APIs und erklären, warum sie notwendige Elemente der JavaBeans-Architektur darstellen.

Die die grafische Benutzeroberfläche vereinigenden APIs bieten einer Komponente ein Werkzeug zur Vereinigung ihrer Elemente der grafischen Benutzeroberfläche mit dem Container-Dokument, das normalerweise nur die die Komponente beinhaltende Webseite ist. Die meisten Container-Dokumente haben Menüs und Werkzeugleisten, die zur Anzeige der speziellen, von dieser Komponenten bereitgestellten Eigenschaften dienen. Die die grafische Benutzeroberfläche vereinigenden APIs ermöglichen der Komponente, dem Menü und der Werkzeugleiste des Container-Dokuments Eigenschaften hinzuzufügen. Diese APIs definieren auch den Mechanismus, der Raumverhandlungen zwischen den Komponenten und ihren Containern ermöglicht. Anders gesagt, die die grafische Benutzeroberfläche vereinigenden APIs sind auch für die Definition der Layout-Eigenschaften von Komponenten zuständig.

Ein Container-Dokument ist ein JavaBeans-Komponenten enthaltendes Dokument (normalerweise HTML), das als Eltern für alle in ihm enthaltenen Komponenten dient. Neben anderen Dingen sind Container-Dokumente normalerweise für die Verwaltung des Hauptmenüs und der Werkzeugleiste zuständig.

Die Persistenz-APIs spezifizieren den Mechanismus, mit dem Komponenten innerhalb des Kontexts eines Container-Dokumentes gespeichert und geladen werden können. Komponenten erben per Voreinstellung den automatischen, von Java bereitgestellten Serialisations-Mechanismus. Entwickler haben ebenfalls die Freiheit, auf den speziellen Erfordernissen ihrer Komponenten basierende, besser ausgearbeitete Persistenz- Lösungen zu entwerfen.

Die APIs zur Ereignisbehandlung spezifizieren eine ereignisgesteuerte Architektur, die die Wechselwirkung der Komponenten miteinander definiert. Das Java-AWT beinhaltet bereits ein leistungsstarkes Ereignisbehandlungsmodell, das als Grundlage für die Komponenten-APIs zur Ereignisbehandlung dient. Diese APIs sind wesentlich, wenn es darum geht, den Komponenten die Freiheit zu gewähren, in konsequenter Weise miteinander zu interagieren.

Die Introspektions-APIs definieren Techniken, die Komponenten dazu veranlassen, ihre interne Struktur zur Entwurfszeit direkt zur Verfügung zu stellen. Diese APIs enthalten die notwendige Funktionalität, es Entwicklungstools zu ermöglichen, eine Komponente nach ihrem internen Status abzufragen, einschließlich der Schnittstellen, Methoden und Member-Variablen, aus denen die Komponente besteht. Die APIs sind, basierend auf der Ebene, auf der sie benutzt werden, in zwei getrennte Abschnitte unterteilt. Die Introspektions-APIs der unteren Ebene ermöglichen beispielsweise Entwicklungswerkzeugen direkten Zugriff auf die Komponenteneigenschaften, also eine Funktion, die Sie nicht unbedingt in den Händen von Komponentenbenutzern sehen wollen. APIs der höheren Ebene verwenden APIs der unteren Ebene zur Bestimmung der Teile einer Komponente, die zur Änderung durch den Benutzer exportiert werden . Das heißt, obwohl Entwicklungswerkzeuge zweifellos Gebrauch von beiden Arten von APIs machen, werden sie die APIs der höheren Ebene nur dann verwenden, wenn sie dem Benutzer Komponenteninformationen bereitstellen.

Application Builder Support APIs stellen die bei Entwurfszeit für Bearbeitung und Manipulation der Komponenten erforderliche Systemverwaltungszeit bereit. Diese APIs werden größtenteils von visuellen Entwicklungswerkzeugen eingesetzt, um die Möglichkeit eines visuellen Layouts und Bearbeitung von Komponenten während der Erstellung einer Anwendung zu bieten. Der Teil einer Komponente, der die visuellen Bearbeitungsmöglichkeiten bereitstellt, wurde speziell so entworfen, daß er physisch von der Komponente selbst getrennt ist und somit dazu beiträgt, autonome Laufzeitkomponenten so kompakt wie möglich zu gestalten. In einer reinen Laufzeitumgebung werden Komponenten nur mit der erforderlichen Laufzeitkomponente übertragen. Entwickler, die sich der Vorteile von Entwurfszeitkomponenten bedienen wollen, können leicht den Entwurfszeitteil der Komponente erlangen.

Reicht das vorerst? Oder wollen Sie noch mehr wissen? Die JavaBeans-Spezifikationen sind verfügbar auf der Java-Webseite unter

http://www.javasoft.com/products/jdk/1.2/docs/guide/beans/index.html

JavaBeans - Technik, Konzepte, Beispiele von Michael Morrison (Markt & Technik, ISBN 3-8272-5284-9) ist sehr gut als Einführung in JavaBeans und die Möglichkeiten, die es Ihnen bietet, geeignet.

Applet-Tricks

Diese Lektion beginne ich mit ein paar kleinen Tips, die sonst nirgendwo hineinpassen: Die Verwendung von showStatus(), um Meldungen in der Browser-Statuszeile auszugeben, Applet-Informationen bereitzustellen und zwischen mehreren Applets auf der gleichen Seite eine Kommunikation zu ermöglichen.

Die showStatus()-Methode

Die in der Klasse Applet verfügbare showStatus()-Methode ermöglicht Ihnen die Anzeige einer Zeichenkette in der Statuszeile des Browsers, in dem das Applet ausgegeben wird. Sie können dies zum Ausgeben von Fehler-, Verknüpfungs-, Hilfs- oder anderen Statusmeldungen benutzen:

getAppletContext().showStatus("Change the color");

Die Methode getAppletContext() ermöglicht Ihrem Applet Zugriff auf Funktionen des Browsers, in dem es enthalten ist. Sie haben dies teilweise schon im Zusammenhang mit Verknüpfungen kennengelernt, für die Sie die showDocument()-Methode benutzt haben, um den Browser zum Laden einer Seite aufzufordern. showStatus() bedient sich desselben Mechanismus, um Statusmeldungen auszugeben.


Möglicherweise wird showStatus() nicht von allen Browsern unterstützt, deshalb sollten Sie sich in bezug auf die volle Funktionalität oder Schnittstelle Ihres Applet nicht auf den Browser verlassen. Diese Methode bietet eine nützliche Art der Kommunikation mit dem Benutzer - wenn Sie jedoch eine zuverlässigere Methode benötigen, richten Sie in Ihrem Applet ein Label ein und aktualisieren es auf die Meldungsänderungen hin.

Applet-Informationen

Das Abstract Windowing Toolkit bietet einen Mechanismus zum Einbinden von Informationen in Ihr Applet. Normalerweise umfaßt der Browser, in dem das Applet betrachtet wird, eine Möglichkeit zur Anzeige von Bildschirminformationen. Mit diesem Mechanismus können Sie Ihr Applet mit Ihrem Namen oder Ihrer Organisation unterzeichnen oder entsprechende Informationen zur Kontaktaufnahme bereitstellen, damit die Benutzer auf Wunsch mit Ihnen in Verbindung treten können.

Zur Angabe von Informationen über Ihr Applet überschreiben Sie die Methode getAppletInfo() :

public String getAppletInfo() {
   return "GetRaven copyright 1995 Laura Lemay";
}

Verknüpfungen in Applets erstellen

Da Applets auf Browser-Webseiten laufen, stellt die Möglichkeit, die Fähigkeit des Browsers zum Laden neuer Webseiten zu nutzen, ein gute Lösung dar. Java bietet einen Mechanismus, der den Browser zum Laden einer neuen Seite veranlaßt. Sie können diesen Mechanismus beispielsweise zu Erstellung von animierten Imagemaps benutzen, die beim Anklicken eine neue Seite laden.

Zur Verknüpfung einer neuen Seite erstellen Sie eine neue Instanz der URL-Klasse. Sie haben dies bereits im Zusammenhang mit Bildern gesehen. Hier steigen wir aber etwas tiefer in die Materie ein.

Die URL-Klasse stellt einen »Uniform Resource Locator« dar, einen Zeiger auf eine Datei oder ein Objekt im World Wide Web. Um einen neuen URL zu erzeugen, können Sie einen von vier unterschiedlichen Konstruktoren verwenden:

Bei der letzten Form (Erstellen einer URL aus einer Zeichenkette) müssen Sie eine eventuell falsch gebildete URL-Adresse berücksichtigen, deshalb umgeben Sie den URL-Konstruktor mit einem try...catch-Block:

String url = "http://www.yahoo.com/";
try { theURL = new URL(url); }
catch ( MalformedURLException e) {
   System.out.println("Bad URL: " + theURL);
}

Das Ermitteln und Erzeugen eines URL-Objektes ist der schwierige Teil. Wenn Sie eines haben, brauchen Sie es nur an den Browser weiterzugeben. Das geschieht in einer einzigen Codezeile, wobei die URL das URL-Objekt ist, mit dem die Verknüpfung hergestellt werden soll:

getAppletContext().showDocument(theURL);

Der Browser, der das Java-Applet mit diesem Code enthält, wird dann das Dokument unter dieser URL laden und anzeigen.

Listing 19.1 beinhaltet die beiden Klassen: ButtonLink und seine Handler-Klasse Bookmark . ButtonLink ist ein einfaches Applet, das drei Schaltflächen anzeigt, die wichtige Web-Standorte darstellen (die Schaltflächen sind in Abbildung 19.1 dargestellt). Durch Anklicken der Schaltflächen wird das Dokument von den Standorten, auf die sich diese Schaltflächen beziehen, geladen.


Abbildung 19.1:
Das Bookmark-Applet


Dieses Applet muß in einem Browser ausgeführt werden, damit die Links funktionieren. Außerdem wurde es mit den Techniken zur Ereignisbehandlung von Java 1.01 geschrieben, um die größtmögliche Zahl von Browsern zu unterstützen. Sie erhalten eine depricated-Warnung, wenn Sie das Applet mit dem javac-Tool von Java 1.2 kompilieren.

Listing 19.1: Der gesamte Quelltext von Buttonlink.java

 1: import java.awt.*;
 2: import java.net.*;
 3:
 4: public class ButtonLink extends java.applet.Applet {
 5:     Bookmark bmList[] = new Bookmark[3];
 6:
 7:     public void init() {
 8:         bmList[0] = new Bookmark("Teach Yourself Java 1.2 in 21 Days",
 9:             "http://www.prefect.com/java21");
10:         bmList[1] = new Bookmark("Macmillan Computer Publishing",
11:             "http://www.mcp.com");
12:         bmList[2]= new Bookmark("JavaSoft",
13:             "http://java.sun.com");
14:
15:         GridLayout gl = new GridLayout(bmList.length, 1, 10, 10);
16:         setLayout(gl);
17:         for (int i = 0; i < bmList.length; i++) {
18:             add(new Button(bmList[i].name));
19:         }
20:     }
21:
22:     public boolean action(Event evt, Object arg) {
23:         if (evt.target instanceof Button) {
24:             linkTo( (String)arg );
25:             return true;
26:         }
27:         else return false;
28:     }
29:
30:     void linkTo(String name) {
31:         URL theURL = null;
32:         for (int i = 0; i < bmList.length; i++) {
33:             if (name.equals(bmList[i].name))
34:                 theURL = bmList[i].url;
35:         }
36:         if (theURL != null)
37:             getAppletContext().showDocument(theURL);
38:     }
39: }
40:
41: class Bookmark {
42:     String name;
43:     URL url;
44:
45:     Bookmark(String name, String theURL) {
46:         this.name = name;
47:         try {
48:             this.url = new URL(theURL);
49:         } catch (MalformedURLException e) {
50:             System.out.println("Bad URL: " + theURL);
51:         }
52:     }
53: }

Mit dem folgenden HTML-Code können Sie das Applet in eine Webseite einbinden:

<APPLET CODE="ButtonLink.class" HEIGHT=120 WIDTH=240>
</APPLET>

Dieses Applet besteht aus zwei Klassen: Die erste, ButtonLink, implementiert das Applet; die zweite, Bookmark, ist eine Klasse, die ein Bookmark (Lesezeichen) darstellt. Bookmarks bestehen wiederum aus zwei Teilen: einem Namen und einer URL.

Dieses spezielle Applet erstellt drei Bookmark-Instanzen (Zeilen 8 bis 13) und speichert sie in einem Bookmark-Array (dieses Applet könnte leicht so abgeändert werden, daß es Bookmarks als Parameter aus einer HTML-Datei enthält). Für jedes Bookmark wird eine Schaltfläche erstellt, deren Beschriftung dem Wert des Bookmark-Namens entspricht.

Durch Anklicken einer Schaltfläche wird die linkTo()-Methode aufgerufen. linkTo() ist in den Zeilen 30 bis 38 definiert und benutzt den Namen der Schaltfläche, die das Ereignis ausgelöst hat, um den eigentlichen URL aus dem Bookmark-Objekt zu ermitteln, und weist dann den Browser an, den URL zu laden, auf den dieses Lesezeichen verweist.

Kommunikation zwischen Applets

Zuweilen möchten Sie vielleicht mehrere Applets in eine HTML-Seite stellen. Um dies zu realisieren, können Sie mehrere verschiedene <APPLET>-Tags einbinden. Der Browser erstellt dann die Instanz für jedes Applet, das auf der HTML-Seite erscheint.

Was nun, wenn diese Applets miteinander kommunizieren sollen? Oder wenn in einem Applet etwas geändert wird, das die übrigen Applets in irgendeiner Weise betrifft? Die beste Möglichkeit hierfür ist die Verwendung des Applet-Kontexts, um mehrere Applets in eine Seite einzubinden.


Bevor Sie intensives Arbeiten mit der Kommunikation zwischen Applets beginnen, muß ich Sie vorab warnen, daß der in diesem Abschnitt beschriebene Mechanismus bei unterschiedlichen Browsern und unterschiedlichen Java-Anwendungen auch unterschiedlich (und oft unzuverlässig) realisiert wird. Wenn Sie sich auf die Kommunikation zwischen Applets für Ihre Webseiten verlassen müssen, ist umfangreiches Testen dieser Applets mit unterschiedlichen Browsern auf unterschiedlichen Plattformen absolut notwendig.

Der Applet-Kontext ist in einer entsprechend benannten Klasse, der Klasse AppletContext , definiert. Um eine Instanz dieser Klasse für Ihr Applet zu holen, verwenden Sie die Methode getAppletContext(). Den Umgang mit der getAppletContext()- Methode haben Sie bereits in verschiedenen Beispielen gelernt. Sie können diese Methode auch verwenden, um andere Applets in eine Seite zu stellen. Um beispielsweise eine Methode mit dem Namen sendMessage() in allen Applets auf einer Seite aufzurufen (einschließlich des jeweils aktuellen Applets), verwenden Sie die getApplets()- Methode und eine for-Schleife, die etwa folgendermaßen aussieht:

for (Enumeration e = getAppletContext().getApplets();
   e.hasMoreElements();) {
   Applet current = (MyAppletSubclass)(e.nextElement());
   current.sendMessage();
}

Die getApplets()-Methode gibt ein Enumeration-Objekt mit einer Liste der auf der Seite befindlichen Applets aus. Die for-Schleife für das Enumeration-Objekt ermöglicht Ihnen den Zugriff auf alle Elemente nacheinander in der Auflistung. Beachten Sie, daß jedes Element in dem Enumeration-Objekt eine Instanz der Objektklasse ist; um ein Ihren Wünschen entsprechendes Verhalten des Applet zu erreichen (und Meldungen von anderen Applets aufzunehmen), müssen Sie es so gestalten, daß es eine Instanz Ihrer Applet-Subklasse ist (in diesem Fall der Klasse MyAppletSubclass).

Etwas komplizierter wird es, wenn Sie eine Methode in einem bestimmten Applet aufrufen wollen. Hierfür geben Sie jedem Applet einen Namen und setzen in den Rumpf des betreffenden Applet-Codes eine Referenz auf diesen Namen.

Um einem Applet einen Namen zu geben, benutzen Sie das NAME-Attribut für <APPLET> in Ihrer HTML-Datei:

<P>This applet sends information:
<APPLET CODE="MyApplet.class" WIDTH=100 HEIGHT=150
   NAME="sender"> </APPLET>
<P>This applet receives information from the sender:
<APPLET CODE="MyApplet.class" WIDTH=100 HEIGHT=150
   NAME="receiver"> </APPLET>

Um eine Referenz zu einem anderen Applet auf der gleichen Seite zu erhalten, verwenden Sie die getApplet()-Methode aus dem Applet-Kontext mit dem Namen des betreffenden Applets. Dadurch erhalten Sie eine Referenz zu dem Applet dieses Namens. Sie können dann auf das Applet so verweisen, als wäre es nur ein anderes Objekt: Methoden aufrufen, seine Instanzvariablen setzen usw. Hier ein entsprechender Code dafür:

// Receiver-Applet holen 
Applet receiver = (MyAppletSubclass)getAppletContext().getApplet("receiver");
// Anweisen zur Aktualisierung.
receiver.update(text, value);

In diesem Beispiel wird die getApplet()-Methode verwendet, um eine Referenz zu dem Applet mit dem Namen receiver zu erhalten. Beachten Sie, daß das von getApplet() ausgegebene Objekt eine Instanz der generischen Applet-Klasse ist; es ist anzunehmen, daß Sie dieses Objekt einer Instanz Ihrer Subklasse zuweisen wollen. Mit der Referenz zu dem benannten Applet können Sie dann Methoden in diesem Applet aufrufen, als ob es ein anderes Objekt in Ihrer eigenen Umgebung wäre. Sie können beispielsweise, vorausgesetzt beide Applets besitzen eine update()-Methode, den Empfänger anweisen, sich selbst unter Verwendung der Informationen des aktuellen Applet zu aktualisieren.

Indem Sie Ihren Applets Namen geben und sich dann auf sie mit den in diesem Abschnitt beschriebenen Methoden beziehen, können Ihre Applets miteinander kommunizieren und sich auf die jeweils geänderten Informationen des anderen Applets aktualisieren, so daß alle Applets auf Ihrer Seite ein einheitliches Verhalten aufweisen.

Ausschneiden, Kopieren und Einfügen

Beginnend mit der Version 1.1 des AWT wurde die Unterstützung für Ausschneiden-, Kopieren- und Einfügen-Operationen zwischen Komponenten einer AWT-Benutzeroberfläche und anderen Programmen, die auf der Plattform ausgeführt werden und nicht in Java implementiert sind, hinzugefügt. Zuvor ermöglichte es das AWT nur, Daten zwischen solchen Komponenten zu kopieren und einzufügen, in denen auf den systemeigenen Plattformen bereits grundlegende Fähigkeiten hierfür integriert waren (Text konnte beispielsweise zwischen Textfeldern und Textbereichen kopiert und eingefügt werden). Mit der Version 1.1 wurde diese Fähigkeit so erweitert, daß auch andere Daten oder Objekte von einer Komponente in eine andere übertragen werden können.

Um Daten von einer Komponente in eine andere übertragen zu können, müssen Sie zuerst ein austauschbares Objekt definieren und dann Komponenten modifizieren oder erstellen, die die Fähigkeit besitzen, dieses Objekt zu übertragen.

Die Klassen und Schnittstellen hierfür sind im java.awt.datatransfer-Paket enthalten.

Austauschbare Objekte erstellen

Daten-Flavors werden durch MIME-Typen beschrieben, demselben Mechanismus, der von zahlreichen E-Mail-Programmen und dem World Wide Web selbst angewandt wird, um Inhalte zu kennzeichnen. Wenn Sie mit MIME-Typen nicht vertraut sind, können Sie in RFC 1521 die MIME-Spezifikation nachlesen (es sollte Ihnen möglich sein, sich diese Spezifikation an jedem Web- oder FTP-Standort, der die verschiedenen Internet-RFC-Dokumente enthält, zu beschaffen, http://ds.internic.net/rfc/ rfc1521.txt ist ein Beispiel hierfür). Zusätzlich zu dem logischen Flavor-Namen, hat das Daten-Flavor ebenfalls einen »benutzerlesbaren« Flavor-Namen, der für unterschiedliche internationale Sprachen entsprechend übersetzt werden kann. Daten-Flavors können außerdem eine entsprechende Java-Klasse haben - wenn beispielsweise das Daten-Flavor eine Unicode-Zeichenkette ist, würde die String-Klasse dieses Flavor repräsentieren. Wenn das Flavor keine es repräsentierende Klasse besitzt, wird die Klasse InputStream benutzt.


Ein austauschbares Objekt ist ein Objekt, das mit dem AWT-Datenübertragungsmechanismus von einer Komponente in eine andere transportiert werden kann und eine bestimmte Menge von zu übertragenden Daten einkapselt (zum Beispiel formatierten Text). Genauer gesagt ist ein austauschbares Objekt ein Objekt, das die Transferable- Schnittstelle implementiert.

Wenn Sie ein austauschbares Objekt erstellen, müssen Sie als erstes entscheiden, welche »Flavors« das Objekt unterstützen soll. Ein Flavor ist im wesentlichen das Format der zu übertragenden Daten. Wenn Sie beispielsweise HTML-formatierten Text aus einem Browser kopieren und versuchen, ihn einzufügen, könnten die Daten in einem von mehreren unterschiedlichen Flavors eingefügt werden: als formatierter Text, als Klartext oder als HTML-Code. Daten-Flavors bestimmen, wie der Teil, von dem kopiert wird, und der Teil, in den eingefügt wird, verhandeln, wie die Daten selbst übertragen werden sollen. Wenn die Quelle und das Ziel der Datenübertragung nicht die gleiche Gruppe von Flavors unterstützen, können die Daten nicht übertragen werden.

Um einen neuen Daten-Flavor zu erstellen, erzeugen Sie eine neue Instanz von der DataFlavor-Klasse, indem Sie einen der beiden folgenden Konstruktoren verwenden:

Mit diesem DataFlavor-Objekt können Sie seine Werte abfragen oder MIME-Typen mit anderen DataFlavor-Objekten vergleichen, um die Übertragungsweise der Daten zu verhandeln.

Daten-Flavors werden von austauschbaren Objekten benutzt, die unter Verwendung der Transferable-Schnittstelle definiert werden. Ein austauschbares Objekt beinhaltet die zu übertragenden Daten und Instanzen jedes Daten-Flavors, das dieses Objekt repräsentiert. Darüber hinaus müssen Sie die Methoden getTransferDataFlavors(), isDataFlavorSupported() und getTransferData() implementieren, damit Ihr übertragbares Objekt auch effektiv verhandelt und übertragen werden kann (Einzelheiten hierzu finden Sie bei der Transferable-Schnittstelle).

Die Klasse StringSelection implementiert ein einfaches übertragbares Objekt zum Übertragen von Zeichenketten und verwendet dabei sowohl DataFlavor-Objekte als auch die Transferable-Schnittstelle. Wenn Sie hauptsächlich Text kopieren möchten, ist StringSelection hierfür die beste Stelle zum Ansatz (und möglicherweise das einzige übertragbare Objekt, das Sie effektiv benötigen). Eingehendes Untersuchen der Quelle der StringSelection-Klasse hilft Ihnen auch herauszufinden, auf welche Weise übertragbare Objekte arbeiten. (Sie können die Quelle mit dem JDK selbst finden, und sie ist ebenfalls in der Datenübertragungsspezifikation unter http://java.sun.com/products/jdk/1.1/docs/guide/awt/designspec/datatransfer.html) angegeben.

Beachten Sie, daß austauschbare Objekte lediglich zum Einkapseln von Daten und zur Beschreibung des Formats verwendet werden; sie führen in keinster Weise Formatierung dieser Daten durch. Dafür ist Ihr Programm zuständig, wenn Sie die Zwischenablage zur Einholung von Daten aus einer Quelle verwenden.

Verwendung der Zwischenablage

Nachdem Sie ein übertragbares Objekt erzeugt haben, können Sie eine Zwischenablage zur Übertragung dieses Objektes zwischen Komponenten und aus Java heraus auf die systemeigene Plattform verwenden. Java 1.2 bietet einen sehr leicht zu handhabenden Mechanismus für die Zwischenablage, der es Ihnen ermöglicht, Daten in die Zwischenablage zu stellen und Daten wieder aus dieser Zwischenablage zu laden. Sie können entweder eine einzelne Standardsystem-Zwischenablage verwenden, um Daten in andere und aus anderen Programmen, die auf der systemeigenen Plattform laufen, zu transportieren, oder Sie können Ihre eigenen Instanzen der Zwischenablage zur Erstellung besonderer Zwischenablagen oder mehrerer Gruppen von Spezialzwischenablagen verwenden.

In Java werden Zwischenablagen durch die Klasse Clipboard repräsentiert, die auch ein Bestandteil des java.awt.datatransfer-Pakets ist. Das Standardsystem Clipboard erhalten Sie durch Verwendung der Methoden getToolkit() und getSystemClipBoard() (wie Sie im letzten Abschnitt gelernt haben, bietet getToolkit() eine Möglichkeit, auf verschiedene systemeigene Fähigkeiten zuzugreifen) wie folgt:

Clipboard clip = getToolkit().getSystemClipboard()

Hier noch ein wichtiger Hinweis in bezug auf die Systemzwischenablage - aus Sicherheitsgründen können Applets derzeit nicht auf die Systemzwischenablage zugreifen (möglicherweise befinden sich sensitive Daten in dieser Zwischenablage). Dies hindert Applets daran, irgendwelche Daten in die oder von der systemeigenen Plattform zu kopieren oder einzufügen (mit Ausnahme der Fähigkeiten, die dort bereits vorhanden sind, wie Text innerhalb von Textfeldern und Textbereichen). Allerdings haben Sie die Möglichkeit, Ihre eigenen internen Zwischenablagen zum Kopieren und Einfügen zwischen Komponenten in einem Applet zu verwenden.

Jede Komponente, die Gebrauch von der Zwischenablage machen möchte - entweder um Daten unter Verwendung von Ausschneiden oder Kopieren in die Zwischenablage zu stellen, oder um Daten unter Verwendung von Einfügen aus der Zwischenablage zu holen -, muß die ClipboardOwner-Schnittstelle implementieren. Diese Schnittstelle verfügt über eine Methode: lostOwnership(), die aufgerufen wird, wenn eine andere Komponente die Kontrolle der Zwischenablage übernimmt.

Zur Durchführung von Ausschneiden oder Kopieren, d.h. um Daten in die Zwischenablage zu stellen, führen Sie folgende Schritte aus:

1. Erzeugen Sie eine Instanz Ihres Transferable-Objekts, um die zu kopierenden Daten zu speichern.

2. Erzeugen Sie eine Instanz des Objekts, das die ClipboardOwner-Schnittstelle realisiert (das kann entweder die aktuelle Klasse sein, oder das Transferable-Objekt kann auch den Inhaber der Zwischenablage realisieren).

3. Wenn Sie die Systemzwischenablage erneut verwenden, benutzen Sie getSystemClipboard() , um eine Referenz zu dieser Zwischenablage zu erhalten.

4. Rufen Sie die setContents()-Methode der Zwischenablage mit dem Transferable -Objekt und dem Objekt, das ClipboardOwner als Argumente implementiert, auf. Mit dieser Methode erhält Ihr Objekt erklärtes »Eigentumsrecht« an der Zwischenablage.

5. Übernimmt ein anderes Objekt die Zwischenablage, wird die Methode lostOwnership() aufgerufen. Ist das der Fall, wollen Sie implementieren, daß diese Methode etwas unternimmt (oder eine leere Methode erzeugen, wenn es Ihnen nichts ausmacht, daß jemand den Inhalt Ihrer Zwischenablage ersetzt hat).

Um die Einfügen-Operation zu implementieren, d.h. Daten aus einer Zwischenablage zu entnehmen, führen Sie die folgenden Schritte aus:

1. Benutzen Sie die getContents()-Methode der Zwischenablage, die ein austauschbares Objekt ausgibt.

2. Benutzen Sie die getTransferDataFlavors()-Methode des austauschbaren Objekts, um zu untersuchen, welche Flavors dieses austauschbare Objekt unterstützt. Legen Sie fest, welcher Flavor benutzt werden soll.

3. Laden Sie die Daten mit dem richtigen Flavor, indem Sie die Methode getTransferData() des austauschbaren Objektes verwenden.

Hier ein sehr einfaches Anwendungsbeispiel, in dem die Zwischenablage zum Kopieren von Text aus einem Textfeld in ein anderes benutzt wird (wie in Abbildung 19.2 gezeigt). Listing 19.2 zeigt den Code für dieses Beispiel auf.


Abbildung 19.2:
Die CopyPaste-Applikation

Listing 19.2: Kopieren und Einfügen

 1: import java.awt.*;
 2: import java.awt.event.*;
 3: import java.awt.datatransfer.*;
 4:
 5: public class CopyPaste extends Frame
 6:     implements ActionListener, ClipboardOwner {
 7:
 8:     Button copy, paste;
 9:     TextField tfCopy, tfPaste;
10:     Clipboard clip;
11:
12:     public static void main(String[] arguments) {
13:         CopyPaste test = new CopyPaste();
14:         WindowListener l = new WindowAdapter() {
15:             public void windowClosing(WindowEvent e) {
16:                 System.exit(0);
17:             }
18:         };
19:         test.addWindowListener(l);
20:         test.setSize(200, 150);
21:         test.show();
22:     }
23:
24:     CopyPaste() {
25:         super("Copy and Paste");
26:         clip = getToolkit().getSystemClipboard();
27:         FlowLayout flo = new FlowLayout();
28:         setLayout(flo);
29:
30:         copy = new Button("Copy From");
31:         tfCopy = new TextField(25);
32:         paste = new Button("Paste To");
33:         tfPaste = new TextField(25);
34:
35:         copy.addActionListener(this);
36:         paste.addActionListener(this);
37:         paste.setEnabled(false);
38:
39:         add(copy);
40:         add(tfCopy);
41:         add(paste);
42:         add(tfPaste);
43:     }
44:
45:     void doCopy() {
46:         if (tfCopy.getText() != null) {
47:             String txt = tfCopy.getText();
48:             StringSelection trans = new StringSelection(txt);
49:             clip.setContents(trans, this);
50:             paste.setEnabled(true);
51:         }
52:     }
53:
54:     void doPaste() {
55:         Transferable toPaste = clip.getContents(this);
56:         if (toPaste != null) {
57:             try {
58:                 String txt = (String)toPaste.getTransferData(
59:                     DataFlavor.stringFlavor);
60:                 tfPaste.setText(txt);
61:                 paste.setEnabled(false);
62:             } catch (Exception e) {
63:                 System.out.println("Error -- " + e.toString());
64:             }
65:         }
66:     }
67:
68:     public void actionPerformed(ActionEvent e) {
69:         if (e.getSource() == copy)
70:             doCopy();
71:         else if (e.getSource() == paste)
72:             doPaste();
73:     }
74:
75:     public void lostOwnership(Clipboard clip,
76:         Transferable contents) {
77:     }
78: }

Der meiste Code in dieser Applikation beinhaltet Verhaltensweisen, um eine grafische Benutzeroberfläche zu erstellen und auf Benutzer-Ereignisse zu reagieren. Sie lernen während der nächsten zwei Tage, wenn Sie Swing-Applikationen mit Java 1.2 entwikkeln, mehr über diese Techniken.

Folgende Anweisungen beziehen sich auf das Kopieren und Einfügen::

RMI (Remote Method Invocation)

RMI wird zur Erstellung von Java-Anwendungen benutzt, die mit anderen Java-Anwendungen über ein Netz kommunizieren können. Um es genauer auszudrücken, ermöglicht RMI einer Java-Anwendung, Methoden und Zugriffsvariablen innerhalb anderer Java-Anwendungen, die in unterschiedlichen Java-Umgebungen oder auf unterschiedlichen Systemen laufen können, aufzurufen und über die Netzverbindung Objekte weiter- und zurückzugeben. RMI ist ein höher entwickelter Mechanismus zur Kommunikation zwischen verteilten Java-Objekten als eine einfache Socket-Verbindung es sein könnte, da der Mechanismus und die Protokolle, durch die Sie zwischen den Objekten kommunizieren, definiert und standardisiert sind. Sie können mit einem anderen Java- Programm mit RMI kommunizieren, ohne vorher das Protokoll zu kennen.


Eine andere Form der Kommunikation zwischen Objekten nennt sich RPC (Remote Procedure Calls), mit der Sie über eine Netzverbindung in anderen Programmen Methoden aufrufen oder Verfahren ausführen können. Obwohl RPC und RMI viele Gemeinsamkeiten haben, besteht der Hauptunterschied darin, daß RPC nur Verfahrensaufrufe über die Leitung sendet, wobei die Argumente entweder derart weitergeleitet oder beschrieben werden, daß sie auf jeder Seite rekonstruierbar sind. Tatsächlich gibt RMI ganze Objekte über das Netz hin und her und eignet sich daher besser für ein vollkommen objektorientiertes verteiltes Objektmodell.

Das RMI-Konzept könnte Visionen von auf der ganzen Welt fröhlich miteinander kommunizierenden Objekten aufkommen lassen, normalerweise wird RMI jedoch in einer traditionelleren Client-Server-Situation benutzt: Eine Einzel-Server-Anwendung erhält Verbindungen und Anfragen von einer Anzahl Clients. RMI ist einfach ein Mechanismus, der es Client und Server ermöglicht, miteinander zu kommunizieren.

Die RMI-Architektur

Die für RMI gesteckten Ziele waren, ein verteiltes Objektmodell in Java zu integrieren, ohne dabei die Sprache oder das bestehende Objektmodell auseinanderzureißen und das Eintreten in eine Wechselbeziehung mit einem Remote-Objekt so einfach wie mit einem lokalen zu gestalten. Beispielsweise sollte es Ihnen möglich sein, Remote-Objekte auf exakt dieselbe Weise wie lokale zu verwenden (sie Variablen zuweisen, sie als Argumente an Methoden weitergeben usw.), und Remote-Objekte in Methoden aufzurufen, sollte auf dieselbe Weise erreichbar sein, wie für entsprechende lokale Aufrufe. Darüber hinaus beinhaltete RMI einen höher entwickelten Mechanismus, um Methoden bei Remote-Objekten aufzurufen, um ganze Objekte oder Teile von Objekten entweder mit Referenz oder mit Wert weiterzugeben sowie zusätzliche Ausnahmen für die Bearbeitung von Netzfehlern, die beim Durchführen von Remote-Operationen vorkommen können.

Zum Erreichen dieser Ziele besitzt RMI mehrere Ebenen und ein einzelner Methodenaufruf durchläuft viele dieser Ebenen, um an seinen Bestimmungsort zu gelangen (siehe Abbildung 19.3). Es gibt drei Ebenen:


Abbildung 19.3:
RMI-Ebenen

Die Verfügbarkeit von drei RMI-Ebenen ermöglicht die unabhängige Kontrolle und Implementierung jeder Ebene. Stubs und Skeletons ermöglichen es Client- und Server- Klassen, sich so zu verhalten, als ob die vorliegenden Objekte lokale seien, und genau dieselben Java-Spracheigenschaften zum Zugriff auf diese Objekte zu verwenden. Die Ebene Remote Reference Layer stellt die Verarbeitung des Remote-Objekts in seine eigene Ebene, die dann unabhängig von den Anwendungen, die von ihr abhängig sind, optimiert und reimplementiert werden kann. Schließlich wird die Ebene Network Transport Layer unabhängig von den beiden anderen benutzt, so daß Sie unterschiedliche Typen von Socket-Verbindungen für RMI benutzen können (TCP/IP, UDP oder TCP mit einem anderen Protokoll wie beispielsweise SSL).

Wenn eine Client-Anwendung einen Remote Method Call durchführt, gelangt der Aufruf über Stub zu der Referenzebene, die die Argumente, falls erforderlich, zusammenstellt und gibt ihn dann über die Netzebene an den Server, wo die serverseitige Referenzebene die Argumente auseinandernimmt und sie an Skeleton und dann an die Server-Implementierung weiterleitet. Die Ausgabewerte für den Aufruf der Methode machen dann den Weg in umgekehrter Reihenfolge zurück zur Client-Seite.


Das Zusammenstellen und Weitergeben von Methodenargumenten ist einer der interessanteren Aspekte von RMI, da Objekte in etwas konvertiert werden müssen, das über das Netz weitergegeben werden kann. Diese Konvertierung nennt man Serialisation . So lange ein Objekt serialisiert werden kann, kann RMI es als einen Methodenparameter oder Ausgabewert benutzen. Serialisierbare Objekte beinhalten alle Java- Primitiv-Typen, Java-Remote-Objekte und jedes beliebige andere Objekt, das die Serializeable -Schnittstelle (was viele der Klassen des Standard-1.2-JDK, wie beispielsweise alle AWT-Komponenten, beinhaltet) implementiert.

Als Methodenparameter oder Rückgabewerte benutzte Java-Remote-Objekte werden so wie lokale Objekte nach Referenz übergeben. Andere Objekte werden allerdings kopiert. Beachten Sie, daß dieses Verhalten die Art und Weise, in der Sie Ihre Java-Programme schreiben, beeinflußt, wenn diese Programme Remote Method Calls benutzen - Sie können beispielsweise ein Array nicht als ein Argument an eine Remote-Methode weitergeben, das Array von dem Remote-Objekt ändern lassen und erwarten, daß die lokale Kopie modifiziert wird. Dies stellt einen Unterschied zur Verhaltensweise von lokalen Kopien dar, wo alle Objekte als Referenzen weitergegeben werden.

RMI-Anwendungen erstellen

Um eine Anwendung zu erstellen, die RMI einsetzt, benutzen Sie die Klassen und Schnittstellen, die im Paket java.rmi definiert sind, das java.rmi.server für Server- seitige Klassen, java.rmi.registry, das die Klassen zur Lokalisierung und Registrierung der RMI-Server auf dem lokalen System enthält, und java.rmi.dgc für Garbage- Collection von verteilten Objekten beinhaltet. Das java.rmi-Paket selbst enthält die allgemeinen RMI-Schnittstellen, -Klassen und -Ausnahmen.

Um eine RMI-basierte Client-Server-Anwendung zu implementieren, definieren Sie zuerst eine Schnittstelle, die alle Methoden, die Ihr Remote-Objekt unterstützen wird, enthält. Die Methoden in dieser Schnittstelle müssen alle ein throws RemoteException -Statement beinhalten, das etwaige Netzprobleme behandelt, die zur Verhinderung der Kommunikation zwischen Client und Server führen können.

Der nächste Schritt besteht in der Implementierung der Remote-Schnittstelle in einer Server-seitigen Anwendung, die in der Regel die UnicastRemoteObject-Klasse erweitern. Innerhalb dieser Klasse können Sie die Methoden in der Remote-Schnittstelle implementieren und auch einen Security-Manager für diesen Server erstellen und installieren (um die Verbindungsherstellung von Random-Clients und die Durchführung nicht autorisierter Aufrufe von Methoden zu verhindern). Sie können natürlich den Security-Manager derart konfigurieren, daß er verschiedene Operationen genehmigt oder nicht genehmigt. In der Server-Anwendung »registrieren« Sie auch die Remote- Anwendung, die diese an einen Host und einen Port anbindet.

Auf der Client-Seite implementieren Sie eine einfache Anwendung, die die Remote- Schnittstelle benutzt und Methoden in dieser Schnittstelle aufruft. Eine Klasse namens Naming (in java.rmi) ermöglicht dem Client eine transparente Verbindungsherstellung zum Server.

Wenn der Code geschrieben ist, können Sie ihn mit dem Standard-Compiler von Java kompilieren, allerdings gibt es noch einen weiteren Schritt auszuführen: benutzen Sie das Programm rmic zur Erzeugung der Ebenen Stubs und Skeletons, damit RMI effektiv zwischen den beiden Seiten des Prozesses arbeiten kann.

Das Programm rmiregistry wird schließlich dazu benutzt, die Server-Anwendung an das Netz selbst anzuschließen und es an einen Port anzubinden, so daß Remote-Verbindungen hergestellt werden können.

Natürlich stellt dies eine sehr vereinfachte Form des Prozesses zur Erstellung einer RMI- basierten Anwendung dar. Weitere Informationen über RMI und wie man die RMI-Klassen einsetzt, finden Sie in den Informationen über die Webseite von JavaSoft unter

http:/www.javasoft.com:80/products/JDK/1.2/docs/guide/rmi/index.html">http://www.javasoft.com:80/products/JDK/1.2/docs/guide/rmi/index.html

JDBC (Java Database Connectivity)

JDBC, das Java Database Connectivity API, definiert eine strukturierte Schnittstelle zu SQL-Datenbanken (Structured Query Language) - Industriestandard für relationale Datenbanken. Durch die Unterstützung von SQL ermöglicht JDBC Entwicklern die Interaktion und Unterstützung einer breiten Palette von Datenbanken. Dies bedeutet, daß die spezifischen Eigenschaften der zugrundeliegenden Datenbankplattform in bezug auf JDBC ziemlich irrelevant sind. Also gute Nachrichten für Java-Entwickler.

SQL-Datenbanken sind auf dem allgemein anerkannten SQL-Standard aufgebaute Datenbanken, der ein striktes Protokoll für den Zugriff auf und die Manipulation von Daten definiert.

Der Ansatz des JDBC-API für den Zugriff auf SQL-Datenbanken ist mit bestehenden Entwicklungstechniken für Datenbanken vergleichbar, so daß Interaktion mit einer SQL-Datenbank per JDBC nicht sehr unterschiedlich zu der Interaktion über traditionelle Datenbankwerkzeuge ist. Dies sollte Java-Programmierer, die schon einige Erfahrung mit Datenbanken haben, in bezug auf JDBC zuversichtlich stimmen. Das JDBC-API wurde bereits von vielen Industrieführern angenommen, inklusive einiger Lieferanten von Entwicklungswerkzeugen, die zukünftige Unterstützung von JDBC bei ihren Entwicklungsprodukten angekündigt haben.

Das JDBC-API beinhaltet Klassen für allgemeine Formen von SQL-Datenbanken wie Datenbankverbindungen, SQL-Anweisungen und Resultsets. Java-Programme mit JDBC sind in der Lage, das vertraute SQL-Programmierungsmodell der Ausgabe von SQL-Anweisungen und Verarbeitung der Ergebnisdaten zu benutzen. Das JDBC-API hängt weitgehend von einem Treibermanager ab, der mehrere Treiber, die die Verbindung zu verschiedenen Datenbanken herstellen, unterstützt. JDBC-Datenbanktreiber können entweder vollständig in Java geschrieben werden oder durch Verwendung systemeigener Methoden implementiert werden, um eine Brücke zwischen Java-Anwendungen und bestehenden Datenbankzugriffsbibliotheken zu schlagen.

JDBC beinhaltet ebenso eine Brücke zwischen JDBC und ODBC, der allgemeinen Schnittstelle zum Zugriff auf SQL-Datenbanken von Microsoft. Die JDBC-ODBC- Bridge ermöglicht es, JDBC-Treiber als ODBC-Treiber zu benutzen.

Die JDBC-Klassen sind als Bestandteil von Java 1.2 im java.sql-Paket enthalten und beinhalten Klassen zur Handhabung der Treiber, zum Verbindungsaufbau zwischen Datenbanken, zur Erstellung von SQL-Abfragen und Handhabung der Ergebnisse.

Die Webseite von JavaSoft enthält umfangreiche Informationen und Spezifikationen über JDBC unter

http://www.javasoft.com/products/JDK/1.2/docs/guide/jdbc/index.html

Zusammenfassung

Als die Version 1 der Sprache Java 1995 veröffentlicht wurde, war die Sprache besser für die Applet-Programmierung geeignet als für den Entwurf großer Applikationen.

Mit Java 1.2 ist dies nicht mehr der Fall. Die Sprache bietet inzwischen eine robuste Unterstützung von Features, wie z.B. Entwurf von Softwarekomponenten, Remote Method Invocation, Datenbankanbindung und Objektserialisation.

Das Material, das heute behandelt wurde, soll als Basis für die weitere Erforschung der Pakete und Klassen, die diese Features anbieten, dienen. Sobald Sie die Grundlagen der Sprache Java gemeistert haben, sind Sie bereit, die fortgeschritteneren Themen in Form von Büchern, Kursen oder Ihrer eigenen Entdeckungsreise durch das Java-API in Angriff zunehmen.

In den nächsten zwei Tagen werden wir Ihre Einführung in die Sprache Java abrunden. Sie werden lernen, wie Sie grafische Benutzeroberflächen mit Swing, der neuen Lösung für den Entwurf grafischer Benutzeroberflächen von Java 1.2, erstellen und wie Sie diese Oberflächen in funktionierende Applikationen verwandeln.

Fragen und Antworten

Frage:
showStatus() funktioniert nicht in meinem Browser. Wie kann ich meinen Lesern Statusinformationen ausgeben?

Antwort:
Wie Sie in dem Abschnitt über showStatus() gelernt haben, liegt es absolut am Browser, ob er showStatus() unterstützt. Wenn Sie in Ihrem Applet ein statusähnliches Verhalten benötigen, können Sie eine Statusbeschriftung (Label) im Applet erstellen, die auf die auszugebenden Informationen aktualisiert wird.

Frage:
Ich habe versucht, zwischen zwei Applets in meiner Webseite unter Verwendung der Methoden getAppletContext() und getApplet() zu kommunizieren. Meine Applets stürzen mit NullPointerException Fehlermeldungen ab. Was bedeutet das?

Antwort:
Der von mir beschriebene Mechanismus bezüglich der Kommunikation zwischen Applets beruht darauf, wie es laut SUN und der Java-Klassenbibliothek funktionieren sollte. Es verhält sich wie bei showStatus(): es hängt von dem jeweiligen Browser ab, ob er diesen Mechanismus unterstützt oder nicht bzw. ob er ihn korrekt ausführt. Die vorherige Version 3.0 von Netscape und Internet Explorer haben beide eigenartige Probleme mit Inter-Applet-Kommunikation.



vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Ein Imprint des Markt&Technik Buch- und Software-Verlag GmbH.
Elektronische Fassung des Titels: Java 2 in 21 Tagen, ISBN: 3-8272-5578-3