Skip to content

10. Dağıtık Uygulamaların Oluşturulması CORBA

10.1. Giriş

Önceki bölümde, RMI paketini kullanarak Java'da dağıtık uygulamaların nasıl oluşturulacağını gördük. Burada aynı konuyu, bu kez CORBA mimarisiyle ele alacağız. CORBA (Common Object Request Broker Architecture), bilgi teknolojisi sektöründeki birçok şirketi bir araya getiren OMG (Object Management Group) tarafından tanımlanan bir spesifikasyondur. CORBA, farklı dillerde yazılmış uygulamaların erişebileceği bir “yazılım veriyolu” tanımlar:

Image

CORBA ile dağıtık bir uygulamanın oluşturulmasının, Java RMI ile kullanılan yönteme yakın olduğunu göreceğiz: kavramlar birbirine benzemektedir. CORBA, diğer dillerde yazılmış uygulamalarla birlikte çalışabilme avantajı sunar.

10.2. Bir CORBA uygulamasının geliştirme süreci

10.2.1. Giriş

Bir CORBA istemci-sunucu uygulaması geliştirmek için aşağıdaki adımları izleyeceğiz:

  1. IDL (Arayüz Tanımlama Dili) ile sunucu arayüzünün yazılması
  2. sunucunun "iskelet" ve "stub" sınıflarının oluşturulması
  3. sunucunun yazılması
  4. istemcinin yazılması
  5. tüm sınıfların derlenmesi
  6. CORBA hizmet dizinini başlatma
  7. sunucunun başlatılması
  8. istemcinin başlatılması

İlk örnek olarak, RMI bağlamında daha önce kullanılan yankı sunucusunu ele alacağız. Böylece okuyucu, iki yöntem arasındaki farkları görebilecektir.

Uygulama, jdk1.2 ile test edilmiştir.

10.2.2. Sunucu arayüzünün yazılması

Java RMI’te olduğu gibi, istemci açısından sunucu, arayüzüyle tanımlanır. Sunucuyu uygulayan sınıflar istemci için gerekli olmasa da, arayüzündeki sınıflar gereklidir. Java RMI'te, sunucunun "iskelet" ve "stub" sınıflarını oluşturan bir Java arayüzü kullanılırken, Java CORBA mimarisinde arayüzün Java dışındaki bir dil ile tanımlanması gerekmektedir. Bu arayüz, bazıları istemci tarafından, bazıları ise sunucu tarafından kullanılan birkaç sınıfın oluşturulmasına yol açacaktır.

Yankı arayüzünün tanımı şu şekilde olacaktır:

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

Arayüz tanımı, echo.idl adlı bir dosyada depolanacaktır. Bu tanım, OMG'in IDL (Arayüz Tanım Dili) dilinde yazılmıştır. Kullanılabilir hale gelmesi için, CORBA uygulamasını geliştirmek için kullanılan dilde kaynak dosyalar oluşturacak bir program tarafından analiz edilmesi gerekir. Burada, önceki arayüzden yola çıkarak uygulama için gerekli olan .java kaynak dosyalarını oluşturacak olan idltojava.exe programını kullanacağız. idltojava.exe programı, JDK ile birlikte sunulmamaktadır. Bu program, Sun’ın http://java.sun.com adresindeki web sitesinden edinilebilir.

Yukarıdaki idl arayüzünün birkaç satırını inceleyelim:

module echo

Java’daki echo paketine eşdeğerdir. Arayüzün derlenmesi sonucunda, Java sınıflarını içeren echo c.a.d java paketi oluşturulur.

interface iSrvEcho

Java'daki iSrvEcho arayüzüne eşdeğerdir. Bir Java arayüzü oluşturacaktır.

string echo(in string msg)

Java'daki String echo(String msg) komutuna eşdeğerdir. IDL dilindeki türler, Java dilindeki türlerle tam olarak eşleşmez. Eşleşmeler bu bölümün ilerleyen kısımlarında verilmiştir. IDL dilinde, bir fonksiyonun parametreleri giriş (in), çıkış (out) veya giriş-çıkış (inout) parametreleri olabilir. Burada, echo yöntemi, bir karakter dizesi olan msg giriş parametresini alır ve sonuç olarak bir karakter dizesi döndürür.

Yukarıdaki arayüz, yankı sunucumuzun arayüzüdür. Hatırlatmak gerekirse, bir uzak arayüz, istemcilerin erişebileceği sunucu nesnesinin yöntemlerini tanımlar. Burada, istemciler için yalnızca echo yöntemi kullanılabilir olacaktır.

10.2.3. Sunucunun IDL arayüzünün derlenmesi

Sunucu arayüzü tanımlandıktan sonra, ilgili Java dosyaları oluşturulur.

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

-fno-cpp seçeneği, ön işlemcinin kullanılmayacağını belirtmek için kullanılır (çoğunlukla C/C++ ile kullanılır). echo.idl dosyasının derlenmesi sonucunda, içinde aşağıdaki dosyaların bulunduğu bir echo alt dizini oluşturulur:

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

iSrvEcho.java dosyası, sunucu arayüzünü tanımlayan Java dosyasıdır:

/*  * Dosya: ./ECHO/ISRVECHO.JAVA  * Kaynak: ECHO.IDL  * Tarih: 15 Mart 1999 Pazartesi 13:56:08  *   Tarafından: D:\JAVAIDL\IDLTOJ~1.EXE Java IDL 1.2 18 Ağustos 1998 16:25:34  */

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

Görüldüğü üzere, bu dosya IDL arayüzünün neredeyse kelimesi kelimesine çevirisidir. Diğer .java dosyalarının içeriğine bakmak isterseniz, daha karmaşık şeyler bulacaksınız. İşte bu farklı dosyaların rolüne ilişkin belgelerde yazanlar:

iSrvEcho.java

sunucu arayüzü

_iSrvEchoImplbase.java

önceki iSrvEcho arayüzünü uygular. Bu, dağıtılmış uygulama için gerekli CORBA işlevlerini sunucuya sağlayan, sunucunun “iskeleti” niteliğindeki soyut bir sınıftır.

_iSrvEchoStub.java

Bu, istemcinin kullanacağı sunucunun görüntüsüdür (“stub”). İstemciye, sunucuya erişmek için gerekli CORBA işlevlerini sağlar.

iSrvEchoHelper.java

CORBA nesne referanslarının yönetimi için gerekli yöntemleri sağlar

iSrvEchoHolder.java

Arayüz yöntemlerinin giriş-çıkış parametrelerinin yönetimi için gerekli yöntemleri sağlar.

10.2.4. IDL arayüzünden oluşturulan sınıfların derlenmesi

Yukarıdaki sınıfları derlemek iyi bir fikirdir. Başka bir örnekte göreceğimiz üzere, burada idltojava oluşturucusunun hatalı çalışmasından kaynaklanan hataları tespit edebiliriz. Burada her şey yolunda gidiyor ve derleme işleminden sonra echo paket dizininde aşağıdaki dosyalar bulunuyor:

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. Sunucu Kaydı

10.2.5.1. iSrvEcho arayüzünün uygulanması

Yukarıda iSrvEcho arayüzünü tanımladık. Şimdi bu arayüzü uygulayan sınıfı yazıyoruz. Bu sınıf, yukarıda belirtildiği gibi iSrvEcho arayüzünü zaten uygulayan _iSrvEchoImplbase.java sınıfından türetilecektir.

// ithal edilen paketler
import echo.*;

// uzaktan yankı işlevini uygulayan sınıf
public class srvEcho extends _iSrvEchoImplBase{
    // yankı işlevini gerçekleştiren yöntem
    public String echo(String msg){
        return  "["  + msg + "]";
    }// yankı sonu
}// sınıf sonu

Kod kendiliğinden anlaşılır. Bu sınıf, iSrvEcho arayüzünün paketinin üst dizininde bulunan srvEcho.java dosyasına kaydedilir.

Doğrulamak için derleme yapabilirsiniz:

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. Sunucu oluşturma sınıfının yazılması

RMI istemci-sunucu uygulamasında olduğu gibi, bir CORBA sunucusunun da istemciler tarafından erişilebilir olması için bir dizine kaydedilmesi gerekir. Geliştirme aşamasında, bu kayıt prosedürü, uygulamanın CORBA mi yoksa RMI mi olduğuna göre farklılık gösterir. Aşağıda, serveurEcho.java dosyasına kaydedilmiş CORBA yankı sunucusuna ait kayıt yer almaktadır:

// ithal edilen paketler
import echo.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;

//----------- serveurEcho sınıfı
public class serveurEcho{
    // ------- main: yankı sunucusunu başlatır
    // pg sözdizimi machineAnnuaire portAnnuaire nomService
    // makine: rehberi destekleyen makine CORBA
    // bağlantı noktası: rehberin bağlantı noktası CORBA
    // nomService: kaydedilecek hizmet adı

  public static void main(String arg[]){
    // argümanlar mevcut mu?
    if(arg.length!=3){
        System.err.println("Syntaxe : pg machineAnnuaire portAnnuaire nomService");
        System.exit(1);
    }
    // argümanları alıyoruz
    String machine=arg[0];
    String port=arg[1];
    String nomService=arg[2];

    try{

    // Çalışmak için bir CORBA nesnesine ihtiyacımız var
    String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
      ORB orb=ORB.init(initORB,null);
    // hizmeti hizmet dizinine ekliyoruz
    // Adı srvEcho olacak
      org.omg.CORBA.Object objRef=
        orb.resolve_initial_references("NameService");
      NamingContext ncRef=NamingContextHelper.narrow(objRef);
      NameComponent nc= new NameComponent(nomService,"");
      NameComponent path[]={nc};
    // sunucuyu oluşturup srvEcho hizmetiyle ilişkilendiriyoruz
    srvEcho serveurEcho=new srvEcho();
      ncRef.rebind(path,serveurEcho);
    orb.connect(serveurEcho);
    // takip
    System.out.println("Serveur d'écho prêt");
    // istemcilerin isteklerini bekleme
      java.lang.Object sync=new java.lang.Object();
      synchronized(sync){
        sync.wait();
      }
    } catch(Exception e){
    // bir hata oluştu
      System.err.println("Erreur " + e);
      e.printStackTrace(System.err);
    }
  }// ana
}// serveurEcho

