Skip to content

10. Erstellen verteilter CORBA-Anwendungen

10.1. Einführung

Im vorigen Kapitel haben wir gesehen, wie man mit dem RMI-Paket verteilte Anwendungen in Java erstellt. Hier behandeln wir dasselbe Problem, diesmal unter Verwendung der CORBA-Architektur. CORBA (Common Object Request Broker Architecture) ist eine Spezifikation, die von der OMG (Object Management Group) definiert wurde, einem Zusammenschluss vieler Unternehmen der IT-Branche. CORBA definiert einen „Software-Bus“, auf den Anwendungen zugreifen können, die in verschiedenen Sprachen geschrieben sind:

Image

Wir werden sehen, dass die Erstellung einer verteilten Anwendung mit CORBA der bei Java RMI verwendeten Methode ähnelt: Die Konzepte sind vergleichbar. CORBA bietet den Vorteil der Interoperabilität mit Anwendungen, die in anderen Sprachen geschrieben sind.

10.2. Der Entwicklungsprozess für eine CORBA-Anwendung

10.2.1. Einführung

Um eine CORBA-Client-Server-Anwendung zu entwickeln, gehen wir wie folgt vor:

  1. Schreiben der Server-Schnittstelle mit IDL (Interface Definition Language)
  2. Generieren der „Skeleton“- und „Stub“-Klassen des Servers
  3. Schreiben des Servers
  4. Schreiben des Clients
  5. Kompilieren aller Klassen
  6. Starten eines CORBA-Dienstverzeichnisses
  7. Starten des Servers
  8. Starten des Clients

Als erstes Beispiel verwenden wir den Echo-Server, der bereits im RMI-Kontext verwendet wurde. So kann der Leser die Unterschiede zwischen den beiden Methoden erkennen.

Die Anwendung wurde mit JDK 1.2 getestet.

10.2.2. Schreiben der Server-Schnittstelle

Wie bei Java RMI wird der Server durch seine Schnittstelle in Bezug auf den Client definiert. Während die Klassen, die den Server implementieren, vom Client nicht benötigt werden, sind diejenigen seiner Schnittstelle erforderlich. Während Java RMI eine Java-Schnittstelle verwendete, um die „Skeleton“- und „Stub“-Klassen des Servers zu generieren, erfordert die Java-CORBA-Architektur, dass die Schnittstelle in einer anderen Sprache als Java beschrieben wird. Diese Schnittstelle generiert mehrere Klassen, von denen einige vom Client und andere vom Server verwendet werden.

Die Beschreibung der Echo-Schnittstelle lautet wie folgt:

module echo{
    interface iSrvEcho{
        string echo(in string msg);
    };
};

Die Schnittstellenbeschreibung wird in einer echo.idl-Datei gespeichert. Sie ist in der IDL (Interface Definition Language) der OMG geschrieben. Um verwendet werden zu können, muss sie von einem Programm geparst werden, das Quelldateien in der Sprache generiert, die zur Entwicklung der CORBA-Anwendung verwendet wird. Hier verwenden wir das Programm idltojava.exe, das die erforderlichen .java-Quelldateien für die Anwendung auf Basis der vorherigen Schnittstelle generiert. Das Programm idltojava.exe ist nicht im JDK enthalten. Es kann von der Sun-Website unter http://java.sun.com heruntergeladen werden.

Betrachten wir einige Zeilen der vorherigen IDL-Schnittstelle:

module echo
entspricht dem **Java-Paket echo**. Durch das Kompilieren der Schnittstelle wird das Java-Paket *echo* generiert, d. h. ein Verzeichnis, das Java-Klassen enthält.
interface iSrvEcho
entspricht der **Java-Schnittstelle iSrvEcho**. Es wird eine Java-Schnittstelle generiert.
string echo(in string msg)
entspricht der Java-Anweisung **String echo(String msg)**. Die Typen in der IDL-Sprache entsprechen nicht genau denen in der Java-Sprache. Die Entsprechungen werden später in diesem Kapitel erläutert. In der IDL-Sprache können die Parameter einer Funktion Eingabe- (**in**), Ausgabe- (**out**) oder Eingabe-Ausgabe-Parameter (**inout**) sein. Hier erhält die echo-Methode einen Eingabeparameter *msg,* der ein String ist, und gibt als Ergebnis einen String 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 echo-Methode zur Verfügung.

10.2.3. Kompilieren der IDL-Schnittstelle des Servers

Sobald die Server-Schnittstelle definiert ist, generieren wir die entsprechenden Java-Dateien.

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 wird verwendet, um anzugeben, dass kein Präprozessor verwendet werden soll (am häufigsten bei C/C++). Durch das Kompilieren der Datei echo.idl wird ein Unterverzeichnis „echo“ erstellt, 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:

