- Hãy chắc chắn để sử dụng URL khi bắt đầu các máy chủ Di chuyển các lớp trong thư mục server vào máy chủ của bạn và bắt đầu đăng ký RMI và máy
2/ Một số khái niệm quan trọng mà bất cứ người sử dụng IDL nào cũng cần phải biết như:
55 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java
- Trong IDL bạn dùng từ khóa sequence để định nghĩa mảng giá trị, bạn phải định nghĩa 1 kiểu dữ liệu trước khi bạn khai báo tham số sequence .VD như ta định nghĩa 1 chuỗi các sản phẩm như sau:
typedef sequence<Product> ProductSeq; - Ta dùng nó trong khai báo phương thức sau: interface Warehouse
{
ProductSeq find(in Customer c); . . .
};
- Trong ngôn ngữ Java thì sequence tương ứng với array , VD như phương thức find được ánh xạ qua ngôn ngữ Java là:
Product[] find(Customer c)
- Để đưa exception vào trong phương thức, đầu tiên ta phải định nghĩa kiểu exception đó, sau đó dùng khai báo raises .VD như:
interface Warehouse {
exception BadCustomer { string reason; };
ProductSeq find(in Customer c) raises BadCustomer;
. . .
};
- Bộ biên dịch IDL sẽ chuyển exception thành class: final public class BadCustomer
extends org.omg.CORBA.UserException
{
public BadCustomer() {}
public BadCustomer(String __reason) { reason =
__reason; }
public String reason;
}
+Còn raises sẽ chuyển thành throws trong phương thức của Java:
ProductSeq find(Customer c) throws BadCustomer - Khai báo hằng trong interface:
interface Warehouse {
const int SOLD_OUT = 404;
. . .
56 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java
- Thuộc tính trong interface ta dùng từ khóa attribute ,VD như ta có thuộc tính isbn trong interface Book như sau:
interface Book {
attribute string isbn;
. . .
};
- Còn trong Java thì nó tương ứng với: String isbn() // accessor
void isbn(String __isbn) // mutator
+ Nếu thuộc tính được khai báo là readonly thì không có phương thức mutator được tạo ra
- CORBA có hỗ trợ cho việc thừa kế interface, VD như: interface Book : Product { /* . . . */ };
+ Bạn sử dụng dấu : để chỉ việc thừa kế, 1 interface có thể thừa kế từ nhiều interface
- Trong IDL, bạn có thể nhóm định nghĩa của các interface, các kiểu, các hằng, các exception(ngoại lệ) vào trong 1 module:
module corejava { interface Product { . . . }; interface Warehouse { . . . }; };
- module được chuyển thành package trong Java
- Một khi bạn đã có file IDL, bạn chạy trình biên dịch IDL để có các lớp stub và các lớp helper cho ngôn ngữ lập trình đích của bạn như Java hay C++.VD :
+ Để chuyển từ file IDL sang Java, bạn dùng lệnh idlj như sau: idlj Product.idl
57 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java
Product.java , định nghĩa interface
ProductOperations.java, interface chứa các thao tác
hiện thời
ProductHolder.java , lớp holder cho các tham số out
ProductHelper.java, lớp helper
_ProductStub.java, lớp stub để giao tiếp với ORB
+ Để chuyển từ file IDL sang C++, ta dùng lệnh omniidl để tạo ra C++ stub:
omniidl -bcxx Product.idl ->Nó sẽ tạo ra 2 file C++ như sau:
ProductSK.cc , 1 file header định nghĩa các lớp Product,
Product_Helper và POA_Product
ProductSK.cc,1 file C++ chứa code nguồn cho các lớp
trên
=>Trình biên dịch IDL sang C++ của những nhà cung cấp khác nhau sẽ tạo ra các file khác nhau
3/. A CORBA Example:
- Trong ví dụ sau, ta sẽ trình bày cách làm sao gọi 1 đối tượng C++ trên sever từ 1 client Java, sử dụng hỗ trợ của CORBA trong JDK. Về phía server ta sử dụng omniORB, 1 mã nguồn mở ORB có thể tải từ http://omniorb.sourceforge.net.
- Ví dụ về đối tượng C++ trên server đơn giản là giá trị của 1 biến trên server. Interface như sau:
interface Env {
string getenv(in string name); };
- Đoạn chương trình Java sau đây thu được giá trị của biến PATH trong quá trình đối tượng trên server chạy:
Env env = . . .;
String value = env.getenv("PATH")
- Code C++ cho interface này thực sự đơn giản, ta chỉ việc gọi phương thức getenv trong thư viện chuẩn của C:
58 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java
: public POA_Env, public PortableServer::RefCountServantBase { {
public:
virtual char* getenv(const char *name) {
char* value = std::getenv(name); return CORBA::string_dup(value); }
};
- Bạn không cần phải hiểu code C++ trong phần này vì nó chỉ là 1 mẩu trong code mà bạn muốn đóng gói trong 1 đối tượng CORBA nên bạn có thể gọi nó từ chương trình Java.
-Trên Server, bạn viết 1 chương trình C++ theo yêu cầu sau: 1. Khởi động ORB.
2. Tạo 1 đối tượng cho lớp EnvImpl và lưu nó với ORB.
3. Sử dụng name server để ràng buộc đối tượng với 1 cái tên nào đó. 4. Chờ lời gọi từ client
- Bạn có thể tìm chương trình đó trong ví dụ 5-19 ở phần cuối.
- Tiếp theo là phần code cho client. Bạn đã biết được làm sao để gọi 1 phương thức từ đối tượng trên server một khi bạn có tham chiếu(reference) tới đối tượng từ xa.Tuy nhiên, để có được tham chiếu đó, bạn phải đi qua 1 bộ mumbo- jumbo khác so với cách của RMI
- Đầu tiên bạn khởi tạo ORB. ORB đơn giản là 1 thư viện code trình bày cách thức làm sao để “nói chuyện” được với các ORB khác và làm sao để sắp xếp thứ tự hoặc không thừ tự cho các tham số.
ORB orb = ORB.init(args, null);
- Tiếp theo là bạn xác định naming service nhằm giúp bạn xác định được vị trí những đối tượng khác. Tuy nhiên trong CORBA, naming service chỉlà 1 đối tượng CORBA khác. Để gọi được naming service , bạn cần xác định vị trí của nó. Trong CORBA 1 thì đây là 1 vần đề lớn bởi vì không có tiêu chuẩn nào để có thể tham chiếu đến nó. Tuy nhiên, CORBA 2 ORB sẽ cho bạn vị trí của những dịch vụ tiêu chuẩn bằng tên:
59 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java
-Naming service có tên tiêu chuẩn là NameService . Hầu hết các ORB đều có các dịch vụ cộng thêm lúc đầu, chẳng hạn như dịch vụ RootPOA cho phép truy cập tới gốc của Portable Object Adaptor
- Để có được 1 đối tượng tham chiếu tới dịch vụ, bạn sử dụng phương thức
resolve_initial_references . Nó return 1 đối tượng CORBA chung, chẳng
hạn như lớp org.omg.corba.Object .Nếu bạn chỉ sử dụng Object thì trình biên dịch sẽ hiểu là java.lang.Object ,sử dụng:
org.omg.CORBA.Object object = orb.resolve_initial_references("NameService"); - Tiếp theo, chuyển tham chiếu này thành tham chiếu NamingContext nên bạn có thể gọi phương thức của interface NamingContext .Trong RMI, bạn đơn giản chỉ nhắc lại tham chiếu sang 1 kiểu khác.Tuy nhiên trong CORBA thì bạn không thể làm vậy được:
NamingContext namingContext = (NamingContext) object; // ERROR - Thay vào đó, bạn phải dùng phương thức narrow của lớp helper của interface đích
NamingContext namingContext = NamingContextHelper.narrow(object); ->sử dụng phương thức narrow để chuyển tham chiếu đối tượng CORBA sang subtype
- Hiện giờ bạn đã có naming context,bạn có thể dùng nó để xác định vị trí của đối tượng. Naming context kết hợp tên gọi với các đối tượng server
- Trong ví dụ của chúng ta thì chương trình server đặt đối tượng EnvImpl theo tên gọi được mô tả bởi chuỗi sau:
(id="corejava", kind="Context"), (id="Env", kind="Object") - Chúng ta truy hồi lại tham số từ xa từ nó bằng cách khai báo 1 mảng các name compoment và truyền nó tới phương thức resolve của interface
NamingContext
NameComponent[] path = {
new NameComponent("corejava", "Context"), new NameComponent("Env", "Object")
};
org.omg.CORBA.Object envObj = namingContext.resolve(path);
- Một lần nữa, chúng ta phải thu hẹp các kết quả của tham chiếu đối tượng: Env env = EnvHelper.narrow(envObj);
60 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java
- Bây giờ chúng ta đã sẵn sàng gọi phương thức từ xa: String value = env.getenv("PATH"); - Bạn sẽ tìm được code hoàn chỉnh ở Ví dụ 5-18
- Đây là các bước thực hiện trong chương trình client điển hình: 1. Khởi động ORB
2. Định vị trí của naming service bằng cách truy hồi lại tham chiếu ban đầu tới "NameService" và thu hẹp nó từ tham chiếu
NamingContext
3. Định vị trí đối tượng của phương thức mà bạn muốn gọi bằng cách thu thập tên của nó và gọi phương thức resolve của NamingContext 4. Thu hẹp đối tượng trả về tới khi đúng và gọi phương thức bạn muốn. - Để kiểm nghiệm chương trình này, các bạn làm như sau:
1. Biên dịch file IDL, sử dụng cả trình biên dịch C++ và Java. omniidl -bcxx Env.idl
idlj Env.idl
2. Biên dịch chương trình C++ trên server. Những câu lệnh được biên dịch phụ thuộc vào ORB, chẳng hạn với OmniORB trên Unix thì bạn dùng: g++ s-o EnvServer -D__x86__ -D__linux__ -D__OSVERSION__=2 -I/usr/local/include/omniORB4 EnvServer.cpp EnvSK.cc
-lomniORB4 -lomnithread -lpthread
3. Biên dịch chương trình Java trên client.
4. Khởi động dịch vụ Naming Service trên server, có thể sử dụng chương trình orbd đi kèm với bộ JDK hay dịch vụ Naming Service trên ORB của bạn, chẳng hạn như omniNames nếu bạn dùng omniORB. Dịch vụ
Naming Service này sẽ chạy cho tới khi nào bạn dừng nó thì thôi + Để bắt đầu orbd , bạn chạy orbd -ORBInitialPort 2809 &
+ Ngoài ra để bắt đầu omniNames , bạn chạy lệnh:
omniNames -ORBsupportBootstrapAgent 1 & 5. Khởi động server:
./EnvServer -ORBInitRef NameService=corbaname::localhost:2809 &
6. Chạy client:
61 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java
- Nếu như server ở trên 1 máy từ xa hay port ban đầu của server ORB không giống với giá trị mặc định của Java IDL là 900 thì hãy đặt giá trị cho thuộc tính của ORBInitialHost và ORBInitialPort .Ví dụ như, OmniORB sử dụng
port 2809, còn khi sử dụng orbd thì port cũng là 2809 bởi vì ta cần phải có quyền
root để khởi động 1 dịch vụ trên cổng 1024 trong Unix/Linux
- Có 2 phương thức để cài đặt các thuộc tính đó. Bạn có thể cài đặt thuộc tính cho hệ thống:
org.omg.CORBA.ORBInitialHost org.omg.CORBA.ORBInitialPort
- Chẳng hạn, bằng việc khởi động bộ biên dịch Java với lựa chọn –D , bạn có thể chỉ định giá trị trên dòng lệnh:
java EnvClient -ORBInitialHost warthog -ORBInitialPort 2809
- Tham số dòng lệnh sẽ được truyền tới ORB bằng cách gọi : ORB orb = ORB.init(args, null);
- Nếu client của bạn không tìm thấy dịch vụ Naming Service ,hãy cố gắng đặt giá trị port ban đầu cho cả server lẫn client cùng 1 giá trị
*Mẹo:
+ Nếu bạn gặp rắc rối trong việc kết nối tới Naming Service , hãy in ra 1 danh sách các dịch vụ ban đầu mà ORB của bạn định được vị trí
public class ListServices {
public static void main(String args[]) throws Exception {
ORB orb = ORB.init(args, null);
String[] services = orb.list_initial_services(); for (int i = 0; i < services.length; i++)
System.out.println(services[i]); }
}
+ Với 1 vài ORB, NameService sẽ không nằm trong danh sách đó. Trong trường hợp này, hãy chuyển sang kế hoạch B, định vị các đối tượng server bằng cách dùng Interoperable Object Reference(IOR) của chính nó
- Trong phần này, bạn đã thấy được làm cách nào để kết nối tới 1 server mà được thực hiện bằng C++. Bạn có thể gói gọn các dịch vụ kế thừa vào trong những
62 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java
đối tượng CORBA và có thể truy xuất tới chúng từ chương trình Java của bạn, mà không cần phải triển khai thêm các hệ thống phần mềm trên client.