Diplomarbeit
Entwurf und Implementation einer generischen graphischen Benutzeroberfläche für ASN.1-Datentypen mit JavaBeans
Dieter Heiliger
Matrikel-Nr.: 389718
27. Februar 1998
TU Darmstadt, Fachbereich Informatik
Fachgebiet Verteilte Systeme
Deutsche Telekom AG,
Forschungszentrum Darmstadt
Meinen Eltern
| API | Application Programming Interface |
| ASN.1 | Abstract Syntax Notation One |
| AWT | Abstract Windowing Toolkit |
| BER | Basic Encoding Rules |
| CCITT | International Telegraph and Telephone Consultative Committee |
| CMIP | Common Management Information Protocol |
| CMIS | Common Management Information Services |
| CMOT | CMIP over TCP/IP |
| CORBA | Common Object Request Broker Architecture |
| DM | Distributed Management |
| GDMO | Guidelines for the Definition of Managed Objects |
| GUI | Graphical User Interface |
| HTML | Hypertext Markup Language |
| IBM | Industrial Business Machines |
| IDL | Interface Definition Language |
| ISO | International Organisation for Standardisation |
| ITU | International Telecommunications Union |
| JAR | Java Archive |
| JAsn API | Java ASN.1 API |
| JDK | Java Development Kit |
| JFC | Java Foundation Classes |
| JMAPI | Java Management API |
| MHS | Message Handling System |
| MIB | Management Information Base |
| MOON | Management Of Optical Networks |
| OLE | Object Linking and Embedding |
| OCX | OLE Control |
| OSI | Open Systems Interconnection |
| PDU | Protocol Data Unit |
| RFC | Request for Comments |
| SNMP | Simple Network Management Protocol |
| TCP/IP | Transmission Control Protocol/Internet Protocol |
| WWW | World Wide Web |
Diese Arbeit entstand im Rahmen des
MOON-Projektes
in einer Zusammenarbeit zwischen der Technischen Universität
Darmstadt, Fachgebiet Verteilte Systeme am Fachbereich Informatik, und
dem Forschungszentrum Darmstadt der Deutsche Telekom AG. An dieser
Stelle möchte ich all jenen danken, die zum Zustandekommen dieser Arbeit
beigetragen haben, speziell meinen Betreuern Heiko Dassow, Gerd
Aschemann und Stefan Fünfrocken.
Innerhalb des MOON-Projektes entstand deshalb der Wunsch, die benutzten - in ASN.1 spezifizierten - Datenstrukturen einschließlich ihrer Werte graphisch anzeigen und verändern zu können. Das zu entwickelnde Graphical User Interface (GUI) sollte sich generisch an die aktuellen Datenstrukturen anpassen können, um nicht für jeden Datentyp neu programmiert werden zu müssen.
Ein wichtiges Merkmal bei der graphischen Repräsentation von Datenstrukturen ist die Möglichkeit, irrelevante Informationen ausblenden zu können. Strukturierte Datentypen mit Komponenten als Untertypen sollten sich bei der Anzeige auf dem Bildschirm im Bedarfsfall soweit verkleinern lassen, daß nur noch wenige Aspekte des ,,Obertyps``, nicht aber die einzelnen Untertypen sichtbar sind. Dies erhöht die Übersichtlichkeit der Anzeige und somit die Bedienbarkeit der Software.
Ziel dieser Arbeit ist die Entwicklung einer graphischen Benutzeroberfläche für die im MOON-Projekt wie in zahlreichen anderen Bereichen des Netzmanagements eingesetzten ASN.1-Datentypen. Da man sich beim Netzmanagement häufig in heterogenen Umgebungen bewegt, wurde mit Java eine plattformunabhängige Entwicklungsumgebung gewählt.
Um die entwickelten Java-Klassen problemlos in eigene (Netzmanagement-) Applikationen integrieren zu können, sollen sie als Komponenten programmiert werden. Java bietet seit der Version 1.1 mit JavaBeans eine eigene Komponentenarchitektur. Ein Hauptaugenmerk bei dieser Arbeit soll deshalb auf der Prüfung liegen, wie gut das Beans-Konzept zur Realisierung der gegebenen Aufgabenstellung geeignet ist.
angefertigt. Auf Teilen dieser Studienarbeit baut die vorliegende
Arbeit auf.
Hubert entwickelte in seiner Studienarbeit eine in Java geschriebene
und somit plattformunabhängige Programmierschnittstelle
(API
) für
das Netzmanagement im Telekommunikationsbereich. Im Zuge dieses
Projektes wurde auch eine API zur Repräsentation von
ASN.1-Datenstrukturen in Java entwickelt (JAsn API ). Darüber
hinaus macht es ein von Hubert programmierter Compiler möglich,
ASN.1-Definitionen in Java-Klassen zu übersetzen. Inhalt der
vorliegenden Diplomarbeit ist es nun, für die erstellten
ASN.1-Java-Klassen eine graphische Benutzeroberfläche zu entwickeln,
um somit deren Werte komfortabel anzeigen und modifizieren zu können.
Diese Oberfläche sollte generisch sein, d.h. sich an die
darzustellenden ASN.1-Klassen automatisch anpassen können.
Die Abkürzung ASN.1 steht für Abstract Syntax Notation
One .
ASN.1 ist eine Sprache
zur Beschreibung strukturierter Informationen. Typischerweise sind
dies Informationen, die zum Transfer über Schnittstellen oder
Kommunikationsmedien gedacht sind. ASN.1 ist international
standardisiert und wird häufig zur Spezifikation von
Kommunikationsprotokollen verwendet. So sind beispielsweise alle
Standards für den Application Layer innerhalb der
OSI-Architektur in ASN.1 definiert.
Möchten zwei oder mehr Systeme miteinander kommunizieren, so tauschen sie zu diesem Zweck Daten aus. Ziel der Datenübertragung ist jedoch der Austausch der Bedeutungen dieser Daten. Die Bedeutungen stellen die Interpretation der Daten in einem bestimmten Kontext und somit die zu übermittelnde Information dar.
Damit zwei Applikationen sinnvoll miteinander kommunizieren können, müssen Sender und Empfänger wissen, welche Informationen die übertragenen Daten beinhalten. Für die beteiligten Programme ist es deshalb von essentieller Bedeutung, daß sie die verwendete abstrakte Syntax kennen. Diese Syntax beschreibt die Menge aller möglichen unterschiedlichen Nachrichten, die gegenseitig ausgetauscht werden können. Auch die jeweilige Bedeutung der Nachrichten wird vom Entwickler der abstrakten Syntax festgelegt. Dies ermöglicht die Implementierung von Aktionen, die auf den ausgetauschten Informationen basieren, in den Applikationen auf beiden Seiten der Kommunikation. Um nicht alle möglichen Nachrichten explizit aufzählen zu müssen, wird die abstrakte Syntax allgemein strukturiert und aus einfacheren Komponenten zusammengesetzt.
Allerdings ist es für eine sinnvolle Kommunikation nicht ausreichend, daß die beteiligten Parteien über die benutzte abstrakte Syntax informiert sind, sondern auch über die verwendete Transfersyntax muß man sich einig sein. Codierungen für den Transfer können bit-, oktet- oder zeichenbasiert sein. Diese Codierungen stellen die uninterpretierten Daten dar, die von Kommunikationsprotokollen zwischen verschiedenen Systemen ausgetauscht werden.
Im OSI-Schichtenmodell (vgl. Abbildung 2.1) befassen sich die
Schichten (Layer ) eins bis fünf mit der Übertragung von
Daten. Fokus der Schichten sechs und sieben ist hingegen die
Informationsübermittlung.
Im Application Layer tauschen
die Standardprotokolle Werte komplexer Typen aus. Diese Werte werden
von den Applikationen interpretiert. Im Session Layer sowie in
den Schichten darunter hingegen werden uninterpretierte Oktet- oder
Zeichensequenzen übertragen. Die Natur der Daten ändert sich
somit im Presentation Layer des OSI-Schichtenmodells,
entsprechende Standards müssen diese Differenz auflösen, ohne die
Freiheiten der anderen Layer zu stark zu beschneiden. Dieser
schwierigen Aufgabe widmet sich ASN.1. ASN.1 ist kein Protokoll,
sondern eine Notationsvorschrift, die von Protokollstandards verwendet
werden soll und auch verwendet wird.
![]() |
Mit ASN.1 können Daten beschrieben werden, die die Schnittstelle zwischen Applikations- und Präsentationsschicht überqueren, ohne die Repräsentation der Informationen auf einer der beiden Seiten zu spezifizieren. Auf diese Weise können Applikationen Informationen austauschen, ohne sich um deren Kodierung während der Datenübermittlung kümmern zu müssen. Bei der Beschreibung der Daten handelt es sich somit um eine abstrakte Syntax, ASN.1 ist demzufolge eine formale Notation zur Definition einer solchen abstrakten Syntax.
Eine abstrakte Syntax muß eine Menge verwandter Werte abstrakt beschreiben. Dies muß so geschehen, daß die abstrakte leicht in eine Transfersyntax umgewandelt werden kann, ohne die lokalen Syntaxen der Applikationen zu spezifizieren.
Wollen zwei Applikationen miteinander kommunizieren, so müssen sie sich auf eine abstrakte Syntax für die auszutauschenden Daten einigen. Die benutzten abstrakten Syntaxen können sich auch während des Ablaufs der Kommunikation ändern, beispielsweise wenn sich zwei Programme nach einem allgemeinen Austauch von grundlegenden Parametern auf ein zu benutzendes Protokoll einigen. Die Syntax an sich kann hingegen nur in einem Standardisierungsprozeß festgelegt werden, da der Presentation Layer im verwendeten Protokollstack wissen muß, für welche Menge von abstrakten Syntaxen er verantwortlich ist. Während der Kommunikation können dann Elemente dieser Menge ausgewählt werden.
ASN.1-Definitionen ähneln sehr stark den Datendeklarationen in höheren Programmiersprachen. Dies ist kein Zufall, denn ASN.1 erleichtert die Protokollspezifikationen, so wie höhere Programmiersprachen die Softwareentwicklung vereinfacht haben, nämlich durch Abstraktion.
Abstraktion ist ein wesentlicher Schlüssel zum erfolgreichen Management von Softwareentwicklungen. Durch sie können Entwickler Teile des Systems spezifizieren, ohne sich um Implementierungsdetails kümmern zu müssen. Auf diese Weise wird die Spezifikation ganz erheblich vereinfacht. Über die spezifizierten Teile der Software können Aussagen (Axiome) aufgestellt werden, auf die sich Module auf höheren Ebenen beziehen können. Darüber hinaus ist anhand dieser Axiome nach der Implementierung eine Überprüfung der Software möglich. Eines der komplexesten Systeme der heutigen Zeit, Open Systems Interconnection (OSI) , benutzt das Mittel der Abstraktion sehr stark.
ASN.1 wird innerhalb von OSI dazu verwendet, abstrakte Objekte zu beschreiben, beispielsweise sind die Protokollparameter aller Application Layer-Protokolle damit spezifiziert. Darüber hinaus findet es auch für weitere verteilte Systeme außerhalb der OSI-Architektur Verwendung.
ASN.1 ist eine flexible Notation, die es einem erlaubt, vielfältige Datentypen zu definieren - von einfachen Typen (z.B. Integer oder Bit String ) über strukturierte Typen (Set , Sequence ) bis hin zu komplexen Typen, die aus anderen Typen zusammengebaut werden.
Um eine abstrakte Syntax in Oktetsequenzen umzusetzen, ist eine
Transfersyntax notwendig. Sie muß alle Informationen der abstrakten
Syntax beinhalten und effizient codiert und decodiert werden können.
Gleichzeitig muß die Transfersyntax von allen Applikationen
unabhängig sein. Zu diesem Zweck sind viele Übersetzungsvarianten
denkbar, die international standardisierte Transfersyntax zur
Übersetzung von ASN.1-Daten wird von den Basic Encoding Rules
(BER)
beschrieben.
Die Formulierung der Transfersyntax macht Entscheidungen über Aspekte wie Repräsentation von Zahlen, Trennung von Feldern usw. notwendig. Die daraus resultierenden ,,Encoding Rules`` sind eine konsistente und vollständige Menge solcher Entscheidungen, die es erlauben, die Transfer- systematisch von der abstrakten Syntax abzuleiten. Demzufolge können die Codierungsregeln erst dann aufgestellt werden, wenn eine allgemein anerkannte Einigkeit über die Notation der abstrakten Syntax herrscht. Durch die Verwendung einer standardisierten Transfersyntax sparen Protokoll- und Anwendungsentwickler darüber hinaus Zeit und Arbeit, da sie Codier- und Decodierroutinen wiederverwenden können.
Die ASN.1 beschreibenden Dokumente beschäftigen sich nicht mit der Transfersyntax, dies geschieht in gesonderten Dokumenten. Es muß lediglich sichergestellt werden, daß die abstrakte Syntax ausreichend Informationen enthält, um eine effiziente Transfersyntax zu ermöglichen.
Das Zusammenspiel von abstrakter Syntax, lokaler Syntax und
Transfersyntax veranschaulicht Abbildung 2.2
.
![]() |
Das International Telegraph and Telephone Consultative Committee
(CCITT) standardisierte ASN.1 1984 in Ihrer Empfehlung X.409
erstmals. Damals wurde es einfach ,,X.409-Notation`` genannt. Erst
die International Organisation for Standardisation (ISO) führte
den Begriff ,,Abstract Syntax Notation One`` ein, als sie sich des
Standards annahm.
Die CCITT stellte den Bedarf für eine standardisierte Spezifikationssprache für Protokollinformationen erstmals während ihres X.400-Projektes fest. Die X.400-Serie ist eine Reihe von Empfehlungen bezüglich Message Handling Systems (MHS) . Zur Unterstützung dieses Projektes wurde als Teil der X.400-Empfehlungen auch X.409 entwickelt, das praktisch aber von den MHS-Anwendungen völlig unabhängig war.
Informationsobjekte innerhalb eines MHS sind sehr komplex strukturiert. Deshalb definierte die MHS-Gruppe innerhalb der CCITT eine Notation zur Spezifizierung komplexer Informationsstrukturen. Zusätzlich zu dieser X.409-Notation wurden im gleichen Dokument Regeln zur Codierung der beschriebenen Informationen spezifiziert. Diese Regeln nannte man ,,X.409-Codierung``, sie wurden später zu den Basic Encoding Rules.
Kurz nach der Definition von X.409 fanden verschiedene Gruppen, die OSI-Applikationen entwickelten, diese Notation auch für ihre Zwecke sehr hilfreich. Die ISO konnte sich mit der gemeinsamen Definition von Notation und Übersetzungsregeln in einem Standard jedoch nicht anfreunden und teilte X.409 in zwei verschiedene Dokumente auf. Teil eins nannte man ,,Abstract Syntax Notation One``, Teil zwei wurde zu den ,,Basic Encoding Rules``. 1985 erklärte sich die CCITT damit einverstanden, bezüglich dieses Themas mit der ISO zusammen zu arbeiten und übernahm als Basis für das weitere Vorgehen sowohl die beiden ISO-Dokumente als auch die Namen ASN.1 und BER. In 1987 veröffentlichte die ISO diese Dokumente als ISO 8824 und ISO 8825. Die von ISO und CCITT gemeinsam entwickelten Erweiterungen wurden in die Standards integriert, 1989 publizierte die CCITT die resultierenden Dokumente als X.208 und X.209.
Grundsätzliche Begriffe innerhalb von ASN.1 sind die des Typs und des Wertes . In ASN.1 ist ein Typ eine Menge möglicher Werte, die leicht von anderen Werten unterschieden werden kann. Die Menge kann dabei auch unendlich sein. Dieser Typ-Begriff ist sehr eng verwandt mit demjenigen in Programmiersprachen, allerdings müssen ASN.1-Typen nicht direkt für konkrete Maschinen implementiert werden und unterliegen demzufolge auch weniger Beschränkungen (beispielsweise bezüglich Genauigkeit oder Größe von Zahlen). Ein Sender verpackt Informationen, indem er einen Wert eines bestimmten Typs auswählt. Ein Typ kann sowohl wenige als auch viele mögliche Werte umfassen. Beispielsweise gibt es für den Typ Boolean nur zwei mögliche Wertausprägungen (True und False ), für Integer- oder Real- Zahlen jedoch unendlich viele.
ASN.1 kennt vier verschiedene Arten von Typen:
| Typname | Verwendung |
| BOOLEAN | Wahrheitswerte True und False |
| INTEGER | Ganzzahlige Werte |
| BIT STRING | Folge von Bits |
| OCTET STRING | Folge von Oktetten (je acht Bit) |
| NULL | Darstellung der Abwesenheit eines Wertes |
| OBJECT IDENTIFIER | Eindeutige Bezeichnung für Informationsobjekte, z.B. von abstrakten Syntaxen |
| Object Descriptor | Darstellung einer für den Menschen lesbaren Bezeichnung eines Object Identifier (als String) |
| EXTERNAL | Für die Modellierung von unspezifizierten oder anderswo festgelegten Datenformaten |
| REAL | Darstellung von Fließkommawerten |
| ENUMERATED | Darstellung von Größen mit einer aufzählbaren (normalerweise kleinen) Zahl von möglichen Werten; entspricht den in verschiedenen Programmiersprachen vorkommenden Aufzählungstypen |
Grundsätzlich sieht die in ASN.1 verfolgte Strategie zur Definition von
Typen folgendermaßen aus:
Typen erlauben die Ableitung von Subtypen. Deren Wertemenge ist dann eine Teilmenge des Typs, von dem sie abgeleitet wurden (Parent Type ). Sie bieten somit die Möglichkeit, nur bestimmte Werte eines Typs zuzulassen, z.B. 0 bis 100 für Prozentangaben oder 10000 bis 99999 für Postleitzahlen.
ASN.1 bietet dem Entwickler bestimmte einfache Typen sowie Techniken, um strukturierte und Subtypen zu definieren, an. Diese Techniken stellen die Typnotation dar.
| Typname | Verwendung |
| SEQUENCE | Folge fester Länge von Werten mit spezifizierten Typen |
| SEQUENCE OF | Folge von keinem, einem oder mehreren Werten des gleichen Typs |
| SET | (Ungeordnete) Menge einer vorgegebenen Zahl von Werten mit spezifizierten Typen |
| SET OF | (Ungeordnete) Menge von keinem, einem oder mehreren Werten des gleichen Typs |
| NumericString, VideotexString, | Ketten von Zeichen aus diversen Zeichensätzen |
| PrintableString, IA5String, | |
| TeletexString (T61String), | |
| VisibleString (ISO646String), | |
| GraphicString, GeneralString | |
| UTCTime | Verschiedene Typen für die Darstellung der Zeit, z.B. UTCTime (Coordinated Universal Time, auch Greenwich Mean Time genannt) |
Ein Wert eines gegebenen ASN.1-Typs ist ein Element der Wertemenge des Typs. ASN.1 erlaubt neben der Definition von Typen auch die Notation von Werten, diese Möglichkeit ist aber für eine abstrakte Syntax eher nebensächlich. Vielmehr stehen für abstrakte Definitionen Typen im Mittelpunkt des Interesses. Grund hierfür ist, daß eine abstrakte Syntax selbst ein Typ ist, und daß in einer Spezifikation die Festlegung von Typen die höchste Bedeutung besitzt. Werte sind in diesem Zusammenhang nur als Beispiele oder Standardwerte von Interesse. Umgekehrt sind in der konkreten Anwendung die Werte wesentlich wichtiger als die Typen.
Typen und Werte können mit Namen versehen werden. Anhand dieser Namen können andere Typen sie ansprechen. Auch den Komponenten der strukturierten Typen können Namen (Identifiers ) gegeben werden.
ASN.1-Definitionen sind Bestandteil von Modulen. Das Modul ist Basis für die Organisation von Definitionen in ASN.1. Ein Modul ist eine mit einem Namen versehene Sammlung von Typ- und Wertdefinitionen, die normalerweise eine Menge von inhaltlich verwandten Definitionen zusammenfaßt.
Module können zwar in sich vollständige Spezifikationen sein, normalerweise müssen sie sich aber auch auf Typen oder Werte beziehen, die in anderen Modulen definiert wurden, z.B. in Bibliotheken mit allgemeinen Definitionen. Deshalb bietet ASN.1 Möglichkeiten zum Im- und Export an. Definitionen müssen in ihrem Modul zum Export freigegeben werden, um in einem anderen Modul importiert werden zu können. Alle nicht exportierten Typen sind in diesem Fall geschützt und können außerhalb des Moduls nicht benutzt werden. Dies kann beispielsweise dann sinnvoll sein, wenn die interne Struktur von Typen nicht stabil ist und noch geändert werden können soll. Wird in einem ASN.1-Modul keine Exportfestlegung getroffen, so tritt der Standardfall in Kraft, der besagt, daß alle Definitionen exportiert werden.
Mit ASN.1 können viele, jedoch nicht alle Aspekte von verteilten Applikationen spezifiziert werden. Die Bedeutung von Typen und Werten kann beispielsweise nur durch entsprechend aussagekräftige Namen beschrieben werden, was häufig zu wenig aussagekräftig ist. Auch Verhaltensaspekte werden nicht von ASN.1 abgedeckt. Solche Beschreibungen müssen auf andere Weise getätigt und mit der ASN.1-Definition verknüpft werden. Dies geschieht vor allem durch Kommentare.
ASN.1 erscheint zwar auf den ersten Blick undurchsichtig, ist aber konzeptionell nicht komplizierter als beispielsweise die Typdefinitionen in Pascal, die eine ähnliche Funktion besitzen.
Typen und Werte werden innerhalb von ASN.1 in einer flexiblen,
programmiersprachenähnlichen Notation ausgedrückt. Dabei gelten
folgende Regeln:
--) oder einem
Bindestrichpaar und einem Zeilenumbruch eingeschlossen.
Mit ASN.1 ist es möglich, sehr komplexe Informationen zu beschreiben, denn die Strukturen können beliebig tief verschachtelt sein. Komplexe Strukturen werden dabei aus einfacheren Strukturen aufgebaut und basieren im Endeffekt auf einigen wenigen einfachen Typen von Informationen.
Eine einfache Definition eines INTEGER-Typen hat folgende Form:
Temperature ::= INTEGER
Dieser INTEGER-Typ kann anhand seines Namens Temperature angesprochen werden. Beispielsweise kann er in strukturierten Typen verwendet werden:
Readings ::= SEQUENCE OF Temperature
Bei der Definition von SEQUENCE-, SET- und CHOICE-Typen werden die Komponenten mit ihren Bezeichnungen (Identifier ) aufgezählt:
TypA ::= SEQUENCE
{
p BOOLEAN,
q INTEGER,
r BIT STRING,
t Temperature
}
Für detailliertere Informationen über die ASN.1-Typen und ihre Syntax sei auf die entsprechende Literatur verwiesen (beispielsweise [13], [8] und [3]).
Im Bereich des Netzmanagements gibt es derzeit zwei dominierende
Systeme: zum einen das Internet-Management
mit dem recht einfach gehaltenen Simple Network Management
Protocol (SNMP) und zum anderen das wesentlich komplexere und
leistungsfähigere OSI-Netzmanagement
mit dem Common Management
Information Protocol (CMIP) bzw. seinen Diensten Common Management Information Services (CMIS) .
SNMP hat vor allem aufgrund seiner Einfachheit und Übersichtlichkeit schnell Verbreitung gefunden und wird heute von zahlreichen Herstellern von Netzelementen unterstützt. Es hat allerdings in seiner ursprünglichen Form mit großen Problemen bezüglich Performance und vor allem Sicherheit zu kämpfen. In komplexen Systemen wird es deshalb nur selten eingesetzt.
Das OSI-Management hingegen ist auch für das Management komplexer Systeme geeignet, die Benutzung lohnt sich aufgrund der hohen Komplexität jedoch bei kleinen Netzwerken nicht. Telekommunikationsanbieter beispielsweise sind mit ihren großen und komplexen Netzen auf Managementanwendungen angewiesen, die diese Systeme auch adäquat verwalten können, sie greifen deshalb i.d.R. auf das OSI-Management zurück.
Sei es nun Internet- oder OSI-Management, in beiden Architekturen
findet ASN.1 seine Verwendung. Im Internet-Management wird ASN.1 zur
formalen Beschreibung der Datentypen der Management Information
Base-Objekte (MIB-Objekte) benutzt.
Auch das SNMP-Protokoll selbst ist in ASN.1
spezifiziert. Da alle Protokolle des OSI-Application Layers mit Hilfe
von ASN.1 spezifiziert werden und CMIP ein Protokoll eben dieser
OSI-Anwendungsschicht darstellt, basiert auch CMIP auf einer in ASN.1
formulierten Spezifikation. Darüber hinaus werden zur Beschreibung
der Managed Objects im OSI-Management
GDMO-Templates
verwendet, die als ASN.1-Makros realisiert
sind.
Neben dem Internet- und OSI-Management gibt es noch weitere Ansätze
im Bereich Netzmanagement, darunter das Management mit Hilfe der
Common Object Request Broker Architecture (CORBA) , oder auch
mit Java und dort speziell der Java Management API
(JMAPI)
. Aufgrund der
gegenüber SNMP und CMIP relativ geringen Verbreitung dieser Systeme
werden zur Integration bestehender Managementapplikationen i.d.R.
Gateways zu Internet- und OSI-Management entwickelt.
Durch
diese Gateways findet auch ASN.1 indirekt Einzug in die genannten
Systeme. Beispielsweise existieren Übersetzer zwischen ASN.1 und
IDL
, der
Spezifikationssprache von CORBA, und umgekehrt.
Dieses Kapitel stellt Anforderungen an eine generische Oberfläche für ASN.1-Datentypen auf, die dann von der Prototypimplementierung möglichst komplett in Software umzusetzen sind.
Grundlegende Anforderung an die graphische Oberfläche für
ASN.1-Datentypen ist natürlich, daß mit ihrer Hilfe die Werte der
zugrundeliegenden Datenstruktur angezeigt und auch modifiziert
werden können. Konkret sollen die die Oberfläche implementierenden
Java-Klassen, wenn sie ein ASN.1-Java-Objekt auf Basis der
JAsn API
übergeben bekommen,
dessen Struktur analysieren sowie ein entsprechendes GUI anbieten.
Der Benutzer sollte nach Änderungen an den Werten der ASN.1-Datentypen die Möglichkeit haben, diese Modifikationen in das der Oberfläche zugrundeliegende ASN.1-Java-Objekt zu übernehmen oder sie aber zu verwerfen. Im letzteren Fall bleibt die eigentliche ASN.1-Datenstruktur in dem Zustand, in dem sie beim Start der graphischen Oberfläche war.
Nimmt der Benutzer Änderungen an den Werten der Datenstrukturen vor, so sollte die Oberflächenklasse in der Lage sein, die Eingabe auf Verträglichkeit mit dem entsprechenden ASN.1-Datentyp hin zu überprüfen. Beispielsweise sollte es nicht möglich sein, Zeichenketten in ein Zahlenfeld einzugeben. Gibt der Benutzer für den zugrundeliegenden ASN.1-Typ ungültige Daten ein, so sollte die Modifikation mit einem entsprechenden Hinweis zurückgewiesen werden. Idealerweise sollten die benutzten ASN.1-Java-Klassen selbst in der Lage sein, eine entsprechende Überprüfung neu eingegebener Werte durchzuführen, denn sie besitzen das meiste Wissen bezüglich gültiger und ungültiger Werte für ,,ihren`` ASN.1-Typ.
Um dem Benutzer exakte Informationen über den an der Oberfläche angezeigten ASN.1-Datentyp anbieten zu können, sollten die GUI-Klassen die Möglichkeit besitzen, die dem ASN.1-Java-Objekt zugrundeliegende ASN.1-Definition auszugeben.
Neben diesen Anforderungen für alle generischen Oberflächenklassen gibt es noch einige allgemeine Aspekte, die nur bei strukturierten ASN.1-Typen zu beachten sind. So sollten diese in der Lage sein, optionale Komponenten entsprechend zu kennzeichnen und zu behandeln. Darüber hinaus sollte es auch möglich sein, rekursive Datenstrukturen verarbeiten zu können.
Eine bereits in Kapitel 1.1 erwähnte Anforderung ist der Aspekt, irrelevante Informationen ausblenden zu können, um sich als Benutzer auf die aus eigener Sicht wichtigen Daten konzentrieren zu können. Dies sollte die Oberfläche bei strukturierten Typen, die durch ihre Komplexität schnell unübersichtlich werden können, ermöglichen. Dabei gibt es mehrere Varianten, wie diese Fokussierung auf relevante Informationen aussehen könnte. Zum einen wäre es denkbar, gewünschte Komponenten eines strukturierten Typs auf Anforderung des Benutzers hin in einem neuen Fenster separat darzustellen. Allerdings besteht hierbei die Gefahr, daß die interessanten Informationen evtl. in einer inflationären Menge von Fenstern untergehen. Eine weitere Möglichkeit wäre ein Mechanismus, der die Komponenten eines strukturierten Typs auf Wunsch des Benutzers auf- bzw. zuklappt. Ist die Struktur aufgeklappt, so sind alle Komponenten an der Oberfläche sichtbar und der Detailgrad der Anzeige ist dementsprechend hoch. Im umgekehrten, dem zugeklappten Fall, sieht der Benutzer nur Namen und Typ der Struktur selbst, die Komponenten sind verborgen und der Detailgrad ist gering. Somit kann der Benutzer über das Anzeigen und Verbergen von Komponenten strukturierter Typen entscheiden, welche Informationen er für relevant bzw. irrelevant hält.
Neben den allgemeinen Anforderungen an die Oberfläche ergeben sich für die verschiedenen ASN.1-Typen auch spezielle Aspekte, die es bei der Implementierung zu beachten gibt. Diese speziellen Anforderungen werden in diesem Kapitel, aufgeteilt nach Datentypen, betrachtet.
Eine Besonderheit des Integer-Typs sind die benannten Konstanten. Eine graphische Oberfläche für den entsprechenden ASN.1-Typ sollte idealerweise in der Lage sein, mit diesen Konstanten adäquat umzugehen, d.h. sie sollte erkennen, ob der Benutzer eine benannte Konstante oder einen numerischen Wert eingegeben hat und die beiden Darstellungsformen im Bedarfsfall ineinander umwandeln können. Darüber hinaus wäre es für den Benutzer komfortabel, wenn er in einem Pop-Up-Menü die definierten benannten Konstanten zur Auswahl angeboten bekäme.
Des weiteren sollte das GUI in der Lage sein, die in ASN.1 evtl. definierten Grenzen des Integer-Typs zu behandeln. Ist ein ASN.1-Integer-Typ beispielsweise auf den Bereich von 0 bis 100 begrenzt, wie es für Prozentzahlen üblich ist, so darf die Oberfläche keine Werte für den Datentyp annehmen, die kleiner als 0 oder größer als 100 sind.
Eine weitere Anforderungen an das GUI ist die Möglichkeit, den Benutzer das Ein- und Ausgabeformat der Werte auswählen zu lassen. Als mögliche Formate bietet sich bei den Integer-Typen dezimal und hexadezimal an. Wechselt der Benutzer das gewünschte Format, dann sollte die Oberfläche den aktuellen Wert entsprechend aus dem alten in das neue Format umwandeln.
Bei der Oberfläche für Bit-Strings ist zu beachten, daß bei diesem Typ benannte Bits existieren können, die es innerhalb von ASN.1 ermöglichen, auf einzelne Bits innerhalb des Bit-Strings per Namen zuzugreifen. Auf diese Weise können beispielsweise Felder von Boolean-Werten effizient codiert werden. Ist ein Bit-String mit solchen benannten Bits ausgestattet, so sollte das GUI ihre direkte Manipulation in Form von Boolean-Werten anbieten.
Darüber hinaus sollte das GUI für Bit-Strings analog der Oberfläche für Integer-Typen eventuelle in ASN.1 definierte Grenzen behandeln können sowie verschiedene Ein- und Ausgabeformate unterstützen. Hier bieten sich für Bit-Strings die binäre und die hexadezimale Darstellung an.
Ein Octet-String unterscheidet sich von einem Bit-String konkret nur dadurch, daß die Anzahl der Stellen des Octet-Strings in der binären Darstellung ein Vielfaches von acht sein muß. Somit lassen sich alle Anforderungen an das GUI der Bit-Strings auf die Oberfläche der Octet-Strings übertragen. Zusätzlich sollte diese mit dem genannten Aspekt der Länge der binären Darstellung umgehen können.
Die Object Identifier in ASN.1 besitzen die Besonderheit, daß man sie in verschiedenen Formen notieren kann. Zum einen ist es möglich, sie in rein numerischer Notation zu beschreiben. Zum anderen gibt es die Möglichkeit, den Object Identifier oder auch nur Teile davon anhand von offiziellen oder selbst eingeführten Namen zu notieren. Auch die Verwendung von ASN.1-Objektdeskriptoren ist möglich. Darüber hinaus kann ein Benutzer diese Varianten auch kombinieren, beispielsweise einen Object Identifier aus numerischer und Namens-Notation zusammensetzen. Diesen Aspekt sollte eine Oberfläche für Object Identifier berücksichtigen und die Ein- und Ausgabe in allen diesen Formaten anbieten. Evtl. sollte auch eine Umwandlung der verschiedenen Formate untereinander möglich sein.
Innerhalb der Oberfläche für Real-Datentypen sollte der Benutzer
erneut die Möglichkeit besitzen, zwischen verschiedenen Ein- und
Ausgabeformaten wählen zu können. Hierbei bieten sich die von ASN.1
verwendete Form
{ Mantisse, Basis, Exponent }, beispielsweise
{ 1 10 -2 } für den Wert 0,01,
sowie das Fließkommaformat an. Darüber hinaus sollte das
GUI in der Lage sein, entsprechende Formatumwandlungen durchzuführen.
Der Enumerated-Datentyp zeichnet sich durch seine benannten Konstanten aus. Das Objekt kann im Gegensatz zum Integer-Typ ausschließlich solche numerischen Werte annehmen, die gemeinsam mit einem Namen in der ASN.1-Definition vereinbart sind. Deshalb sollte eine Oberfläche für Enumerated-Typen dem Benutzer die existierenden benannten Konstanten für den entsprechenden Typen in einer Liste zur Auswahl anbieten. Auf diese Weise wird der Versuch ausgeschlossen, dem Datentyp einen ungültigen Wert zuzuweisen.
In ASN.1 gibt es zahlreiche Datentypen für Zeichenketten, die sich ausschließlich durch den verwendeten Zeichensatz unterscheiden. Für die Oberfläche bedeutet dies, daß ein GUI für einen speziellen String-Typ die vom Benutzer eingegebenen Werte korrekt auf den gültigen Zeichensatz überprüfen muß. Dieser Test sollte jedoch, wie bereits oben erwähnt, von der entsprechenden ASN.1-Java-Klasse angeboten werden. Dadurch ist es möglich, die Oberflächenklassen für alle String-Typen einheitlich zu gestalten, da nur beim Aufruf des Gültigkeitstests zwischen den verschiedenen String-Typen unterschieden werden muß. Auf diese Weise kann man die Oberflächen für die String-Varianten zusammenfassen.
Grundsätzlich unterscheiden sich die Sequence- und Set-Typen in ASN.1 nur durch die vorhandene bzw. nicht vorhandene Ordnung der in ihnen enthaltenen Komponenten. Dies ist jedoch in der Oberfläche weniger relevant, da durch das zugrundeliegende ASN.1-Java-Objekt bereits eine Ordnung vorgegeben ist. Deshalb können die GUIs für Sequence und Set gemeinsam behandelt werden.
Die Oberflächen für Sequence und Set sollten, wie bereits oben ausgeführt, in der Lage sein, ihre Komponenten auf Wunsch des Benutzers hin zu verbergen, um die Übersichtlichkeit durch das Ausblenden von Informationen zu erhöhen.
Für die Sequence Of- und Set Of-Typen gelten ebenfalls die für Sequence und Set angeführten Aspekte. Darüber hinaus sollte es die Oberfläche für Sequence Of- und Set Of-Typen dem Benutzer ermöglichen, der Struktur neue Komponenten hinzuzufügen bzw. bestehende zu löschen.
Der Choice-Typ in ASN.1 zeichnet sich vor allem dadurch aus, daß er eine bestimmte Anzahl von alternativen Komponenten enthält, von denen immer genau eine aktiv ist. Die Oberfläche für Choice-Typen sollte deshalb dem Benutzer alle Komponenten anzeigen, die nicht aktivierten Alternativen jedoch für den Zugriff sperren. Darüber hinaus muß der Benutzer natürlich die Möglichkeit haben, eine bisher inaktive Komponente zu aktivieren. Dies sollte durch einfaches Anklicken eines entsprechenden, der jeweiligen Komponente zugeordneten Buttons möglich sein.
Der Any-Typ nimmt innerhalb von ASN.1 insofern eine Sonderstellung ein, als er als Wert einen beliebigen ASN.1-Typ annehmen kann. Deshalb ist die Darstellung eines mit Werten gefüllten ASN.1-Java-Objektes einfach durch Verwendung der Oberfläche des konkret im Any-Typ gespeicherten ASN.1-Objektes möglich.
Darüber hinaus sollte das GUI für den Any-Typ dem Benutzer jedoch auch die Möglichkeit bieten, ein anfangs leeres ASN.1-Objekt anzuzeigen sowie mit einem existierenden ASN.1-Typ zu füllen. Bei Eingabe des Namens der gewünschten Java-ASN.1-Klasse sollte diese geladen und dem Any-Typen zugewiesen werden. Demzufolge sollte die Any-Oberfläche das GUI des ,,neuen`` ASN.1-Typs anzeigen.
Der Wunsch nach Wiederverwendbarkeit von Software-Modulen existiert in der Informatik bereits sehr lange und ist auch nur zu verständlich, denn kein Programmierer verbringt seine Zeit gerne damit, immer wieder das Rad neu zu erfinden. Der Traum, komplexe Anwendungen leicht und schnell aus bereits existierenden Teilen zusammensetzen zu können, ist bis heute allerdings ein solcher geblieben.
Die einfachste Form der Wiederverwendung geschieht auf Quelltextebene. Man nimmt Sourcecode aus einer bereits entwickelten Software und fügt ihn in ein neues Projekt ein. Dies ist allerdings mit zahlreichen Problemen behaftet, denn nur zu häufig beziehen sich verschiedene Teile eines Softwareprojektes gegenseitig aufeinander und erschweren oder verhindern auf diese Weise das ,,Kopieren und Einfügen``.
Die Objektorientierung sollte dieses Problem mit dem Prinzip der Kapselung aus der Welt schaffen, doch obwohl dieses Konzept durchaus Fortschritte mit sich brachte, ergaben sich in der Praxis immer wieder neue Tücken, vor allem hervorgerufen durch mangelhaftes Design.
Besserung versprechen sich die Informatiker von den
Komponenten , das sind kleine Programme, die jeweils eine ganz
spezielle Aufgabe erfüllen.
Die von der Komponentenarchitektur
spezifizierten Schnittstellen ermöglichen die Kommunikation der
Komponenten untereinander. Komponentenarchitekturen wurden von
verschiedenen Herstellern entwickelt, beispielsweise OpenDoc
von IBM , Apple u.a. oder OLE/OCX/ActiveX von
Microsoft .
Die Integration existierender Komponenten in eigene Applikationen soll durch die Verwendung von Softwareentwicklungsumgebungen erleichtert werden. Diese Umgebungen stellen Softwarepakete dar, die durch zahlreiche Maßnahmen dem Entwickler die Arbeit erleichtern sollen. Vor allem nehmen sie dem Programmierer stupide Arbeiten ab, beispielsweise die Codierung von graphischen Benutzeroberflächen oder die Versions- und Projektverwaltung. Da sich die Komponenten in diese Tools integrieren, soll sich die Applikationsentwicklung im Idealfall auf die Auswahl adäquater Komponenten sowie deren geeignete Verbindung beschränken (vgl. Abbildung 4.1).
Die JavaBeans API stellt einen Rahmen zur Erstellung
wiederverwendbarer, integrierbarer, modularer Softwarekomponenten dar.
Sun Microsystems definiert JavaBean wie folgt:
,,Ein JavaBean ist eine wiederverwendbare Softwarekomponente,
die in einem Builder Tool visuell verändert werden
kann.``
Ein Builder Tool ist dabei eine Software, die den Anwender bei der Erstellung einer Applikation oder eines Dokumentes unterstützt. Dies können beispielsweise Web-Editoren, visuelle Programmierumgebungen, Oberflächeneditoren oder auch ein einfacher Dokumenteditor sein, der Beans als Bestandteil eines zusammengesetzten Dokumentes beinhaltet.
Diese Definition für JavaBeans ist sehr allgemein und deckt eine breite Palette von Möglichkeiten ab. JavaBeans können einfache Oberflächenelemente wie Schaltflächen oder Schieberegler sein, aber auch anspruchsvolle visuelle Softwarekomponenten beispielsweise zur Anzeige des Inhalts von Datenbanken oder Kalkulationstabellen.
Es ist zu erwarten, daß viele Beans einen starken visuellen Aspekt haben werden, sowohl innerhalb des Builder Tools als auch in den Applikationen, in denen sie verwendet werden, d.h. der Großteil der JavaBeans wird eine graphische Oberfläche besitzen, und oftmals ist dies auch der offensichtlichste Teil einer Komponente. Nichtsdestotrotz ist es aber ebenfalls möglich, Beans ohne GUI zu entwickeln und sie dann trotzdem visuell mit Entwicklungswerkzeugen, z.B. zur Erstellung von Software (Application Builder Tools oder einfach Application Builder ), zu bearbeiten.
Darüber hinaus ist es möglich, Beans zu entwickeln, die in Abhängigkeit von ihrer Umgebung eine graphische Oberfläche anbieten oder nicht. Beispielsweise können Komponenten in einer Anwenderapplikation ein GUI anbieten, in einer Serveranwendung hingegen nicht.
Obwohl es ein wichtiges Ziel des Beans-Konzeptes ist, die entstehenden Komponenten mit Hilfe eines graphischen Builder Tools leicht und schnell bearbeiten zu können, ist es ebenfalls möglich, die entsprechenden Operationen ,,per Hand`` durchzuführen, d.h. ohne Zuhilfenahme von Werkzeugen.
Ziel der JavaBeans API ist die Definition eines Softwarekomponentenmodells für Java. Mit Hilfe dieses Modells sollen Softwarehersteller in die Lage versetzt werden, Java-Komponenten zu erstellen, die von den Benutzern ohne großen Aufwand angepaßt und in eigene Applikationen eingebaut werden können.
Der Benutzer soll dann die JavaBeans, die ihm für seine Applikation nützlich erscheinen, aus dem Programm der Hersteller auswählen und diese innerhalb eines Builder Tools mit eigenen Beans verknüpfen sowie alle Komponenten seinen Wünschen entsprechend konfigurieren. Aus diesen Beans sowie evtl. manuell hinzugefügtem Programmcode erstellt das Application Builder Tool daraufhin eine lauffähige Java-Applikation, die sich entsprechend der vorgenommenen Konfiguration verhält.
Die JavaBeans API strebt die Bereitstellung einer plattformunabhängigen Komponentenarchitektur an. Zu diesem Zweck gleicht die API Unterschiede zwischen den Möglichkeiten verschiedener Plattformen aus. Dadurch können die Entwickler auf den unterschiedlichen Systemen mit einer konsistenten Menge von API-Funktionen arbeiten und darauf vertrauen, daß die Software auf allen Plattformen korrekt ausgeführt wird.
Die JavaBeans API soll einfach zu benutzen sein, um kleine Komponenten leicht und schnell erstellen zu können. Gleichzeitig soll aber auch die Erstellung umfangreicher und komplexer Beans möglich sein. Ziel ist es, das JavaBeans-Konzept schnell erlernen zu können, um mit wenig Aufwand in der Lage zu sein, Komponenten zu schreiben und zu benutzen. Anschließend soll der Entwickler die anspruchsvolleren Merkmale und Möglichkeiten der API erkunden können und so Schritt für Schritt dazulernen.
Die Bandbreite möglicher JavaBeans-Komponenten reicht von einfachen
Bausteinen, die zu einem Programm zusammengesetzt werden
(Composite Applications ), bis zu Applikationen, die in
zusammengesetzten Dokumenten verwendet werden, beispielsweise eine
Tabellenkalkulation innerhalb einer WWW-Seite
(Compound Documents ). Diese beiden Aspekte
überlappen sich und bilden somit eher eine Bandbreite von
Möglichkeiten als eine strikte Trennung. Die Komponenten werden in
der Praxis i.d.R. zwischen diesen beiden Extrema angesiedelt sein. Im
Zentrum des JavaBeans-Designs stehen somit Anwendungsfälle wie kleine
Kontrollelemente oder zusammengesetzte Dokumente. Darüber hinaus kann
man jedoch auch die Entwicklung von JavaBeans zur Bearbeitung von
Bürodokumenten erwarten, z.B. zur Textverarbeitung. Für den
Regelfall gehen die Entwickler der JavaBeans API jedoch davon aus,
daß die sie benutzenden Komponenten kleine bis mittlere
Kontrollelemente sein werden.
Jedes Java-Objekt, das bestimmten Regeln gehorcht, ist ein
JavaBean. Diese Regeln stellen ein Design
Pattern
dar.
Unter dem Begriff Design Pattern wird die Verwendung einheitlicher Namen und Typsignaturen für Methoden bzw. Schnittstellen verstanden, die zu Standardzwecken eingesetzt werden, z.B. die Methodennamen getLabel und setlabel zum Zugriff auf das Attribut label einer Klasse.
Mit dem Einsatz von Design Patterns werden zwei Ziele verfolgt: Zum einen dienen sie den Entwicklern dazu, Klassen einfacher und schneller zu verstehen. Zum anderen können die Komponenten durch Tools und Bibliotheken programmgesteuert und somit automatisch analysiert werden. Die JavaBeans API setzt diese Möglichkeit ein, um Attribute, Methoden und Ereignisse von Komponenten zu identifizieren.
Im JavaBeans-Konzept ist die Verwendung der aus den vorgegebenen
Design Patterns abgeleiteten Bezeichnungen jedoch optional. Die
Methoden einer Komponente können ohne Beeinträchtigung der
Funktionalität mit beliebigen Namen versehen werden, wenn der
Entwickler die Informationen über die (Nicht-Standard-) Bezeichnungen
in Form von speziellen Klassen anbietet. Trotzdem wird von den
Entwicklern der JavaBeans API die Verwendung der Design Patterns aus
den genannten Gründen dringend empfohlen.
Bei JavaBeans ist es nicht notwendig, daß alle Komponenten von einer allgemeinen Beans-Klasse erben. Beans mit einer graphischen Oberfläche müssen lediglich von der Java-Klasse Component abgeleitet sein, um die Komponenten einer Java-Oberflächencontainerklasse wie Panel hinzufügen zu können.
Bei der Frage, ob man ein Softwaremodul als Bean entwickeln sollte, spielt der Aspekt der visuellen Bearbeitung eine wichtige Rolle. Soll die zu entwickelnde Komponente von dem Benutzer visuell manipuliert und angepaßt werden können, so bietet sich die Beans API zur Realisierung an. Kann das Modul jedoch aus der graphischen Manipulation keinen Vorteil schlagen, so ist evtl. die Entwicklung einer Klassenbibliothek eher angebracht.
Beans müssen in zwei verschiedenen Umgebungen lauffähig sein. Zum einen muß man sie in Entwicklungsumgebungen ablaufen lassen können, wo die Komponente möglichst viele Informationen über ihr Design anbieten sollte, um den Anpassungsprozeß zu erleichtern. Zum anderen müssen die Beans natürlich in der Laufzeitumgebung ausführbar sein, um innerhalb der erstellten Applikation zu funktionieren.
Für JavaBeans gilt das gleiche Sicherheitsmodell wie für alle Java-Klassen, insbesondere Applets. Unsichere Applets, also solche, denen man aufgrund ihrer unbekannten Herkunft aus dem Netz nicht vertraut (Untrusted Applets ), unterliegen hohen Restriktionen beispielsweise beim Zugriff auf Dateien, Netzwerk-Hosts oder sonstige Ressourcen. Sichere Applets (Trusted Applets ) hingegen sehen sich geringeren Restriktionen ausgesetzt. Da ein Entwickler i.d.R. nicht weiß, ob seiner Komponente im späteren Einsatz vertraut wird oder nicht, wird empfohlen, i.d.R. von der Ausführung als Untrusted Applet auszugehen. Soll eine Bean-Komponente jedoch Aufgaben erfüllen, für die sie auf geringe Restriktionen angewiesen ist - beispielsweise wenn sie drucken möchte - so muß sichergestellt sein, daß die Komponente in einem Trusted Applet oder aber in einer eigenständig ausgeführten Applikation verwendet wird.
Weiterhin ist zu beachten, daß die JavaBeans-Komponenten wie alle Java-Klassen in einer Multi-Thread-Umgebung ausgeführt werden und sie deshalb mit dieser Tatsache adäquat umgehen können müssen.
Um Beans in einem Builder Tool benutzen zu können, müssen sie in
eine JAR- Datei
gepackt werden.
Diese Dateien sind eine Neuerung der Java 1.1-Spezifikation und
basieren auf dem ZIP-Format . Eine JAR-Datei kann Klassen,
serialisierte Objekte, Bilder, Hilfe-Dateien
und ähnliche Ressourcen enthalten.
Zusätzliche Informationen zum Inhalt der JAR-Datei finden sich in der
Manifest- Datei, in der u.a. spezifiziert wird, bei welchen
Klassen innerhalb des Archivs es sich um Beans handelt. Eine JAR-Datei
kann auch mehrere JavaBeans enthalten.
JavaBeans variieren sehr stark in ihrer Funktionalität, haben jedoch
einige Dinge gemeinsam:
Die drei wichtigsten Merkmale eines JavaBeans sind die von ihm veröffentlichten Attribute (Properties ), seine aufrufbaren Methoden sowie die von ihm ausgelösten Ereignisse (Events ). Diese Merkmale charakterisieren die Komponente und legen somit ihren Einsatzbereich fest.
Auf die Aspekte Ereignisse, Properties, Introspection, Customization und Persistenz wird in den folgenden Unterkapiteln detaillierter eingegangen.
Ereignisse (Events ) gehören zu den zentralen Merkmalen der JavaBeans-Architektur. Sie stellen eine komfortable Möglichkeit dar, Komponenten mittels eines Builder Tools funktional miteinander zu verbinden. Komponenten können dabei als Quelle für Ereignisbenachrichtigungen dienen, die von anderen Komponenten aufgefangen und weiterverarbeitet werden.
Konzeptuell sind Ereignisse ein Mechanismus, um Zustandsänderungen eines Quellobjektes an ein oder mehrere Listener-Objekte zu propagieren. Ein bekanntes Beispiel für die Ereignisbearbeitung findet sich in Window-Systemen. Sie nutzen Ereignisse beispielsweise zur Weitergabe von Benachrichtigungen der GUI-Elemente.
Der Ereignismechanismus von Java und somit auch von JavaBeans erfüllt
einige wichtige Voraussetzungen:
der Netscape Communications Corporation
ausgetauscht werden.
Ereignisbenachrichtigungen werden durch das Aufrufen von bestimmten Methoden im Listener-Objekt weitergegeben. Für jede Art von Ereignis ist eine eigene Java-Methode definiert, diese Methoden werden zu EventListener -Schnittstellen zusammengefaßt. Listener-Klassen implementieren die Menge an EventListener-Schnittstellen, für die sie sich interessieren.
Methoden zur Ereignisbehandlung, die in EventListener-Schnittstellen definiert werden, gehorchen einem standardisierten Design Pattern. Dies erleichtert die Verwendung und Dokumentation des Ereignissystems und erlaubt die programmgesteuerte, automatische Analyse der JavaBeans.
Nähere Informationen bezüglich der Ereignisbenachrichtigung werden in Form von Event-Objekten an die aufgerufene Methode des Listener-Objektes übergeben.
Ereignisquellen definieren Registrierungsmethoden für die
Ereignistypen, die sie anbieten. Interessierte Listener-Objekte
können sich über diese Methoden bei der Ereignisquelle ,,anmelden``.
Diese Methoden folgen ebenfalls einem festgelegten Design Pattern und
akzeptieren als Argument Referenzen auf Instanzen der
EventListener-Schnittstellen. Unter bestimmten Umständen kann es
darüber hinaus notwendig bzw. ratsam sein, Adapterklassen zwischen
Quell- und Listenerobjekte zu schalten.
Um einen Ereignisfluß vom Quell- zum Listener-Objekt zu etablieren, registrieren sich die EventListener-Objekte bei den Instanzen der Ereignisquellen. Dazu müssen die Klassen der Ereignisquellen entsprechende Methoden zur An- und Abmeldung von EventListenern anbieten. Durch die Implementierung der Registrierungsmethoden wird die Klasse zu einer Multicast-Ereignisquelle für die angemeldeten Listener-Objekte. Auch diese Methoden sollen einem Design Pattern gehorchen, um die Dokumentation zu erleichtern und die automatische Analyse der Klassen durch die JavaBeans Introspection API sowie Builder Tools zu ermöglichen.
Ein Bean definiert somit ein Ereignis, indem es Methoden zum An- und Abmelden entsprechender EventListener anbietet.
Ein kleines Beispiel soll die Verwendung von Ereignissen in JavaBeans verdeutlichen.
import java.awt.*;
import java.awt.event.*;
public class MyActionListener implements ActionListener {
// diese Methode wird ausgefuehrt, wenn ein Objekt, bei dem
// ein MyActionListener-Objekt registriert ist, ein Ereignis
// "actionPerformed" ausloest
public void actionPerformed(ActionEvent e) {
// es wird eine kurze Beschreibung des Objektes ausgegeben,
// das das Ereignis ausgeloest hat ...
System.out.println(e.getSource());
}
}
Die Klasse MyActionListener realisiert einen einfachen Event-Listener, dessen einzige Funktionalität darin besteht, eine kurze Beschreibung desjenigen Objektes auf der Konsole auszugeben, das das Ereignis auslöst. Objekte dieser Klasse kann man nun bei Klassen, die das ActionEvent auslösen, als Listener registrieren. Genau dies geschieht in der Klasse MyExample :
import java.awt.*;
import java.awt.event.*;
public class MyExample extends Panel {
public static void main(String[] args) {
Frame aFrame = new Frame();
// es wird ein Button erzeugt ...
Button aButton = new Button("Klick mich!");
// ... und ihm das Listener-Objekt zugewiesen
aButton.addActionListener(new MyActionListener());
// Button dem Frame hinzufuegen und anzeigen
aFrame.add(aButton);
aFrame.setSize(new Dimension(100,100));
aFrame.setVisible(true);
}
}
MyExample erzeugt einen Button und registriert bei diesem Objekt eine Instanz der Klasse MyActionListener als ,,Zuhörer``. Somit wird bei jedem Klick auf den Button die Methode actionPerformed des Listener-Objektes ausgeführt.
Properties sind diskrete, benannte Attribute eines JavaBeans, die sein Aussehen oder Verhalten beeinflussen und über entsprechende Methodenaufrufe abgefragt bzw. geändert werden können. Beispielsweise hat ein Button i.d.R. ein Attribut ,,Label``, das seine Beschriftung beinhaltet. Properties sind somit ein Teil des internen Zustands der Komponente.
Auf die Attribute eines JavaBeans kann mit zur Verfügung gestellten
Methoden zugegriffen werden, den sogenannten Getter- und
Setter- Methoden.
Erstere liefern den aktuellen Wert eines Attributes
zurück, letztere ersetzen ihn durch einen neuen, an die Methode zu
übergebenden Wert.
Während des Anpassungsprozesses einer Komponente können die Attributwerte innerhalb eines Builder Tools vom Benutzer bearbeitet werden, dies geschieht meist in einem Property Sheet .
Die Beans-Properties können von beliebigen Java-Typen sein, typischerweise sind sie persistent, d.h. ihr Zustand wird dauerhaft auf nichtflüchtigen Datenträgern abgespeichert.
Zugriffe auf die Beans-Attribute erfolgen immer über den Aufruf einer Methode des Objektes, zu dem das Attribut gehört. Lesbare Attribute werden über die Getter- Methode abgefragt, es kann sich deshalb auch um berechnete Werte handeln. Schreibbare Attribute werden über die Setter- Methode verändert. Attributzugriffe können auch programmierte Seiteneffekte haben.
Die Zugriffsmethoden können zwar prinzipiell beliebige Namen haben, die Standardkonvention sieht aber feste Namen nach einem Design Pattern vor (getProperty und setProperty ). Besitzt ein Bean beispielsweise ein Attribut classStatus vom Typ int , auf das sowohl lesend als auch schreibend zugegriffen werden kann, so existieren für diese Zugriffe Methoden. Diese Methoden heißen bei Einhaltung der JavaBeans Design Pattern getClassStatus (Getter-Methode) und setClassStatus (Setter-Methode), so daß die Deklaration des Attributs und die Definition der Zugriffsmethoden folgendes Aussehen haben könnten:
protected int classStatus;
public int getClassStatus() {
return classStatus;
}
public void setClassStatus(int newStatus) {
classStatus = newStatus;
}
Neben den Attributen mit einzelnen Werten gibt es auch die Indexed Properties , die mehrere Werte beinhalten. Sie entsprechen weitestgehend den in vielen Programmiersprachen bekannten Arrays. Zur Verfügung gestellt werden Methoden zum Zugriff sowohl auf einzelne Elemente als auch auf das ganze Array. Beim Zugriff auf einzelne Elemente wird ein Index angegeben, anhand dessen der gewünschte Wert spezifiziert wird.
Als erweiterte Merkmale für anspruchsvollere Projekte bietet JavaBeans Bound und Constrained Properties an.
Enthält ein Objekt Bound Properties , so wird nach jeder
Änderung dieser Attribute ein Ereignis
(PropertyChange-Event ) ausgelöst. Somit
werden alle bei dem Quellobjekt des Ereignisses registrierten Zuhörer
von der Änderung des Attributwertes benachrichtigt. Bei diesem
Ereignis werden der Name der Property sowie alter und neuer Wert an
die EventListener-Objekte übergeben. Dies geschieht nach der
Änderung des Attributwertes innerhalb des Objektes.
Constrained Properties ähneln den Bound Properties sehr stark, allerdings können andere Komponenten gegen die beabsichtige Änderung des Attributwertes ihr Veto einlegen, sie somit zurückweisen und auf diese Weise verhindern. Das entsprechende Ereignis (VetoableChange-Event ) wird deshalb vor der Änderung des Attributwertes ausgelöst, die i.d.R. nur dann ausgeführt wird, wenn keines der Listener-Objekte dagegen Einspruch erhebt.
Introspection bezeichnet den Prozeß der Analyse eines JavaBeans mit dem Ziel, die unterstützten Properties, Methoden und Ereignisse zu ermitteln. Dies kann sowohl in der Entwicklungsumgebung als auch zur Laufzeit derjenigen Applikation geschehen, die die Komponente benutzt. JavaBeans können wie alle Java-Klassen dynamisch geladen werden.
Zur Definition der Merkmale eines JavaBeans ist keine separate Spezifikationssprache notwendig, denn alle interessanten Aspekte sind in Java selbst beschrieben. Ein Ziel der JavaBeans-Konzeption ist es, schnell einfache Komponenten entwickeln zu können. Deshalb sollen Beans ohne zusätzlichen Aufwand ihrer Entwickler inspiziert werden können. Andererseits soll den Programmierern die Möglichkeit gegeben werden, volle Kontrolle darüber zu haben, was die Komponente über ihre Properties, Methoden und Ereignisse an Informationen preisgibt - vorausgesetzt die Entwickler möchten dies.
Zu diesem Zweck beinhaltet das JavaBeans-Konzept einen zweistufigen Mechanismus. Standardmäßig wird zur Analyse der von der Komponente bereitgestellten Methoden die Java Reflection API benutzt. Auf Basis des dadurch gewonnenen Wissens über die Methoden werden durch die Anwendung der verschiedenen Design Patterns die Properties, Methoden und Ereignisse des Beans ermittelt. Stellt der Entwickler der Komponente jedoch eine BeanInfo-Klasse zur Beschreibung der Komponente zur Verfügung, so wird diese statt der Reflection API benutzt.
Um diesen zweistufigen Mechanismus transparent zu machen, gibt es in der JavaBeans API die Introspector- Klasse, die Entwicklern oder Builder Tools einen einheitlichen Weg zur Untersuchung der Beans liefert. Die Introspector-Klasse ,,versteht`` dabei sowohl die Standardschnittstellen als auch die Design Patterns.
Zur expliziten Spezifikation der von einem Bean unterstützten
Properties, Methoden und Ereignisse werden Klassen verwendet, die die
BeanInfo- Schnittstelle implementieren. Diese Schnittstelle
bietet Methoden an, um Wissenswertes über ein Bean zu erfahren.
Durch die Implementierung dieser Methoden kann der Entwickler dem
Anwender die Nutzung der Komponente erleichtern, indem er zusätzliche
bzw. feinere Informationen liefert.
Die BeanInfo-Klassen arbeiten ausschließlich mit API-Methoden, nicht mit Beschreibungsdateien. Den Entwicklern steht es allerdings frei, beliebige solcher Dateien zur Beschreibung der Beans zu definieren und in die BeanInfo-Klasse nur die Methoden zum Zugriff auf diese Dateien einzubauen.
Die BeanInfo-Klasse kann zahlreiche Informationen über ein JavaBean spezifieren, beispielsweise:
Es ist darüber hinaus auch möglich, in der BeanInfo-Klasse nur einen Teil der Informationen zu spezifizieren. Das restliche Wissen wird dann durch die Reflection API zusammengetragen.
Ein Beispiel für eine BeanInfo-Klasse, die ein sehr einfaches Bean beschreibt, findet sich in Anhang A.
Um ein einheitliches Bild von einer JavaBeans-Komponente zu bekommen, sollte man die Introspector-Schnittstelle benutzen, die die Informationen aus verschiedenen Quellen sammelt und dem Benutzer ,,aus einer Hand`` anbietet. Die Introspector-Klassen sind in der Lage, alle zur Verfügung stehenden Informationsquellen (Reflection API und evtl. BeanInfo-Klassen) auszuwerten und daraufhin ein BeanInfo-Objekt zu liefern, das die Komponente beschreibt. Zu diesem Zweck trägt die Introspector-Klasse Informationen aus der kompletten Klassenhierarchie eines JavaBeans zusammen.
Beim Zusammensetzen der Komponenten in einem Builder Tool soll der Benutzer die Möglichkeit haben, Aussehen und Verhalten der Beans an seine Wünsche anzupassen (Customization ).
Dies kann auf zwei Arten geschehen. Zum einen kann das Builder Tool mit dem Wissen über die durch die Komponente exportierten Properties ein Property Sheet erstellen und für jedes Attribut einen Property Editor zur Verfügung stellen. Mit Hilfe von Property Sheet und Property Editoren kann der Benutzer der Komponente nacheinander die Werte aller Attribute ändern. Dieses Vorgehen ist vor allem für kleine bis mittelgroße Beans geeignet. Zum anderen soll der Benutzer bei größeren und komplexeren Komponenten, bei denen das Setzen eines Propertywertes nach dem anderen nicht mehr sinnvoll ist, die Möglichkeit haben, von kleinen ,,Helfern``, den sogenannten Wizards , durch den Customization-Prozeß geleitet zu werden. Dies wird durch eine Customizer- Klasse erreicht, die die Anpassung der Komponente kontrolliert. Diese Customizer-Klasse ist eine AWT-Komponente mit beliebigem Verhalten und sollte von den Entwicklern umfangreicher Beans mit der Komponente ausgeliefert werden. Die Customizer-Klasse eines JavaBeans wird mit einer speziellen Methode der zur Komponente gehörenden BeanInfo-Klasse ermittelt.
Property Editoren erlauben das Setzen von Attributwerten innerhalb eines Builder Tools mit Hilfe von GUI-Elementen. Bean-Entwickler können für neue Datentypen, die sie in ihren Komponenten verwenden, neue Property Editoren programmieren und dem Benutzer anbieten. Dies ist vor allem dann angebracht, wenn es sich dabei um komplexe Datentypen handelt. Die Funktionalität der Property Editoren kann von einem simplen Texteingabefeld bis zu komplett ausgestatteten AWT-Komponenten, die bei Bedarf per Pop-Up-Mechanismus angezeigt werden, reichen. Ein Property Editor ist somit eine flexible Schnittstelle, die es dem Builder Tool erlaubt, bestimmte Attributwerte anzuzeigen und bearbeiten zu lassen.
Ein Beispiel für einen sehr einfachen PropertyEditor befindet sich im Anhang B.
Die Property Editoren sollten nach einer Wertänderung ein PropertyChange- Ereignis auslösen, um anderer Software die Änderung mitzuteilen. Zu diesem Zweck muß natürlich auch eine Liste der EventListener verwalten werden, die bei Änderungen der Propertywerte an einer Benachrichtigung interessiert sind.
Obwohl bzgl. der Programmierung von Property Editor-Klassen einiges beachtet werden muß, ist die Erstellung nicht sehr kompliziert, da es Hilfsklassen gibt, die die Entwickler unterstützen (Klasse PropertyEditorSupport ).
Property Editoren können sowohl als Teil von Property Sheets als auch in Customizer-Klassen benutzt werden. Die JavaBeans-Laufzeitumgebung beinhaltet bereits einige Property Editoren, andere können von Beans-Entwicklern oder den Builder Tools zur Verfügung gestellt werden. Die Entwicklungswerkzeuge beispielsweise bieten i.d.R. bereits solche Editoren für einfache Typen wie Zahlen, Zeichenketten, Zeichensätze oder Farben an.
Die einfachen Property Sheets sind zur Anpassung der meisten wenig komplexen Komponenten gut geeignet. Für größere, komplexere Beans sollte ein als AWT-Komponente spezifizierter Customizer eingesetzt werden.
Die Klasse PropertyEditorManager organisiert die Zuordnung zwischen Datentypen und zugehörigen Property Editor-Klassen. Diese können sich beim Manager registrieren lassen. Für die Standard-Java-Typen sind im PropertyEditorManager bereits Einträge vorhanden. Der Manager erkennt die Property Editoren i.d.R. an dem Klassennamen, der wiederum einem standardisierten Design Pattern folgt. So ergibt sich der Name der Property Editor-Klasse durch den Namen der zu bearbeitenden Klasse plus den Zusatz ,,Editor``. Beispielsweise würden Attribute der Klasse Label durch ein Objekt der Property Editor-Klasse LabelEditor bearbeitet werden können.
Nach dem Customization-Prozeß sollte der Zustand der Komponente durch das Builder Tool mittels der Java-Persistenzmechanismen gesichert werden. Von derjenigen Applikation, die ein Bean benutzt, kann die Komponente dann mit diesem Zustand initialisiert werden.
Customizer-Klassen müssen AWT-Komponenten sein, die in einer Dialogbox des Builder Tools angezeigt werden können. Typischerweise sind sie deshalb Unterklassen von java.awt.Panel . Darüber hinaus muß die Customizer-Schnittstelle implementiert sein. Analog zu den Property Editoren sollten die Customizer das PropertyChange-Ereignis unterstützen.
Die JavaBeans-API erlaubt es, mit Hilfe der Serialisierung den internen Zustand eines Objektes persistent zu machen. Ein Bean-Objekt kann sich dann später beim Laden in den flüchtigen Speicher mit genau dem Zustand initialisieren, in dem es vorher gespeichert wurde.
Durch diesen Mechanismus ist es möglich, Beans vorkonfiguriert weiterzugeben. Der Anwender bekommt in diesem Fall mit der eigentlichen Komponente einen gebrauchsfähigen Zustand des Beans ausgeliefert.
Eine weitere denkbare Anwendungsmöglichkeit des Persistenzmechanismus ist die Verteilung von Dokumenten, die sich selbst darstellen bzw. drucken können. Dies wird erreicht, indem man ein Bean zur Darstellung bestimmter Daten (beispielsweise eines Text- oder Tabellenformats) erstellt, diesen Viewer mit seinen internen Datenstrukturen persistent macht und weitergibt. So kann sich die Darstellungskomponente beim Start im gespeicherten Zustand initialisieren und das enthaltene Dokument anzeigen bzw. drucken.
Die Tabellen 4.1 und 4.2 zeigen die JavaBeans Design Patterns im Überblick. Anhand dieser Muster können Entwickler und Builder Tools vorhandene Komponenten leicht analysieren.
| Beans | |
| Klassenname: | Beliebig |
| Superklasse: | Beliebig |
| Konstruktor: | Muß einen Konstruktor ohne Argument oder eine serialisierte Templatedatei haben |
| Verpackung: | Manifest in der JAR-Datei muß Java-Bean: True spezifizieren |
| Properties (Property p vom Typ T ) | |
| Get-Methode: | public T getP () |
| Set-Methode: | public void setP (T value) |
| Boolean Properties (Property p vom Typ boolean) | |
| Get-Methode: | public boolean getP () oder |
public boolean isP () | |
| Set-Methode: | public void setP (boolean value) |
| Indexed Properties (Property p vom Typ T ) | |
| Get-Methode Array: | public T [ ] getP () |
| Set-Methode Array: | public void setP (T [ ] value) |
| Get-Methode Element: | public T getP (int index) |
| Set-Methode Element: | public void setP (int index, T value) |
| Bound Properties (Property p vom Typ T ) | |
| Get-Methode: | public T getP () |
| Set-Methode: | public void setP (T value) |
| Listener: | eine Liste aller EventListener für alle Bound Properties eines Beans |
| Listener-Anmeldung: | public void addPropertyChangeListener |
(PropertyChangeListener l) | |
| Listener-Abmeldung: | public void removePropertyChangeListener
|
(PropertyChangeListener l) | |
| Constrained Properties (Property p vom Typ T ) | |
| Get-Methode: | public T getP () |
| Set-Methode: | public void setP (T value) |
throws PropertyVetoException | |
| Listener: | eine Liste aller EventListener für alle Constrained Properties eines Beans |
| Listener-Anmeldung: | public void addVetoableChangeListener |
(VetoableChangeListener l) | |
| Listener-Abmeldung: | public void removeVetoableChangeListener
|
(VetoableChangeListener l) | |
| Ereignisse (Name des Ereignisses: E ) | |
| Name der Ereignisklasse: | E Event |
| Name des Listeners: | E Listener |
| Listener-Methode: | public void methodenname (E Event e) |
| Listener-Anmeldung: | public void addE Listener(E Listener l) |
| Listener-Abmeldung: | public void removeE Listener(E Listener l)
|
| Unicast Ereignisse (Name des Ereignisses: E , es ist nur ein Listener erlaubt) | |
| Listener-Anmeldung: | public void addE Listener(E Listener l) |
throws TooManyListenersException | |
| Listener-Abmeldung: | public void removeE Listener(E Listener l) |
| Methoden | |
| Methodenname: | Beliebig |
| Methodenargumente: | Beliebig, einige Tools erkennen nur Methoden ohne Argumente |
| BeanInfo-Klassen (für Bean B ) | |
| Klassenname: | B BeanInfo |
| Property Editoren (für Properties vom Typ T ) | |
| Klassenname: | T Editor |
| Konstruktor: | muß einen Konstruktor ohne Argumente besitzen |
| Property Editoren (für individuelle Properties) | |
| Klassenname: | Beliebig, muß per PropertyDescriptor
registriert werden |
| Konstruktor: | muß einen Konstruktor ohne Argumente besitzen |
| Customizer (für Bean B ) | |
| Klassenname: | Beliebig, muß per BeanDescriptor registriert
werden |
(Namenskonvention: B Customizer) | |
| Dokumentationsdatei (für Bean B ) | |
| Standarddokumente: | B .html |
| Lokalisierte Dokumente: | locale/B .html |
Vorwiegendes Ziel der im folgenden beschriebenen Prototypimplementierung ist das Aufzeigen eines möglichen Weges bei der Realisierung einer generischen Oberfläche für ASN.1-Datentypen mit Hilfe der JavaBeans-Technologie. Es soll verdeutlicht werden, wie die Implementierung von ASN.1-Komponenten für Java aussehen könnte und inwieweit JavaBeans bei der Entwicklung von Applets zur Anzeige und Modifikation von ASN.1-Datenstrukturen hilfreich sein kann.
Innerhalb des MOON-Projektes soll die generische Oberfläche für ASN.1-Datentypen es ermöglichen, auf unkomplizierte Art und Weise Java-Anwendungen zur Anzeige und Modifikation von ASN.1-Daten erstellen zu können.
Das angestrebte Einsatzszenario läßt sich wie folgt beschreiben: Die zur Kommunikation verwendeten Datenstrukturen werden in ASN.1 spezifiziert. Diese Spezifikation wird mit Hilfe von Christian Huberts Compiler in Quelltext für entsprechende Java-Klassen übersetzt. Ein Java-Compiler erzeugt aus diesen Quelltexten Java-Klassen. Diese Klassen beinhalten nach ihrer Instanziierung die Werte der ASN.1-Datentypen.
Um nun für diese ASN.1-Java-Objekte eine Applikation zur Anzeige und
Änderung der Werte zu generieren, sollen mit Hilfe einer
Softwareentwicklungsumgebung, die das JavaBeans-Konzept unterstützt,
die entsprechenden Komponenten mit weiteren Standard-Bedienungselementen
(beispielsweise Buttons) kombiniert und verknüpft werden. Das
Entwicklungstool ist dann in der Lage, aus diesen Bausteinen ein
Java-Applet zu generieren. Darüber hinaus kann im Bedarfsfall die
erzeugte Java-Klasse instanziiert sowie sinnvoll vorkonfiguriert und
dieser Zustand basierend auf der Technik der Serialisierung persistent
gemacht werden. Dies kann beispielsweise innerhalb des
AppletViewers aus dem Java-Entwicklungskit
(JDK
) von Sun geschehen.
Dieses Vorgehen erfordert nur ein Minimum an Programmieraufwand und
läßt sich fast ausschließlich mit entsprechenden Tools realisieren.
Als Resultat entsteht ein Applet zur Anzeige und
Modifikation von ASN.1-Daten, das man auf einer beliebigen Java-fähigen
Plattform in seinem vorkonfigurierten Zustand starten kann. In Form von
Applets eignen sich die generierten Klassen darüber hinaus hervorragend
zur Übertragung zwischen den beteiligten Parteien per Internet, wenn
man die notwendigen Sicherheitsmaßnahmen beachtet.
Das Ablaufdiagramm in Abbildung 5.1 veranschaulicht die angestrebte Vorgehensweise.
Ziel dieser Arbeit ist die Bereitstellung einer Oberflächen-Schnittstelle für die JAsn API. Die entwickelte API wurde gui4asn genannt. Sie beinhaltet Klassen zur Anzeige und Modifikation von JAsn-Objekten und basiert auf dem JavaBeans-Konzept, um den Einsatz in entsprechenden Softwareentwicklungsumgebungen zu gewährleisten.
Alle Klassen der gui4asn API verfügen über eine main -Methode und können somit auch eigenständig mit Hilfe eines Java-Interpreters benutzt werden.
Analog der Struktur der JAsn-Programmierschnittstelle existiert in der gui4asn API eine allgemeine Basisklasse BaseGui , von der die Oberflächenklassen für die einzelnen ASN.1-Datentypen erben. BaseGui erbt ihrerseits von der Standard-AWT-Klasse Panel , um die gui4asn-Objekte Graphik-Containern hinzufügen zu können. Desweiteren werden die Klassen hierdurch serialisierbar.
BaseGui enthält als Attribut einen Verweis auf das JAsn-Objekt, für das die Oberfläche bereitgestellt werden soll. Das zu verwendende JAsn-Objekt kann entweder bereits bei dem Anlegen der BaseGui-Instanz per Konstruktor-Argument oder alternativ jederzeit per Setter-Methode zugewiesen werden. Darüber hinaus besitzt BaseGui zwei Attribute des Typs Label aus dem Standard-AWT-Paket. Mit Hilfe dieser Labels werden der Name und der Typ des zugrundeliegendne ASN.1-Datentyps angezeigt. Diese Attribute sind als lesbare Beans-Properties realisiert und können somit per Getter-Methoden abgefragt werden.
Die Basisklasse BaseGui enthält außerdem zwei Methoden zur Initialisierung des internen Objektzustands. Die statischen Einstellungen werden durch Aufruf von initialize() vorgenommen, dies ist während des Lebenszyklus eines BaseGui-Objekts nur einmal notwendig und wird im Klassen-Konstruktor realisiert. Die dynamischen Elemente der Klasse werden mit der Methode initDynamicElements() gesetzt, sie sind abhängig vom zugrundeliegenden JAsn-Objekt (beispielsweise Name des Datentyps). Somit wird diese Methode immer dann aufgerufen, wenn dem BaseGui-Objekt ein JAsn-Objekt zugewiesen wird.
Zur Übernahme der innerhalb der Oberfläche vorgenommenen Änderungen an den ASN.1-Datentypen dienen die Methoden apply() und applyAndGetJasnObject() . Sie weisen dem zugrundeliegenden JAsn-Objekt die im GUI vorhandenen Werte zu und geben im Fall von applyAndGetJasnObject() dieses modifizierte JAsn-Objekt auch zurück.
Für jeden unterstützten ASN.1-Datentyp wurde eine Klasse der Art TypGui entwickelt, die von BaseGui erbt und sich bezüglich Konstruktoren, Wertzuweisungen, Initialisierung und Übernahme der Wertänderungen auch analog verhält. Auf die Besonderheiten einiger dieser Klassen soll im folgenden eingegangen werden.
Laut den in Kapitel 3.2.1 formulierten Anforderungen an eine Oberfläche für ASN.1-Boolean-Typen sollte das zu entwickelnde GUI dem Benutzer die Möglichkeit bieten, aus den beiden alternativen Werten True und False in Form einer Liste oder von Buttons auswählen zu können. Die Klasse BooleanGui (vgl. Abbildung 5.2) realisiert dies mittels Checkboxen aus dem Standard-AWT-Paket. BooleanGui besitzt als Attribute eine CheckboxGroup sowie zwei Checkboxen, die die beiden möglichen Werte repräsentieren. Der Benutzer kann immer genau eine dieser beiden Boxen selektieren und somit den Wert des Boolean-Datentyps auf True oder False setzen.
Das Eingabefeld für Integer-Typen wird in der Klasse IntegerGui (vgl. Abbildung 5.3) mittels eines Textfeldes realisiert. Hier kann der Benutzer beliebige Werte eintragen. Eine Unterstützung der beim ASN.1-Integer-Typ möglichen benannten Konstanten ist derzeit nicht implementiert, da diese von der JAsn API nicht behandelt werden und somit bei der Übersetzung von ASN.1-Definitionen in Java-Klassen-Quelltexte verlorengehen. Auch die Überprüfung der Eingabe auf einen gültigen ganzzahligen Wert ist bisher nicht realisiert. Trägt der Benutzer für Integer-Typen nicht sinnvolle Daten ein, so werden diese von der Umwandlungsroutine so weit als möglich als ganzzahlig interpretiert. Handelt es sich bei der Eingabe um einen Text, so ergibt dies i.d.R. den Wert 0.
Neben dem Textfeld zur Eingabe des ASN.1-Wertes besitzt die Klasse IntegerGui ein Attribut des Typs CheckboxGroup sowie zwei Checkboxen . Mit Hilfe dieser Checkboxen wird eine Auswahlmöglichkeit bezüglich des Ein- und Ausgabeformates des Integer-Typs realisiert. Zur Wahl stehen dabei das dezimale sowie das hexadezimale Zahlenformat. Jeweils eine der Checkboxen steht für eines der Formate. Durch Anklicken der nicht selektierten Box kann der Benutzer das aktive Zahlenformat ändern. Der aktuelle Wert im Eingabefeld wird daraufhin aus dem vorherigen in das neue Format konvertiert. Ein Attribut der IntegerGui-Klasse vom Typ Integer enthält das aktuelle Zahlenformat und kann per Getter- und Setter-Methoden abgefragt bzw. gesetzt werden.
Eventuelle in ASN.1 definierte Grenzen oder Einschränkungen für den Integer-Typ werden von der Oberfläche nicht beachtet, da sie von der JAsn API nicht unterstützt werden.
Die Klassen BitStringGui (vgl. Abbildung 5.4) und OctetStringGui (vgl. Abbildung 5.5) ähneln der Klasse IntegerGui sehr stark, aufgrund der Semantik der in Bit- und Octet-Strings enthaltenen Daten stehen jedoch das binäre sowie das hexadezimale Zahlenformat zur Verfügung.
Aufgrund fehlender Unterstützung von Seiten der JAsn API können benannte Bits von den Oberflächenklassen nicht behandelt werden.
Die Klasse ObjectIdentifierGui erweitert zur Eingabe der Werte ihre Vaterklasse BaseGui um ein Textfeld. In dieses Feld kann der Benutzer beliebige Werte eingeben. Da der Wert des ASN.1-Object Idenitifiers innerhalb der entsprechenden JAsn-Klasse ebenfalls als Zeichenkette verwaltet wird, steht somit bezüglich Ein- und Ausgabeformaten die gleiche Funktionalität zur Verfügung wie im zugrundeliegenden JAsn-Objekt. Eine Umwandlung der Werte zwischen verschiedenen Formaten ist in ObjectIdentifierGui nicht implementiert.
Auch die Klasse RealGui verwendet zur Ein- und Ausgabe der Werte ein Textfeld. Wie bei IntegerGui werden die eingegebenen Daten nicht auf Gültigkeit bezüglich Fließkommazahlen getestet, sondern bei der Umwandlung des Textfeldinhalts wird dieser soweit als möglich als Fließkommazahl interpretiert. Reine Texteingaben ergeben i.d.R. den Wert 0. Eine Umwandlung zwischen verschiedenen Zahlenformaten ist derzeit nicht realisiert.
Die Klasse EnumeratedGui (vgl. Abbildung 5.6) bietet dem Benutzer die für den zugrundeliegenden ASN.1-Typ möglichen Werte in einer Liste zur Auswahl an. Dazu wird die Standard-AWT-Klasse Choice benutzt.
Die JAsn API legt die in einem ASN.1-Enumerated-Typen definierten Konstanten in der entsprechenden JAsn-Klasse als finale, also unveränderliche Variablen ab. Da die benannten Konstanten jedoch nicht durch einen Methodenaufruf innerhalb der JAsn API zugänglich sind, ermittelt die EnumeratedGui-Klasse sie mit Hilfe der Reflection API von Java und legt sie in zwei Containern vom Typ Hashtable ab. In diesen Containern werden die Konstanten ihren jeweiligen numerischen Werten zugeordnet, eine Hashtable benutzt dazu die Konstante als Key , die andere den numerischen Wert. Die ermittelten Informationen werden zum Füllen der Choice-Komponente verwendet.
Sowohl die beiden Hashtables als auch die Choice sind als lesbare Properties der Klasse EnumeratedGui realisiert und können somit per Getter-Methoden abgefragt werden.
Die Klasse CharacterStringGui (vgl. Abbildung 5.7) implementiert eine allgemeine Oberflächenkomponente für Zeichenketten. Da sich die verschiedenen in ASN.1 existierenden String-Typen ausschließlich durch den jeweils gültigen Zeichensatz unterscheiden, muß innerhalb der Oberflächenklasse nur beim Überprüfen des eingegebenen Wertes auf Gültigkeit zwischen den verschiedenen String-Typen differenziert werden. Dieser Test wird jedoch von den JAsn-Klassen, die die Zeichenketten implementieren, angeboten. Deshalb besteht keine dringende Notwendigkeit, die gui4asn API bezüglich weiterer Oberflächen-Komponenten für die einzelnen String-Typen zu verfeinern. Trotzdem beinhaltet die gui4asn API als Beispiel für eine Verfeinerung die Klasse GraphicStringGui , die von CharacterStringGui erbt und die Oberfläche für die JAsn-Klasse GraphicString implementiert. Einziger Unterschied zwischen CharacterStringGui und GraphicStringGui sind verschiedene Typbezeichnungen der Komponenten.
Die Ein- und Ausgabe wird mit Hilfe eines Textfeldes realisiert. Bei jeder Änderung des Wertes dieses Textfeldes wird der Inhalt auf Gültigkeit bezüglich des verwendeten ASN.1-String-Typs überprüft. Dieser Test geschieht unter Zuhilfenahme der bereits erwähnten Methoden aus dem JAsn API. Stellt sich der neu eingegebene Wert als nicht zum entsprechenden Typ passend heraus, so wird der Benutzer aufgefordert, eine Korrektur vorzunehmen.
Die Klasse SequenceGui (vgl. Abbildung 5.8) ist ein zentrales Element der gui4asn API. Sie realisiert die Funktionalität für die ASN.1-Typen Sequence und Sequence Of sowie Set und Set Of. Die Klassen SequenceOfGui , SetGui und SetOfGui erben von SequenceGui und fügen nur wenig eigene Funktionalität hinzu. Dieser Weg wurde gewählt, da sich die Anforderungen an diese vier ASN.1-Typen nur wenig voneinander unterscheiden.
Ein wichtiges Ziel bei der Implementierung der strukturierten ASN.1-Typen war die Möglichkeit, die enthaltenen Informationen im Bedarfsfall verbergen zu können. Dies wurde durch einen Mechanismus zum Auf- und Zuklappen der jeweiligen Struktur realisiert. Im aufgeklappten Zustand sieht der Benutzer alle Details der Struktur, im zugeklappten hingegen nur Namen und Typ der Struktur. Zur Verwaltung dieses Zustandes enthält SequenceGui ein Flag vom Typ Boolean, auf das über die üblichen Getter- und Setter-Methoden zugegriffen werden kann. Auf- bzw. Zuklappen kann der Benutzer die Struktur über einen Button, der den Wert des beschriebenen Zustandsflags des Objektes ändert.
Die eigentlichen AWT-Komponenten zur Anzeige der in der Struktur enthaltenen Informationen sind auf der Basis von Panels sowie eines ScrollPanes realisiert und ebenfalls als lesbare Beans-Properties zugänglich. Darüber hinaus beinhaltet SequenceGui ein les- und schreibbares Attribut vom Typ Dimension , mit dessen Hilfe man die Größe des ScrollPanes beeinflussen kann.
Während der Initialisierung analysiert SequenceGui die in der ASN.1-Struktur enthaltenen Informationen und erzeugt entsprechende Oberflächenkomponenten. Diese sind in Form eines Vektors ebenfalls zum lesenden Zugriff zugänglich.
Auch die Behandlung rekursiver Datentypen ist mit SequenceGui möglich, sofern es sich um eine direkte Rekursion handelt. Eine solche wird vom ASN.1-Java-Compiler erkannt und die entsprechende Komponente innerhalb der Struktur durch einen Any-Typen ersetzt. Der Übersetzer ist allerdings nicht in der Lage, indirekte Rekursionen adäquat zu behandeln, denn die resultierenden Klassen führen zu einer Endlosschleife im Konstruktor der entsprechenden ASN.1-Typen.
Durch die Behandlung direkter Rekursionen unter Zuhilfenahme eines Any-Typen ist es auch innerhalb von SequenceGui möglich, rekursive ASN.1-Typen anzuzeigen und zu modifizieren. Der Any-Typ erlaubt das dynamische Nachladen beliebiger ASN.1-Java-Klassen und somit auch der den Any-Typen umgebenden Struktur. Allerdings kann, wie beschrieben, auch ein anderer ASN.1-Typ geladen werden, wodurch die Struktur innerhalb der SequenceGui nicht mehr dem in der ASN.1-Definition deklarierten Datentypen entspricht.
Die Klassen SequenceOfGui (vgl. Abbildung 5.9) und SetOfGui bieten darüber hinaus dem Benutzer die Möglichkeit, der Struktur neue Komponenten hinzuzufügen. Dies wird über einen entsprechenden Button realisiert. Das Löschen vorhandener Komponenten wird nicht unterstützt.
Problematisch bei SequenceGui und den darauf basierenden Klassen ist die Tatsache, daß hier die Trennung der Eingabe von den zugrundeliegenden JAsn-Objekten nicht realisiert werden konnte. Grund hierfür ist die Tatsache, daß die zum Kopieren von JAsn-Objekten gedachte Methode BASE.clone() nicht fehlerfrei arbeitet und deshalb das Anlegen einer Sicherheitskopie des Zustandes vor dem Aufrufen der Oberfläche nicht möglich ist. Deshalb wirken sich Änderungen an den Werten der Strukturen innerhalb der Oberfläche teilweise direkt auf die entsprechenden JAsn-Objekte aus, ohne daß die Apply -Methode aufgerufen wurde.
Eine spezielle Behandlung optionaler Komponenten von ASN.1-Strukturen ist derzeit nicht realisiert.
Die Klasse ChoiceGui (vgl. Abbildung 5.10) ermöglicht dem Benutzer die Auswahl zwischen alternativen Komponenten einer ASN.1-Choice-Struktur. Dies wird durch eine CheckboxGroup sowie pro selektierbarer Alternative einer Checkbox realisiert. Mit diesen Boxen wählt der Benutzer die aktive Komponente der Struktur aus und auch nur diese Komponente ist daraufhin modifizierbar. Die inaktiven Elemente der Choice-Struktur werden zwar angezeigt, sind aber für Änderungen gesperrt. Dieses Verhalten ist mittels einer den einzelnen Checkboxen zugeordneten Ereignisbehandlung implementiert.
Der Klasse AnyGui kommt aufgrund ihrer Universalität eine Sonderrolle zu, denn ein Any-Typ kann als Wert einen beliebigen anderen ASN.1-Typen annehmen.
Die Oberfläche von AnyGui bietet deshalb dem Benutzer die Möglichkeit, eine beliebige JAsn-Klasse nachzuladen (vgl. Abbildung 5.11). Zu diesem Zweck werden ein Textfeld und ein Button angezeigt. Bei einem Klick auf den Button versucht AnyGui, die im Textfeld spezifizierte Klasse (die dort unter Angabe eventueller Packages eingegeben werden muß) dynamisch nachzuladen sowie eine entsprechende Oberflächenkomponente zu erzeugen. Gelingt dies, so wird das kreierte GUI der AnyGui-Komponente hinzugefügt (vgl. Abbildung 5.12).
Befindet sich ein ANY-Objekt, das der Instanz der AnyGui-Klasse zugewiesen wird, bereits in einem initialisierten Zustand, d.h. beinhaltet dieses ANY-Objekt bereits ein anderes, konkretes JAsn-Objekt, so wird für letzteres unmittelbar eine Oberflächenkomponente erzeugt und angezeigt - analog zu dem Vorgehen nach einem erfolgreichen dynamischen Nachladen.
Ein späterer Wechsel des konkreten JAsn-Objektes innerhalb der AnyGui-Komponente ist jederzeit innerhalb der Oberfläche durch Eingabe eines neuen Klassennamens sowie Betätigen des ,,Laden``-Buttons möglich.
Besondere Bedeutung erlangt die Klasse AnyGui u.a. durch die Tatsache, daß mit ihrer Hilfe die Behandlung direkter Rekursionen in strukturierten ASN.1-Datentypen möglich wird (vgl. Kapitel 5.2.2.8). Darüber hinaus ist es auf der Basis von AnyGui möglich, ein Applet zu erzeugen, mit dem man beliebige JAsn-Objekte anzeigen und modifizieren kann. Dazu ist es ausreichend, ein GUI für einen ANY-Typen zu kreieren, denn dieses kann dann zur Laufzeit eine Oberfläche für einen anderen ASN.1-Typen erzeugen.
Interessant ist bei der Klasse AnyGui weiterhin, daß diese die Verwendung von PropertyChange -Ereignissen demonstriert. Ein solches Event wird von einem AnyGui-Objekt immer dann ausgelöst, wenn sich nach dem dynamischen Nachladen eines JAsn-Objektes das JasnObject-Attribut der Klasse geändert hat. Interessierte Listener-Klassen können daraufhin im Bedarfsfall entsprechend reagieren.
Zu den Hilfsklassen zählen die Klassen, die den mit der gui4asn API arbeitenden Entwicklern die Verwendung dieser Programmierschnittstelle vereinfachen sollen. Insbesondere handelt es sich dabei um die in Kapitel 4.6.3 beschriebenen Auxiliary-Klassen der JavaBeans-Architektur wie BeanInfo-Klassen oder Property Editoren.
Eine zentrale Hilfsklasse stellt BASEEditor dar. Sie implementiert einen Property Editor für den BASE -Datentyp aus der JAsn API. Jede Oberflächenklasse der gui4asn API besitzt ein Attribut von diesem Typ und das Anbieten eines entsprechenden Property Editors ermöglicht die Änderung dieses Attributwertes innerhalb einer Softwareentwicklungsumgebung. Da es sich bei dem Datentyp BASE nicht um einen Standardtyp wie Zahl, Zeichenkette, Farbe oder Zeichensatz handelt, wäre eine solche Modifikation ohne die Klasse BASEEditor nicht möglich.
BASEEditor erlaubt es dem Benutzer, einen Wert für das Attribut jasnObject der Oberflächenklassen in Form eines Strings einzugeben. Enthält dieser String den gültigen Namen einer JAsn-Klasse, so wird diese Klasse dynamisch geladen, eine Instanz von ihr erzeugt und die Referenz auf das kreierte Objekt der Methode setJasnObject() übergeben. Umgekehrt zeigt BASEEditor auch den Klassennamen eines bereits initialisierten Attributs jasnObject als Text an. Durch die auf Basis von BASEEditor bereitgestellte Möglichkeit, Attribute von dem Typ BASE in Form von Strings ein- bzw. auszugeben, ist die Softwareentwicklungsumgebung in der Lage, dieses Property in den PropertySheet aufzunehmen, wo es gemeinsam mit den Bean-Attributen modifiziert werden kann.
Darüber hinaus ist in der gui4asn API auch ein Property Editor für den Datentyp Dimension enthalten. Mit Hilfe der Klasse DimensionEditor ist es möglich, Beans-Attribute von dem Typ java.awt.Dimension innerhalb eines PropertySheets zu modifizieren. Wie bei BASEEditor wird es auch hier dem Application Builder Tool ermöglicht, Dimension-Datentypen in Form von Strings ein- bzw. auszugeben. Zu diesem Zweck werden die Breiten- und Höhenangaben eines Dimension-Objektes in eine Zeichenkette der Form ,,Breite/Höhe`` umgewandelt und umgekehrt. Gibt der Benutzer für ein Dimension-Attribut im PropertySheet den String ,,400/300`` an, so wird dem Property ein Dimension-Objekt mit der Breite ,,400`` und der Höhe ,,300`` zugewiesen. Da die Klassen SequenceGui, SequenceOfGui, SetGui und SetOfGui über ein Attribut scrollDimension verfügen, das die Größe des ScrollPanes innerhalb der GUI-Komponente beinhaltet, können Breite und Höhe des scrollbaren Bereichs dieser strukturierten Typen innerhalb der Entwicklungsumgebung konfiguriert werden.
Auch das Anbieten von Customizer-Klassen wäre möglich, jedoch ergäbe sich dadurch aufgrund der relativ geringen Komplexität der einzelnen Beans nur ein geringer Gewinn an Komfort innerhalb der Softwareentwicklungsumgebung.
Wesentlich sinnvoller sind BeanInfo-Klassen, mit deren Hilfe man Entwicklern, die die gui4asn API benutzen, detaillierte Informationen über die Beans zur Verfügung stellen kann. Beispiele für solche BeanInfo-Klassen sind in der gui4asn API enthalten.
Darüber hinaus wäre es für eine spätere Version der JAsn API wünschenswert, wenn auch die indirekte Rekursion von ASN.1-Typen ermöglicht würde, die derzeit noch durch den Aufbau der Konstruktoren zu Endlosschleifen führt und auch nicht vom Compiler - wie die direkte Rekursion - entdeckt und adäquat behandelt wird. Des weiteren würde eine Fehlerbereinigung der Methode clone() in der Klasse BASE es den Oberflächenklassen der gui4asn API ermöglichen, einen besseren Mechanismus zur Zurücknahme von eventuellen Wertänderungen zu realisieren.
Zusätzlichen Komfort könnten die Programmierschnittstellen JAsn und gui4asn den Benutzern bieten, wenn der ASN.1-Java-Compiler sowie die Klassen BIT_STRING und INTEGER benannte Konstanten unterstützen würden. Eine potentielle Fehlerquelle könnte darüber hinaus durch das Hinzufügen einer Methode zum Abfragen der alternativen Werte einer ASN.1-Choice-Datenstruktur in die Klasse CHOICE ausgeschlossen werden.
Weiterhin könnte der Nutzungskomfort durch die Aufnahme einer Methode zum Abfragen des ASN.1-Quelltextes, aus dem eine Klasse generiert wurde, in die JAsn API gesteigert werden.
Der Einsatz der gui4asn-Klassen ist vorwiegend in zwei verschiedenen Szenarien denkbar. Zum einen sind die Komponenten durch das JavaBeans-Konzept für den Einsatz innerhalb von Softwareentwicklungsumgebungen prädestiniert. Zum anderen können die Klassen durch ihre einfache Programmierschnittstelle auch in manuell erstelltem Java-Quelltext problemlos verwendet werden. Beide Verwendungsmöglichkeiten werden in den folgenden Unterkapiteln detaillierter beschrieben.
In beiden Fällen ist es notwendig, das erstellte Applet mit allen zur Ausführung notwendigen Klassen (JAsn-, gui4asn- und vom ASN.1-Compiler generierte Klassen) sowie eventuell benötigten Ressourcen in eine JAR-Datei zu packen. Aus dieser Archivdatei heraus läßt sich das ASN.1-Applet auf der Zielplattform starten.
Unter Zuhilfenahme von Softwareentwicklungsumgebungen, die das JavaBeans-Konzept unterstützen, können auf Basis der gui4asn-Komponenten komfortabel Applets zur Anzeige und Modifikation von ASN.1-Datenstrukturen erstellt werden. Dabei wird das in Kapitel 5.1 beschriebene Einsatzszenario realisiert.
![]() |
Voraussetzung für die toolgestützte Erstellung von ASN.1-Applets ist, daß durch die Übersetzung von ASN.1-Definitionen mit Hilfe des ASN.1- sowie des Java-Compilers ASN.1-Klassen entsprechend der JAsn API vorhanden sind. Ist dies der Fall, kann innerhalb der Entwicklungsumgebung ein neues Applet erstellt werden. In dieses zunächst leere Applet setzt man die gui4asn-Komponente des gewünschten ASN.1-Typs (beispielsweise SequenceGui oder ChoiceGui). Unter Zuhilfenahme des PropertySheets des Application Builder Tools kann dem Bean eine Instanz einer JAsn-Klasse des entsprechenden Typs zugewiesen werden. Würde man den Prozeß in diesem Moment abbrechen, hätte man bereits ein Applet zur Anzeige und Modifikation von ASN.1-Strukturen zur Verfügung. Für einen sinnvollen Einsatz dieses Applets ist es jedoch darüber hinaus notwendig, einige Steuerungskomponenten in das Applet einzubauen. Es bietet sich beispielsweise das Hinzufügen eines AWT-Buttons zur Übernahme der innerhalb der Oberflächenklasse durchgeführten Änderungen an. Im späteren Applet würde ein Betätigen dieses Buttons dazu führen, daß das zugrundeliegende JAsn-Objekt mit den in der gui4asn-Komponente vorhandenen Werten gefüllt würde. Der Aufwand für das Hinzufügen einer solchen Komponente beschränkt sich darauf, innerhalb des Entwicklungstools den Button in das Applet zu setzen und sein actionPerformed -Ereignis mit der apply() -Methode des gui4asn-Beans zu verknüpfen. Beliebige sonstige Erweiterungen sind denkbar.
Am Ende des visuellen Entwicklungsprozesses generiert das Application Builder Tool das gewünschte Applet. Dieses ist anschließend in einer beliebigen Java-Umgebung ausführbar. Darüber hinaus kann der Entwickler das erzeugte Applet auch selbst aufrufen, einige sinnvolle Konfigurationen vornehmen und diesen Zustand anschließend per Serialisierungsmechanismus, z.B. innerhalb des AppletViewers , persistent machen. Das Applet kann dann später in genau diesem Zustand wieder gestartet werden - beispielsweise nachdem es auf einen anderen Rechner übertragen wurde.
Einen Eindruck von der Erstellung eines ASN.1-Applets unter Zuhilfenahme des Application Builder Tools IBM Visual Age for Java vermitteln die Abbildungen 5.13 und 5.14. Zur Realisierung dieser Arbeit wurde u.a. dieses Produkt eingesetzt.
Neben dem Einsatz einer Softwareentwicklungsumgebung ist auch das manuelle Erstellen eines ASN.1-Applets auf Basis der JAsn- und gui4asn-Klassen möglich. Der Quelltext in Abbildung 5.15 implementiert ein Applet als Oberfläche für den ASN.1-Typ RainbowColour , der wie folgt definiert ist:
RainbowColour ::= INTEGER
Dabei wird dem ASN.1-Objekt vom Typ RainbowColour vor Erstellung des graphischen Oberfläche der Wert 123 zugewiesen. Die Klasse RainbowColour wurde vom ASN.1-Compiler innerhalb des Packages DIETER erstellt.
![]() |
Wie man an dem Beispiel sieht, ist die manuelle Verwendung der JAsn- und gui4asn-Programmierschnittstellen denkbar einfach. Für ein Applet ist es ist ausreichend, eine Instanz der gewünschten ASN.1-Klasse zu erzeugen, diesem Objekt einen adäquaten Wert zuzuweisen und auf Basis dieses Objektes die gui4asn-Oberflächenkomponente zu kreieren.
Diesem Rumpfapplet kann man darüber hinaus beliebige weitere AWT-Komponenten mit entsprechender Funktionalität hinzufügen.
Einige Erweiterungsmöglichkeiten stehen in direktem Bezug zu wünschenswerten Modifikationen der JAsn API, wie sie in Kapitel 5.3 beschrieben wurden. Hier sind vor allem die verbesserte Behandlung von Rekursionen, die Unterstützung benannter Konstanten bei den ASN.1-Typen Integer und Bit String sowie die Möglichkeit der Ausgabe des ASN.1-Quelltextes, auf dem ein Typ beruht, zu nennen.
Darüber hinaus könnten die gui4asn-Klassen dahingehend erweitert werden, daß sie die vom Benutzer eingegebenen Werte genauer auf ihre Gültigkeit bezüglich des zugrundeliegenden ASN.1-Typs überprüfen. In diesem Zusammenhang wäre auch die Behandlung von eventuellen Grenzen oder Einschränkungen der ASN.1-Datentypen von Interesse für den Anwender. Diese müßten jedoch ebenfalls erst von der JAsn API unterstützt werden.
Speziell für die strukturierten ASN.1-Typen existieren einige weitere
Verbesserungsmöglichkeiten. Zum einen wäre es denkbar, in späteren
Versionen der gui4asn API die adäquate Behandlung optionaler
Komponenten zu ermöglichen. Zum anderen wäre es wünschenswert, wenn
sich Werteänderungen innerhalb der Oberflächenkomponenten nicht vor
einem Aufruf der Apply -Methode auf den Zustand der
zugrundeliegenden ASN.1-Objekte auswirken würden, indem zur Anzeige
am Bildschirm eine Kopie der eigentlichen Objektinstanz verwendet
wird.
Auch am äußeren Erscheinungsbild der
Oberflächenkomponenten könnten Verbesserungen vorgenommen werden. Denkbar
sind hier vor allem das Einfügen von Trennern bei strukturierten Typen zur
Erhöhung der Übersichtlichkeit. Im Hinblick auf ein einheitliches
Erscheinungsbild der gui4asn-Klassen auf unterschiedlichen Plattformen
sollte man desweiteren die Verwendung der Java Foundation
Classes (JFC)
in Erwägung ziehen, sobald deren
Entwicklung einen stabilen Zustand erreicht hat. Auf Basis der
Standard-AWT-Komponenten unterscheiden sich die generierten Applets
beispielsweise auf X11- und Microsoft Windows-Plattformen teilweise
erheblich, wie die Abbildungen 5.6 und
5.16 verdeutlichen.
Darüber hinaus wäre es auch möglich, die gui4asn-Beans dahingehend zu erweitern, daß man mit ihrer Hilfe innerhalb von Application Builder Tools ASN.1-Datentypen definieren kann. Zu diesem Zweck müßten die Beans in der Lage sein, einen Namen für die ASN.1-Struktur zu verwalten sowie ASN.1-Quelltext für das zugrundeliegende Objekt zu generieren.
Grundsätzlich sollten in den gui4asn-Klassen mehr Sicherheitsabfragen eingefügt werden. Vor allem die Behandlung eventuell auftretender Exceptions ist noch verbesserungs- und ausbaufähig.
Die gui4asn API ermöglicht in Verbindung mit dem ASN.1-Java-Compiler und der JAsn API die einfache Erstellung von plattformunabhängigen Applets zur Anzeige und Modifikation von ASN.1-Datenstrukturen, wie sie beispielsweise als Parameter für Protokollaufrufe im Netzmanagement benötigt werden. Dadurch wird die Verwendung von Informationen, die in ASN.1 spezifiziert wurden, deutlich vereinfacht und der Weg geebnet für die Entwicklung und den Einsatz komfortablerer Netzmanagementtools.
Durch die Realisierung der Programmierschnittstellen in Java können die ASN.1-Datenstrukturen auf beliebigen Rechnersystemen inspiziert und bearbeitet werden, denn mittlerweile gibt es für alle relevanten Plattformen eine Java-Laufzeitumgebung. Dieser Aspekt ist vor dem Hintergrund der Heterogenität der zu verwaltenden Netze von großer Bedeutung. Die Benutzer der auf Basis der gui4asn- und JAsn-Klassen entwickelten Software finden auf allen Systemen die gleiche Funktionalität vor und benötigen dadurch keine zusätzliche Einarbeitungszeit.
ASN.1-Datenstrukturen, vor allem im Bereich Netzmanagement, besitzen eine sehr hohe Komplexität. Deshalb ist es als weiterer Vorteil der gui4asn-Klassen zu betrachten, daß die mit dieser Programmierschnittstelle realisierten ASN.1-Applets vorkonfiguriert weitergegeben werden können. Dadurch ist die Möglichkeit gegeben, daß der Benutzer nur diejenigen Komponenten einer ASN.1-Datenstruktur modifizieren muß, mit denen er vertraut ist. Die übrigen Werte innerhalb der Struktur kann er unangetastet und somit in dem Zustand lassen, in den der Entwickler des ASN.1-Applets die Komponente versetzt hat.
Ein Ziel dieser Arbeit war es, die Eignung der JavaBeans-Architektur für die gegebene Aufgabenstellung zu untersuchen. Zusammenfassend kann man sagen, daß sich Suns Komponentenarchitektur für Java im gegebenen Umfeld bewährt hat. Die einfache Struktur des JavaBeans-Konzeptes ermöglicht einen einfachen Einstieg, erlaubt aber andererseits dem ambitionierten Benutzer auch ausreichend Entwicklungsmöglichkeiten.
Durch die Realisierung der Oberflächenklassen für ASN.1 auf Basis der JavaBeans-Architektur ergeben sich einige Vorteile. Zum einen wird die Verwendung der Komponenten in eigenen Applikationen durch die Beans-Unterstützung in Softwareentwicklungsumgebungen stark vereinfacht. Bestes Beispiel für diesen Aspekt ist die simple Erstellung von ASN.1-Applets mit Hilfe eines Application Builder Tools. Allerdings ist auch die Einbeziehung der Beans in komplexere Applikationen jederzeit möglich und auch denkbar. Dadurch kann bei der Erstellung von Tools, die ASN.1-Daten verarbeiten sollen, viel Entwicklungsaufwand eingespart werden.
Zum anderen ergibt sich auch durch den Ansatz der Plattformunabhängigkeit, der mit der JavaBeans API verfolgt wird, ein geringerer Entwicklungs- und Wartungsaufwand, denn die gewünschte Software muß nur noch einmal und nicht für jede verwendete Rechnerplattform separat erstellt und gewartet werden. Die zusätzliche Reduzierung des Einarbeitungs- und Schulungsaufwands wurde bereits angesprochen.
Mit der gui4asn API liegt ein Prototyp vor, der aufzeigt, wie eine auf der JavaBeans-Architektur basierende generische ASN.1-Oberfläche aussehen könnte. Es liegt nun an den Verwendern, etwaige Schwachstellen und Probleme der gui4asn-Klassen zu identifizieren. Darüber hinaus kann die API, wie in Kapitel 5.5 aufgezeigt, durchaus noch erweitert werden.
Aufbauend auf den Ergebnissen dieser Diplomarbeit kann man sich in Java realisierte Netzmanagementtools sehr gut vorstellen. Die genannten Vorteile dieser Programmiersprache sind evident, mit der JavaBeans-Architektur kommt ein weiteres Argument für die Verwendung von Java hinzu.
Inwieweit sich Java auch in großen Projekten bewährt, muß die Praxis zeigen. Evtl. ist hier auch ein Zusammenspiel verschiedener Programmierumgebungen denkbar. So kann man sich beispielsweise sehr gut vorstellen, zentrale Managementapplikationen aufgrund der Performancevorteile in C++ zu realisieren, die graphische Oberfläche jedoch in Java zu imlementieren, um Vorteile wie die Plattformunabhängigkeit oder die einfache Einbindung von JavaBeans-Komponenten zu nutzen. In solch einer Architektur würden die gui4asn-Klassen mit Sicherheit ihren Platz finden.
In diesem Anhang soll beispielhaft eine einfache BeanInfo-Klasse vorgestellt werden. Diese Klasse beschreibt die folgende simple Komponente MyBean :
public class MyBean {
protected int classStatus;
public int getClassStatus() {
return classStatus;
}
public void setClassStatus(int newStatus) {
classStatus = newStatus;
}
}
Die zu dieser Komponente gehörende BeanInfo-Klasse MyBeanBeanInfo beschreibt lediglich die in MyBean enthaltenenen Properties, Methoden und Ereignisse. Darüber hinaus wird für die Komponente ein Icon bereitgestellt. Dieses kann als Symbol innerhalb von Application Builder Tools o.ä. benutzt werden.
import java.beans.*;
import java.lang.reflect.*;
public class MyBeanBeanInfo extends java.beans.SimpleBeanInfo {
/**
* Liefert die Beans-Klasse.
*/
public static Class getBeanClass() {
return MyBean.class;
}
/**
* Liefert den Namen des Beans.
*/
public static String getBeanClassName() {
return "MyBean";
}
/**
* Liefert den Bean Descriptor.
*/
public BeanDescriptor getBeanDescriptor() {
BeanDescriptor aDescriptor = null;
/* Bean Descriptor fuer MyBean wird erzeugt und zurueckgegeben. */
aDescriptor = new BeanDescriptor(MyBean.class);
aDescriptor.setDisplayName("MyBean");
aDescriptor.setShortDescription("MyBean");
return aDescriptor;
}
/**
* Liefert die Methodenbeschreibungen fuer diese Komponente.
*/
public MethodDescriptor[] getMethodDescriptors() {
try {
/* Diese Komponente besitzt die Methoden getClassStatus und
setClassStatus. */
/* Fuer diese Methoden werden Deskriptoren erzeugt und
zurueckgegeben. */
MethodDescriptor aDescriptorList[] = {
getClassStatusMethodDescriptor(),
setClassStatus_intMethodDescriptor()
};
return aDescriptorList;
} catch (Exception e) {
return super.getMethodDescriptors();
}
}
/**
* Liefert die Attributbeschreibungen fuer diese Komponente.
*/
public PropertyDescriptor[] getPropertyDescriptors() {
try {
/* Diese Komponente besitzt das Attribut classStatus. */
/* Fuer dieses Attribut wird ein Deskriptor erzeugt und
zurueckgegeben. */
PropertyDescriptor aDescriptorList[] = {
classStatusPropertyDescriptor()
};
return aDescriptorList;
} catch (Exception e) {
return super.getPropertyDescriptors();
}
}
/**
* Liefert den Property Descriptor fuer das Attribut classStatus.
*/
public PropertyDescriptor classStatusPropertyDescriptor()
throws NoSuchMethodException, IntrospectionException {
PropertyDescriptor aDescriptor = null;
/* Suchen der Get-Methode zum lesenden Zugriff auf das Attribut */
/* Get-Methode hat keine Parameter. */
Class aGetMethodParameterTypes[] = {};
Method aGetMethod = null;
aGetMethod = getBeanClass().getMethod("getClassStatus",
aGetMethodParameterTypes);
/* Suchen der Set-Methode zum schreibenden Zugriff auf das Attribut */
/* Set-Methode hat einen Parameter vom Typ int. */
Class aSetMethodParameterTypes[] = { int.class };
Method aSetMethod = null;
aSetMethod = getBeanClass().getMethod("setClassStatus",
aSetMethodParameterTypes);
/* Erzeugen eines Property Descriptors anhand der vorhandenen
Informationen. */
aDescriptor = new PropertyDescriptor("classStatus", aGetMethod,
aSetMethod);
return aDescriptor;
}
/**
* Liefert den Method Descriptor fuer getClassStatus().
*/
public MethodDescriptor getClassStatusMethodDescriptor()
throws NoSuchMethodException {
MethodDescriptor aDescriptor = null;
/* getClassStatus hat keine Parameter. */
Class aParameterTypes[] = {};
/* Suchen der Methode getClassStatus. */
Method aMethod = null;
aMethod = getBeanClass().getMethod("getClassStatus", aParameterTypes);
/* Erzeugen eines Method Descriptors anhand der vorhandenen
Informationen. */
ParameterDescriptor aParameterDescriptors[] = {};
aDescriptor = new MethodDescriptor(aMethod, aParameterDescriptors);
return aDescriptor;
}
/**
* Liefert den Method Descriptor fuer setClassStatus(int).
*/
public MethodDescriptor setClassStatus_intMethodDescriptor()
throws NoSuchMethodException {
MethodDescriptor aDescriptor = null;
/* setClassStatus(int) hat einen Parameter vom Typ int. */
Class aParameterTypes[] = { int.class };
/* Suchen der Methode setClassStatus. */
Method aMethod = null;
aMethod = getBeanClass().getMethod("setClassStatus", aParameterTypes);
/* Erzeugen eines Method Descriptors anhand der vorhandenen
Informationen. */
ParameterDescriptor aParameterDescriptor1 = new ParameterDescriptor();
aParameterDescriptor1.setName("arg1");
aParameterDescriptor1.setDisplayName("newStatus");
ParameterDescriptor aParameterDescriptors[] = { aParameterDescriptor1 };
aDescriptor = new MethodDescriptor(aMethod, aParameterDescriptors);
return aDescriptor;
}
/**
* Liefert die von dieser Komponente unterstuetzten Ereignisse.
*/
public EventSetDescriptor[] getEventSetDescriptors() {
/* Diese Bean unterstuetzt keine Ereignisse. */
EventSetDescriptor aDescriptorList[] = { };
return aDescriptorList;
}
/**
* Liefert ein Icon fuer diese Komponente.
*/
public java.awt.Image getIcon(int iconKind) {
java.awt.Image image = null;
/* Das Icon "ICON.GIF" wird geladen und zurueckgegeben. */
if (iconKind == BeanInfo.ICON_COLOR_16x16) {
image = loadImage("ICON.GIF");
};
return image;
}
}
Nachfolgend soll anhand einer einfachen PropertyEditor-Klasse die Verwendung dieser JavaBeans-Hilfsklassen illustriert werden.
Die Klasse DimensionEditor realisiert einen PropertyEditor für die Standard-AWT-Klasse Dimension , die innerhalb der gui4asn API zur Beschreibung der Größe von Komponenten der Typen SequenceGui, SequenceOfGui, SetGui und SetOfGui verwendet wird.
Dimension besitzt zwei Attribute: eine Breite und eine Höhe. DimensionEditor ermöglicht nun die Ein- und Ausgabe dieser Werte in Form von Strings der Form ,,Breite/Höhe``. Durch diese Umsetzung von Dimension-Objekten in Strings und umgekehrt können Bean-Attribute vom Typ Dimension innerhalb der Property Sheets von Application Builder Tools bearbeitet werden.
package gui4asn;
import java.awt.*;
import java.beans.*;
/**
* DimensionEditor implements a simple PropertyEditor for the
* java.awt.Dimension datatype.
* With DimensionEditor it is possible to edit attributes of type
* java.awt.Dimension within the PropertySheet of Application Builder Tools
* supporting JavaBeans.
*
* @author Dieter Heiliger
* @since JDK1.1
*/
public class DimensionEditor extends PropertyEditorSupport {
/**
* Delivers the width and height of a java.awt.Dimension object as string.
* The format of the string is 'x/y', x being the width and y being
* the height (as expected).
*/
public String getAsText( ) {
Dimension d = (Dimension) getValue();
if(d != null)
return d.width + "/" + d.height;
else
return "null";
}
/**
* delivers the JavaInitializationString which is very important
* for Application Builder Tools
* @return java.lang.String the JavaInitializationString
*/
public String getJavaInitializationString( ) {
Dimension d = (Dimension) getValue();
return "new Dimension(" + d.width + "," + d.height + ")";
}
/**
* Assigns a value to an attribute of type java.awt.Dimension.
*
* <p> This methods gets a string of the form 'x/y', anlyses this
* string, creates an appropriate Dimension object and assigns this
* object to the attribute of type java.awt.Dimension.
*
* @param s a string containing width and height of the desired dimension
* in the form 'x/y'
*/
public void setAsText(String s) {
if(s.length() > 0) {
String s1 = null, s2 = null;
int x,y;
int index = s.indexOf("/");
if(index > 0) {
s1 = s.substring(0, index);
s2 = s.substring(index+1, s.length());
x = Integer.parseInt(s1);
y = Integer.parseInt(s2);
setValue(new Dimension(x,y));
}
}
}
}
This document was generated using the LaTeX2HTML translator Version 97.1 (release) (July 13th, 1997)
Copyright © 1993, 1994, 1995, 1996, 1997, Nikos Drakos, Computer Based Learning Unit, University of Leeds.
The command line arguments were:
latex2html -split 1 -show_section_numbers -html_version 3.2,table -local_icons -dir html da.
The translation was initiated by Dieter Heiliger on 2/26/1998