Ngôn ngữ định nghĩa giao diện JAVA (IDL) và CORBA

Khác với RMI, CORBA cho phép ta thục hiện các lời gọi giữa các đối tượng Java với các đối tượng viết bằng các ngôn ngừ khác, ví dụ đổi tượng C++. COREA phụ thuộc vào bộ môi giới yêu cầu ORB có sẵn sàng trên cà Server lẫn Client hay không.

1. Ngôn ngữ định nghĩa giao diện IDL

Sun xây dựng J a va IDL như là ngôn ngũ định nghĩa giao diện CORBA trong Java 2 SDK. Bản thân IDL là ngôn ngữ định nghĩa giao diện ờ dạng ngôn ngữ tự nhiên [2].

Vori CORBA, một giao diện trong IDL có thể được viết đom giản như sau: interface Product{

string getDescription() ;

};

Ỏ đây có sự khác biệt giữa IDL và Java. Trong IDL, kết thúc việc định nghĩa giao diện là và string không bắt đầu bằng chữ in hoa ‘S’ như trong Java. Trong Java, các xâu (thuộc lớp String) bao gồm các ký tự Unicode 16-bit, còn trong CORBA, các xâu chỉ chứa các ký tự 8-bit. Do vậy, nếu ta gửi đi những xâu I6-bit qua ORB và những ký tự trong xâu có các bit cao khác 0 thi sẽ phát sính ngoại lệ. Đây chính là một vấn đề không tương thích giữa các ngôn ngữ lập trình.

Chựơng trình dịch Java IDL Compiler (trong J2sdk. 1.4.0 là idlj . exe) làm nhiệm vụ dịch các định nghĩa trong IDL sang Java.

Ví dụ

idlj Product.idl

Chương trình sẽ tạo ra các tệp sau:

  • Product. java, định nghĩa giao diện
  • j ava, định nghĩa lớp cất giữ cho các tham số out
  • ProductHelper . java, định nghĩa lớp trợ giúp
  • _Product Imp 1 Ba se . j a va, định nghĩa lớp cha của lớp cài đật
  • j ava, định nghĩa lớp trung gian stub để trao đổi với ORB.

Một số giao diện Ja va được sinh tự động sau câu lệnh fren, như:

/**

  • java.
  • Generated by the IDL-to-Java compiler (portable), version “3.1”
  • from Product.idl
  • Wednesday, July 20, 2005 6:28:29 PM ICT

*/

public interface Product extends ProductOperations, org.omg.CORBA.Object, org. omg. CORBA.portable.IDLEntity

{

} // interface Product !**

  • java.
  • Generated by the IDL-to-Java compiler (portable), version “3.1”
  • from Product.idl
  • Wednesday, July 20, 2005 6 28:29 PM ICT */

public interface ProductOperations

1

String getDescription ();

} // interface ProductOperations

/**

  • java.
  • Generated by the IDL-to-Java compiler (portable), version “3.1”
  • from Product idl
  • Wednesday, July 20, 2005 6:28:29 PM ICT */