/*
 * File: ./ECHO/ISRVECHO.JAVA
 * From: ECHO.IDL
 * Date: Mon Mar 15 13:56:08 1999
 *   By: D:\JAVAIDL\IDLTOJ~1.EXE Java IDL 1.2 Aug 18 1998 16:25:34
 */

package echo;
public interface iSrvEcho
    extends org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity {
    String echo(String msg)
;
}

Wir sehen, dass dies fast eine wortwörtliche Übersetzung der IDL-Schnittstelle ist. Wenn Sie neugierig genug sind, sich den Inhalt der anderen .java-Dateien anzusehen, werden Sie komplexere Dinge finden. Hier ist, was die Dokumentation über die Rolle dieser verschiedenen Dateien sagt:

iSrvEcho.java

die Server-Schnittstelle

_iSrvEchoImplbase.java

implementiert die oben genannte iSrvEcho-Schnittstelle. Es handelt sich um eine abstrakte Klasse, das „Gerüst“ des Servers, das dem Server die von der verteilten Anwendung benötigte CORBA-Funktionalität bereitstellt.

_iSrvEchoStub.java

Dies ist der Server-„Stub“, den der Client verwenden wird. Er stellt dem Client die CORBA-Funktionalität zur Verfügung, die für den Zugriff auf den Server erforderlich ist.

iSrvEchoHelper.java

Stellt die Methoden bereit, die zur Verwaltung von CORBA-Objektreferenzen benötigt werden

iSrvEchoHolder.java

Stellt die Methoden bereit, die zur Verwaltung der Eingabe- und Ausgabeparameter der Schnittstellenmethoden benötigt werden.

10.2.4. Kompilieren der aus der IDL-Schnittstelle generierten Klassen

Es empfiehlt sich, die vorangegangenen Klassen zu kompilieren. In einem anderen Beispiel werden wir sehen, dass hier Fehler erkannt werden können, die durch eine fehlerhafte Ausführung des idltojava-Generators verursacht wurden. Hier läuft alles reibungslos, und nach der Kompilierung befinden sich die folgenden Dateien im Verzeichnis des echo-Pakets:

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-Implementierung

10.2.5.1. Implementierung der iSrvEcho-Schnittstelle

Wir haben die iSrvEcho-Schnittstelle zuvor definiert. Nun werden wir die Klasse schreiben, die diese Schnittstelle implementiert. Sie wird von der Klasse _iSrvEchoImplbase.java abgeleitet, die, wie oben erwähnt, die iSrvEcho-Schnittstelle bereits implementiert.

// imported packages
import echo.*;

// class implementing remote echo
public class srvEcho extends _iSrvEchoImplBase{
    // method performing the echo
    public String echo(String msg){
        return  "["  + msg + "]";
    }// fine echo
}// end of class

Der Code ist selbsterklärend. Diese Klasse ist in der Datei srvEcho.java im übergeordneten Verzeichnis des iSrvEcho-Interface-Pakets gespeichert.

Sie können ihn kompilieren, um dies zu überprüfen:

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. Schreiben der Server-Erstellungsklasse

Wie bei einer RMI-Client-Server-Anwendung muss ein CORBA-Server in einem Verzeichnis registriert werden, damit er für Clients zugänglich ist. Es ist dieses Registrierungsverfahren, das sich auf der Entwicklungsebene je nachdem unterscheidet, ob Sie eine CORBA- oder eine RMI-Anwendung haben. Hier ist das Verfahren für den Echo-CORBA-Server, der in der Datei serverEcho.java registriert ist:

// imported packages
 import echo.*
; import org.omg.CosNaming.
*; import org.omg.CosNaming.NamingContextPackage
.*; import org.omg.CORB