Aşağıda, ilk bakışta karmaşık görünen ayrıntılara girmeden sunucunun başlatılmasının ana hatlarını açıklıyoruz. Önceki örnekten, tüm CORBA sunucularında tekrar karşımıza çıkacak olan ana hatları akılda tutmak gerekir.

10.2.5.2.1. Sunucu ayarları

Bir CORBA sunucusu, belirli bir makine ve bağlantı noktasında çalışan bir dizin hizmetine kaydolmalıdır. Uygulamamız bu iki veriyi parametre olarak alacaktır. Bu şekilde kaydedilen hizmetin bir adı olmalıdır; bu, üçüncü parametre olacaktır.

10.2.5.2.2. CORBA dizin hizmetine erişim nesnesini oluşturma

Dizin hizmetine erişmek ve yankı sunucumuzu kaydetmek için, aşağıdaki sınıf yöntemiyle elde edilen ORB (Object Request Broker) adlı bir nesneye ihtiyacımız var:

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

Örnekte, ORB nesnesini elde etmek için aşağıdaki dizi kullanılmaktadır:


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

Kullanılan (parametre, değer) çiftleri şunlardır:


("-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.

init yönteminin ikinci parametresi null olarak bırakılmıştır. İlk parametre de null olarak bırakılmış olsaydı, kullanılan (makine, bağlantı noktası) çifti varsayılan olarak (localhost,900) olurdu.

10.2.5.2.3. Sunucuyu hizmet dizinine kaydetme CORBA

Sunucunun dizinine kaydı aşağıdaki işlemlerle gerçekleştirilir:

    // hizmet, hizmetler dizinine ekleniyor
    // adı srvEcho olacak
      org.omg.CORBA.Object objRef=
        orb.resolve_initial_references("NameService");
      NamingContext ncRef=NamingContextHelper.narrow(objRef);
      NameComponent nc= new NameComponent(nomService,"");
      NameComponent path[]={nc};
    // sunucu oluşturulur ve srvEcho hizmetiyle ilişkilendirilir
    srvEcho serveurEcho=new srvEcho();
          ncRef.rebind(path,serveurEcho);
            orb.connect(serveurEcho);

Kodun ilk kısmı, hizmet adının hazırlanmasından oluşur. Bu ad, kodda path değişkeni ile temsil edilir. Bir hizmet adı birkaç bileşenden oluşur:

  • objRef adlı başlangıç bileşeni; bu, NamingContext türüne dönüştürülmesi gereken genel bir nesnedir; burada ncRef.
  • hizmet adı, burada sunucuya parametre olarak aktarılan nomService

Adın bu bileşenleri (NameComponent) bir dizide bir araya getirilir; burada path. Oluşturulan hizmeti kesin olarak “adlandıran” bu dizidir. Ad oluşturulduktan sonra geriye kalan

  • sunucunun bir örneğiyle (daha önce oluşturulan srvEcho sınıfı) ilişkilendirmek kalır

srvEcho serveurEcho=new srvEcho();
  • ve bunu dizinine kaydetmek
    ncRef.rebind(path,serveurEcho);
    orb.connect(serveurEcho);

10.2.5.3. Sunucu başlatma sınıfının derlenmesi

Önceki sınıfı derliyoruz:

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. Müşterinin yazısı

10.2.6.1. Kod

Yankı hizmetimizi test etmek için bir istemci yazıyoruz. İstemciye, sunucuya verdiğimiz üç parametrenin aynısını vereceğiz:

Makine: CORBA hizmet dizinlerinin bulunduğu makine

Bağlantı noktası: Bu dizinin çalıştığı bağlantı noktası

nomService: yankı hizmetinin adı

İstemci, yankı hizmetine bağlanır ve ardından kullanıcıdan klavyeyle mesajlar yazmasını ister. Bu mesajlar yankı sunucusuna gönderilir ve sunucu da bunları geri gönderir. Bu diyalogun takibi ekranda yapılır.

Yankı hizmetinin CORBA istemcisi, daha önce yazılan RMI istemcisine çok benzemektedir. Burada da istemci, bağlanmak istediği sunucu nesnesinin referansını almak için bir dizin hizmetine bağlanmalıdır. İki istemci arasındaki fark, sadece ve sadece budur. İşte CORBA yankı istemcisinin kodu:


    

10.2.6.2. İstemcinin sunucuya bağlanması

Yukarıdaki CORBA istemcisi, şu komutla sunucuya bağlanır:

        // yankı sunucusuyla bağlantı kurulur
        iSrvEcho serveurEcho=getServeurEcho(machine,port,nomService);

Bu işlemin ardından, istemci echo sunucusunun bir referansını elde eder. Bundan sonra, CORBA istemcisi ile RMI istemcisi arasında bir fark kalmaz. Sunucuya bağlantıyı sağlayan özel yöntem şöyledir:

// ithal edilen paketler
import java.io.*;
import echo.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;

// ---------- cltEcho sınıfı
public class cltEcho {

    public static void main(String arg[]){
         // sözdizimi: cltEcho machineAnnuaire portAnnuaire hizmetadı
         // makine: hizmet rehberinin çalıştığı makine CORBA
         // bağlantı noktası: hizmet dizininin çalıştığı bağlantı noktası
         // nomService: yankı hizmetinin adı

         // argümanların doğrulanması
        if(arg.length!=3){
            System.err.println("Syntaxe : pg machineAnnuaire portAnnuaire nomservice");
            System.exit(1);
        }

         // parametreler alınır
        String machine=arg[0];
        String port=arg[1];
        String nomService=arg[2];

         // yankı sunucusuyla bağlantı kuruluyor
        iSrvEcho serveurEcho=getServeurEcho(machine,port,nomService);

         // istemci-sunucu iletişimi
        BufferedReader in=null;
        String msg=null;
        String reponse=null;
        iSrvEcho serveur=null;

        try{
             // klavye akışının açılması
            in=new BufferedReader(new InputStreamReader(System.in));
             // yankı sunucusuna gönderilecek mesajları okuma döngüsü
            System.out.print("Message : ");
            msg=in.readLine().toLowerCase().trim();
            while(! msg.equals("fin")){
                 // mesajın sunucuya gönderilmesi ve yanıtın alınması
                reponse=serveurEcho.echo(msg);
                 // izleme
                System.out.println("Réponse serveur : " + reponse);
                 // sonraki mesaj
                System.out.print("Message : ");                
                msg=in.readLine().toLowerCase().trim();
            }// while
             // işlem tamamlandı
            System.exit(0);
         // hata yönetimi         
        } catch (Exception e){
            System.err.println("Erreur : " + e);
            System.exit(2);
        }// try
    }// main

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

         // yankı sunucusundan referans ister
         // takip
        System.out.println("--> Connexion au serveur CORBA en cours...");
         // yankı sunucusunun referans numarası
        iSrvEcho serveurEcho=null;
        try{
             // çalışmak için CORBA nesnesi talep ediliyor
            String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};    
          ORB orb=ORB.init(initORB,null);
             // yankı sunucusunu bulmak için dizin hizmeti kullanılıyor
          org.omg.CORBA.Object objRef=
                orb.resolve_initial_references("NameService");
          NamingContext ncRef=NamingContextHelper.narrow(objRef);
             // aranan hizmetin adı srvEcho'tir - bu hizmet talep ediliyor
          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
         // sunucuya referans veriliyor
        return serveurEcho;
    }// getServeurEcho

}// sınıf