abstract public class ProductHelper {

private static String _id = “IDL:Product:1.0”;

public static void insert (org. rang. CORBA. Any a, Product that) {

org.omg.CORBA.portable.OutputStream out = a.create_output_stream (); a.type (type ()); write (out, that);

a.read_value (out.create_input_stream (), type ());

public static Product extract (org. orcig. CORBA. Any a) {

return read (a.create_input_stream ());

}

private static org.omg.CORBA.TypeCode ___________ typeCode = null;

synchronized public static org.omg.CORBA.TypeCode type ()

{

if (_typeCode == null)

{

_typeCode = org.cmg.CORBA.ORB. init () . create_interface tc (ProductHelper.id (), “Product”);

}

return __typeCode;

} public static String id ()

{

return _id;

)

public static Product read (org.omg.CORBA. portable. Inputstream istream)

{

return narrow (istream. read__Object (_ProductStub . class));

} public static void write (org.omg.CORBA. portable.

OutputStream ostream, Product value)

{

ostream.write_Object ((org.omg.CORBA.Object) value);

public static Product narrow (org.omg.CORBA. object obj )

{

if (obj == null)
return null;

else if (obj instanceof Product) return (Product)obj; else if (!obj._is_a (id ()))

throw new org.omg.CORBA.BAD_PARAM (); else {

org.ctmg.CORBA.portable.Delegate delegate =

((org. cmg. COREA, portable. Cbj ectlirpl) abj) . _get_delegate (); _ProductStub stub = new _ProductStub (); stub._set_delegate(delegate); return stub;

}

}

}

Java cũng cung cẨp chương trình dịch ngược từ tệp class (kết quả dịch của giao diện trong Java) sang IDL như sau:

rmic -idl Yourlnterface.class

Ta xét tiếp cách đặc tả các hàm trong IDL. Khi định nghĩa một phương thức, ta phải lựa chọn các tham số để truyền và nhận kểt quả. Mỗi tham số có thể khai báo ìn, out hoặc inout.

  • Những tham số khai báo in là những tham sổ được sử dụng để truyền dữ liệu.
  • Những tham số khai báo out được sừ dụng để lưu giữ nhừng kết quả tnrớc khi quay trở lại thực hiện chương trình chính.

Ví dụ, phương thức locate () có thể lưu giữ sản phẩm tìm thấy, được định nghĩa trong IDL như sau:

interface Warehouse!

boolean locate(in string descr, out Product p);

Đối với mỗii giao diện, chương trình dịch IDL sẽ sinh ra một lớp có hậu tố là Holder, được gọi là ìớp cất giữ. Như trên ta thấy, sau khi dịch giao diện Product (viết trong IDL) sang Java, ngoài tệp Product.j a va, còn sinh tự động ra hai tệp

ProductHolder . java và ProductOperation. java. Mọi lớp lưu giữ đều có một biến public là value.

Khi gọi một phương thức, ta phải truyền vào cho đổi tượng cẩt giữ. Sau khi kết thúc lời gọi hàm, muốn tìm lại kết quả thi tìm qua value của đối tượng cất giữ đó. Ví dụ.

Warehouse w = … ;

String descr =

ProductHolder pHolder = new ProductHolder(); if(w.locate{descr, pHolder)) p = pHolder.value ;

Trong IDL, ta có thể sù dụng cấu trúc sequence để định nghĩa các màng có kích cỡ biển đổi. Ví dụ, định nghĩa một kiểu chuỗi các sản phẩm:

typedef sequence<Product> ProductSeq;

Sau đó ta có thể sử dụng kiểu dữ liệu này để khai báo phương thức

interface Warehouse!

ProductSeq find(in Customer c);

>;

Trong Java, cấu trúc sequence tương ímg với cấu trúc màng.

Nếu một phương thức có thể phát sinh ngoại lệ, thi trước hết ta phải định nghĩa kiểu ngoại lệ và sau đó sử dụng khai báo nó với từ raises. Ví dụ, phương thức find() có thể gặp phải ngoại lệ BadCustomer.

interface Warehouse{

exception BadCustomer{ string reason;}

ProductSeq find(in Custamer c) raises BadCustơmer;

Chương trình dịch IDL sẽ dịch sang lớp BađCustomer final class BadCustomer extends org.omg.COREA.UserException{ public BadCustomer(){;}

public BadCustomer(String _reason){reason = _reason;} public String reason;

Các giao diện cũng có thể chứa thuộc tính attribute. Một thuộc tính được xem như là một biến thế hiện, nhưng nó được gắn với một cặp hàm truy cập và cấm truy cập. Ví dụ; giao diện Book có thuộc tính isbn

interface Book{

attribute string isbn;

};

Thuộc tính này chuyển tương đương sang Java thành cặp hàm có cùng tên i sbn; String isbn()                                        //Accessor

void isbn (String _isbn)              //Mutator

Nếu thuộc tính khai báo là readonly thì các hàm này không cần phải sinh ra. CORBA hỗ trợ kế thừa giữa các giao diện và sử dụng ký pháp gần giống với c++.

interface Book : Product { /* …                        */l;

Dấu ký hiệu cho sự kế thừa.

Trong IDL, ta có thể tạo ra một nhóm các interface và tạo thành các module, module corejava {

interface Product { /* …                    */};

interface Warehouse! /* …                   */};

};

Các module được chuyển tương ứng sang Java thành các package.

2. Phát triển ứng dụng với IDL và CORBA

Java ra đời với mong muốn tạo ra được những chương trinh ứng dụng được viết, dịch ở một ncn nhưng chạy được ờ mọi nơi. Tuy nhiên, Java không thể thay thế tất cả các ngôn ngữ khác vì nhiều lập trình viên đã quen thuộc với C/C++, Visual Basic,… và nhiều phần mềm đã được phát triển rất hiệu quả bằng những ngôn ngữ đó. Cộng đồng lập trình mong muốn tìm được tiếng nói chung cho các ngôn ngữ lập trình và thế là CORBA ra đời. CORBA tạm dịch là kiến trúc môi giới đối tượng chung được hình thành từ tổ chức quản trị đối tượng quốc tế CMG với sự hợp tác cùa hơn 800 công ty. Mục đích của OMG là đưa ra cách để các đối tượng viết bằng những ngôn ngữ lập trình hướng đối tượng khác nhau có thể triệu gọi lẫn nhau theo mô hình đối tượng phân tán.

CORBA không phải là ngôn ngữ lập trình, nó là ngôn ngữ đặc tả. CORBA quy định một tập các mô tả hàm, kiểu dữ liệu, cách khai báo để đặc tả đối tượng giống như giao diện trong Java. Chính vỉ thế CORBA còn được gọi là ngôn ngữ định nghĩa giao diện IDL.

Tất cả các chương trình úng dụng độc lập và ứng dụng applet được phát tnển trên Java 2 SDK đều có khả năng kết nối được với các đối tượng CORBA

Để cài đặt các đối tượng CORBA, ta cần thực hiện:

  1. Sử dụng IDL để viết giao diện để chỉ ra cách hoạt động cứa các đối tượng.
  2. Sừ dụng chương trinh dịch IDL để dịch các chương trình viết trong các ngôn ngữ đích, sinh ra các lớp trung gian stub và các lóp trợ giúp.
  3. Bổ sung mẵ trình cài đặt cho các đối tượng Server viết bằng ngôn ngữ mà bạn lựa chọn. Dịch các mã trình cài đặt đó.
  4. Viết chương trình phục vụ trong đó tạo lâp và đăng ký các đối tượng dịch vụ. Phương thức phù hợp nhất để đăng ký là sử dụng các dịch vụ đặt tên cùa CORBA, một dịch vụ tương tự như rmiregìst rỵ.
  5. Viết chương trình khách trong đó xác định các đối tượng phục vụ và gọi các dịch vụ của chúng.
  6. Khởi động các dịch vụ đặt tên và chương trình phục vụ trên máy Serve r, sau đó là chương trình khách trên

Ví dụ 2.4. Trước tiên chúng ta xét ví dụ, trong đó một chương trình khách (viểt bằng Java) muốn triệu gọi các đối tượng từ xa ở máy chủ (viết bằng c++) có sừ dụng sự hỗ trợ của CORBA và được phát triển trên nền Java 2 SDK.

Ở phía mảy chủ, ta phải sử dụng omniORRB, được cung cấp miễn phí ở http: //www, uk. research, att. com/omniORB/index.html.

Đối tượng c++ trong ví dụ trên sử dụng biến môi trường ờ Server, được khai bảo trong giao diện:

interface Env{

string getenv(in string name);

} ;

Lớp cài đặt giao diện này trong c++ có thể sử dụng hàm getenv ( ) cúa thu viện chuẩn của c.

class Envlmpl : public Virtual _Sk_Env{ public:

Virtual char* getenv(const char *name){ char* value = ::getenv(name); return CORRBA::string_dup(value);

}

};

Nhìn chung trên Server, ta phải viết chương trình để thực hiện:

  1. Khởi động ORB.
  2. Tạo ra đối tượng cùa lớp Envlmpl và đàng ký nó vói ORB.
  3. Sừ dụng tên gợi nhớ ờ Server để liên kết với đối tượng theo tên gọi.
  4. Chờ lời triệu gọi từ xa của chương trình khách

// EnvServer.cpp chương ưình C++ ờ trên Server

#include <lostream.h>

#include “Omnithread.h”

#include “Env.hh”

class Envlmpl : public virtual _sk_Env{ public:

virtual -Envlmpl(){}

virtual char* getenv(const char* name);

};

char* Envlmpl::getenv(const char* name){ char* value = ::getenv(name); return CORBA::string_dup(value);

}

void bindobjectToName(CORBA::ORB_ptr obj){

CosNaming::NamingContext_var rootContext; try (

CORBA::Object_var initServ =

orb -> resolve_initial_references(“NameService”); rootContext = CosNaming: :NamingContext: :_narrow (initServ) ; if(CORBA::is_nil(rootContext)){

cerr « “Failed to narrow naming context!” « endl; return;

}

}catch(CORBA: :ORB::InvalidNameS ex){

cerr << “Service does not exit!” << endl;

}

try{

CosNaming::Name contextName; contextName.length(1); contextName[0].id = “corejava”; contextName[0].kind = “context”;

CosNaming::NamingContext_var corej avaContext; try{

corejavaContext =

rootContext -> bind_new_context (contextName) ;

}catch(CosNaming::NamingContext::AlreadyBoundk){ CORBA::Object_var contextObj =

rootContext -> resolve(contextName); corejavaContext =

CosNaming: :NamingContext: :_tiarrow (contextObj ) ; if(CORBA::is_nil(corejavaContext)){

cerr « “Service does not exit!” « endl; return;

}

}

CosNaming::Name objectName; obj ectName.length(1) ; objectName[0].id = name; objectName[0].kind = “Object”; corej avaContext -> rebind(objectName, obj); y catch(CORBA::COMM_FAILURE&{

cerr << “Comm Failure!” << endl;

}

}

int main(int argc, char *argv[j){ cout « “Creating and initializing the ORN …” « endl;

CORBA: :QRB_ptr orb = CORBA::GRB_init (argc, argv, “amiCRB2”) ;

CORBA:: BGA_ptr boa = orb -> BQA_init (argc, argv, “anni’CRB2″_BQA); cout « “Registring server with the ORB …” « endl;

Envlmpl* impl = new Envlmpl(); impl -> _obj__is_ready (boa) ;

CORBA::String_var s = orb -> object_to_string(impl); cout << s << endl;

cout « “Binding server to name service … ” « endl;

Env__var env = impl->this () ; bindObjectToName(orb, “Env”, env);

coût « “Waiting for invocation from client … ” « endl; boa -> impl_is_ready(); return 0;

}

Trên máy khách, ta cần thực hiện các bước sau:

  1. Khởi động ORB,
  2. Xác định việc gắn tên gọi gợi nhớ thông qua tham chiếu vào “NameServi ce” và NamíngContext.
  3. Xác định đối tượng có các phuomg thức cần triệu gọi,
  4. Ép đối tượng nhận lại về cho phù hợp về kiểu và thực hiện triệu gọi từ xa.

// EnvClient java chưorng trình khách

import org.omg.CosNaming.* ; import org.omg.CORBA.* ; public class EnvClient{

public static void main(string args[]){ try {

ORB orb = ORB.init(args, null);

org.omg.CORBA.Obj ect namingContextObj =

orb.resolve_ìnìtial_references(“NaraeService”); NamingContext namingContext =

NamingContextHelper.narrow(namingContextObj); NameComponent [ ] path = { new NameComponent(“corejava”, “context”),new NameComponent(“Env”, “Object”) }; org.omg.CORBA.Object envObj = namingContext.résolve(path);

Env env = EnvHelper.narrow(envObj);

System.out.println(env.getenv(“PATH”));

}catch(Exception e){

System.out.println(“Error: ” + e); e.printStackTrace(System.out);

}

Để kiểm tra chương trình trên, ta thực hiện như sau:

  1. Dịch tệp IDL: idl , sử dụng cả C++và Java IDL Compiler
  2. Dịch chương trình EnvServer . cpp
  3. Dịch chương trình j ava
  4. Khởi động dịch vụ đặt tên: naming service
  5. Chạy chương trình phục vụ: EnvServer
  6. Chạy chương trinh khách: j ava EnvClient.