A.*; //----------- class serveu
rEcho public class serveu
    rEcho{ // ------- main: launches the ech
    o server // syntax pg machineAnnuaire portAnnuaire n
    omService // machine: machine supporting CORBA 
    directory // port: directory port
     CORBA // nomService: name of the service t

o  be registered public static void 
    main(String arg[]){ // are th
    e arguments there?
         if(arg.length!=3){ System.err.println("Syntaxe : pg machineAnnuaire por
        tAnnuaire nomSe
    r
    vice"); System.exit(1); }
     // retrieve the argu
    ments String machi
    ne=arg[0]; String port=arg[1]; String nomService=arg[2]; 

    try{

    // you need a CORBA object to work
    String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
      ORB orb=ORB.init(initORB,null);
    // put the service in the service directory
    // it will be called srvEcho
      org.omg.CORBA.Object objRef=
        orb.resolve_initial_references("NameService");
      NamingContext ncRef=NamingContextHelper.narrow(objRef);
      NameComponent nc= new NameComponent(nomService,"");
      NameComponent path[]={nc};
    // create the server and associate it with the srvEcho service
    srvEcho serveurEcho=new srvEcho();
      ncRef.rebind(path,serveurEcho);
    orb.connect(serveurEcho);
    // follow-up
    System.out.println("Serveur d'écho prêt");
    // waiting for customer requests
      java.lang.Object sync=new java.lang.Object();
      synchronized(sync){
        sync.wait();
      }
    } catch(Exception e){
    // there has been an error
      System.err.println("Erreur " + e);
      e.printStackTrace(System.err);
    }
  }// hand
}// serveurEcho

Im Folgenden skizzieren wir die Grundlagen zum Starten des Servers, ohne auf Details einzugehen, die auf den ersten Blick komplex erscheinen mögen. Es ist wichtig, sich die Kernpunkte aus dem vorherigen Beispiel zu merken, da sie in jedem CORBA-Server vorkommen.

10.2.5.2.1. Serverparameter

Ein CORBA-Server muss sich bei einem Verzeichnisdienst registrieren, der auf einem bestimmten Rechner und Port läuft. Unsere Anwendung erhält diese beiden Informationen als Parameter. Der registrierte Dienst muss einen Namen haben, der als dritter Parameter angegeben wird.

10.2.5.2.2. Erstellen des CORBA-Verzeichnisdienst-Zugriffsobjekts

Um auf den Verzeichnisdienst zuzugreifen und unseren Echo-Server zu registrieren, benötigen wir ein Objekt namens ORB (Object Request Broker), das über die folgende Klassenmethode abgerufen wird:

ORB ORB.init(String [] args, Properties prop)


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 ORB-Objekt zu erhalten:


    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 init-Methode wird auf null gesetzt. Wäre auch der erste Parameter auf null gesetzt worden, wäre das verwendete (Maschine,Port)-Paar das Standardpaar (localhost,900) gewesen.

10.2.5.2.3. Registrierung des Servers im CORBA-Dienstverzeichnis

Die Registrierung des Servers im Verzeichnis erfolgt mit den folgenden Schritten:

     // put the service in the service directory // 
    it will be called srvEcho
       org.omg.CORBA.Object o
b       jRef= orb.resolve_initial_references("
N     ameService"); NamingContext ncRef=NamingContextHe
l     per.narrow(objRef); NameComponent nc= new Nam
e     Component(nomService,""); 
     NameComponent path[]={nc}; // create the server a
    nd associate it with the srvEcho s
e         rvice 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 dargestellt. Ein Dienstname besteht aus mehreren Komponenten:

  • einer Anfangskomponente objRef, einem generischen Objekt, das in einen NamingContext-Typ umgewandelt werden muss, hier ncRef.
  • dem Servicenamen, hier `serviceName`, der als Parameter an den Server übergeben wurde

Diese Namenskomponenten (NameComponent) werden in einem Array gesammelt, hier path. Es ist dieses Array, das den erstellten Dienst genau „benennt“. Sobald der Name erstellt ist, bleibt er bestehen

  • ihn einer Instanz des Servers zuzuordnen (der zuvor erstellten Klasse srvEcho)


srvEcho serveurEcho=new srvEcho();
  • und sie im Verzeichnis registrieren

    ncRef.rebind(path,serveurEcho);
    orb.connect(serveurEcho);

10.2.5.3. Kompilieren der Server-Startklasse

Kompilieren Sie die vorherige Klasse:

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. Client-Schreiben

10.2.6.1. Der Code

Wir schreiben einen Client, um unseren Echo-Dienst zu testen. Wir übergeben dem Client dieselben drei Parameter wie zuvor dem Server:

Rechner: der Rechner, auf dem sich das CORBA-Dienstverzeichnis befindet

Port: der Port, auf dem dieses Verzeichnis läuft

serviceName: 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 Nachrichten werden an den Echo-Server gesendet, der sie zurücksendet. Ein Protokoll dieses Dialogs wird auf dem Bildschirm angezeigt.

Der CORBA-Client für den Echo-Dienst ist dem bereits geschriebenen RMI-Client sehr ähnlich. 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 für den CORBA-Echo-Client:


    

10.2.6.2. Verbindung des Clients mit dem Server

Der oben genannte CORBA-Client verbindet sich mit dem Server mithilfe der folgenden Anweisung:

        // on fait la liaison avec le serveur d'écho
        iSrvEcho serveurEcho=getServeurEcho(machine,port,nomService);

Nach diesem Vorgang verfügt der Client über eine Referenz auf den Echo-Server. Ab diesem Zeitpunkt unterscheidet sich ein CORBA-Client nicht mehr von einem RMI-Client. Die private Methode, die die Verbindung zum Server herstellt, lautet wie folgt:

// imported packages
import java.io.*;
import echo.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;

// ---------- class cltEcho
public class cltEcho {

    public static void main(String arg[]){
         // syntax : cltEcho machineAnnuaire portAnnuaire nameservice
         // machine: machine where the CORBA service directory operates
         // port: port where the service directory operates
         // nomService: echo service name

         // argument verification
        if(arg.length!=3){
            System.err.println("Syntaxe : pg machineAnnuaire portAnnuaire nomservice");
            System.exit(1);
        }

         // parameters are retrieved
        String machine=arg[0];
        String port=arg[1];
        String nomService=arg[2];

         // link to echo server
        iSrvEcho serveurEcho=getServeurEcho(machine,port,nomService);

         // client-server dialogue
        BufferedReader in=null;
        String msg=null;
        String reponse=null;
        iSrvEcho serveur=null;

        try{
             // open keyboard flow
            in=new BufferedReader(new InputStreamReader(System.in));
             // loop for reading msg to be sent to echo server
            System.out.print("Message : ");
            msg=in.readLine().toLowerCase().trim();
            while(! msg.equals("fin")){
                 // send msg to server and receive response
                reponse=serveurEcho.echo(msg);
                 // follow-up
                System.out.println("Réponse serveur : " + reponse);
                 // next msg
                System.out.print("Message : ");                
                msg=in.readLine().toLowerCase().trim();
            }// while
             // it's over
            System.exit(0);
         // error management         
        } catch (Exception e){
            System.err.println("Erreur : " + e);
            System.exit(2);
        }// try
    }// hand

     // ---------------------- getServeurEcho
    private static iSrvEcho getServeurEcho(String machine, String port, 
            String nomService){

         // requests an echo server reference
         // follow-up
        System.out.println("--> Connexion au serveur CORBA en cours...");
         // echo server reference
        iSrvEcho serveurEcho=null;
        try{
             // we request a CORBA object to work with
            String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};    
          ORB orb=ORB.init(initORB,null);
             // use the directory service to locate the echo server
          org.omg.CORBA.Object objRef=
                orb.resolve_initial_references("NameService");
          NamingContext ncRef=NamingContextHelper.narrow(objRef);
             // the service required is called srvEcho - it is requested
          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
         // return the reference to the server
        return serveurEcho;
    }// getServeurEcho

}// class

Wir sehen dieselben Codeabschnitte wie auf dem Server:

  • Wir erstellen ein ORB-Objekt, mit dem wir das CORBA-Dienstverzeichnis kontaktieren können

String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};    
      ORB orb=ORB.init(initORB,null);

  • Wir definieren die verschiedenen Komponenten des Echo-Dienstnamens

        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 auf den Echo-Dienst an (hier unterscheiden wir uns vom Server)

serveurEcho=iSrvEchoHelper.narrow(ncRef.resolve(path));

10.2.6.3. Kompilierung

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:

E:\data\java\corba\ECHO>start j:\jdk12\bin\tnameserv -ORBInitialPort 1000

Dadurch wird der Verzeichnisdienst auf Port 1000 des Rechners gestartet.

Der Verzeichnisdienst tnameserv erzeugt eine Bildschirmausgabe, die wie folgt aussieht:

Initial Naming Context:
IOR:000000000000002849444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f
6e746578743a312e3000000000010000000000000030000100000000000a69737469612d30303900
044700000018afabcafe000000027620dd9a000000080000000000000000
TransientNameServer: setting port for initial object references to: 1000

Es ist schwer zu lesen, aber beachten Sie die letzte Zeile: Der Dienst läuft auf Port 1000.

10.2.7.2. Starten 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 zeigt Folgendes an:

    Serveur d’écho prêt

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. Starten des Clients auf einem anderen Windows-Rechner als dem Server

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 SQL-Server

10.3.1. Einleitung

Hier greifen wir den zuvor im Zusammenhang mit Java RMI untersuchten SQL-Server-Code wieder auf, um erneut die Gemeinsamkeiten und Unterschiede zwischen den beiden Ansätzen hervorzuheben. Zur Erinnerung: Die Rolle dieses SQL-Servers ist folgende: Er läuft auf einem Windows-Rechner und ermöglicht es Remote-Clients, auf die öffentlichen ODBC-Datenbanken auf diesem Windows-Rechner zuzugreifen.

Image

Der CORBA-Client könnte drei Operationen ausführen:

  • eine Verbindung zur Datenbank seiner Wahl herstellen
  • SQL-Abfragen senden
  • die Verbindung schließen

Der Server führt die SQL-Abfragen des Clients aus und sendet die Ergebnisse an den Client zurück. Dies ist seine Hauptfunktion, weshalb wir ihn als SQL-Server bezeichnen. Wir wenden die verschiedenen Schritte an, die zuvor beim Echo-Server behandelt wurden.

10.3.2. Schreiben der IDL-Schnittstelle des Servers

Zur Erinnerung: Hier ist die RMI-Schnittstelle, die wir für den Server verwendet haben:

import java.rmi.*;

 // remote interface p
ublic interface interSQL extends Remote{ 
     public String connect(String pilote, String url, String id, String mdp
        ) throws java.rmi.RemoteExcept
    ion; public String[] executeSQL(String requete, String separa
        teur) throws java.rmi.RemoteE
    xception; public Str
        ing close() throws java.rmi.Re
moteException; }

Die verschiedenen Methoden hatten folgende Funktionen:

Connect: Der Client stellt eine Verbindung zu einer Remote-Datenbank her und übergibt dabei den Treiber, die JDBC-URL sowie seine ID und sein Passwort für den Zugriff auf die Datenbank. Der Server gibt eine Zeichenkette zurück, die das Ergebnis der Verbindung angibt:

    200 - Connexion réussie
    500 - Echec de la connexion

executeSQL: Der Client fordert die Ausführung einer SQL-Abfrage in der Datenbank an, mit der er verbunden ist. Er gibt das Zeichen an, das die Felder in den zurückgegebenen Ergebnissen trennen soll. Der Server gibt ein Array von Zeichenfolgen zurück:

    100 n
für eine Datenbank-Update-Abfrage, wobei n die Anzahl der aktualisierten Zeilen ist
    500 msg d’erreur
    wenn die Abfrage einen Fehler erzeugt hat
    501 Pas de résultats
    wenn die Abfrage keine Ergebnisse lieferte
    101 ligne1
    101 ligne2
    101 ...
wenn die Abfrage Ergebnisse zurückgegeben hat. Die vom Server zurückgegebenen Zeilen sind die Ergebniszeilen der Abfrage.

Schließen: Der Client schließt seine Verbindung zur Remote-Datenbank. Der Server gibt eine Zeichenkette zurück, die das Ergebnis dieses Schließvorgangs angibt:

    200 Base fermée
    500 Erreur lors de la fermeture de la base (msg d’erreur)

Die IDL-Schnittstelle 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();
    };// interface
};// module

