Projektstudium SS98 - distributed computing


 

Eine erste Java/CORBA-Anwendung

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.

 

Die Count Anwendung

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.

 

Die einzelnen Entwicklungsschritte

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:

  1. Schreiben einer Spezifikation für jedes Objekt in OMG IDL.
  2. Generierung des Client Stub Codes und des Server Skeleton Codes mit Hilfe eines IDL Compilers.
  3. Schreiben der Objekt Implementation
  4. Schreiben des Objekt Server Codes.
  5. Schreiben des Client Codes.
  6. Compilieren des Client und Server Codes.
  7. Starten des Servers.
  8. Starten des Clients.

 

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. 

 

Die Count Idl Definition

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:

 

Listing 1: Count.IDL: CORBA IDL Definition des Count Interfaces


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.

 

Mapping CORBA IDL nach Java

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:

 

Counts Server Seite

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:

 

Listing 2: CountImpl: Die Count Implementation


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:

  1. Initialisierung des ORB
  2. Initialisierung der BOA
  3. Erzeugung eines CountImpl Objektes
  4. Exportieren der neuen erzeugten Objekte an den ORB
  5. Warten auf Anfragen

 

Abbildung 2: Objekt Interaktions Diagramm für die Server Seite von Count

 

Listing 3: CountServer: Das Main Server Programm:


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.

 

Die Client Seite von Count

Das Client Programm besteht aus einer einzigen Java Klasse-CountClient. Diese Klasse beinhaltet die main Methode. Die folgenden Funktionen müssen verrichtet werden:

  1. Initialisierung des ORB
  2. Lokalisierung des remote Count Objekts
  3. Setzen des remote sum Attributs auf null
  4. Ermittlung der Startzeit
  5. 1000maliger Aufruf der Methode increment
  6. Berechnung der vergangenen Zeit
  7. Ausgabe des Ergebnisses

 

Abbildung 3: Objekt Interaktionsdiagramm für die Client Seite von Count

 

Listing 4: CountClient: Das Client Programm


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.

 

Compilierung & Start des Programmes

 

Compilierung


Prompt> vbjc CountClient.java

Prompt> vbjc CountServer.java

Prompt> vbjc CountImpl.java


 

Start


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:

nächste Seite 


© Copyright 1998 André Möller, Oliver Mentz & Magnus Wiencke