10. ساخت برنامههای توزیعشده CORBA
10.1. مقدمه
در فصل قبلی، ما نحوه ایجاد برنامههای توزیعشده در جاوا با استفاده از بسته RMI را بررسی کردیم. در اینجا، همان مشکل را بررسی میکنیم، این بار با استفاده از معماری CORBA. CORBA (معماری مشترک کارگزار درخواست شیء) یک مشخصهای است که توسط OMG (گروه مدیریت شیء) تعریف شده است، که شرکتهای متعددی از بخش فناوری اطلاعات را گرد هم میآورد. CORBA یک «اتوبوس نرمافزاری» را تعریف میکند که برای برنامههای نوشته شده به زبانهای مختلف قابل دسترسی است:

در ادامه خواهیم دید که ساخت یک برنامه توزیعشده با استفاده از CORBA مشابه روشی است که در جاوا RMI استفاده میشود: مفاهیم مشابه هستند. CORBA مزیت تعاملپذیری با برنامههای نوشته شده به زبانهای دیگر را ارائه میدهد.
10.2. فرآیند توسعه یک برنامه CORBA
10.2.1. مقدمه
برای توسعه یک برنامهٔ کلاینت-سرور CORBA، مراحل زیر را دنبال خواهیم کرد:
- نوشتن رابط سرور با استفاده از IDL (زبان تعریف رابط)
- تولید کلاسهای «اسکلت» و «استاب» سرور
- نوشتن سرور
- نوشتن کلاینت
- کامپایل کردن تمام کلاسها
- راهاندازی دایرکتوری سرویس CORBA
- راهاندازی سرور
- راهاندازی کلاینت
ما اولین مثال خود را با سرور اکو که قبلاً در زمینه RMI استفاده شده است، در نظر میگیریم. این به خواننده امکان میدهد تا تفاوتهای بین این دو روش را ببیند.
این برنامه با jdk1.2 آزمایش شده است.
10.2.2. نوشتن رابط سرور
همانند Java RMI، از دیدگاه کلاینت، سرور با رابط آن تعریف میشود. در حالی که کلاسهای پیادهساز سرور برای کلاینت لازم نیستند، کلاسهای رابط آن ضروریاند. در حالی که Java RMI از یک رابط جاوا برای تولید کلاسهای «اسکلت» و «استاب» سرور استفاده میکرد، معماری Java CORBA ایجاب میکند که رابط در زبانی غیر از جاوا تعریف شود. این رابط چندین کلاس تولید میکند که برخی از آنها توسط کلاینت و برخی دیگر توسط سرور استفاده میشوند.
توضیحات رابط echo به شرح زیر خواهد بود:
توضیحات این رابط در فایلی به نام echo.idl ذخیره خواهد شد. این فایل به زبان IDL (زبان تعریف رابط) نوشته شده است. برای اینکه قابل استفاده باشد، باید توسط برنامهای تحلیل شود که فایلهای منبعی را در زبان مورد استفاده برای توسعه برنامه CORBA ایجاد کند. در اینجا، ما از برنامه idltojava.exe استفاده خواهیم کرد که بر اساس رابط قبلی، فایلهای منبعی .java مورد نیاز برنامه را ایجاد میکند. برنامه idltojava.exe همراه با JDK ارائه نمیشود. میتوان آن را از وبسایت Sun به آدرس http://java.sun.com دانلود کرد.
بیایید چند خط از رابط کاربری قبلی idl را تحلیل کنیم:
معادل **package echo** در جاوا است. کامپایل کردن این رابط، بسته جاوا echo c.a.d را تولید میکند، یک دایرکتوری حاوی کلاسهای جاوا.
معادل رابط جاوا iSrvEcho است. این یک رابط جاوا تولید خواهد کرد.
معادل دستور جاوا **String echo(String msg)** است. انواع در زبان IDL دقیقاً با انواع در زبان جاوا مطابقت ندارند. تطابقها بعداً در این فصل ارائه میشوند. در زبان IDL، پارامترهای تابع میتوانند ورودی (in)، خروجی (out) یا ورودی-خروجی (inout) باشند. در اینجا، متد echo یک پارامتر ورودی msg را که یک رشته است، میپذیرد و یک رشته را به عنوان نتیجه برمیگرداند.
رابط قبلی مربوط به سرور اکو ما است. به یاد داشته باشید که یک رابط از راه دور، متدهای شیء سرور را که برای کلاینتها قابل دسترسی هستند، توصیف میکند. در اینجا، تنها متد echo برای کلاینتها در دسترس خواهد بود.
10.2.3. کامپایل رابط IDL سرور
پس از تعریف رابط سرور، فایلهای جاوا متناظر آن تولید میشوند.
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 برای مشخص کردن عدم استفاده از پیشپردازشگر به کار میرود (معمولاً با C/C++ استفاده میشود). کامپایل کردن فایل echo.idl یک زیرپوشه به نام echo ایجاد میکند که شامل فایلهای زیر است:
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، فایل جاوا است که رابط سرور را توصیف میکند:
/* * فایل: ./ECHO/ISRVECHO.JAVA * از: ECHO.IDL * تاریخ: دوشنبه ۱۵ مارس ۱۹۹۹، ساعت ۱۳:۵۶:۰۸ * توسط: D:\JAVAIDL\IDLTOJ~1.EXE Java IDL 1.2 18 اوت 1998 16:25:34 */
package echo;
public interface iSrvEcho
extends org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity {
String echo(String msg)
;
}
میتوانیم ببینیم که این عملاً یک ترجمه کلمه به کلمه از رابط IDL است. اگر به اندازه کافی کنجکاو باشید که به محتویات سایر فایلهای .java نگاهی بیندازید، عناصر پیچیدهتری خواهید یافت. در اینجا آنچه مستندات در مورد نقش این فایلهای مختلف میگوید:
رابط سرور
رابط iSrvEcho قبلی را پیادهسازی میکند. این یک کلاس انتزاعی است، «اسکلت» سرور، که قابلیت CORBA مورد نیاز برنامه توزیعشده را برای سرور فراهم میکند.
این «استاب» (stub) سرور است که کلاینت از آن استفاده خواهد کرد. این کلاس، قابلیتهای CORBA مورد نیاز برای دسترسی به سرور را در اختیار کلاینت قرار میدهد.
متدهای لازم برای مدیریت ارجاعات شیء را فراهم میکند CORBA
روشهای لازم برای مدیریت پارامترهای ورودی و خروجی متدهای رابط را فراهم میکند.
10.2.4. کامپایل کلاسهای تولیدشده از رابط IDL
توصیه میشود کلاسهای فوق را کامپایل کنید. در مثال دیگری خواهیم دید که این کار میتواند خطاهای ناشی از عدم کارکرد صحیح ژنراتور idltojava را آشکار سازد. در اینجا همه چیز بهخوبی پیش میرود و پس از کامپایل، فایلهای زیر در دایرکتوری بسته echo موجود هستند:
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. ورود به سرور
10.2.5.1. پیادهسازی رابط iSrvEcho
ما قبلاً رابط iSrvEcho را تعریف کردیم. اکنون کلاسی را مینویسیم که این رابط را پیادهسازی میکند. این کلاس از کلاس _iSrvEchoImplbase.java مشتق خواهد شد که همانطور که در بالا ذکر شد، از قبل رابط iSrvEcho را پیادهسازی کرده است.
//بستههای واردشده
import echo.*;
//کلاس پیادهسازیکننده اکو از راه دور
public class srvEcho extends _iSrvEchoImplBase{
// متد پیادهسازی اکو
public String echo(String msg){
return "[" + msg + "]";
}// پایان اکو
}// پایان کلاس
این کد خودگویا است. این کلاس در فایلی به نام srvEcho.java در دایرکتوری والد بسته رابط iSrvEcho ذخیره میشود.
میتوانید آن را کامپایل کنید تا بررسی کنید:
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. ایجاد کلاس سرور
مانند یک برنامهٔ مشتری-سرور RMI، یک سرور CORBA باید در یک دایرکتوری ثبت شود تا برای مشتریان قابل دسترسی باشد. این رویهٔ ثبتنام است که در مرحلهٔ توسعه، بسته به اینکه از یک برنامهٔ CORBA یا RMI استفاده میکنید، متفاوت است. در اینجا سرور اکو CORBA در فایل serveurEcho.java ثبت شده است:
// پکیجهای واردشده
import echo.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
//----------- کلاس serveurEcho
public class serveurEcho{
// ------- main: سرور اکو را راهاندازی میکند
// دستور زبان pg machineAnnuaire portAnnuaire nomService
// machine: ماشینی که میزبان دایرکتوری است CORBA
// port: پورت دایرکتوری CORBA
// nomService: نام سرویس برای ثبت
public static void main(String arg[]){
//آیا آرگومانها موجود هستند؟
if(arg.length!=3){
System.err.println("Syntaxe : pg machineAnnuaire portAnnuaire nomService");
System.exit(1);
}
// بازیابی آرگومانها
String machine=arg[0];
String port=arg[1];
String nomService=arg[2];
try{
// ما به یک شیء CORBA برای کار نیاز داریم
String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
ORB orb=ORB.init(initORB,null);
// افزودن سرویس به دایرکتوری سرویسها
// این srvEcho نامیده خواهد شد
org.omg.CORBA.Object objRef=
orb.resolve_initial_references("NameService");
NamingContext ncRef=NamingContextHelper.narrow(objRef);
NameComponent nc= new NameComponent(nomService,"");
NameComponent path[]={nc};
// ما سرور را ایجاد میکنیم و آن را با سرویس srvEcho مرتبط میسازیم
srvEcho serveurEcho=new srvEcho();
ncRef.rebind(path,serveurEcho);
orb.connect(serveurEcho);
// نظارت
System.out.println("Serveur d'écho prêt");
//در انتظار درخواستهای کلاینت
java.lang.Object sync=new java.lang.Object();
synchronized(sync){
sync.wait();
}
} catch(Exception e){
// یک خطا رخ داده است
System.err.println("Erreur " + e);
e.printStackTrace(System.err);
}
}//اصلی
}// serveurEcho
در زیر، مراحل اصلی را برای راهاندازی سرور بدون ورود به جزئیات تشریح میکنیم که ممکن است در نگاه اول پیچیده به نظر برسد. مهم است که نکات کلیدی مثال قبلی را در نظر داشته باشید، زیرا این موارد برای هر سرور CORBA صدق میکند.
10.2.5.2.1. تنظیمات سرور
یک سرور CORBA باید در یک سرویس دایرکتوری که روی یک ماشین و پورت مشخص در حال اجرا است، ثبتنام کند. برنامه ما این دو اطلاعات را به عنوان پارامتر دریافت خواهد کرد. سرویس ثبتشده باید نامی داشته باشد؛ این نام، پارامتر سوم خواهد بود.
10.2.5.2.2. ایجاد شیء دسترسی به سرویس دایرکتوری CORBA
برای دسترسی به سرویس دایرکتوری و ثبت سرور اکو خود، به یک شیء به نام ORB (واسطه درخواست شیء) نیاز داریم که با استفاده از روش کلاسی زیر به دست میآید:
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
این مثال برای به دست آوردن شی ORB از توالی زیر استفاده میکند:
String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
ORB orb=ORB.init(initORB,null);
جفتهای (پارامتر، مقدار) مورد استفاده به شرح زیر است:
("-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 روی null تنظیم شده است. اگر پارامتر اول نیز روی null تنظیم شده بود، جفت (ماشین،پورت) استفادهشده پیشفرض (localhost,900) میبود.
10.2.5.2.3. ثبت سرور در دایرکتوری خدمات CORBA
سرور با انجام مراحل زیر در دایرکتوری ثبت میشود:
// افزودن سرویس به دایرکتوری سرویسها
// این srvEcho نامیده خواهد شد
org.omg.CORBA.Object objRef=
orb.resolve_initial_references("NameService");
NamingContext ncRef=NamingContextHelper.narrow(objRef);
NameComponent nc= new NameComponent(nomService,"");
NameComponent path[]={nc};
// سرور را ایجاد کرده و آن را با سرویس srvEcho مرتبط کنید
srvEcho serveurEcho=new srvEcho();
ncRef.rebind(path,serveurEcho);
orb.connect(serveurEcho);
بخش اول کد شامل آمادهسازی نام سرویس است. این نام در کد با متغیر </span>**<span style="color: #000000">path **نشان داده میشود. نام یک سرویس از چندین مؤلفه تشکیل شده است:
- یک مؤلفهٔ اولیه objRef، یک شیء عمومی که باید به نوع NamingContext تبدیل شود، در این مورد ncRef.
- نام سرویس، در این مورد nomService، که بهعنوان پارامتر به سرور ارسال شده است
این اجزای نام (NameComponent) در یک آرایه، در این مورد path، گروهبندی شدهاند. این آرایه است که دقیقاً سرویس ایجادشده را «نامگذاری» میکند. پس از ایجاد نام، تنها کاری که باقی میماند این است که
- تا آن را با یک نمونه از سرور (کلاسی که قبلاً ایجاد شده است: srvEcho) مرتبط سازد
srvEcho serveurEcho=new srvEcho();
- و آن را در دایرکتوری ثبت کرد
10.2.5.3. کامپایل کلاس راهاندازی سرور
کلاس قبلی را کامپایل کنید:
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. ورودی مشتری
10.2.6.1. کد
ما در حال نوشتن یک کلاینت برای آزمایش سرویس اکو خود هستیم. ما همان سه پارامتر را که به سرور دادیم، به کلاینت نیز ارسال خواهیم کرد:
ماشین: ماشینی که میزبان دایرکتوری سرویس CORBA است
پورت: پورتی که این دایرکتوری روی آن کار میکند
nomService: نام سرویس اکو
کلاینت به سرویس اکو متصل میشود و سپس از کاربر میخواهد که پیامها را از روی صفحهکلید تایپ کند. این پیامها به سرور اکو ارسال میشوند و سرور آنها را بازمیگرداند. این مکالمه روی صفحه نمایش داده میشود.
کلاینت سرویس اکو CORBA بسیار شبیه به کلاینت RMI است که قبلاً نوشته شده است. در اینجا نیز، کلاینت باید به یک سرویس دایرکتوری متصل شود تا مرجعی به شیء سرور مورد نظر خود برای اتصال به دست آورد. تفاوت بین این دو کلاینت تنها در همین نکته نهفته است. در اینجا کد کلاینت اکو CORBA آورده شده است:
10.2.6.2. اتصال کلاینت به سرور
کلاینت CORBA فوق با استفاده از عبارت زیر به سرور متصل میشود:
//ما یک اتصال با سرور echo برقرار میکنیم
iSrvEcho serveurEcho=getServeurEcho(machine,port,nomService);
پس از اتمام این عملیات، کلاینت یک مرجع به سرور echo در اختیار دارد. پس از آن، کلاینت CORBA تفاوتی با کلاینت RMI ندارد. متد خصوصی که اتصال به سرور را برقرار میکند به شرح زیر است:
//بستههای واردشده
import java.io.*;
import echo.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
// ---------- کلاس cltEcho
public class cltEcho {
public static void main(String arg[]){
// دستور زبان: cltEcho machineAnnuaire portAnnuaire نام سرویس
// ماشین: ماشینی که دایرکتوری خدمات روی آن اجرا میشود CORBA
// پورت: پورتی که دایرکتوری سرویس روی آن کار میکند
// nomService: نام سرویس اکو
//اعتبارسنجی آرگومان
if(arg.length!=3){
System.err.println("Syntaxe : pg machineAnnuaire portAnnuaire nomservice");
System.exit(1);
}
// بازیابی پارامترها
String machine=arg[0];
String port=arg[1];
String nomService=arg[2];
// برقراری ارتباط با سرور اکو
iSrvEcho serveurEcho=getServeurEcho(machine,port,nomService);
// گفتگوی کلاینت-سرور
BufferedReader in=null;
String msg=null;
String reponse=null;
iSrvEcho serveur=null;
try{
// باز کردن جریان صفحهکلید
in=new BufferedReader(new InputStreamReader(System.in));
// حلقه برای خواندن پیامها جهت ارسال به سرور اکو
System.out.print("Message : ");
msg=in.readLine().toLowerCase().trim();
while(! msg.equals("fin")){
//ارسال پیام به سرور و دریافت پاسخ
reponse=serveurEcho.echo(msg);
//پیگیری
System.out.println("Réponse serveur : " + reponse);
// پیام بعدی
System.out.print("Message : ");
msg=in.readLine().toLowerCase().trim();
}// در حالی که
// تمام شد
System.exit(0);
// مدیریت خطا
} catch (Exception e){
System.err.println("Erreur : " + e);
System.exit(2);
}// سعی کنید
}// main
// ---------------------- getServeurEcho
private static iSrvEcho getServeurEcho(String machine, String port,
String nomService){
// درخواست ارجاع از سرور اکو میکند
//ردیابی
System.out.println("--> Connexion au serveur CORBA en cours...");
// مرجع سرور اکو
iSrvEcho serveurEcho=null;
try{
//یک شیء CORBA برای پردازش درخواست شده است
String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
ORB orb=ORB.init(initORB,null);
//سرویس دایرکتوری برای یافتن سرور اکو استفاده میشود
org.omg.CORBA.Object objRef=
orb.resolve_initial_references("NameService");
NamingContext ncRef=NamingContextHelper.narrow(objRef);
// خدمتی که مورد جستجو است srvEcho نامیده میشود – در حال درخواست است
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 serveurEcho;
}//getServeurEcho
}//کلاس
ما همان توالیهای کد را که در سرور وجود دارد، پیدا میکنیم:
- ما یک شیء ORB ایجاد میکنیم که به ما امکان میدهد با دایرکتوری سرویس CORBA تماس بگیریم
String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
ORB orb=ORB.init(initORB,null);
- ما اجزای مختلف نام سرویس echo را تعریف میکنیم
org.omg.CORBA.Object objRef=orb.resolve_initial_references("NameService");
NamingContext ncRef=NamingContextHelper.narrow(objRef);
NameComponent nc= new NameComponent(nomService,"");
NameComponent path[]={nc};
- ما یک مرجع برای سرویس اکو از سرویس دایرکتوری درخواست میکنیم (اینجا است که ما با سرور متفاوت هستیم)
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. آزمایشها
10.2.7.1. راهاندازی سرویس دایرکتوری
در یک سیستم ویندوزی، سرویس دایرکتوری را به شرح زیر راهاندازی میکنیم:
این کار سرویس دایرکتوری را روی پورت ۱۰۰۰ در ماشین راهاندازی میکند.
سرویس دایرکتوری tnameserv یک نمایش روی صفحه ایجاد میکند که شبیه به شکل زیر است:
Initial Naming Context:
IOR:000000000000002849444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f
6e746578743a312e3000000000010000000000000030000100000000000a69737469612d30303900
044700000018afabcafe000000027620dd9a000000080000000000000000
TransientNameServer: setting port for initial object references to: 1000
خواندنش کمی سخت است، اما به خط آخر توجه کنید: سرویس روی پورت ۱۰۰۰ در حال اجرا است.
10.2.7.2. راهاندازی سرور اکو
سرویس اکو با سه پارامتر راهاندازی میشود:
E:\data\java\corba\ECHO>start j:\jdk12\bin\java serveurEcho localhost 1000 srvEcho
سرور نمایش میدهد:
10.2.7.3. راهاندازی کلاینت روی همان ماشین سرور
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. راهاندازی کلاینت روی یک رایانه ویندوزی دیگر به غیر از سرور
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. مثال ۲: یک سرور SQL
10.3.1. مقدمه
در اینجا پیادهسازی سرور SQL را که پیشتر در زمینه RMI جاوا بررسی کردهایم، بار دیگر مرور میکنیم تا شباهتها و تفاوتهای بین این دو روش را برجسته سازیم. بیایید نقش این سرور SQL را به یاد بیاوریم: این سرور بر روی یک ماشین ویندوزی قرار دارد و به کلاینتهای راه دور امکان دسترسی به پایگاههای داده عمومی ODBC را بر روی آن ایستگاه کاری ویندوزی میدهد.

کلاینت CORBA میتواند سه عملیات را انجام دهد:
- اتصال به پایگاهداده دلخواه
- ارسال پرسوجوهای SQL
- بستن اتصال
سرور پرسوجوهای SQL کلاینت را اجرا میکند و نتایج را به کلاینت بازمیگرداند. این کارکرد اصلی آن است و به همین دلیل آن را سرور SQL مینامیم. ما مراحل مختلفی را که قبلاً با سرور اکو بررسی کردیم، اعمال میکنیم.
10.3.2. نوشتن رابط IDL سرور
بهعنوان یادآوری، در اینجا رابط RMI را که برای سرور استفاده کردیم، میبینید:
import java.rmi.*;
// رابط راه دور
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;
}
نقش روشهای مختلف به شرح زیر بود:
Connect: کلاینت به یک پایگاه دادهٔ راه دور متصل میشود و درایور، URL JDBC و نام کاربری (id) و رمز عبور (mdp) خود را برای دسترسی به پایگاه داده مشخص میکند. سرور رشتهای را بازمیگرداند که نتیجهٔ اتصال را نشان میدهد:
executeSQL: کلاینت درخواست میکند که یک پرسوجو SQL روی پایگاه دادهای که به آن متصل است اجرا شود. این کلاینت کاراکتری را مشخص میکند که باید فیلدهای نتایج بازگرداندهشده را از هم جدا کند. سرور یک آرایه از رشتهها را بازمیگرداند:
برای یک پرسوجوی بهروزرسانی پایگاه داده، که در آن n تعداد ردیفهای بهروزرسانیشده است
اگر پرسوجو خطایی ایجاد کرده باشد
اگر پرسوجو هیچ نتیجهای بازنگرداند
اگر پرسوجو نتایجی را بازگردانده باشد. خطوط بازگرداندهشده توسط سرور، نتایج پرسوجو هستند.
بستن: کلاینت اتصال خود را به پایگاه دادهٔ راه دور میبندد. سرور رشتهای را بازمیگرداند که نتیجهٔ این بستن را نشان میدهد:
رابط IDL سرور به شرح زیر خواهد بود:
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();
};//رابط
};// ماژول
تنها تفاوت نسبت به آنچه در رابط IDL سرور echo دیدیم، استفاده از کلمه کلیدی sequence است. این کلمه کلیدی به شما امکان میدهد یک آرایه یکبعدی تعریف کنید. تعریف در دو مرحله انجام میشود:
- تعریف یک نوع برای مشخص کردن آرایه، در این مورد `resultats`:
کلیدواژه typedef برای برنامهنویسان C/C++ کاملاً آشناست: از آن برای تعریف یک نوع جدید استفاده میشود. در اینجا نوع resultats بهعنوان معادل نوع sequence<string> تعریف شده است، c.a.d – یک آرایهٔ پویا (بدون اندازه) از رشتههای کاراکتری.
- استفاده از نوع جدید در جایی که لازم است
بنابراین متد executeSQL آرایهای از رشتههای کاراکتری را بازمیگرداند.
10.3.3. کامپایل رابط IDL سرور
رابط IDL قبلی در فایل srvSQL.idl قرار میگیرد. این فایل سپس کامپایل میشود:
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
میتوانیم ببینیم که کامپایل یک دایرکتوری به نام ماژول رابط IDL (srvSQL) ایجاد کرده است. بیایید نگاهی به محتویات این دایرکتوری بیندازیم:
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 و Holder کلاسهایی هستند که مربوط به پارامترهای ورودی/خروجی و نتایج متدهای رابط از راه دور میباشند. پوشه srvSQL شامل تمام فایلهای .java مرتبط با رابط interSQL تعریفشده در فایل .idl است. این دایرکتوری همچنین شامل فایلهای مربوط به نوع resultats است که در رابط IDL ایجاد شده است.
فایل interSQL.java فایل جاوا برای رابط سرور ما است. مهم است که بررسی کنیم آنچه بهطور خودکار تولید شده با نیازهای ما مطابقت دارد. فایل تولیدشده interSQL.java به شرح زیر است:
/* * فایل: ./SRVSQL/INTERSQL.JAVA * از: SRVSQL.IDL * تاریخ: جمعه ۱۹ مارس ۱۹۹۹، ساعت ۰۹:۵۹:۴۸ * توسط: D:\JAVAIDL\IDLTOJ~1.EXE Java IDL 1.2 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()
;
}
میتوانیم ببینیم که رابط ما مشابه رابط مورد استفاده برای RMI کلاینت-سرور است. بنابراین میتوانیم ادامه دهیم. بیایید همه این فایلهای .java را کامپایل کنیم:
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
ما اکنون در حال نوشتن کد سرور SQL هستیم. به یاد داشته باشید که این کلاس باید از کلاس انتزاعی _nomInterfaceImplBase که با کامپایل کردن فایل IDL تولید میشود، ارث ببرد. به جز این ویژگی خاص، و با مستثنی کردن توالیهای کدی که به ثبت سرویس در یک دایرکتوری مربوط میشوند، کد سرور CORBA با کد سرور RMI یکسان است:
//بستههای واردشده
import java.sql.*;
import java.util.*;
import srvSQL.*;
// کلاس SQLServant
public class SQLServant extends _interSQLImplBase{
// دادههای کلاس جهانی
private Connection DB;
// --------------- اتصال
public String connect(String pilote, String url, String id,
String mdp){
//اتصال به URL پایگاه داده با استفاده از درایور
// احراز هویت با استفاده از شناسه و رمز عبور
String resultat=null; // نتیجهٔ متد
try{
// بارگذاری درایور
Class.forName(pilote);
// درخواست اتصال
DB=DriverManager.getConnection(url,id,mdp);
// OK
resultat="200 Connexion réussie";
} catch (Exception e){
// خطا
resultat="500 Echec de la connexion (" + e + ")";
}
// پایان
return resultat;
}
// ------------- executeSQL
public String[] executeSQL(String requete, String separateur){
// یک پرسوجو SQL را روی پایگاه داده DB اجرا میکند
//و نتایج را در آرایهای از رشتهها قرار میدهد
//دادههای مورد نیاز برای اجرای پرسوجو
Statement S=null;
ResultSet RS=null;
String[] lignes=null;
Vector resultats=new Vector();
String ligne=null;
try{
//ایجاد مخزن پرسوجو
S=DB.createStatement();
//اجرای پرسوجو
if (! S.execute(requete)){
// پرسوجوی بهروزرسانی
// تعداد ردیفهای بهروزرسانیشده را برمیگرداند
lignes=new String[1];
lignes[0]="100 "+S.getUpdateCount();
return lignes;
}
// این یک پرسوجو بود
// بازیابی نتایج
RS=S.getResultSet();
// تعداد ستونها در مجموعه نتایج
int nbChamps=RS.getMetaData().getColumnCount();
// آنها را پردازش میکند
while(RS.next()){
// ایجاد سطر نتایج
ligne="101 ";
for (int i=1;i<nbChamps;i++)
ligne+=RS.getString(i)+separateur;
ligne+=RS.getString(nbChamps);
// افزودن به بردار نتایج
resultats.addElement(ligne);
}// در حالی که
//پایان پردازش نتایج
//منابع آزاد میشوند
RS.close();
S.close();
// بازگرداندن نتایج
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);
}//اگر
return lignes;
} catch (Exception e){
//خطا
lignes=new String[1];
lignes[0]="500 " + e;
return lignes;
}// try-catch
}//executeSQL
// --------------- بستن
public String close(){
// اتصال پایگاه داده را میبندد
String resultat=null;
try{
DB.close();
resultat="200 Base fermée";
} catch (Exception e){
resultat="500 Erreur à la fermeture de la base ("+e+")";
}
// نتیجه را بازمیگرداند
return resultat;
}
}// کلاس SQLServant
این کلاس در فایل SQLServant.java قرار دارد که ما آن را کامپایل میکنیم:
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
کلاس قبلی نمایانگر سرور SQL پس از راهاندازی آن است. پیش از آن، باید در دایرکتوری سرویس CORBA ثبت شود. همانند سرویس echo، این کار را با استفاده از یک کلاس ویژه انجام میدهیم که در زمان اجرا سه پارامتر را به آن ارسال میکنیم:
Machine: ماشینی که دایرکتوری سرویس CORBA روی آن قرار دارد
پورت: پورتی که این دایرکتوری روی آن کار میکند
nomService: نام سرویس SQL
کد این کلاس تقریباً با کد کلاسی که همان وظیفه را برای سرویس اکو انجام میداد، یکسان است. ما خطی را که بین این دو کلاس متفاوت است، پررنگ کردهایم: این خط شیء سرور یکسانی را ایجاد نمیکند. بنابراین میتوانیم ببینیم که مکانیزم راهاندازی سرور همچنان یکسان باقی میماند. اگر این مکانیزم را، همانطور که در اینجا انجام شده است، در یک کلاس مجزا قرار دهیم، عملاً برای توسعهدهنده شفاف میشود.
//بستههای واردشده
import srvSQL.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
//----------- کلاس serveurSQL
public class serveurSQL{
// ------- main: سرور SQL را راهاندازی میکند
public static void main(String arg[]){
//سرویس پورت ماشین serveurSQL
//آیا تعداد آرگومانها صحیح است
if(arg.length!=3){
System.err.println("Syntaxe : pg machineAnnuaireCorba portAnnuaireCorba nomService");
System.exit(1);
}
// بازیابی آرگومانها
String machine=arg[0];
String port=arg[1];
String nomService=arg[2];
String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
try{
//ما برای کار کردن به یک شیء CORBA نیاز داریم
ORB orb=ORB.init(initORB,null);
// ما سرویس را به دایرکتوری سرویسها اضافه میکنیم
org.omg.CORBA.Object objRef=
orb.resolve_initial_references("NameService");
NamingContext ncRef=NamingContextHelper.narrow(objRef);
NameComponent nc= new NameComponent(nomService,"");
NameComponent path[]={nc};
// ما سرور را ایجاد میکنیم و آن را با سرویس srvSQL مرتبط میسازیم
SQLServant serveurSQL=new SQLServant();
ncRef.rebind(path,serveurSQL);
orb.connect(serveurSQL);
// نظارت
System.out.println("Serveur SQL prêt");
// در انتظار درخواستهای مشتری
java.lang.Object sync=new java.lang.Object();
synchronized(sync){
sync.wait();
}
} catch(Exception e){
//خطایی رخ داده است
System.err.println("Erreur " + e);
e.printStackTrace(System.err);
}
}// آرام
}// srvSQL
ما این کلاس جدید را کامپایل میکنیم:
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. فراخوانی کلاینت
کلاینت برای سرور CORBA با پارامترهای زیر فراخوانی میشود:
ماشین: ماشینی که دایرکتوری سرویس CORBA روی آن قرار دارد
port: پورتی که این دایرکتوری روی آن کار میکند
nomService: نام سرویس SQL
driver: درایوری که سرور SQL باید برای مدیریت پایگاه داده مورد نظر از آن استفاده کند
urlBase: URL پایگاه داده برای مدیریت
id: شناسهٔ مشتری یا null اگر شناسه وجود نداشته باشد
رمز عبور: رمز عبور مشتری یا null در صورت عدم وجود رمز عبور
جداساز: کاراکتری که سرور SQL باید برای جدا کردن فیلدها در سطرهای نتیجه یک پرسوجو استفاده کند
در اینجا مثالی از پارامترهای ممکن آورده شده است:
where:
machine: ماشینی که دایرکتوری سرویس CORBA روی آن قرار دارد
پورت: پورتی که این دایرکتوری روی آن کار میکند
srvSQL: srvSQL، نام سرور CORBA
راننده: sun.jdbc.odbc.JdbcOdbcDriver, رانر استاندارد برای پایگاههای داده با رابط ODBC
urlBase: jdbc:odbc:articles، برای استفاده از پایگاه داده «articles» که در لیست پایگاه دادههای عمومی ODBC روی ماشین ویندوز اعلام شده است
شناسه: null، بدون شناسه
رمز عبور: null، بدون رمز عبور
جداساز: , فیلدهای نتایج با یک ویرگول از هم جدا خواهند شد
پس از راهاندازی با پارامترهای فوق، کلاینت مراحل زیر را دنبال میکند:
- به ماشین machine روی پورت port متصل میشود تا سرویس CORBA srvSQL را درخواست کند
- یک اتصال به پایگاه داده محصول را درخواست میکند
- از کاربر میخواهد تا پرسوجویی را SQL روی صفحهکلید تایپ کند
- آن را به سرور SQL ارسال میکند
- نتایج بازگرداندهشده توسط سرور را روی صفحه نمایش میدهد
- بار دیگر از کاربر میخواهد عبارت SQL را روی صفحهکلید تایپ کند. وقتی عبارت کامل شود، متوقف میشود.
کد کلاینت جاوا در ادامه آمده است. توضیحات باید برای درک آن کافی باشد. توجه کنید که:
- این کد با کد کلاینت RMI که قبلاً بررسی شده بود یکسان است. تفاوت آن در فرآیند ارسال درخواست به سرویس دایرکتوری است، فرایندی که در متد getServeurSQL ایزوله شده است.
- روش getServeurSQL دقیقاً مشابه روشی است که برای کلاینت echo نوشته شده است.
بنابراین میتوانیم ببینیم که:
- یک کلاینت CORBA تنها در نحوه تماس با سرور با یک کلاینت RMI متفاوت است
- این روش برای همه کلاینتهای CORBA یکسان است
import srvSQL.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
import java.io.*;
public class clientSQL {
// دادههای سراسری کلاس
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[]){
// دستور دستوری: cltSQL پورت ماشین جداکننده درایور آدرس اینترنتی شناسه رمز عبور
// پورت ماشین: ماشین و پورت دایرکتوری سرویس CORBA برای تماس
// سرویس: نام سرویس
// راننده: رانندهای که برای دسترسی به پایگاه داده باید استفاده شود
// urlBase: URL JDBC پایگاه داده مورد استفاده
// id: شناسه کاربر
// رمز عبور: رمز عبور کاربر
// جداساز: رشتهای که فیلدها را در نتایج پرسوجو از هم جدا میکند
// بررسی تعداد آرگومانها
if(arg.length!=8)
erreur(syntaxe,1);
// ابتداییسازی پارامترهای اتصال پایگاه داده
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
String[] initORB={"-ORBInitialHost",arg[0],"-ORBInitialPort",arg[1]};
// کلاینت CORBA – درخواست مرجع سرور SQL
interSQL serveurSQL=getServeurSQL(machine,port,service);
// گفتگوی کلاینت-سرور
String requete=null;
String reponse=null;
String[] lignes=null;
String codeErreur=null;
try{
// باز کردن جریان صفحهکلید
in=new BufferedReader(new InputStreamReader(System.in));
//ردیابی
System.out.println("--> Connexion à la base de données en cours");
//درخواست اتصال اولیه به پایگاه داده
reponse=serveurSQL.connect(pilote,urlBase,id,mdp);
//پیگیری
System.out.println("<-- "+reponse);
// تحلیل پاسخ
codeErreur=reponse.substring(0,3);
if(codeErreur.equals("500"))
erreur("Abandon sur erreur de connexion à la base",3);
// حلقه خواندن پرسوجوهایی که باید به سرور ارسال شوند SQL
System.out.print("--> Requête : ");
requete=in.readLine().toLowerCase().trim();
while(! requete.equals("fin")){
//ارسال درخواست به سرور و دریافت پاسخ
lignes=serveurSQL.executeSQL(requete,separateur);
// نظارت
afficheLignes(lignes);
// درخواست بعدی
System.out.print("--> Requête : ");
requete=in.readLine().toLowerCase().trim();
}// در حالی که
//پیگیری
System.out.println("--> Fermeture de la connexion à la base de données distante");
// اتصال بسته شد
reponse=serveurSQL.close();
//پیگیری
System.out.println("<-- " + reponse);
// پایان
System.exit(0);
// پردازش خطا
} catch (Exception e){
erreur("Abandon sur erreur : " + e,2);
}// سعی کنید
}// اصلی
// ----------- AfficheLignes
private static void afficheLignes(String[] lignes){
for (int i=0;i<lignes.length;i++)
System.out.println("<-- " + lignes[i]);
}// afficheLignes
// ------------ خطا
private static void erreur(String msg, int exitCode){
// پیام خطا نمایش داده شد
System.err.println(msg);
// آزادسازی احتمالی منابع
try{
in.close();
serveurSQL.close();
} catch(Exception e){}
//خروج
System.exit(exitCode);
}// خطا
// ---------------------- getServeurSQL
private static interSQL getServeurSQL(String machine, String port, String service){
// درخواست ارجاع سرور SQL
// ماشین: ماشین از دایرکتوری خدمات CORBA
// پورت: پورت دایرکتوری سرویس CORBA
// سرویس: نام سرویس CORBA که باید درخواست شود
// ردیابی
System.out.println("--> Connexion au serveur CORBA en cours...");
// مرجع سرور SQL
interSQL serveurSQL=null;
//پارامترهای سرویس دایرکتوری برای CORBA
String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
try{
//یک شیء CORBA برای اجرا درخواست میشود – پورت برای این منظور ارسال میشود
// پورت گوشدادن سرویس دایرکتوری CORBA
ORB orb=ORB.init(initORB,null);
// از سرویس دایرکتوری برای یافتن سرور SQL استفاده میشود
org.omg.CORBA.Object objRef=
orb.resolve_initial_references("NameService");
NamingContext ncRef=NamingContextHelper.narrow(objRef);
// خدمتی که به دنبال آن هستیم srvSQL نام دارد – ما آن را درخواست میکنیم
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 serveurSQL;
}//getServeurSQL
}//کلاس
بیایید کلاس کلاینت را کامپایل کنیم:
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
ما برای آزمونها آمادهایم.
10.3.7. آزمایشها
10.3.7.1. Pré-requis
ما فرض میکنیم که یک پایگاه داده به نام «Articles» به صورت عمومی روی سرور ویندوز در دسترس است:

این پایگاه داده ساختار زیر را دارد:
نام | نوع |
code | کد آیتم ۴ کاراکتری |
nom | نام آن (رشتهٔ کاراکتری) |
prix | قیمت آن (واقعی) |
stock_actu | موجودی فعلی آن (اعداد صحیح) |
stock_mini | حداقل سطح موجودی (اعداد صحیح) که پس از آن باید کالا دوباره موجودیگذاری شود |
10.3.7.2. راهاندازی سرویس دایرکتوری
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
سرور SQL در حال راهاندازی است:
در یک پنجره موارد زیر را نمایش میدهد: DOS:
10.3.7.4. راهاندازی یک کلاینت روی همان دستگاهی که سرور روی آن قرار دارد
در اینجا نتایج بهدستآمده با یک کلاینت روی همان دستگاهی که سرور روی آن قرار دارد، آورده شده است:
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
--> پرسوجو: select name, stock_actu, stock_mini from articles
<-- 101 vélo,31,8
<-- 101 arc,9,8
<-- 101 canoé,7,7
<-- 101 fusil,9,8
<-- 101 skis nautiques,13,8
<-- 101 essai3,13,9
<-- 101 cachalot,6,6
<-- 101 léopard,7,7
<-- 101 panthère,7,7
--> پرسوجو: حذف از مقالات جایی که stock_mini<7
<-- 100 1
--> پرسوجو: select name, stock_actu, stock_mini from articles
<-- 101 vélo,31,8
<-- 101 arc,9,8
<-- 101 canoé,7,7
<-- 101 fusil,9,8
<-- 101 skis nautiques,13,8
<-- 101 essai3,13,9
<-- 101 léopard,7,7
<-- 101 panthère,7,7
--> Requête : fin
--> Fermeture de la connexion à la base de données distante
<-- 200 Base fermée
10.3.7.5. راهاندازی یک کلاینت روی ماشینی غیر از سرور
در اینجا نتایج بهدستآمده با یک کلاینت روی ماشینی غیر از سرور آورده شده است:
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
--> پرسوجو: 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
در اینجا ما تطابقها بین انواع ساده IDL و JAVA را ارائه میدهیم:
نوع IDL | نوع جاوا |
boolean | boolean |
char | char |
wchar | char |
byte | بايت |
رشته | java.lang.String |
string | java.lang.String |
کوتاه | شورت |
شورت بدون علامت | کوتاه |
long | integer |
long بدون علامت | int |
long long | long |
long long بدون علامت | long |
شناور | float |
double | double |
به خاطر داشته باشید که برای تعریف آرایهای از عناصر از نوع T در رابط IDL، از عبارت زیر استفاده میکنید:
و سپس از nomType برای ارجاع به نوع آرایه استفاده میشود. بنابراین، در رابط سرور SQL، اعلامیهی زیر استفاده شد:
به طوری که resultats به یک آرایه String[] در جاوا اشاره میکند.