Die einzige Neuerung gegenüber der IDL-Schnittstelle des Echo-Servers ist die Verwendung des Schlüsselworts sequence. Mit diesem Schlüsselwort können Sie ein eindimensionales Array definieren. Die Definition erfolgt in zwei Schritten:

  • Definition eines Typs zur Bezeichnung des Arrays, hier „results“:
typedef sequence<string> 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> definiert, d. h. als dynamisches (größenunabhängiges) Array von Zeichenketten.

  • Verwendung des neuen Typs an den erforderlichen Stellen
resultats executeSQL(in string requete, in string separateur);

Die Methode executeSQL gibt daher ein Array von Strings zurück.

10.3.3. Kompilieren der IDL-Schnittstelle des Servers

Die vorstehende IDL-Schnittstelle befindet sich in der Datei srvSQL.idl. Wir kompilieren diese Datei:

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

Wir sehen, dass bei der Kompilierung ein Verzeichnis erstellt wurde, das nach dem IDL-Schnittstellenmodul (srvSQL) benannt ist. 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

Beachten Sie, dass es sich bei den „Helper“- und „Holder“-Dateien um Klassen handelt, die mit den Ein- und Ausgabeparametern sowie den Ergebnissen der Methoden der Remote-Schnittstelle verknüpft sind. Das Verzeichnis „srvSQL“ enthält alle .java-Dateien, die sich auf die in der .idl-Datei definierte interSQL-Schnittstelle beziehen. Es enthält außerdem Dateien, die sich auf den in der IDL-Schnittstelle definierten Ergebnistyp beziehen.

