In diesem Abschnitt wird eine erste Java/CORBA-Anwendung entwickelt, was anhand des JDK 1.16 und Visibroker 3.1 geschildert wird. Daher können bei anderen Versionen leichte Abweichungen vorhanden sein.
Ziel ist es, einen Eindruck von der Entwicklung von verteilten Anwendungen mit Java und CORBA zu vermitteln.
Als Beispiel soll ein Zähler Objekt auf das über einen Server und ein ORB zugegriffen wird, dienen. Der Zähler wird inkrementiert und dabei die Zeit stoppen, die zwischen dem Aufruf und der Antwort vergeht.
Bei der Entwicklung einer Anwendung müssen zunächst die einzelnen Objekte, die für die Anwendung benötigt werden, identifiziert werden. Danach werden die folgenden Schritte durchlaufen:
In dem Count Beispiel werden die folgenden Objekte benötigt:
Die Entwicklungsschritte sehen grafisch dann wie folgt aus:
Abbildung 1:
Die Entwicklungsschritte, die ein Java/CORBA Programm durchläuft.
Bevor das Interface geschrieben werden kann, muß festgelegt werden, welche Funktionalität im einzelnen das Count Objekt zur Verfügung stellen soll.:
Es soll die Möglichkeit bestehen einen Zähler setzen, inkrementieren und lesen zu können.
Diese Überlegungen führen zum folgendem Interface:
module Counter {
interface Count {
attribute long sum;
long increment();
};
};
Die CORBA IDL Syntax sieht der von Java oder C++ sehr ähnlich. Ein module
ist das CORBA Äquivalent zu einem package
in Java beziehungsweise einer namespace
in C++. Es ist ein Namensraum für eine Menge von verwandten Interfaces. Die einzelnen Namen müssen innerhalb eines module
einzigartig sein.
Nachdem eine IDL Datei vorhanden ist, muß es nach etwas, das von Java Clients und Servern verstanden werden kann, transformiert werden. Deswegen wird ein IDL-to-Java Compiler benötigt. Im folgenden wird dafür der Visibroker idl2java Compiler verwendet:
Prompt> idl2java count.idl -no_comments -no_tie
CORBA unterstützt zwei verschiedene Programmierstile. Inheritance-based und delegation-based. Win den meisten Beispielen wird der Inheritance-based Stil angewendet. Gewöhnlich wird der delegation-style zur Integration von Code, der in einer Nicht-OO Sprache geschrieben wurden ist, verwendet. Die -no_tie Option weist den IDL Compiler an, keine speziellen Delegations Klassen zu erzeugen. Der idl2java Compiler erzeugt auch ohne diesen Klassen bereits ein Java package, das sechs Java Klassen und ein Interface beinhaltet:
Count
generiert. Diese Klasse bringt das Java und CORBA Objektmodell zusammen. Dies geschieht indem sie ein Java Objekt ist, das zusätzlich das Java org.omg.CORBA.Object Interface
(OMG nennt es CORBA::Object
) implementiert. Dies ist die CORBA Wurzelklasse. Sämtliche CORBA Objekte müssen es implmentieren. Die Count
Implementation wird einfach diese duale Funktionalität durch Erweiterung der vom Compiler generierten _CountImplBase
Klasse erben. Count
Objekt Implementation. Sie enthält Konstruktoren und Beispiel Methoden für das sum
Attribut und die increment()
Methode. Mit diesem Beispiel als Ausgangspunkt ist es einfach die Count
Objekt Implementation zu vervollständigen. _CountImplBase
zu ersetzen. Count
Clients bietet. Count
hält. Sie wird zur Übergabe von Objekten des Typs Count
als out
oder inout
Parameter innerhalb des Methodenaufrufs verwendet.
Jeder CORBA Server muß eine Art Hauptprogarmm besitzen, das die ORB Umgebung initialisiert und die Objekte startet. Im folgenden wird eine Klasse CountServer, die diese Hauptfunktion besitzt, geschrieben. Zusätzlich muß der Server die Implementationen der CORBA Interfaces, die in IDL definiert sind, dem Client zur Verfügung stellen. In diesem Fall muß nur ein Interface implementiert werden: Counter.Count. Deswegen müssen nur zwei Klassen seitens des Servers geschrieben werden. Die Implmentation wird in einer Klasse CountImpl geschrieben.
Bei dem CORBA Inheritance Model wird die Server Implementation immer von der entsprechenden XXXImplBase Klasse hergeleitet. Dadurch erbt die Implementationsklasse die Funktionalität sowohl von dem CORBA als auch vom Java Objektmodell. Außerdem wird die Skeleton Funktion von dieser Klasse geerbt. Dies sind Up-Calls, die es dem ORB erlauben, automatisch die Methoden des Objektes aufzurufen. Es muß kein dispatching Code geschrieben werden. Deswegen muß lediglich das Counter.Count Interface implementiert werden. Am einfachsten ist es, Counter.example_Count als Basis zu nehmen. Im folgendem ist eine Beispiel Implementation zu sehen:
class CountImpl extends Counter._CountImplBase {
//Das Attribut, das inkrementiert wird.
private int sum;
//Der Konstruktor
CountImpl(String name) {
super(name);
System.out.println("Count Object Created");
sum = 0;
}
//liefert den Wert von sum zurück
public int sum() {
return sum;
}
//weist dem Attribut sum einen anzugebenen Wert zu
public void sum(int val) {
sum = val;
}
//inkrementiert sum
public int increment() {
sum++;
return sum;
}
}
Zusätzlich zu dem Count Interface Funktionen wurde ein Konstruktor für die CountImpl Klasse implementiert. Der Konnstruktor ruft seine Superklasse-in disem Fall ist es die Skeleton Klasse-auf, um eine Objektimplementation mit Namen zu erzeugen. Diesführt dazu, daß jede Instanz von CountImpl einen persistenten Namen besitzt. Wenn ein super
ohne Argumente aufgerufen wird, werden transiente Objekte erzeugt.
Nun muß der CountServer implementiert werden. Es ist die Klasse, die die Hauptfunktion der Server Seite bietet. Wenn nur einem Objekt benutzt wird, wirkt die Klasse wie eine Menge Overhead. In einer realistischeren Situation, werden mehrere Objekte, von denen jedes in seinem eigenen Thread läuft, zu managen sein. In der simpelsten Form muß das folgendes geleistet werden:
Abbildung 2:
Objekt Interaktions Diagramm für die Server Seite vonCount
class CountServer {
static public void main(String[] args) {
try {
//Initialisierung des ORB
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);
//Initialisierung des BOA
org.omg.CORBA.BOA boa = orb.BOA_init();
//Erzeugen eines Count Objektes
CountImpl count = new CountImpl("My Count");
//Exportieren des neu erzeugten Objektes an den ORB
boa.obj_is_ready(count);
//Warten auf Anfragen
boa.impl_is_ready();
}
catch(org.omg.CORBA.SystemException e) {
System.err.println(e);
}
}
}
Die org.omg.ORB Klasse ist Teil der VisiBroker Run Time. Es implementiert die meisten Funktionen, die die OMG im CORBA::ORB
Interface spezifiziert. Es sollte beachtet werden, daß org.omg.CORBA.ORB.init
eine Java Klassen Methode ist. Die Methode gibt ein Objekt des Typs org.omg.CORBA.ORB
zurück Diese Methode versetztet den Entwickler in die Lage, Argumente via command line des Hauptprogrammes zu übergeben, wodurch bestimmte Eigenschaften zur Laufzeit gesetzt werden können. Wir haben nun eine Referenz zum VisiBroker ORB Objekt, die zur Initialisierung des BOAs aufgerufen werden kann. Der BOA_init
Aufruf liefert eine Referenz für einen BOA. Danach wird diese Referenz zur Registrierung des neu erzeugten CountImpl
Objektes. Schließlich wird dem BOA mitgeteilt, daß das Objekt bereit für Anfragen ist. Die Server Seite ist nun komplett. Es sollte beachtet werden, daß keine Endlosschleife geschrieben werden mußte. CORBA und der BOA bieten diese Funktion automatisch. Es müssen lediglich die Interfaces implementiert und beim ORB via BOA registriert werden.
Das Client Programm besteht aus einer einzigen Java Klasse-CountClient. Diese Klasse beinhaltet die main
Methode. Die folgenden Funktionen müssen verrichtet werden:
Count
Objektssum
Attributs auf nullincrement
Abbildung 3:
Objekt Interaktionsdiagramm für die Client Seite von Count
class CountClient {
public static void main(String args[]) {
try {
//Initialisierung des ORB
System.out.println("Initializing the ORB");
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);
//Binden an das Count Objekt
System.out.println("Binding to Count Object");
Counter.Count counter = Counter.CountHelper.bind(orb, "My Count");
//Initialisieren des sum-Attributes
System.out.println("Setting sum to 0");
counter.sum((int)0);
//Startzeit ermitteln
long startTime = System.currentTimeMillis();
//1000 mal sum inkrementieren
System.out.println("Incrementing");
for (int i = 0; i < 1000; i++)
counter.increment();
//Kalkulation der vergangenen Zeit und Ausgabe der Ergebnisse
long stopTime = System.currentTimeMillis();
System.out.println("Avg Ping = "
+ ((stopTime - startTime)/1000f) + "msecs");
System.out.println("Sum = " + counter.sum());
}
catch(org.omg.CORBA.SystemException e) {
System.err.println("System Exception");
System.err.println(e);
}
}
}
Hieran ist zu erkenenn, wie einfach es ist, ein remote Objekt aufzurufen. Es ist einfach der Aufruf eines lokalen Java Objektes. Zudem ist es genau so einfach das Attribut sum
zu manipulieren.
Selbstverständlich muß zunächst eine Objektreferenz beschafft werden. Dies geschieht mit der bind Methode der Counter.CountHelper Klasse.
Es sollte beachtet werden, daß Entwickler in der Lage sind, durch einen Namen ein bestimmtes Objekt spezifizieren zu können.
Prompt> vbjc CountClient.java
Prompt> vbjc CountServer.java
Prompt> vbjc CountImpl.java
Prompt> start osagnet -c
Zunächst muß der VisiBroker OSAgent gestartet werden. Dadurch werden Directory Services und Fehlerbehandlungsroutinen bereitgestellt.
Prompt> start vbj CountServer
Danach wird der Server gestartet.
Prompt> vbj CountClient
Die Quellen:
© Copyright 1998 André Möller, Oliver Mentz & Magnus Wiencke