Sunucudakiyle aynı kod dizileri karşımıza çıkıyor:

  • ORB adlı bir nesne oluşturuyoruz; bu nesne, CORBA hizmet dizinine bağlanmamızı sağlayacak
String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};    
      ORB orb=ORB.init(initORB,null);
  • yankı hizmetinin adının çeşitli bileşenlerini tanımlıyoruz
        org.omg.CORBA.Object objRef=orb.resolve_initial_references("NameService");
      NamingContext ncRef=NamingContextHelper.narrow(objRef);
      NameComponent nc= new NameComponent(nomService,"");
      NameComponent path[]={nc};
  • dizin hizmetinden yankı hizmetinin referansını talep ediyoruz (işte bu noktada sunucudan farklılık gösteriyoruz)
serveurEcho=iSrvEchoHelper.narrow(ncRef.resolve(path));

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. Testler

10.2.7.1. Dizin hizmetinin başlatılması

Bir Windows makinesinde, dizin hizmetini şu şekilde başlatıyoruz:

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

Bu komut, makinenin 1000 numaralı bağlantı noktasında dizin hizmetini başlatır.

tnameserv dizin hizmeti, aşağıdakine benzer bir ekran çıktısı üretir:

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

Okunması biraz zor, ancak son satırı not edelim: hizmet 1000 numaralı bağlantı noktasında aktif.

10.2.7.2. Echo sunucusunun başlatılması

Echo hizmeti üç parametreyle başlatılır:


E:\data\java\corba\ECHO>start j:\jdk12\bin\java serveurEcho localhost 1000 srvEcho

Sunucu şunu görüntüler:

    Serveur d’écho prêt

10.2.7.3. Sunucuyla aynı bilgisayarda istemcinin başlatılması


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. Sunucudan farklı bir Windows bilgisayarda istemcinin başlatılması

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. Örnek 2: bir SQL sunucusu

10.3.1. Giriş

Burada, daha önce Java bağlamında incelediğimiz SQL sunucusunun kodunu tekrar ele alıyoruz. RMI, her iki yöntemin ortak noktalarını ve farklılıklarını vurgulamak amacıyla. SQL sunucusunun işlevini hatırlatmak gerekirse: Bu sunucu bir Windows makinesinde bulunur ve uzak istemcilerin bu Windows makinesindeki ODBC genel veritabanlarını kullanmasına olanak tanır.

Image

CORBA istemcisi 3 işlem gerçekleştirebilir:

  • seçtiği veritabanına bağlanmak
  • SQL sorguları gönderebilir
  • bağlantıyı kapatmak

