10. Entwicklung verteilter Anwendungen CORBA
10.1. Einführung
Im vorigen Kapitel haben wir gesehen, wie man mit dem Paket RMI verteilte Anwendungen in Java erstellt. Hier befassen wir uns mit demselben Problem, diesmal jedoch mit der CORBA-Architektur. CORBA (Common Object Request Broker Architecture) ist eine Spezifikation, die von der OMG (Object Management Group) definiert wurde, einem Zusammenschluss zahlreicher Unternehmen aus der IT-Branche. CORBA definiert einen „Software-Bus“, auf den Anwendungen zugreifen können, die in verschiedenen Sprachen geschrieben sind:

Wir werden sehen, dass die Erstellung einer verteilten Anwendung mit CORBA der bei Java RMI verwendeten Methode sehr ähnlich ist: Die Konzepte sind vergleichbar. CORBA bietet den Vorteil der Interoperabilität mit Anwendungen, die in anderen Sprachen geschrieben sind.
10.2. Entwicklungsprozess einer CORBA-Anwendung
10.2.1. Einleitung
Um eine Client-Server-Anwendung CORBA zu entwickeln, gehen wir wie folgt vor:
- Erstellung der Server-Schnittstelle mit IDL (Interface Definition Language)
- Generierung der „Skelett“- und „Stub“-Klassen des Servers
- Erstellung des Servers
- Erstellung des Clients
- Kompilierung aller Klassen
- Starten eines Verzeichnisses der Dienste CORBA
- Starten des Servers
- Starten des Clients
Als erstes Beispiel nehmen wir den Echo-Server, der bereits im Kontext RMI verwendet wurde. So kann der Leser die Unterschiede zwischen den beiden Methoden erkennen.
Die Anwendung wurde mit jdk1.2 getestet.
10.2.2. Erstellung der Server-Schnittstelle
Wie bei Java RMI wird der Server gegenüber dem Client durch seine Schnittstelle definiert. Auch wenn die Klassen, die den Server implementieren, für den Client nicht erforderlich sind, so sind doch die Klassen seiner Schnittstelle notwendig. Während Java RMI eine Java-Schnittstelle verwendete, aus der die „Skelett“- und „Stub“-Klassen des Servers hervorgingen, erfordert die Architektur von Java CORBA die Beschreibung der Schnittstelle in einer anderen Sprache als Java. Aus dieser Schnittstelle entstehen mehrere Klassen, von denen einige vom Client, andere vom Server verwendet werden.
Die Beschreibung der Echo-Schnittstelle lautet wie folgt:
Die Beschreibung der Schnittstelle wird in einer Datei namens echo.idl gespeichert. Sie ist in der Sprache IDL (Interface Definition Language) des OMG verfasst. Um verwertbar zu sein, muss sie von einem Programm analysiert werden, das Quelldateien in der Sprache erstellt, die zur Entwicklung der Anwendung CORBA verwendet wird. Hier verwenden wir das Programm idltojava.exe, das ausgehend von der vorangegangenen Schnittstelle die für die Anwendung erforderlichen Quelldateien .java erstellt. Das Programm idltojava.exe ist nicht im Lieferumfang von JDK enthalten. Es kann auf der Website von Sun unter http://java.sun.com heruntergeladen werden.
Betrachten wir die wenigen Zeilen der oben gezeigten Schnittstelle idl:
entspricht dem Java-Paket „echo“. Durch die Kompilierung der Schnittstelle entsteht das Java-Paket echo c.a.d – ein Verzeichnis, das Java-Klassen enthält.
entspricht der Java-Schnittstelle „iSrvEcho“. Daraus entsteht eine Java-Schnittstelle.
entspricht der Java-Anweisung **String echo(String msg)**. Die Typen der Sprache IDL stimmen nicht genau mit denen der Sprache Java überein. Die Entsprechungen finden Sie etwas weiter unten in diesem Kapitel. In der Sprache IDL können die Parameter einer Funktion Eingabeparameter (in), Ausgabeparameter (out) oder Ein- und Ausgabeparameter (inout) sein. Hier erhält die Methode echo einen Eingabeparameter msg, bei dem es sich um eine Zeichenkette handelt, und gibt als Ergebnis eine Zeichenkette zurück.
Die vorstehende Schnittstelle ist die unseres Echo-Servers. Zur Erinnerung: Eine Remote-Schnittstelle beschreibt die Methoden des Serverobjekts, auf die Clients zugreifen können. Hier steht den Clients nur die Methode echo zur Verfügung.
10.2.3. Kompilierung der Server-Schnittstelle IDL
Sobald die Server-Schnittstelle definiert ist, werden die entsprechenden Java-Dateien generiert.
E:\data\java\corba\ECHO>dir *.idl
ECHO IDL 78 15/03/99 13:56 ECHO.IDL
E:\data\java\corba\ECHO>d:\javaidl\idltojava.exe -fno-cpp echo.idl
Die Option -fno-cpp dient dazu, anzugeben, dass kein Präprozessor verwendet werden soll (wird meist bei C/C++ verwendet). Die Kompilierung der Datei echo.idl erzeugt ein Unterverzeichnis echo, das die folgenden Dateien enthält:
E:\data\java\corba\ECHO>dir echo
_ISRVE~1 JAV 1 095 17/03/99 17:19 _iSrvEchoStub.java
ISRVEC~1 JAV 311 17/03/99 17:19 iSrvEcho.java
ISRVEC~2 JAV 825 17/03/99 17:19 iSrvEchoHolder.java
ISRVEC~3 JAV 1 827 17/03/99 17:19 iSrvEchoHelper.java
_ISRVE~2 JAV 1 803 17/03/99 17:19 _iSrvEchoImplBase.java
Die Datei iSrvEcho.java ist die Java-Datei, die die Server-Schnittstelle beschreibt:
/* * Datei: ./ECHO/ISRVECHO.JAVA * Von: ECHO.IDL * Datum: Mo, 15. März 13:56:08 1999 * Von: D:\JAVAIDL\IDLTOJ~1.EXE Java IDL 1.2 18. Aug. 1998 16:25:34 */
package echo;
public interface iSrvEcho
extends org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity {
String echo(String msg)
;
}
Man sieht, dass es sich fast um eine wörtliche Übersetzung der Schnittstelle IDL handelt. Wenn man neugierig ist und sich den Inhalt der anderen Dateien .java ansieht, findet man komplexere Dinge. Hier ist, was die Dokumentation über die Rolle dieser verschiedenen Dateien sagt:
die Server-Schnittstelle
implementiert die oben genannte Schnittstelle iSrvEcho. Es handelt sich um eine abstrakte Klasse, das „Gerüst“ des Servers, das dem Server die für die verteilte Anwendung erforderlichen Funktionen CORBA bereitstellt.
Dies ist das „Stub“-Image des Servers, das vom Client verwendet wird. Es stellt dem Client die Funktionen von CORBA zur Verfügung, um den Server zu erreichen.
Stellt die für die Verwaltung von Objektverweisen erforderlichen Methoden bereit: CORBA
Stellt die erforderlichen Methoden zur Verwaltung der Ein- und Ausgabeparameter der Methoden der Schnittstelle bereit.
10.2.4. Kompilierung der aus der Schnittstelle IDL generierten Klassen
Es empfiehlt sich, die oben genannten Klassen zu kompilieren. In einem anderen Beispiel werden wir sehen, dass hier Fehler aufgrund einer fehlerhaften Funktionsweise des Generators idltojava entdeckt werden können. Hier läuft alles reibungslos, und nach der Kompilierung befinden sich im Verzeichnis des Pakets echo die folgenden Dateien:
E:\data\java\corba\ECHO\echo>dir
_ISRVE~1 JAV 1 095 17/03/99 17:19 _iSrvEchoStub.java
ISRVEC~1 JAV 311 17/03/99 17:19 iSrvEcho.java
ISRVEC~2 JAV 825 17/03/99 17:19 iSrvEchoHolder.java
ISRVEC~3 JAV 1 827 17/03/99 17:19 iSrvEchoHelper.java
_ISRVE~2 JAV 1 803 17/03/99 17:19 _iSrvEchoImplBase.java
_ISRVE~1 CLA 2 275 18/03/99 11:25 _iSrvEchoImplBase.class
_ISRVE~2 CLA 1 383 18/03/99 11:25 _iSrvEchoStub.class
ISRVEC~1 CLA 251 18/03/99 11:25 iSrvEcho.class
ISRVEC~2 CLA 2 078 18/03/99 11:25 iSrvEchoHelper.class
ISRVEC~3 CLA 858 18/03/99 11:25 iSrvEchoHolder.class
10.2.5. Server-Eintrag
10.2.5.1. Implementierung der Schnittstelle iSrvEcho
Wir haben oben die Schnittstelle iSrvEcho definiert. Nun schreiben wir die Klasse, die diese Schnittstelle implementiert. Sie wird von der Klasse _iSrvEchoImplbase.java abgeleitet, die, wie oben angegeben, bereits die Schnittstelle iSrvEcho implementiert.
// importierte Pakete
import echo.*;
// Klasse, die das Remote-Echo implementiert
public class srvEcho extends _iSrvEchoImplBase{
// Methode zur Umsetzung des Echos
public String echo(String msg){
return "[" + msg + "]";
}// Ende des Echos
}// Ende der Klasse
Der Code ist selbsterklärend. Diese Klasse wird in der Datei srvEcho.java im übergeordneten Verzeichnis des Pakets der Schnittstelle iSrvEcho gespeichert.
Zur Überprüfung kann man kompilieren:
E:\data\java\corba\ECHO>j:\jdk12\bin\javac srvEcho.java
E:\data\java\corba\ECHO>dir
ECHO IDL 78 15/03/99 13:56 ECHO.IDL
SRVECH~1 CLA 488 18/03/99 11:30 srvEcho.class
SRVECH~1 JAV 252 15/03/99 14:02 srvEcho.java
ECHO <REP> 17/03/99 17:19 echo
10.2.5.2. Eintrag der Server-Erstellungsklasse
Wie bei einer Client-Server-Anwendung RMI muss ein Server CORBA in einem Verzeichnis registriert werden, damit er für Clients zugänglich ist. Dieser Registrierungsvorgang unterscheidet sich auf der Entwicklungsebene je nachdem, ob es sich um eine CORBA- oder eine RMI-Anwendung handelt. Hier ist das Echo des Servers CORBA, das in der Datei serveurEcho.java gespeichert ist:
// importierte Pakete
import echo.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
//----------- Klasse serveurEcho
public class serveurEcho{
// ------- main: startet den Echo-Server
// PG-Syntax machineAnnuaire portAnnuaire nomService
// Rechner: Rechner, der das Verzeichnis unterstützt CORBA
// Port: Port des Verzeichnisses CORBA
// nomService: Name des zu registrierenden Dienstes
public static void main(String arg[]){
// Sind die Argumente vorhanden?
if(arg.length!=3){
System.err.println("Syntaxe : pg machineAnnuaire portAnnuaire nomService");
System.exit(1);
}
// Die Argumente werden abgerufen
String machine=arg[0];
String port=arg[1];
String nomService=arg[2];
try{
// Wir benötigen ein Objekt CORBA, um weiterarbeiten zu können
String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
ORB orb=ORB.init(initORB,null);
// Der Dienst wird in das Dienstverzeichnis aufgenommen
// Er wird srvEcho heißen
org.omg.CORBA.Object objRef=
orb.resolve_initial_references("NameService");
NamingContext ncRef=NamingContextHelper.narrow(objRef);
NameComponent nc= new NameComponent(nomService,"");
NameComponent path[]={nc};
// Wir erstellen den Server und ordnen ihn dem Dienst srvEcho zu
srvEcho serveurEcho=new srvEcho();
ncRef.rebind(path,serveurEcho);
orb.connect(serveurEcho);
// Weiterverfolgung
System.out.println("Serveur d'écho prêt");
// Warten auf Client-Anfragen
java.lang.Object sync=new java.lang.Object();
synchronized(sync){
sync.wait();
}
} catch(Exception e){
// Es ist ein Fehler aufgetreten
System.err.println("Erreur " + e);
e.printStackTrace(System.err);
}
}// Hauptprozess
}// serveurEcho
Im Folgenden erläutern wir die Grundzüge der Inbetriebnahme des Servers, ohne auf Details einzugehen, die auf den ersten Blick komplex erscheinen. Behalten Sie die Grundzüge des vorangegangenen Beispiels im Hinterkopf, da diese bei jedem CORBA-Server wiederkehren.
10.2.5.2.1. Die Serverparameter
Ein CORBA-Server muss sich bei einem Verzeichnisdienst registrieren, der auf einem bestimmten Rechner und einem bestimmten Port läuft. Unsere Anwendung erhält diese beiden Daten als Parameter. Der so registrierte Dienst muss einen Namen tragen; dies ist der dritte Parameter.
10.2.5.2.2. Erstellen des Zugriffsobjekts auf den Verzeichnisdienst CORBA
Um den Verzeichnisdienst zu erreichen und unseren Echo-Server zu registrieren, benötigen wir ein Objekt namens ORB (Object Request Broker), das mit der folgenden Klassenmethode abgerufen wird:
Args : tableau de paires de chaînes de caractères, chaque paire étant de la forme (paramètre,valeur)
Prop : propriétés de l’application
Das Beispiel verwendet die folgende Sequenz, um das Objekt ORB abzurufen:
String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
ORB orb=ORB.init(initORB,null);
Die verwendeten (Parameter, Wert)-Paare lauten wie folgt:
("-ORBInitialHost",machine) : ce couple précise la machine ou opère l’annuaire des services CORBA, ici la machine passée en paramètre au serveur.
("-ORBInitialPort",port ) : ce couple précise le port ou opère l’annuaire des services CORBA, ici le port passé en paramètre au serveur.
Der zweite Parameter der Methode init wird auf null gesetzt. Hätte man auch den ersten Parameter auf null gesetzt, wäre das verwendete Paar (Rechner, Port) standardmäßig (localhost,900) gewesen.
10.2.5.2.3. Den Server im Dienstverzeichnis registrieren CORBA
Die Registrierung des Servers im Verzeichnis erfolgt mit den folgenden Schritten:
// Der Dienst wird in das Dienstverzeichnis aufgenommen
// Er wird srvEcho heißen
org.omg.CORBA.Object objRef=
orb.resolve_initial_references("NameService");
NamingContext ncRef=NamingContextHelper.narrow(objRef);
NameComponent nc= new NameComponent(nomService,"");
NameComponent path[]={nc};
// Der Server wird erstellt und dem Dienst srvEcho zugeordnet
srvEcho serveurEcho=new srvEcho();
ncRef.rebind(path,serveurEcho);
orb.connect(serveurEcho);
Der erste Teil des Codes dient der Vorbereitung des Dienstnamens. Dieser Name wird im Code durch die Variable „path“ symbolisiert. Der Name eines Dienstes besteht aus mehreren Komponenten:
- eine Ausgangskomponente objRef, ein generisches Objekt, das auf einen Typ NamingContext reduziert werden muss, in diesem Fall ncRef.
- den Namen des Dienstes, hier nomService, der als Parameter an den Server übergeben wurde
Diese Bestandteile des Namens (NameComponent) werden in einem Array zusammengefasst, hier path. Dieses Array „benennt“ den erstellten Dienst eindeutig. Sobald der Name erstellt ist, muss er noch
- ihn einer Instanz des Servers zuzuordnen (die zuvor erstellte Klasse srvEcho)
srvEcho serveurEcho=new srvEcho();
- und im Verzeichnis zu speichern
10.2.5.3. Kompilierung der Server-Startklasse
Die vorherige Klasse wird kompiliert:
E:\data\java\corba\ECHO>j:\jdk12\bin\javac serveurEcho.java
E:\data\java\corba\ECHO>dir
ECHO IDL 78 15/03/99 13:56 ECHO.IDL
SERVEU~1 CLA 1 793 18/03/99 13:18 serveurEcho.class
SERVEU~1 JAV 1 806 16/03/99 15:38 serveurEcho.java
SRVECH~1 CLA 488 18/03/99 11:30 srvEcho.class
SRVECH~1 JAV 252 15/03/99 14:02 srvEcho.java
ECHO <REP> 17/03/99 17:19 echo
10.2.6. Kundeneintrag
10.2.6.1. Der Code
Wir schreiben einen Client, um unseren Echo-Dienst zu testen. Wir übergeben dem Client dieselben drei Parameter wie dem Server:
Rechner: Rechner, auf dem sich das Dienstverzeichnis CORBA befindet
Port: Port, über den dieses Verzeichnis läuft
nomService: Name des Echo-Dienstes
Der Client stellt eine Verbindung zum Echo-Dienst her und fordert den Benutzer anschließend auf, Nachrichten über die Tastatur einzugeben. Diese werden an den Echo-Server gesendet, der sie zurücksendet. Der Verlauf dieses Dialogs wird auf dem Bildschirm angezeigt.
Der Echo-Dienst-Client CORBA ähnelt stark dem bereits geschriebenen Client RMI. Auch hier muss sich der Client mit einem Verzeichnisdienst verbinden, um eine Referenz auf das Serverobjekt zu erhalten, mit dem er sich verbinden möchte. Der Unterschied zwischen den beiden Clients liegt genau darin und nur darin. Hier ist der Code des Echo-Clients CORBA:
10.2.6.2. Die Verbindung des Clients zum Server
Der oben genannte Client CORBA stellt die Verbindung zum Server mit folgendem Befehl her:
// Man stellt die Verbindung zum Echo-Server her
iSrvEcho serveurEcho=getServeurEcho(machine,port,nomService);
Nach Abschluss dieses Vorgangs verfügt der Client über eine Referenz auf den Echo-Server. Anschließend unterscheidet sich ein Client CORBA nicht von einem Client RMI. Die private Methode, die die Verbindung zum Server herstellt, lautet wie folgt:
// importierte Pakete
import java.io.*;
import echo.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
// ---------- Klasse cltEcho
public class cltEcho {
public static void main(String arg[]){
// Syntax: cltEcho machineAnnuaire portAnnuaire nameservice
// Rechner: Rechner, auf dem das Dienstverzeichnis läuft CORBA
// Port: Port, auf dem das Dienstverzeichnis läuft
// nomService: Name des Echo-Dienstes
// Überprüfung der Argumente
if(arg.length!=3){
System.err.println("Syntaxe : pg machineAnnuaire portAnnuaire nomservice");
System.exit(1);
}
// Die Parameter werden abgerufen
String machine=arg[0];
String port=arg[1];
String nomService=arg[2];
// Verbindung zum Echo-Server herstellen
iSrvEcho serveurEcho=getServeurEcho(machine,port,nomService);
// Client-Server-Dialog
BufferedReader in=null;
String msg=null;
String reponse=null;
iSrvEcho serveur=null;
try{
// Tastatur-Stream öffnen
in=new BufferedReader(new InputStreamReader(System.in));
// Schleife zum Einlesen der an den Echo-Server zu sendenden Nachrichten
System.out.print("Message : ");
msg=in.readLine().toLowerCase().trim();
while(! msg.equals("fin")){
// Senden der Nachricht an den Server und Empfang der Antwort
reponse=serveurEcho.echo(msg);
// Weiterverfolgung
System.out.println("Réponse serveur : " + reponse);
// nächste Nachricht
System.out.print("Message : ");
msg=in.readLine().toLowerCase().trim();
}// while
// Fertig
System.exit(0);
// Fehlerbehandlung
} catch (Exception e){
System.err.println("Erreur : " + e);
System.exit(2);
}// try
}// main
// ---------------------- getServeurEcho
private static iSrvEcho getServeurEcho(String machine, String port,
String nomService){
// Anfrage einer Referenz vom Echo-Server
// Sendungsverfolgung
System.out.println("--> Connexion au serveur CORBA en cours...");
// die Referenz des Echo-Servers
iSrvEcho serveurEcho=null;
try{
// Es wird ein Objekt CORBA für die Bearbeitung angefordert
String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
ORB orb=ORB.init(initORB,null);
// Der Verzeichnisdienst wird verwendet, um den Echo-Server zu lokalisieren
org.omg.CORBA.Object objRef=
orb.resolve_initial_references("NameService");
NamingContext ncRef=NamingContextHelper.narrow(objRef);
// Der gesuchte Dienst heißt srvEcho – er wird angefordert
NameComponent nc= new NameComponent(nomService,"");
NameComponent path[]={nc};
serveurEcho=iSrvEchoHelper.narrow(ncRef.resolve(path));
} catch (Exception e){
System.err.println("Erreur lors de la localisation du serveur d'écho ("
+ e + ")");
System.exit(10);
}// try-catch
// Die Referenz zum Server wird zurückgegeben
return serveurEcho;
}// getServeurEcho
}// Klasse
Es handelt sich um dieselben Code-Sequenzen wie auf dem Server:
- Wir erstellen ein Objekt ORB, mit dem wir das Verzeichnis der Dienste CORBA ansprechen können
String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
ORB orb=ORB.init(initORB,null);
- Wir definieren die verschiedenen Bestandteile des Namens des Echo-Dienstes
org.omg.CORBA.Object objRef=orb.resolve_initial_references("NameService");
NamingContext ncRef=NamingContextHelper.narrow(objRef);
NameComponent nc= new NameComponent(nomService,"");
NameComponent path[]={nc};
- Wir fordern vom Verzeichnisdienst eine Referenz des Echo-Dienstes an (hier unterscheiden wir uns vom Server)
10.2.6.3. Compilation
E:\data\java\corba\ECHO>j:\jdk12\bin\javac cltEcho.java
E:\data\java\corba\ECHO>dir
CLTECH~1 CLA 2 599 18/03/99 13:51 cltEcho.class
CLTECH~1 JAV 2 907 16/03/99 16:15 cltEcho.java
ECHO IDL 78 15/03/99 13:56 ECHO.IDL
SERVEU~1 CLA 1 793 18/03/99 13:18 serveurEcho.class
SERVEU~1 JAV 1 806 16/03/99 15:38 serveurEcho.java
SRVECH~1 CLA 488 18/03/99 11:30 srvEcho.class
SRVECH~1 JAV 252 15/03/99 14:02 srvEcho.java
ECHO <REP> 17/03/99 17:19 echo
10.2.7. Tests
10.2.7.1. Starten des Verzeichnisdienstes
Auf einem Windows-Rechner starten wir den Verzeichnisdienst wie folgt:
Dadurch wird der Verzeichnisdienst auf Port 1000 des Rechners gestartet.
Der Verzeichnisdienst „tnameserv“ erzeugt eine Bildschirmausgabe, die in etwa wie folgt aussieht:
Initial Naming Context:
IOR:000000000000002849444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f
6e746578743a312e3000000000010000000000000030000100000000000a69737469612d30303900
044700000018afabcafe000000027620dd9a000000080000000000000000
TransientNameServer: setting port for initial object references to: 1000
Das ist zwar schwer lesbar, aber wir behalten die letzte Zeile im Hinterkopf: Der Dienst läuft auf Port 1000.
10.2.7.2. Start des Echo-Servers
Der Echo-Dienst wird mit drei Parametern gestartet:
E:\data\java\corba\ECHO>start j:\jdk12\bin\java serveurEcho localhost 1000 srvEcho
Der Server gibt Folgendes aus:
10.2.7.3. Starten des Clients auf demselben Rechner wie der Server
E:\data\java\corba\ECHO>j:\jdk12\bin\java cltEcho localhost 1000 srvEcho
--> Connexion au serveur CORBA en cours...
Message : msg1
Réponse serveur : [msg1]
Message : msg2
Réponse serveur : [msg2]
Message : fin
10.2.7.4. Start des Clients auf einem Windows-Rechner, der nicht der Server ist
E:\data\java\corba\ECHO>j:\jdk12\bin\java cltEcho tahe.istia.univ-angers.fr 1000 srvEcho
--> Connexion au serveur CORBA en cours...
Message : abcd
Réponse serveur : [abcd]
Message : efgh
Réponse serveur : [efgh]
Message : fin
10.3. Beispiel 2: Ein Server SQL
10.3.1. Einleitung
Wir greifen hier die Beschreibung des Servers SQL wieder auf, der bereits im Zusammenhang mit Java RMI behandelt wurde, um erneut die Gemeinsamkeiten und Unterschiede zwischen den beiden Methoden hervorzuheben. Zur Erinnerung: Die Aufgabe dieses Servers SQL besteht darin, auf einem Windows-Rechner zu laufen und es Remote-Clients zu ermöglichen, die öffentlichen Datenbanken ODBC dieses Windows-Rechners zu nutzen.