Die Datei „interSQL.java“ ist die Java-Datei für die Schnittstelle unseres Servers. Es ist wichtig zu überprüfen, ob das automatisch Generierte unseren Erwartungen entspricht. Die generierte Datei „interSQL.java“ sieht wie folgt aus:

/*
 * File: ./SRVSQL/INTERSQL.JAVA
 * From: SRVSQL.IDL
 * Date: Fri Mar 19 09:59:48 1999
 *   By: D:\JAVAIDL\IDLTOJ~1.EXE Java IDL 1.2 Aug 18 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 sehen, dass wir dieselbe Schnittstelle haben wie die, die für den RMI-Client-Server verwendet wird. Wir können also fortfahren. Kompilieren wir nun 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 SQL-Servers

Wir werden nun den SQL-Server-Code schreiben. Denken Sie daran, dass diese Klasse von der abstrakten Klasse \_nomInterfaceImplBase abgeleitet sein muss, die durch die Kompilierung der IDL-Datei generiert wurde. Abgesehen von dieser Besonderheit und unter Ausschluss der Codeabschnitte, die sich auf die Registrierung des Dienstes in einem Verzeichnis beziehen, ist der CORBA-Server-Code identisch mit dem des RMI-Servers:

// imported packages
import java.sql.*;
import java.util.*;
import srvSQL.*;

// class SQLServant
public class SQLServant extends _interSQLImplBase{

    // global class data
    private Connection DB;

    // --------------- connect
    public String connect(String pilote, String url, String id,
        String mdp){

        // connection to url database via driver
        // identification with identity id and password mdp

        String resultat=null;            // result of the method
        try{
            // loading the driver
            Class.forName(pilote);
            // connection request
            DB=DriverManager.getConnection(url,id,mdp);
            // ok
            resultat="200 Connexion réussie";
        } catch (Exception e){
            // error
            resultat="500 Echec de la connexion (" + e + ")";
        }
        // end
        return resultat;
    }            

    // ------------- executeSQL
    public String[] executeSQL(String requete, String separateur){

        // executes a SQL query on the DB database
        // and puts the results in an array of strings

        // data required to execute the request
        Statement S=null;
        ResultSet RS=null;
        String[] lignes=null;
        Vector resultats=new Vector();
        String ligne=null;

        try{
            // create query container
            S=DB.createStatement();
            // request execution
            if (! S.execute(requete)){
                // update request
                // returns the number of lines updated
                lignes=new String[1];
                lignes[0]="100 "+S.getUpdateCount();
                return lignes;
            }
            // it was a query request
            // retrieve results
            RS=S.getResultSet();
            // number of Resultset fields
            int nbChamps=RS.getMetaData().getColumnCount();
            // we exploit them
            while(RS.next()){
                // create results line
                ligne="101 ";
                for (int i=1;i<nbChamps;i++)
                    ligne+=RS.getString(i)+separateur;
                ligne+=RS.getString(nbChamps);
                // add to results vector
                resultats.addElement(ligne);
            }// while
            // end of results processing
            // free up resources
            RS.close();
            S.close();
            // we return the results
            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){
            // error
            lignes=new String[1];
            lignes[0]="500 " + e;
            return lignes;
        }// try-catch
    }// executeSQL

    // --------------- close
    public String close(){
        // closes database connection
        String resultat=null;
        try{
            DB.close();
            resultat="200 Base fermée";
        } catch (Exception e){
            resultat="500 Erreur à la fermeture de la base ("+e+")";
        }
        // return result
        return resultat;
    }
}// class SQLServant

Diese Klasse befindet sich in der Datei „SQLServant.java“, die wir gerade 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. Das SQL Server-Startprogramm schreiben

Die vorherige Klasse repräsentiert den SQL-Server, sobald er gestartet wurde. Zuvor muss er jedoch in einem CORBA-Dienstverzeichnis registriert werden. Wie beim Echo-Dienst werden wir dies mithilfe einer speziellen Klasse tun, an die wir zur Laufzeit drei Parameter übergeben:

Rechner: der Rechner, auf dem sich das CORBA-Dienstverzeichnis befindet

Port: der Port, auf dem dieses Verzeichnis läuft

serviceName: Name des SQL-Dienstes

Der Code für diese Klasse ist nahezu identisch mit dem der Klasse, die dieselbe Aufgabe für den Echo-Dienst ausgeführt hat. Wir haben die Zeile, die sich zwischen den beiden Klassen unterscheidet, fett hervorgehoben: Es wird nicht dasselbe Serverobjekt erstellt. Wir sehen also, dass der Mechanismus zum Starten des Servers derselbe bleibt. Wenn wir diesen Mechanismus in eine Klasse auslagern, wie es hier geschehen ist, wird er für den Entwickler praktisch transparent.

// imported packages
import srvSQL.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;

//----------- class serveurSQL
public class serveurSQL{
    // ------- main: launches the SQL server
  public static void main(String arg[]){
        // serveurSQL machine port service

        //do we have the right number of arguments
        if(arg.length!=3){
            System.err.println("Syntaxe : pg machineAnnuaireCorba portAnnuaireCorba nomService");
            System.exit(1);
        }
        // retrieve the arguments
        String machine=arg[0];
        String port=arg[1];
        String nomService=arg[2];
        String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
    try{
            // you need a CORBA object to work
      ORB orb=ORB.init(initORB,null);
            // put the service in the service directory
      org.omg.CORBA.Object objRef=
        orb.resolve_initial_references("NameService");
      NamingContext ncRef=NamingContextHelper.narrow(objRef);
      NameComponent nc= new NameComponent(nomService,"");
      NameComponent path[]={nc};
        // create the server and associate it with the srvSQL service
        SQLServant serveurSQL=new SQLServant();
      ncRef.rebind(path,serveurSQL);
        orb.connect(serveurSQL);
        // follow-up
        System.out.println("Serveur SQL prêt");
        // waiting for customer requests
      java.lang.Object sync=new java.lang.Object();
      synchronized(sync){
        sync.wait();
      }
    } catch(Exception e){
            // there has been an error
      System.err.println("Erreur " + e);
      e.printStackTrace(System.err);
    }
  }// hand
}// 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-Code

Der CORBA-Server-Client wird mit den folgenden Parametern aufgerufen:

    machine port nomServiceAnnuaire pilote urlBase id mdp separateur

Rechner: Rechner, auf dem sich das CORBA-Dienstverzeichnis befindet

port: der Port, auf dem dieses Verzeichnis läuft

serviceName: Name des SQL-Dienstes

Treiber: Der Treiber, den der SQL-Server zur Verwaltung der gewünschten Datenbank verwenden muss

baseUrl: JDBC-URL der zu verwaltenden Datenbank

id: Client-ID oder null, falls keine ID vorhanden ist

password: Client-Passwort oder null, falls kein Passwort vorhanden ist

separator: Zeichen, das der SQL-Server verwenden muss, um Felder in den Ergebniszeilen einer Abfrage zu trennen

Hier ist ein Beispiel für mögliche Parameter:

    localhost 1000 srvSQL sun.jdbc.odbc.JdbcOdbcDriver jdbc:odbc:articles null null ,

wobei:

machine: Rechner, auf dem sich das CORBA-Dienstverzeichnis befindet

port: der Port, über den dieses Verzeichnis läuft

srvSQL: srvSQL, der CORBA-Name des SQL-Servers

Treiber: sun.jdbc.odbc.JdbcOdbcDriver, der Standardtreiber für Datenbanken mit einer ODBC-Schnittstelle

urlBase: jdbc:odbc:articles, um eine Artikeldatenbank zu verwenden, die in der Liste der öffentlichen ODBC-Datenbanken auf dem Windows-Rechner deklariert ist

id: null, keine ID

password: null, kein Passwort

Trennzeichen: , Ergebnisfelder werden durch ein Komma getrennt

Nach dem Start mit den oben genannten Parametern führt der Client die folgenden Schritte aus:

  • Er verbindet sich mit dem Rechner machine über den Port port, um den CORBA-Dienst srvSQL anzufordern
  • Er fordert eine Verbindung zur Artikeldatenbank an
connect(‘’sun.jdbc.odbc.JdbcOdbcDriver’’, ‘‘jdbc:odbc:articles’’, ’’’’, ’’’’)
  • sie fordern den Benutzer auf, eine SQL-Abfrage über die Tastatur einzugeben
  • sie sendet diese an den SQL-Server
executeSQL(requete, ’’,’’);
  • Es zeigt die vom Server zurückgegebenen Ergebnisse auf dem Bildschirm an
  • Es fordert den Benutzer erneut auf, eine SQL-Abfrage über die Tastatur einzugeben. Der Vorgang wird beendet, sobald die Abfrage abgeschlossen ist.

Nachfolgend finden Sie den Java-Client-Code. Die Kommentare sollten zum Verständnis ausreichen. Beachten Sie bitte Folgendes:

  • Der Code ist identisch mit dem des bereits behandelten RMI-Clients. Er unterscheidet sich lediglich im Ablauf der Anforderung des Dienstes aus dem Verzeichnis, ein Vorgang, der in der Methode getServeurSQL isoliert ist.
  • Die Methode getServeurSQL ist identisch mit der für den Echo-Client geschriebenen.

Wir können daher feststellen, dass:

  • sich ein CORBA-Client von einem RMI-Client nur in der Art und Weise unterscheidet, wie er den Server kontaktiert
  • Diese Methode ist für alle CORBA-Clients identisch
import srvSQL.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
import java.io.*;

public class clientSQL {

    // global class data
    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 machine port separator driver url id mdp
        // machine port: machine & service directory port CORBA to contact
        // department: department name
        // driver: driver to be used for the database to be processed
        // urlBase: jdbc url of the database to be used
        // id: user identity
        // mdp: password
        // separator: string separating fields in query results

        // check number of arguments
        if(arg.length!=8)
            erreur(syntaxe,1);

        // init database connection parameters
        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];        

        // directory service parameters CORBA
        String[] initORB={"-ORBInitialHost",arg[0],"-ORBInitialPort",arg[1]};
        // client CORBA - request a server reference SQL
        interSQL serveurSQL=getServeurSQL(machine,port,service);

        // client-server dialogue
        String requete=null;
        String reponse=null;
        String[] lignes=null;
        String codeErreur=null;

        try{
            // open keyboard flow
            in=new BufferedReader(new InputStreamReader(System.in));
            // follow-up
            System.out.println("--> Connexion à la base de données en cours");
            // initial database connection request
            reponse=serveurSQL.connect(pilote,urlBase,id,mdp);
            // follow-up
            System.out.println("<-- "+reponse);
            // response analysis
            codeErreur=reponse.substring(0,3);
            if(codeErreur.equals("500")) 
                erreur("Abandon sur erreur de connexion à la base",3);
            // loop for reading requests to be sent to the server SQL
            System.out.print("--> Requête : ");
            requete=in.readLine().toLowerCase().trim();
            while(! requete.equals("fin")){
                // send request to server and receive response
                lignes=serveurSQL.executeSQL(requete,separateur);
                // follow-up
                afficheLignes(lignes);
                // following request
                System.out.print("--> Requête : ");                
                requete=in.readLine().toLowerCase().trim();
            }// while
            // follow-up
            System.out.println("--> Fermeture de la connexion à la base de données distante");
            // close the connection
            reponse=serveurSQL.close();
            // follow-up
            System.out.println("<-- " + reponse);
            // end
            System.exit(0);
        // error management        
        } catch (Exception e){
            erreur("Abandon sur erreur : " + e,2);
        }// try
    }// hand

    // ----------- AfficheLignes
    private static void afficheLignes(String[] lignes){
        for (int i=0;i<lignes.length;i++)
            System.out.println("<-- " + lignes[i]);
    }// afficheLignes

    // ------------ error
    private static void erreur(String msg, int exitCode){
        // error msg display
        System.err.println(msg);
        // possible release of resources
        try{
            in.close();
            serveurSQL.close();
        } catch(Exception e){}
        // we leave
        System.exit(exitCode);
    }// error

    // ---------------------- getServeurSQL
    private static interSQL getServeurSQL(String machine, String port, String service){
        // requests a server reference SQL
        // machine: service directory machine CORBA
        // port: service directory port CORBA
        // service: service name CORBA to request

        // follow-up
        System.out.println("--> Connexion au serveur CORBA en cours...");
        // server reference SQL
        interSQL serveurSQL=null;
        // directory service parameters CORBA
        String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
                try{
            // a CORBA object is required to work - to do this, we pass the port 
            // service directory listening CORBA
      ORB orb=ORB.init(initORB,null);
            // use the directory service to locate the SQL server
      org.omg.CORBA.Object objRef=
        orb.resolve_initial_references("NameService");
      NamingContext ncRef=NamingContextHelper.narrow(objRef);
            // the service required is called srvSQL - it is requested
      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
        // return the reference to the server
        return serveurSQL;
    }// getServeurSQL

}// class

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 den Test.

10.3.7. Tests

10.3.7.1. Voraussetzungen

Wir gehen davon aus, dass eine ACCESS-Datenbank namens „Articles“ auf dem Windows-Rechner des SQL-Servers öffentlich verfügbar ist:

Image

Diese Datenbank hat folgende Struktur:

name
Typ
Code
4-stelliger Artikelcode
Name
sein Name (Zeichenkette)
Preis
sein Preis (tatsächlich)
aktueller_bestand
aktueller Lagerbestand (Ganzzahl)
min_stock
der Mindestbestand (Ganzzahl), unterhalb dessen der Artikel nachbestellt werden muss

10.3.7.2. Starten 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. Starten des SQL-Servers

Starten des SQL-Servers:

E:\data\java\corba\sql>start j:\jdk12\bin\java serveurSQL localhost 1000 srvSQL

In einem DOS-Fenster wird Folgendes angezeigt:

    Serveur SQL prêt

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 ,
--> Connection to server CORBA in progress...
--> Current database connection
<-- 200 Successful connection
--> Requête : select nom, stock_actu, stock_mini from articles
<-- 101 bicycle,31,8
<-- 101 arc,9,8
<-- 101 canoeing,7,7
<-- 101 rifle,9,8
<-- 101 water skis,13.8
<-- 101 test3,13,9
<-- 101 sperm whale,6,6
<-- 101 leopard,7,7
<-- 101 panther,7,7
--> Requête : delete from articles where stock_mini<7
<-- 100 1
--> Requête : select nom, stock_actu, stock_mini from articles
<-- 101 bicycle,31,8
<-- 101 arc,9,8
<-- 101 canoeing,7,7
<-- 101 rifle,9,8
<-- 101 water skis,13.8
<-- 101 test3,13,9
<-- 101 leopard,7,7
<-- 101 panther,7,7
--> Query: end
--> Closing the remote database connection
<-- 200 Closed base

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 ,
--> Connection to server CORBA in progress...
--> Current database connection
<-- 200 Successful connection
--> Requête : select * from articles
<-- 101 a300,v_lo,1202,31,8
<-- 101 d600,arc,5000,9,8
<-- 101 d800,canoe,1502,7,7
<-- 101 x123,rifle,3000,9,8
<-- 101 s345,water skis,1800,13,8
<-- 101 f450,test3,3,13,9
<-- 101 z400,leopard,500000,7,7
<-- 101 g457,panther,800000,7,7
--> Query: end
--> Closing the remote database connection
<-- 200 Closed base

10.4. IDL-JAVA-Entsprechungen

Hier stellen wir die Zuordnungen zwischen einfachen IDL- und Java-Typen bereit:

IDL-Typ
Java-Typ
boolean
bool
Zeichen
char
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 von Elementen des Typs T in der IDL-Schnittstelle zu definieren, verwenden wir die Anweisung:

    typedef   sequence<T> nomType;

und dass wir anschließend TypeName verwenden, um auf den Array-Typ zu verweisen. Daher haben wir in der SQL-Server-Schnittstelle die folgende Deklaration verwendet:

    typedef sequence<string> resultats;

verwendet, sodass „results“ in Java auf ein String[]-Array verweist.