Sunucu, istemcinin SQL isteklerini yürütür ve sonuçları istemciye gönderir. Bu, sunucunun temel işlevidir ve bu nedenle ona SQL sunucusu diyoruz. Daha önce yankı sunucusu ile gördüğümüz çeşitli adımları burada da uygularız.

10.3.2. Sunucunun IDL arayüzünün yazılması

Hatırlatmak gerekirse, sunucu için kullandığımız RMI arayüzü şöyledir:

import java.rmi.*;

// uzak arayüz
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;
}

Farklı yöntemlerin rolleri şu şekildeydi:

Connect: İstemci, uzak bir veritabanına bağlanır ve bu veritabanına erişmek için sürücüsünü, JDBC URL'sini, kimliğini (id) ve şifresini (mdp) belirtir. Sunucu, bağlantının sonucunu gösteren bir karakter dizisini istemciye döndürür:

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

executeSQL: İstemci, bağlı olduğu veritabanında SQL sorgusunun yürütülmesini ister. Geri gönderilen sonuçlarda alanları ayıracak karakteri belirtir. Sunucu, bir dizi karakter dizisi döndürür:

    100 n

veritabanı güncelleme isteği için; burada n, güncellenen satır sayısını ifade eder

    500 msg d’erreur

istek bir hata oluşturduysa

    501 Pas de résultats

istek herhangi bir sonuç üretmediyse

    101 ligne1
    101 ligne2
    101 ...

sorgu sonuç ürettiğinde. Sunucu tarafından bu şekilde döndürülen satırlar, sorgunun sonuç satırlarıdır.

Close: İstemci, uzak veritabanıyla olan bağlantısını kapatır. Sunucu, bu kapatma işleminin sonucunu belirten bir dize döndürür:

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

Sunucunun IDL arayüzü şu şekilde olacaktır:

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();
    };// arayüz
};// modül

Echo sunucusunun IDL arayüzünde gördüğümüzden tek fark, sequence anahtar sözcüğünün kullanılmasıdır. Bu anahtar sözcük, tek boyutlu bir dizi tanımlamaya olanak tanır. Tanımlama iki adımda yapılır:

  • diziyi tanımlamak için bir tür belirleme, burada "resultats":
typedef sequence<string> resultats;

typedef anahtar sözcüğü, C/C++ programcıları tarafından iyi bilinir: bu anahtar sözcük, yeni bir tür tanımlamaya olanak tanır. Burada, resultats türü, sequence<string> türü olan c.a.d ile eşdeğer olarak tanımlanmıştır. Bu, dinamik (boyutu belirlenmemiş) bir karakter dizisi dizisidir.

  • Yeni türün ihtiyaç duyulan yerlerde kullanımı
resultats executeSQL(in string requete, in string separateur);

Dolayısıyla, executeSQL yöntemi bir karakter dizisi dizisi döndürür.

10.3.3. Sunucunun IDL arayüzünün derlenmesi

Önceki IDL arayüzü, srvSQL.idl dosyasına eklenir. Bu dosya derlenir:

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

Derleme sonucunda, IDL (srvSQL) adlı arayüz modülünün adını taşıyan bir dizin oluşturulduğu görülmektedir. Bu dizinin içeriğine bir göz atalım:

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

Helper ve Holder dosyalarının, uzaktan arayüzün yöntemlerinin giriş-çıkış parametreleri ve sonuçlarıyla ilişkili sınıflar olduğu hatırlatılmalıdır. srvSQL dizini, .idl dosyasında tanımlanan interSQL arayüzüyle ilgili tüm .java dosyalarını içerir. Ayrıca, IDL arayüzünde oluşturulan resultats türüyle ilgili dosyalar da bulunmaktadır.

interSQL.java dosyası, sunucumuzun arayüzüne ait Java dosyasıdır. Otomatik olarak oluşturulan dosyanın beklentilerimize uygun olup olmadığını kontrol etmek önemlidir. Oluşturulan interSQL.java dosyası şöyledir:

/*  * Dosya: ./SRVSQL/INTERSQL.JAVA  * Kaynak: SRVSQL.IDL  * Tarih: 19 Mart 1999 Cuma 09:59:48  *   Tarafından: D:\JAVAIDL\IDLTOJ~1.EXE Java IDL 1.2 18 Ağustos 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()
;
}

Görüldüğü gibi, RMI istemci-sunucu için kullanılan arayüzle aynı arayüze sahibiz. Dolayısıyla devam edebiliriz. Tüm bu .java dosyalarını derleyelim:

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. SQL sunucusunun kodu

Şimdi SQL sunucu kodunu yazıyoruz. Bu sınıfın, IDL dosyasının derlenmesi sonucu üretilen _nomInterfaceImplBase soyut sınıfından türetilmesi gerektiğini hatırlayalım. Bu özellik dışında ve hizmetin bir dizine kaydedilmesiyle ilgili kod dizileri hariç tutulduğunda, CORBA sunucusunun kodu, RMI sunucusunkiyle aynıdır:

// ithal edilen paketler
import java.sql.*;
import java.util.*;
import srvSQL.*;

// sınıf SQLServant
public class SQLServant extends _interSQLImplBase{

    // sınıfın genel verileri
    private Connection DB;

    // --------------- bağlantı
    public String connect(String pilote, String url, String id,
        String mdp){

        // sürücü aracılığıyla url veritabanına bağlantı
        // id kimliği ve mdp şifresi ile kimlik doğrulama

        String resultat=null;            // yöntemin sonucu
        try{
            // sürücünün yüklenmesi
            Class.forName(pilote);
            // bağlantı isteği
            DB=DriverManager.getConnection(url,id,mdp);
            // tamam
            resultat="200 Connexion réussie";
        } catch (Exception e){
            // hata
            resultat="500 Echec de la connexion (" + e + ")";
        }
        // son
        return resultat;
    }            

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

        // SQL sorgusunu DB veritabanında yürütür
        // ve sonuçları bir dize dizisine yerleştiriyor

        // sorgunun yürütülmesi için gerekli veriler
        Statement S=null;
        ResultSet RS=null;
        String[] lignes=null;
        Vector resultats=new Vector();
        String ligne=null;

        try{
            // sorgu konteynerinin oluşturulması
            S=DB.createStatement();
            // sorgunun yürütülmesi
            if (! S.execute(requete)){
                // güncelleme sorgusu
                // güncellenen satır sayısı döndürülür
                lignes=new String[1];
                lignes[0]="100 "+S.getUpdateCount();
                return lignes;
            }
            // bu bir sorgu idi
            // sonuçlar alınır
            RS=S.getResultSet();
            // Sonuç kümesindeki alan sayısı
            int nbChamps=RS.getMetaData().getColumnCount();
            // bunlar işlenir
            while(RS.next()){
                // sonuç satırının oluşturulması
                ligne="101 ";
                for (int i=1;i<nbChamps;i++)
                    ligne+=RS.getString(i)+separateur;
                ligne+=RS.getString(nbChamps);
                // sonuç vektörüne eklenir
                resultats.addElement(ligne);
            }// while
            // sonuçların işlenmesi sona erdi
            // kaynaklar serbest bırakılıyor
            RS.close();
            S.close();
            // sonuçların döndürülmesi
            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){
            // hata
            lignes=new String[1];
            lignes[0]="500 " + e;
            return lignes;
        }// try-catch
    }// executeSQL

    // --------------- kapat
    public String close(){
        // veritabanı bağlantısını kapatır
        String resultat=null;
        try{
            DB.close();
            resultat="200 Base fermée";
        } catch (Exception e){
            resultat="500 Erreur à la fermeture de la base ("+e+")";
        }
        // sonucun döndürülmesi
        return resultat;
    }
}// SQLServant sınıfı

Bu sınıf, derlediğimiz SQLServant.java dosyasına yerleştirilmiştir:

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. SQL sunucusunun başlatma programının yazılması

Yukarıdaki sınıf, SQL sunucusunun başlatıldıktan sonraki halini temsil eder. Bundan önce, sunucunun CORBA hizmet dizinine kaydedilmesi gerekir. Yankı hizmetinde olduğu gibi, bunu özel bir sınıf kullanarak yapacağız ve yürütme sırasında bu sınıfa üç parametre aktaracağız:

Makine: CORBA hizmet dizinlerinin bulunduğu makine

Bağlantı Noktası: Bu dizinin çalıştığı bağlantı noktası

nomService: SQL hizmetinin adı

Bu sınıfın kodu, yankı hizmeti için aynı işlevi gören sınıfın koduyla neredeyse aynıdır. İki sınıf arasındaki farkı büyük harflerle vurguladık: bu sınıf, aynı sunucu nesnesini oluşturmuyor. Dolayısıyla, sunucuyu başlatma mekanizmasının her zaman aynı olduğunu görüyoruz. Bu mekanizmayı burada yapıldığı gibi bir sınıfa ayırırsak, geliştirici için neredeyse görünmez hale gelir.

// ithal edilen paketler
import srvSQL.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;

//----------- serveurSQL sınıfı
public class serveurSQL{
    // ------- ana program: SQL sunucusunu başlatır
  public static void main(String arg[]){
        // serveurSQL makine bağlantı noktası hizmeti

        //doğru sayıda argüman var mı
        if(arg.length!=3){
            System.err.println("Syntaxe : pg machineAnnuaireCorba portAnnuaireCorba nomService");
            System.exit(1);
        }
        // argümanları alıyoruz
        String machine=arg[0];
        String port=arg[1];
        String nomService=arg[2];
        String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
    try{
            // çalışmak için bir nesneye ihtiyacımız var CORBA
      ORB orb=ORB.init(initORB,null);
            // hizmeti hizmet dizinine ekliyoruz
      org.omg.CORBA.Object objRef=
        orb.resolve_initial_references("NameService");
      NamingContext ncRef=NamingContextHelper.narrow(objRef);
      NameComponent nc= new NameComponent(nomService,"");
      NameComponent path[]={nc};
        // sunucuyu oluşturuyoruz ve srvSQL hizmetiyle ilişkilendiriyoruz
        SQLServant serveurSQL=new SQLServant();
      ncRef.rebind(path,serveurSQL);
        orb.connect(serveurSQL);
        // takip
        System.out.println("Serveur SQL prêt");
        // müşterilerden gelen istekleri bekleme
      java.lang.Object sync=new java.lang.Object();
      synchronized(sync){
        sync.wait();
      }
    } catch(Exception e){
            // bir hata oluştu
      System.err.println("Erreur " + e);
      e.printStackTrace(System.err);
    }
  }// bekleme
}// srvSQL

Bu yeni sınıfı derliyoruz:

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. İstemci komutu

CORBA sunucusunun istemcisi aşağıdaki parametrelerle çağrılır:

    machine port nomServiceAnnuaire pilote urlBase id mdp separateur

makine: CORBA hizmet dizinlerinin bulunduğu makine

bağlantı noktası: bu dizinin çalıştığı bağlantı noktası

nomService: SQL hizmetinin adı

sürücü: SQL sunucusunun istenen veritabanını yönetmek için kullanması gereken sürücü

urlBase: yönetilecek veritabanının URL’si JDBC

id: müşterinin kimliği veya kimlik yoksa null

mdp: müşterinin şifresi; şifre yoksa null

ayırıcı: SQL sunucusunun, bir sorgunun sonuç satırlarındaki alanları ayırmak için kullanması gereken karakter

İşte olası parametrelerin bir örneği:

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

burada:

makine: CORBA hizmet dizinlerinin bulunduğu makine

bağlantı noktası: bu rehberin çalıştığı bağlantı noktası

srvSQL: srvSQL, CORBA sunucusunun adı SQL

sürücü: sun.jdbc.odbc.JdbcOdbcDriver, ODBC arayüzüne sahip veritabanları için kullanılan standart sürücü

urlBase: jdbc:odbc:articles, Windows makinesindeki ODBC adlı genel veritabanları listesinde bildirilen articles veritabanını kullanmak için

id: null, kimlik yok

şifre: null, şifre yok

ayırıcı: , sonuçlardaki alanlar virgülle ayrılacaktır

Yukarıdaki parametrelerle başlatıldığında, istemci aşağıdaki adımları izler:

  • machine makinesine port bağlantı noktası üzerinden bağlanarak CORBA srvSQL hizmetini talep eder
  • ürün veritabanına bağlanmayı talep eder
connect(‘’sun.jdbc.odbc.JdbcOdbcDriver’’, ‘‘jdbc:odbc:articles’’, ’’’’, ’’’’)
  • kullanıcıdan klavyeden bir sorgu SQL girmesini ister
  • bunu sunucuya gönderir: SQL
executeSQL(requete, ’’,’’);
  • sunucu tarafından gönderilen sonuçları ekrana görüntüler
  • kullanıcıdan klavyeden bir sorgu SQL girmesini tekrar ister. Sorgu bittiğinde durur.

İstemcinin Java kodu aşağıdadır. Açıklamalar, kodu anlamak için yeterli olacaktır. Şu hususlara dikkat edilmelidir:

  • kod, daha önce incelediğimiz RMI istemcisiyle aynıdır. Aradaki fark, dizin hizmetine yapılan istek sürecidir; bu süreç, getServeurSQL yönteminde ayrı olarak ele alınmıştır.
  • getServeurSQL yöntemi, echo istemcisi için yazılan yöntemle aynıdır

Dolayısıyla şunu görüyoruz ki:

  • bir CORBA istemcisi ile bir RMI istemcisi arasındaki tek fark, sunucuya bağlanma şeklidir
  • bu yöntem, tüm CORBA istemcileri için aynıdır
import srvSQL.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
import java.io.*;

public class clientSQL {

    // sınıfın genel verileri
    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[]){
        // sözdizimi: cltSQL makine bağlantı noktası ayırıcı sürücü url kimlik şifre
        // makine bağlantı noktası: iletişime geçilecek hizmet dizinindeki makine ve bağlantı noktası CORBA
        // hizmet: hizmet adı
        // sürücü: kullanılacak veritabanı için sürücü
        // urlBase : kullanılacak veritabanının JDBC URL'si
        // id: kullanıcı kimliği
        // mdp: şifresi
        // ayırıcı: sorgu sonuçlarındaki alanları ayıran dize

        // argüman sayısının doğrulanması
        if(arg.length!=8)
            erreur(syntaxe,1);

        // veritabanı bağlantı parametrelerini başlatma
        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];        

        // CORBA dizin hizmeti parametreleri
        String[] initORB={"-ORBInitialHost",arg[0],"-ORBInitialPort",arg[1]};
        // CORBA istemcisi - SQL sunucusundan referans isteniyor
        interSQL serveurSQL=getServeurSQL(machine,port,service);

        // istemci-sunucu diyaloğu
        String requete=null;
        String reponse=null;
        String[] lignes=null;
        String codeErreur=null;

        try{
            // klavye akışının açılması
            in=new BufferedReader(new InputStreamReader(System.in));
            // takip
            System.out.println("--> Connexion à la base de données en cours");
            // veritabanına ilk bağlantı talebi
            reponse=serveurSQL.connect(pilote,urlBase,id,mdp);
            // takip
            System.out.println("<-- "+reponse);
            // yanıt analizi
            codeErreur=reponse.substring(0,3);
            if(codeErreur.equals("500")) 
                erreur("Abandon sur erreur de connexion à la base",3);
            // sunucuya gönderilecek isteklerin okunma döngüsü SQL
            System.out.print("--> Requête : ");
            requete=in.readLine().toLowerCase().trim();
            while(! requete.equals("fin")){
                // sunucuya isteğin gönderilmesi ve yanıtın alınması
                lignes=serveurSQL.executeSQL(requete,separateur);
                // izleme
                afficheLignes(lignes);
                // sonraki istek
                System.out.print("--> Requête : ");                
                requete=in.readLine().toLowerCase().trim();
            }// while
            // takip
            System.out.println("--> Fermeture de la connexion à la base de données distante");
            // bağlantı sonlandırılıyor
            reponse=serveurSQL.close();
            // takip
            System.out.println("<-- " + reponse);
            // son
            System.exit(0);
        // hata yönetimi        
        } catch (Exception e){
            erreur("Abandon sur erreur : " + e,2);
        }// deneme
    }// ana

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

    // ------------ hata
    private static void erreur(String msg, int exitCode){
        // hata mesajı görüntüleniyor
        System.err.println(msg);
        // kaynakların serbest bırakılması (gerekirse)
        try{
            in.close();
            serveurSQL.close();
        } catch(Exception e){}
        // çıkılıyor
        System.exit(exitCode);
    }// hata

    // ---------------------- getServeurSQL
    private static interSQL getServeurSQL(String machine, String port, String service){
        // sunucudan referans isteniyor SQL
        // makine: hizmet dizini makinesi CORBA
        // bağlantı noktası: hizmet dizinindeki bağlantı noktası CORBA
        // hizmet: talep edilecek CORBA hizmetinin adı

        // izleme
        System.out.println("--> Connexion au serveur CORBA en cours...");
        // sunucu referansı SQL
        interSQL serveurSQL=null;
        // CORBA dizin hizmetinin parametreleri
        String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
                try{
            // çalışmak için bir CORBA nesnesi talep ediliyor - bunun için bağlantı noktası aktarılıyor 
            // CORBA hizmet rehberinin dinleme bağlantı noktası
      ORB orb=ORB.init(initORB,null);
            // SQL sunucusunu bulmak için dizin hizmetini kullanıyoruz
      org.omg.CORBA.Object objRef=
        orb.resolve_initial_references("NameService");
      NamingContext ncRef=NamingContextHelper.narrow(objRef);
            // aranan hizmetin adı srvSQL'tir - bu hizmet talep edilir
      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
        // sunucuya referans veriliyor
        return serveurSQL;
    }// getServeurSQL

}// sınıf

İstemci sınıfını derleyelim:

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

Testlere hazırız.

10.3.7. Testler

10.3.7.1. Pré-requis

"Articles" adlı bir veritabanının ACCESS adlı sunucunun Windows makinesinde herkese açık olarak mevcut olduğu varsayılmaktadır:

Image

Bu veritabanının yapısı şu şekildedir:

ad
tür
code
4 karakterlik ürün kodu
nom
adı (karakter dizisi)
prix
fiyatı (gerçek)
stock_actu
mevcut stoğu (tamsayı)
stock_mini
ürünün yeniden stoklanması gereken minimum stok miktarı (tamsayı)

10.3.7.2. Rehber hizmetinin başlatılması

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. SQL sunucusunun başlatılması

SQL sunucusu başlatılıyor:

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

DOS penceresinde şunlar görüntüleniyor:

    Serveur SQL prêt

10.3.7.4. Sunucuyla aynı makinede bir istemci başlatılıyor

Sunucuyla aynı makinede bir istemci kullanıldığında elde edilen sonuçlar şunlardır:

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
--> Sorgu: select isim, 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
--> Sorgu: articles tablosundan stock_mini<7 olanları sil
<-- 100 1
--> Sorgu: select isim, 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. Sunucudan farklı bir makinede istemciyi başlatma

Aşağıda, sunucudan farklı bir makinede bir istemci kullanıldığında elde edilen sonuçlar yer almaktadır:

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
--> Sorgu: 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. IDL - JAVA Eşleşmeleri

Burada, basit türler IDL ve JAVA arasındaki eşleşmeleri veriyoruz:

IDL türü
Java türü
boolean
boolean
char
char
wchar
char
bayt
byte
dize
java.lang.String
wstring
java.lang.String
short
short
işaretsiz kısa tamsayı
short
long
int
işaretsiz long
int
long long
long
işaretsiz uzun uzun
long
float
float
double
double

IDL arayüzünde T türündeki elemanlardan oluşan bir dizi tanımlamak için şu komut kullanılır:

    typedef   sequence<T> nomType;

komutu kullanılır ve ardından dizinin türünü belirtmek için nomType kullanılır. Dolayısıyla, SQL sunucu arayüzünde şu bildirim kullanılmıştır:

    typedef sequence<string> resultats;

kullanılmıştır; böylece resultats, Java'da String[] tablosunu işaret eder.