Der Client CORBA könnte drei Vorgänge ausführen:
- eine Verbindung zu einer Datenbank seiner Wahl herstellen
- SQL-Abfragen senden
- die Verbindung schließen
Der Server führt die Abfragen SQL des Clients aus und sendet ihm die Ergebnisse zurück. Das ist seine wesentliche Aufgabe, weshalb wir ihn als SQL-Server bezeichnen. Wir wenden die verschiedenen zuvor beim Echo-Server behandelten Schritte an.
10.3.2. Implementierung der Server-Schnittstelle IDL
Zur Erinnerung: Hier ist die Schnittstelle RMI, die wir für den Server verwendet hatten:
import java.rmi.*;
// die Remote-Schnittstelle
public interface interSQL extends Remote{
public String connect(String pilote, String url, String id, String mdp)
throws java.rmi.RemoteException;
public String[] executeSQL(String requete, String separateur)
throws java.rmi.RemoteException;
public String close()
throws java.rmi.RemoteException;
}
Die verschiedenen Methoden hatten folgende Funktionen:
Connect: Der Client stellt eine Verbindung zu einer entfernten Datenbank her, wobei er den Treiber, die URL JDBC sowie seine ID und sein Passwort angibt, um auf diese Datenbank zuzugreifen. Der Server gibt ihm eine Zeichenkette zurück, die das Ergebnis der Verbindung angibt:
executeSQL: Der Client fordert die Ausführung einer Abfrage SQL in der Datenbank an, mit der er verbunden ist. Er gibt das Trennzeichen an, das die Felder in den zurückgegebenen Ergebnissen trennen soll. Der Server gibt ein Array von Zeichenfolgen zurück:
bei einer Abfrage zur Aktualisierung der Datenbank, wobei n die Anzahl der aktualisierten Zeilen ist
, wenn die Abfrage einen Fehler verursacht hat
wenn die Abfrage kein Ergebnis geliefert hat
wenn die Abfrage Ergebnisse geliefert hat. Die vom Server zurückgegebenen Zeilen sind die Ergebniszeilen der Abfrage.
Close: Der Client schließt seine Verbindung zur entfernten Datenbank. Der Server gibt eine Zeichenkette zurück, die das Ergebnis dieses Schließvorgangs angibt:
Die Schnittstelle IDL des Servers sieht wie folgt aus:
module srvSQL{
typedef sequence<string> resultats;
interface interSQL{
string connect(in string pilote, in string urlBase, in string id, in string mdp);
resultats executeSQL(in string requete, in string separateur);
string close();
};// Schnittstelle
};// Modul
Die einzige Neuerung gegenüber der Schnittstelle IDL des Echo-Servers ist die Verwendung des Schlüsselworts „sequence“. Mit diesem Schlüsselwort lässt sich ein eindimensionales Array definieren. Die Definition erfolgt in zwei Schritten:
- Definition eines Typs zur Bezeichnung des Arrays, hier „resultats“:
Das Schlüsselwort typedef ist C/C++-Programmierern wohlbekannt: Es ermöglicht die Definition eines neuen Typs. Hier wird der Typ resultats als Äquivalent zum Typ sequence<string>, c.a.d, definiert – ein dynamisches (nicht dimensioniertes) Array von Zeichenketten.
- Verwendung des neuen Typs dort, wo er benötigt wird
Die Methode executeSQL gibt somit ein Array von Zeichenfolgen zurück.
10.3.3. Kompilierung der Server-Schnittstelle IDL
Die vorherige Schnittstelle IDL wird in die Datei srvSQL.idl übernommen. Diese Datei wird kompiliert:
E:\data\java\corba\sql>d:\javaidl\idltojava -fno-cpp srvSQL.idl
E:\data\java\corba\sql>dir
SRVSQL IDL 275 19/03/99 9:59 srvSQL.idl
SRVSQL <REP> 19/03/99 9:41 srvSQL
Es ist festzustellen, dass durch die Kompilierung ein Verzeichnis mit dem Namen des Schnittstellenmoduls IDL (srvSQL) erstellt wurde. Sehen wir uns den Inhalt dieses Verzeichnisses an:
E:\data\java\corba\sql>dir srvSQl
RESULT~1 JAV 833 19/03/99 10:00 resultatsHolder.java
RESULT~2 JAV 1 883 19/03/99 10:00 resultatsHelper.java
_INTER~1 JAV 2 474 19/03/99 10:00 _interSQLStub.java
INTERS~1 JAV 448 19/03/99 10:00 interSQL.java
INTERS~2 JAV 841 19/03/99 10:00 interSQLHolder.java
INTERS~3 JAV 1 855 19/03/99 10:00 interSQLHelper.java
_INTER~2 JAV 4 535 19/03/99 10:00 _interSQLImplBase.java
Zur Erinnerung: Die Dateien Helper und Holder sind Klassen, die mit den Ein- und Ausgabeparametern sowie den Ergebnissen der Methoden der Remote-Schnittstelle in Verbindung stehen. Das Verzeichnis srvSQL enthält alle .java-Dateien, die mit der in der .idl-Datei definierten Schnittstelle interSQL zusammenhängen. Es enthält außerdem Dateien, die mit dem Typ resultats zusammenhängen, der in der Schnittstelle IDL definiert wurde.
Die Datei interSQL.java ist die Java-Datei der Schnittstelle unseres Servers. Es ist wichtig zu überprüfen, ob das automatisch Erzeugte unseren Erwartungen entspricht. Die generierte Datei interSQL.java sieht wie folgt aus:
/* * Datei: ./SRVSQL/INTERSQL.JAVA * Von: SRVSQL.IDL * Datum: Fr, 19. März 09:59:48 1999 * Von: D:\JAVAIDL\IDLTOJ~1.EXE Java IDL 1.2 18. Aug. 1998 16:25:34 */
package srvSQL;
public interface interSQL
extends org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity {
String connect(String pilote, String urlBase, String id, String mdp)
;
String[] executeSQL(String requete, String separateur)
;
String close()
;
}
Wir stellen fest, dass wir dieselbe Benutzeroberfläche haben wie die, die für den Client-Server RMI verwendet wird. Wir können also fortfahren. Kompilieren wir alle diese .java-Dateien:
E:\data\java\corba\sql\srvSQL>j:\jdk12\bin\javac *.java
Note: _interSQLImplBase.java uses or overrides a deprecated API. Recompile with
"-deprecation" for details.
1 warning
E:\data\java\corba\sql\srvSQL>dir *.class
_INTER~1 CLA 3 094 19/03/99 10:01 _interSQLImplBase.class
_INTER~2 CLA 1 953 19/03/99 10:01 _interSQLStub.class
INTERS~1 CLA 430 19/03/99 10:01 interSQL.class
INTERS~2 CLA 2 096 19/03/99 10:01 interSQLHelper.class
INTERS~3 CLA 870 19/03/99 10:01 interSQLHolder.class
RESULT~1 CLA 2 047 19/03/99 10:01 resultatsHelper.class
RESULT~2 CLA 881 19/03/99 10:01 resultatsHolder.class
10.3.4. Schreiben des Servers SQL
Wir schreiben nun den Code für den Server SQL. Zur Erinnerung: Diese Klasse muss von der abstrakten Klasse _nomInterfaceImplBase abgeleitet sein, die durch die Kompilierung der Datei IDL erzeugt wurde. Abgesehen von dieser Besonderheit und mit Ausnahme der Codeabschnitte, die sich auf die Registrierung des Dienstes in einem Verzeichnis beziehen, ist der Code des Servers CORBA identisch mit dem des Servers RMI:
// importierte Pakete
import java.sql.*;
import java.util.*;
import srvSQL.*;
// Klasse SQLServant
public class SQLServant extends _interSQLImplBase{
// globale Daten der Klasse
private Connection DB;
// --------------- Verbindung
public String connect(String pilote, String url, String id,
String mdp){
// Verbindung zur Datenbank-URL über den Treiber
// Authentifizierung mit ID und Passwort
String resultat=null; // Ergebnis der Methode
try{
// Laden des Treibers
Class.forName(pilote);
// Verbindungsanfrage
DB=DriverManager.getConnection(url,id,mdp);
// OK
resultat="200 Connexion réussie";
} catch (Exception e){
// Fehler
resultat="500 Echec de la connexion (" + e + ")";
}
// Ende
return resultat;
}
// ------------- executeSQL
public String[] executeSQL(String requete, String separateur){
// führt eine Abfrage SQL in der Datenbank DB
// und speichert die Ergebnisse in einem String-Array
// Daten, die für die Ausführung der Abfrage erforderlich sind
Statement S=null;
ResultSet RS=null;
String[] lignes=null;
Vector resultats=new Vector();
String ligne=null;
try{
// Erstellung des Abfragecontainers
S=DB.createStatement();
// Abfrage ausführen
if (! S.execute(requete)){
// Aktualisierungsabfrage
// Die Anzahl der aktualisierten Zeilen wird zurückgegeben
lignes=new String[1];
lignes[0]="100 "+S.getUpdateCount();
return lignes;
}
// Es handelte sich um eine Abfrage
// Die Ergebnisse werden abgerufen
RS=S.getResultSet();
// Anzahl der Felder im Resultset
int nbChamps=RS.getMetaData().getColumnCount();
// Auswertung der Ergebnisse
while(RS.next()){
// Erstellung der Ergebniszeile
ligne="101 ";
for (int i=1;i<nbChamps;i++)
ligne+=RS.getString(i)+separateur;
ligne+=RS.getString(nbChamps);
// Hinzufügen zum Ergebnisvektor
resultats.addElement(ligne);
}// while
// Ende der Auswertung der Ergebnisse
// Ressourcen werden freigegeben
RS.close();
S.close();
// Ergebnisse werden zurückgegeben
int nbLignes=resultats.size();
if (nbLignes==0){
lignes=new String[1];
lignes[0]="501 Pas de résultats";
} else {
lignes=new String[resultats.size()];
for(int i=0;i<lignes.length;i++)
lignes[i]=(String) resultats.elementAt(i);
}//if
return lignes;
} catch (Exception e){
// Fehler
lignes=new String[1];
lignes[0]="500 " + e;
return lignes;
}// try-catch
}// executeSQL
// --------------- schließen
public String close(){
// schließt die Verbindung zur Datenbank
String resultat=null;
try{
DB.close();
resultat="200 Base fermée";
} catch (Exception e){
resultat="500 Erreur à la fermeture de la base ("+e+")";
}
// Rückgabe des Ergebnisses
return resultat;
}
}// Klasse SQLServant
Diese Klasse befindet sich in der Datei SQLServant.java, die wir kompilieren:
E:\data\java\corba\sql>dir
SRVSQL IDL 275 19/03/99 9:59 srvSQL.idl
SRVSQL <REP> 19/03/99 9:41 srvSQL
SQLSER~1 JAV 2 941 15/03/99 9:09 SQLServant.java
E:\data\java\corba\sql>j:\jdk12\bin\javac SQLServant.java
E:\data\java\corba\sql>dir *.class
SQLSER~1 CLA 2 568 19/03/99 10:19 SQLServant.class
10.3.5. Erstellung des Startprogramms für den Server SQL
Die vorstehende Klasse stellt den Server SQL nach dem Start dar. Zuvor muss er in einem Verzeichnis der Dienste CORBA registriert werden. Wie beim Echo-Dienst werden wir dies mit einer speziellen Klasse tun, an die wir zur Laufzeit drei Parameter übergeben:
Rechner: Rechner, auf dem sich das Dienstverzeichnis CORBA befindet
Port: Port, über den dieses Verzeichnis läuft
nomService: Name des Dienstes SQL
Der Code dieser Klasse ist nahezu identisch mit dem der Klasse, die dasselbe für den Echo-Dienst erledigt hat. Wir haben die Zeile, die sich zwischen den beiden Klassen unterscheidet, fett hervorgehoben: Sie erstellt nicht dasselbe Serverobjekt. Man sieht also, dass wir immer noch denselben Mechanismus zum Starten des Servers haben. Wenn man diesen Mechanismus in eine Klasse auslagert, wie es hier geschehen ist, wird er für den Entwickler nahezu transparent.
// importierte Pakete
import srvSQL.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
//----------- Klasse serveurSQL
public class serveurSQL{
// ------- main: startet den Server SQL
public static void main(String arg[]){
// serveurSQL Port-Dienst der Maschine
//– Ist die Anzahl der Argumente korrekt?
if(arg.length!=3){
System.err.println("Syntaxe : pg machineAnnuaireCorba portAnnuaireCorba nomService");
System.exit(1);
}
// Die Argumente werden abgerufen
String machine=arg[0];
String port=arg[1];
String nomService=arg[2];
String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
try{
// Wir benötigen ein Objekt CORBA, um arbeiten zu können
ORB orb=ORB.init(initORB,null);
// Der Dienst wird in das Dienstverzeichnis aufgenommen
org.omg.CORBA.Object objRef=
orb.resolve_initial_references("NameService");
NamingContext ncRef=NamingContextHelper.narrow(objRef);
NameComponent nc= new NameComponent(nomService,"");
NameComponent path[]={nc};
// Der Server wird erstellt und dem Dienst zugeordnet srvSQL
SQLServant serveurSQL=new SQLServant();
ncRef.rebind(path,serveurSQL);
orb.connect(serveurSQL);
// Weiterverfolgung
System.out.println("Serveur SQL prêt");
// Warten auf Client-Anfragen
java.lang.Object sync=new java.lang.Object();
synchronized(sync){
sync.wait();
}
} catch(Exception e){
// Es ist ein Fehler aufgetreten
System.err.println("Erreur " + e);
e.printStackTrace(System.err);
}
}// Hauptprozess
}// srvSQL
Wir kompilieren diese neue Klasse:
E:\data\java\corba\sql>j:\jdk12\bin\javac serveurSQL.java
E:\data\java\corba\sql>dir *.class
SQLSER~1 CLA 2 568 19/03/99 10:19 SQLServant.class
SERVEU~1 CLA 1 800 19/03/99 10:33 serveurSQL.class
10.3.6. Client-Schreibvorgang
Der Client des Servers CORBA wird mit folgenden Parametern aufgerufen:
Rechner: Rechner, auf dem sich das Verzeichnis der Dienste befindet CORBA
Port: Port, über den dieses Verzeichnis läuft
nomService: Name des Dienstes SQL
Treiber: Treiber, den der Server SQL zur Verwaltung der gewünschten Datenbank verwenden soll
urlBase: URL JDBC der zu verwaltenden Datenbank
id: ID des Kunden oder null, falls keine ID vorhanden ist
mdp: Passwort des Kunden oder null, falls kein Passwort vorhanden ist
Trennzeichen: Zeichen, das der Server SQL verwenden muss, um die Felder in den Ergebniszeilen einer Abfrage voneinander zu trennen
Hier ein Beispiel für mögliche Parameter:
wobei hier:
Rechner: Rechner, auf dem sich das Dienstverzeichnis CORBA befindet
Port: Port, über den dieses Verzeichnis läuft
srvSQL: srvSQL, Name CORBA des Servers SQL
Treiber: sun.jdbc.odbc.JdbcOdbcDriver, der übliche Treiber für Datenbanken mit ODBC-Schnittstelle
urlBase: jdbc:odbc:articles, zur Verwendung einer Datenbank „articles“, die in der Liste der öffentlichen Datenbanken ODBC des Windows-Rechners deklariert ist
ID: null, keine Identität
Passwort: null, kein Passwort
Trennzeichen: , die Felder der Ergebnisse werden durch ein Komma getrennt
Nach dem Start mit den oben genannten Parametern führt der Client die folgenden Schritte aus:
- Er stellt eine Verbindung zum Rechner „machine“ über den Port „port“ her, um den Dienst CORBA srvSQL anzufordern
- Er fordert die Verbindung zur Artikeldatenbank an
- Er fordert den Benutzer auf, eine Abfrage SQL über die Tastatur einzugeben
- sie wird an den Server gesendet SQL
- Er zeigt die vom Server zurückgegebenen Ergebnisse auf dem Bildschirm an
- Er fordert den Benutzer erneut auf, eine Abfrage SQL über die Tastatur einzugeben. Er beendet den Vorgang, sobald die Abfrage beendet ist.
Der Java-Code des Clients folgt. Die Kommentare sollten zum Verständnis ausreichen. Man wird feststellen, dass:
- Der Code ist identisch mit dem des bereits behandelten Clients RMI. Er unterscheidet sich davon durch den Prozess der Abfrage des Verzeichnisdienstes, der in der Methode getServeurSQL isoliert ist.
- Die Methode getServeurSQL entspricht der für den Echo-Client geschriebenen Methode
Daraus folgt:
- sich ein Client CORBA von einem Client RMI lediglich in der Art und Weise unterscheidet, wie er den Server kontaktiert
- Diese Art der Kontaktaufnahme ist für alle CORBA-Clients identisch
import srvSQL.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
import java.io.*;
public class clientSQL {
// globale Daten der Klasse
private static String syntaxe =
"syntaxe : cltSQL machine port service pilote urlBase id mdp separateur";
private static BufferedReader in=null;
private static interSQL serveurSQL=null;
public static void main(String arg[]){
// Syntax: cltSQL Rechner Port Trennzeichen Treiber URL ID Passwort
// Rechner, Port: Rechner und Port des zu kontaktierenden Dienstverzeichnisses CORBA
// Dienst: Name des Dienstes
// Treiber: Zu verwendender Treiber für die zu nutzende Datenbank
// urlBase: JDBC-URL der zu verwendenden Datenbank
// ID: Benutzer-ID
// mdp: sein Passwort
// Trennzeichen: Zeichenfolge, die die Felder in den Ergebnissen einer Abfrage trennt
// Überprüfung der Anzahl der Argumente
if(arg.length!=8)
erreur(syntaxe,1);
// Initialisierung der Parameter für die Datenbankverbindung
String machine=arg[0];
String port=arg[1];
String service=arg[2];
String pilote=arg[3];
String urlBase=arg[4];
String id, mdp, separateur;
if(arg[5].equals("null")) id=""; else id=arg[5];
if(arg[6].equals("null")) mdp=""; else mdp=arg[6];
if(arg[7].equals("null")) separateur=" "; else separateur=arg[7];
// Parameter des Verzeichnisdienstes CORBA
String[] initORB={"-ORBInitialHost",arg[0],"-ORBInitialPort",arg[1]};
// Client CORBA – eine Referenz vom Server wird angefordert SQL
interSQL serveurSQL=getServeurSQL(machine,port,service);
// Client-Server-Dialog
String requete=null;
String reponse=null;
String[] lignes=null;
String codeErreur=null;
try{
// Öffnen des Tastaturstroms
in=new BufferedReader(new InputStreamReader(System.in));
// Nachverfolgung
System.out.println("--> Connexion à la base de données en cours");
// erster Verbindungsversuch zur Datenbank
reponse=serveurSQL.connect(pilote,urlBase,id,mdp);
// Weiterverfolgung
System.out.println("<-- "+reponse);
// Antwortanalyse
codeErreur=reponse.substring(0,3);
if(codeErreur.equals("500"))
erreur("Abandon sur erreur de connexion à la base",3);
// Schleife zum Einlesen der an den Server SQL zu sendenden Anfragen
System.out.print("--> Requête : ");
requete=in.readLine().toLowerCase().trim();
while(! requete.equals("fin")){
// Senden der Anfrage an den Server und Empfang der Antwort
lignes=serveurSQL.executeSQL(requete,separateur);
// Weiterverfolgung
afficheLignes(lignes);
// nächste Anfrage
System.out.print("--> Requête : ");
requete=in.readLine().toLowerCase().trim();
}// while
// Weiterverfolgung
System.out.println("--> Fermeture de la connexion à la base de données distante");
// Verbindung wird beendet
reponse=serveurSQL.close();
// Weiter
System.out.println("<-- " + reponse);
// Ende
System.exit(0);
// Fehlerbehandlung
} catch (Exception e){
erreur("Abandon sur erreur : " + e,2);
}// try
}// main
// ----------- AfficheLignes
private static void afficheLignes(String[] lignes){
for (int i=0;i<lignes.length;i++)
System.out.println("<-- " + lignes[i]);
}// afficheLignes
// ------------ Fehler
private static void erreur(String msg, int exitCode){
// Anzeige einer Fehlermeldung
System.err.println(msg);
// Mögliche Freigabe der Ressourcen
try{
in.close();
serveurSQL.close();
} catch(Exception e){}
// Beenden
System.exit(exitCode);
}// Fehler
// ---------------------- getServeurSQL
private static interSQL getServeurSQL(String machine, String port, String service){
// Anfrage einer Referenz vom Server SQL
// Rechner: Rechner aus dem Dienstverzeichnis CORBA
// Port: Port des Dienstverzeichnisses CORBA
// Dienst: Name des anzufragenden Dienstes CORBA
// Verfolgung
System.out.println("--> Connexion au serveur CORBA en cours...");
// Server-ID SQL
interSQL serveurSQL=null;
// Parameter des Verzeichnisdienstes CORBA
String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
try{
// Ein Objekt CORBA wird für die Arbeit angefordert – dazu wird der Port
// des Dienstverzeichnisses CORBA
ORB orb=ORB.init(initORB,null);
// Man nutzt das Verzeichnis, um den Server SQL zu finden
org.omg.CORBA.Object objRef=
orb.resolve_initial_references("NameService");
NamingContext ncRef=NamingContextHelper.narrow(objRef);
// Der gesuchte Dienst heißt srvSQL – er wird angefordert
NameComponent nc= new NameComponent(service,"");
NameComponent path[]={nc};
serveurSQL=interSQLHelper.narrow(ncRef.resolve(path));
} catch (Exception e){
System.err.println("Erreur lors de la localisation du serveur SQL ("
+ e + ")");
System.exit(10);
}// try-catch
// Die Referenz zum Server wird zurückgegeben
return serveurSQL;
}// getServeurSQL
}// Klasse
Kompilieren wir die Client-Klasse:
E:\data\java\corba\sql>j:\jdk12\bin\javac clientSQL.java
E:\data\java\corba\sql>dir *.class
SQLSER~1 CLA 2 568 19/03/99 10:19 SQLServant.class
SERVEU~1 CLA 1 800 19/03/99 10:33 serveurSQL.class
CLIENT~1 CLA 3 774 19/03/99 10:45 clientSQL.class
Wir sind bereit für die Tests.
10.3.7. Tests
10.3.7.1. Pré-requis
Es wird angenommen, dass eine Datenbank namens „Articles“ (ACCESS) auf dem Windows-Server (SQL) öffentlich verfügbar ist:

Diese Datenbank hat folgende Struktur:
Name | Typ |
code | 4-stelliger Artikelcode |
nom | Name (Zeichenkette) |
prix | Preis (tatsächlich) |
stock_actu | sein aktueller Lagerbestand (Ganzzahl) |
stock_mini | der Mindestbestand (ganze Zahl), bei Unterschreitung dessen der Artikel nachbestellt werden muss |
10.3.7.2. Start des Verzeichnisdienstes
E:\data\java\corba\sql>start j:\jdk12\bin\tnameserv -ORBInitialPort 1000
Le service d’annuaire est lancé sur le port 1000. Il affiche dans une fenêtre DOS quelque chose du genre :
Initial Naming Context:
IOR:000000000000002849444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f
6e746578743a312e3000000000010000000000000030000100000000000a69737469612d30303900
052800000018afabcafe000000027693d3fd000000080000000000000000
TransientNameServer: setting port for initial object references to: 1000
10.3.7.3. Start des Servers SQL
Der SQL-Server wird gestartet:
In einem Fenster wird Folgendes angezeigt: DOS:
10.3.7.4. Starten eines Clients auf demselben Rechner wie der Server
Hier sind die Ergebnisse, die mit einem Client auf demselben Rechner wie der Server erzielt wurden:
E:\data\java\corba\sql>j:\jdk12\bin\java clientSQL localhost 1000 srvSQL sun.jdbc.odbc.JdbcOdbcDriver jdbc:odbc:articles null null ,
--> Connexion au serveur CORBA en cours...
--> Connexion à la base de données en cours
<-- 200 Connexion réussie
--> Abfrage: select name, stock_actu, stock_mini from articles
<-- 101 vélo,31,8
<-- 101 arc,9,8
<-- 101 canoé,7,7
<-- 101 fusil,9,8
<-- 101 skis nautiques,13,8
<-- 101 essai3,13,9
<-- 101 cachalot,6,6
<-- 101 léopard,7,7
<-- 101 panthère,7,7
--> Abfrage: delete from articles where stock_mini<7
<-- 100 1
--> Abfrage: SELECT Name, stock_actu, stock_mini FROM articles
<-- 101 vélo,31,8
<-- 101 arc,9,8
<-- 101 canoé,7,7
<-- 101 fusil,9,8
<-- 101 skis nautiques,13,8
<-- 101 essai3,13,9
<-- 101 léopard,7,7
<-- 101 panthère,7,7
--> Requête : fin
--> Fermeture de la connexion à la base de données distante
<-- 200 Base fermée
10.3.7.5. Starten eines Clients auf einem anderen Rechner als dem Server
Hier sind die Ergebnisse, die mit einem Client auf einem anderen Rechner als dem Server erzielt wurden:
E:\data\java\corba\sql>j:\jdk12\bin\java clientSQL tahe.istia.univ-angers.fr 1000 srvSQL sun.jdbc.odbc.JdbcOdbcDriver jdbc:odbc:articles null null ,
--> Connexion au serveur CORBA en cours...
--> Connexion à la base de données en cours
<-- 200 Connexion réussie
--> Abfrage: SELECT * FROM articles
<-- 101 a300,v_lo,1202,31,8
<-- 101 d600,arc,5000,9,8
<-- 101 d800,canoé,1502,7,7
<-- 101 x123,fusil,3000,9,8
<-- 101 s345,skis nautiques,1800,13,8
<-- 101 f450,essai3,3,13,9
<-- 101 z400,léopard,500000,7,7
<-- 101 g457,panthère,800000,7,7
--> Requête : fin
--> Fermeture de la connexion à la base de données distante
<-- 200 Base fermée
10.4. Zuordnungen IDL – JAVA
Hier geben wir die Zuordnungen zwischen den einfachen Typen IDL und JAVA an:
Typ IDL | Java-Typ |
boolean | boolean |
char | Zeichen |
wchar | char |
Byte | Byte |
Zeichenkette | java.lang.String |
wstring | java.lang.String |
short | short |
unsigned short | short |
long | int |
unsigned long | int |
long long | long |
unsigned long long | long |
float | float |
double | double |
Zur Erinnerung: Um ein Array mit Elementen vom Typ T in der Schnittstelle IDL zu definieren, verwendet man die Anweisung:
und dass anschließend nomType verwendet wird, um auf den Typ des Arrays zu verweisen. So wurde in der Server-Schnittstelle SQL folgende Deklaration verwendet:
verwendet, damit resultats in Java auf das Array String[] verweist.