báo cáo chương 5-core java volume ii

81
Đại Hc Công NghThông Tin ĐH Quốc Gia Tp HCM ____________***********_____________ Báo cáo môn hc Lp Trình HThng vi Java Đề tài s7: Tìm hiu Lp trình phân tán trong Java (Nguồn Chương 5 cuốn Core Java™ 2 Volume II - Advanced Features, Seventh Edition) GVHD: Bùi Thanh Hiếu(Msc) Thành viên nhóm: Hunh Thái Bình 08520031 Hoàng Minh Hi 08520105 Hunh Xuân Tâm 08520326 Phan Thanh Hưng 08520164 26/04/2011

Upload: hunteckuit

Post on 02-Jul-2015

293 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Báo cáo Chương 5-Core Java Volume II

Đại Học Công Nghệ Thông Tin

ĐH Quốc Gia Tp HCM ____________***********_____________

Báo cáo môn học Lập Trình

Hệ Thống với Java

Đề tài số 7: Tìm hiểu Lập trình phân tán trong Java (Nguồn Chương 5 cuốn Core Java™ 2 Volume II - Advanced Features, Seventh Edition)

GVHD: Bùi Thanh Hiếu(Msc)

Thành viên nhóm:

Huỳnh Thái Bình 08520031

Hoàng Minh Hải 08520105

Huỳnh Xuân Tâm 08520326

Phan Thanh Hưng 08520164

26/04/2011

Page 2: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

1 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

Lời nói đầu

Lập trình đối tượng phân tán là một trong những vấn đề nóng bỏng của

công nghệ phần mền ngày nay. Java là ngôn ngữ đi tiên phong trong

việc giải quyết vấn đề lập trình phân tán. Ngày nay nếu bạn không biết

đến kỹ thuật lập trình này thì quả là một thiếu sót lớn. Từ .NET của

Microsoft cho đến Java của Sun tất cả đều hướng đến môi trường hợp

tác và tận dụng nguồn tài nguyên phân tán trên mạng. Chương này sẽ

giới thiệu với bạn khái niệm và cách cài đặt các đối tượng phân tán

bằng kỹ thuật RMI trong Java.

Nội dung chính:

The Roles of Client and Server.

Remote Method Invocations.

Setup for Remote Method Invocation.

Parameter Passing in Remote Methods.

Server Object Activation.

Java IDL and CORBA.

Remote Method Calls with SOAP.

Phân chia công việc trong nhóm:

Bạn Huỳnh Thái Bình phụ trách phần:

The Roles of Client and Server.

Remote Method Invocations

Bạn Hoàng Minh Hải phụ trách phần:

Setup for Remote Method Invocation

Bạn Huỳnh Xuân Tâm phụ trách phần:

Parameter Passing in Remote Methods

Server Object Activation

Bạn Phan Thanh Hưng phụ trách 2 phần cuối:

Java IDL and CORBA

Remote Method Calls with SOAP

Page 3: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

2 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/. The Roles of Client and Server(Vai trò của Client và

Server):

- Lấy ý tưởng là thu thập thông tin trên một máy tính khách hàng và gửi

thông tin qua mạng cho máy chủ. Giả sử rằng một người sử dụng trên một máy

tính cá nhân sẽ điền vào mẫu yêu cầu thông tin. Dữ liệu được gửi đến máy chủ của

nhà cung cấp. Các máy chủ xử lý yêu cầu và gửi lại thông tin sản phẩm cho khách

hàng.

Figure 5-1. Transmitting objects between client and server

- Trong mô hình truyền thống client/server, khách hàng yêu cầu một định

dạng truyền tải và gửi dữ liệu yêu cầu đến máy chủ. Các máy chủ phân tích yêu

cầu định dạng và các định dạng phản ứng để truyền cho khách hàng. Khách hàng

sau đó phân tích những phản ứng và hiển thị nó cho người dùng.

- Nếu bạn thực hiện bằng tay, có một rắc rối lớn: Bạn phải thiết kế một định

dạng truyền tải, và bạn phải viết code cho việc chuyển đổi giữa dữ liệu và định

dạng truyền.

Page 4: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

3 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

Note:

Trong ví dụ này, chúng tôi giả định rằng khách hàng là một máy tính tương tác với

một người sử dụng. Tuy nhiên, khách hàng đều có thể chạy một ứng dụng web và

yêu cầu một dịch vụ từ một chương trình chạy trên máy tính khác. Có hai đối

tượng giao tiếp, đối tượng khách hàng trong ứng dụng web và các đối tượng máy

chủ thực hiện các dịch vụ. Đây là một mô hình rất phổ biến trong thực tế.

- Chúng tôi quan tâm vào mô hình truyền thống client/server bởi vì nó làm

cho vai trò của các máy khách và máy chủ trực quan hơn.

- Cơ chế mà các lập trình viên làm cho khách hàng một phương pháp gọi

thường xuyên, mà không lo lắng về việc gửi dữ liệu qua mạng hay phân tích phản

ứng.đối tượng đã thực hiện công việc đó không nằm trong cùng một máy ảo. Nó có

thể không được thực hiện trong các ngôn ngữ lập trình Java.

- Giải pháp là cài đặt một proxy(sử uỷ quyền) cho các đối tượng server trên

client. Proxy là một phương pháp phổ biến. Các proxy client liên lạc với server.

- Lập trình viên của đối tượng máy chủ không muốn phiền phức với các giao

tiếp khách hàng. Giải pháp là cài đặt một đối tượng proxy thứ hai trên máy chủ.

Các máy chủ proxy giao tiếp với các proxy của khách hàng, và nó làm cho phương

pháp này phổ biến.

Figure 5-2. Remote method call with proxies

Page 5: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

4 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

- Vậy làm thế nào để các proxy giao tiếp với nhau?

-> Điều đó phụ thuộc vào công nghệ thực hiện.

- Có ba sự lựa chọn phổ biến:

RMI, Java Remote Method Invocation Technology hỗ trợ phương thức gọi

phân phối giữa các đối tượng Java.

CORBA, Common Object Request Broker Architecture hỗ trợ phương thức

gọi giữa các đối tượng của bất kỳ ngôn ngữ lập trình. CORBA sử dụng

Internet Inter-ORB Protocol, hoặc IIOP, để giao tiếp giữa các đối tượng.

SOAP, Simple Object Access Protocol cũng là ngôn ngữ lập trình trung gian.

Tuy nhiên, SOAP sử dụng một định dạng truyền dẫn dựa trên XML.

Note:

Microsoft sử dụng COM. Trong quá khứ, Microsoft đặt COM là một đối thủ so với

CORBA. Tuy nhiên, tại thời điểm này, Microsoft tập trung vào SOAP.

- CORBA và SOAP hoàn toàn là ngôn ngữ trung gian. Chương trình client

và server có thể được viết bằng C, C + +, Java, hoặc ngôn ngữ khác. Bạn cung cấp

một giao diện để xác định tín hiệu của các phương thức và các loại dữ liệu đối

tượng của bạn có thể xử lý. Những mô tả được định dạng bằng một ngôn ngữ đặc

biệt, được gọi là ngôn ngữ định nghĩa giao diện (IDL) cho CORBA và ngôn ngữ

mô tả các dịch vụ Web (WSDL) cho SOAP.

- Khá ít người tin rằng CORBA là mô hình đối tượng của tương lai. Thành

thật mà nói CORBA đã có ích trong việc triển khai các vấn đê phức tạp và các vấn

đề tương thích.

- SOAP có thể đơn giản, nhưng nó cũng có thể trở nên khá phức tạp, vì nó

yêu cầu nhiều tính năng hơn mà CORBA đã có. Các giao thức XML có lợi thế là

ngôn ngữ gần gũi với con người nên giúp ích cho việc gỡ rối. Nhìn chung,

CORBA hiệu quả hơn, mặc dù SOAP là một phù hợp tốt hơn cho một kiến trúc

web.

- Nếu cả hai đối tượng giao tiếp được thực hiện trong code Java, thì việc

dùng CORBA và SOAP là không cần thiết. Sun đã phát triển một cơ chế đơn giản,

đó là phương pháp triệu gọi phương thức từ xa-Remote Method Invocation (RMI),

đặc biệt dùng cho giao tiếp giữa các ứng dụng Java.

Page 6: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

5 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

II./ Remote Method Invocations(Gọi phương thức từ xa):

- Nếu bạn có quyền truy cập vào một đối tượng trên một máy tính khác, bạn

có thể gọi các phương thức của đối tượng từ xa. Tất nhiên, các tham số phương

thức bằng cách nào đó phải được gửi đến các máy khác, máy chủ phải được thông

báo để thực hiện các phương thức, và giá trị trả về phải được return trở lại. RMI xử

lý việc này.

- Ví dụ: client tìm kiếm thông tin sản phẩm có thể truy vấn một đối tượng

trên máy chủ. Nó gọi một phương thức từ xa, tìm kiếm, trong đó có một tham số:

một đối tượng khách hàng. Việc tìm thấy trả về một đối tượng cho client: đối

tượng của sản phẩm

Figure 5-3. Invoking a remote method on a server object

- Trong thuật ngữ RMI , các đối tượng của phương thức tạo ra lời gọi từ xa

được gọi là client object. Các đối tượng từ xa được gọi là server object. Điều quan

trọng là phải nhớ rằng thuật ngữ client/server chỉ áp dụng cho một lời gọi phương

thức duy nhất. Các máy tính đang chạy code Java mà gọi phương thức từ xa là

client và máy tính lưu trữ các đối tượng mà thực hiện lời gọi là server. Điều này

hoàn toàn làm cho vai trò được đảo ngược lại. Server của một lời gọi trước đó có

thể trở thành client khi gọi một một đối tượng bằng phương thức từ xa ở trên máy

tính khác.

Page 7: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

6 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

1/. Stubs and Parameter Marshalling:

- Khi client muốn gọi một phương thức từ xa trên một đối tượng từ xa, thì nó

gọi 1 phương pháp thông thường trên một đối tượng proxy gọi là stub. Stub nằm

trên máy client, không phải trên server. Ví dụ, trong giao thức RMI các đối tượng

được mã hoá với cơ chế tuần tự. Quá trình mã hóa các thông số được gọi là tham

số marshalling(parameter marshalling). Mục đích của tham số marshalling là

chuyển đổi các tham số vào một định dạng thích hợp cho việc vận chuyển từ máy

ảo với nhau.

- Phương thức stub trên client xây dựng một khối thông tin bao gồm:

o Nhận dạng đối tượng từ xa sẽ được sử dụng;

o Một mô tả của phương thức được gọi ;

o Các tham số marshalled.

- Phương thức stub sau đó gửi thông tin này tới server. Về phía server, một

đối tượng thực hiện các hành động cho mỗi lời gọi phương thức từ xa:

o Nó không có các thông số marshals.

o Nó định vị đối tượng được gọi .

o Nó gọi phương thức mong muốn.

o Nó sẽ giữ và sắp đặt giá trị trả về hoặc ngoại lệ của cuộc gọi.

o Nó sẽ gửi một gói gồm các dữ liệu trả về marshalled tới stub trên client

Page 8: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

7 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

Figure 5-4. Parameter marshalling

- Quá trình này rõ ràng là phức tạp, nhưng nó hoàn toàn tự động và minh

bạch cho các lập trình viên. Hơn nữa, các nhà thiết kế của các đối tượng Java từ xa

đã cố gắng để cung cấp cho các đối tượng từ xa cùng "look and feel(xem và cảm

thấy)" như các đối tượng nội tại.

2./ Dynamic Class Loading:

- Khi truyền một đối tượng từ xa đến một chương trình khác, như là một

tham số hay giá trị trả về của một phương thức từ xa, thì chương trình đó phải có

các file class cho đối tượng đó. Ví dụ, hãy xem xét một phương thức với kiểu trả

về là các sản phẩm. Tất nhiên, chương trình client cần các lớp Product.class để

biên dịch. Nhưng bây giờ giả sử server khởi tạo và trả về một đối tượng sách, và

sách là một phân nhóm của sản phẩm. Các client có thể chưa bao giờ thấy class

Book, và nó có thể đã không biết nơi để tìm file lớp Book.class

- Do đó, một bộ nạp lớp đó sẽ được tải từ máy chủ. Quá trình này cũng

tương tự như quá trình nạp lớp của các applet chạy trong trình duyệt. Bất cứ khi

nào một chương trình tải mới mã từ một vị trí mạng, sẽ phát sinh vấn đề an ninh.

Page 9: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

8 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

Vì lý do đó, bạn cần sử dụng một chương trình quản lý bảo mật(security manager)

trong các ứng dụng client RMI. Đây là một cơ chế an toàn để bảo vệ các chương

trình từ virus trong mã stub. Đối với các ứng dụng chuyên ngành, các lập trình có

thể thay thế bộ tải lớp của mình và quản lý an ninh, nhưng được cung cấp bởi hệ

thống RMI là đủ cho sử dụng bình thường.

III/. Setup for Remote Method Invocation(Cài đặt cho

phương pháp truyền dẫn dữ liệu từ xa):

- Ngay cả khi chạy những ví dụ đơn giản nhất các đối tượng từ xa(remote

object) yêu cầu nhiều hơn những thiết lập không chạy một chương trình độc lập

hoặc applet. Bạn phải chạy các chương trình trên cả các máy tính máy chủ và máy

khách. Các thông tin object cần thiết phải được tách vào vào phía giao diện máy

khách và giao diện máy chủ phía triển khai. Ngoài ra, một cơ chế đặc biệt cho phép

client tra cứu để xác định vị trí các object trên máy chủ.

- Để bắt đầu, chúng ta đi qua từng yêu cầu, sử dụng ví dụ đơn giản. Trong ví

dụ đầu tiên của chúng ta tạo ra một vài đối tượng của một loại sản phẩm trên máy

chủ. Sau đó chúng ta chạy một chương trình trên một máy tính client để xác định

vị trí và truy vấn các đối tượng này.

1/. Interfaces and Implementations(Giao diện và Triển khai):

- Chương trình client cần để thao tác các đối tượng server nhưng nó không

thực sự copy chúng . Các đối tượng tự cư trú trên máy chủ. Mã client vẫn phải biết

những gì nó có thể làm với các đối tượng, khả năng của chúng được thể hiện trong

một giao diện được chia sẻ giữa client và server và để cư trú đồng thời trên cả hai

máy.

interface Product // shared by client and server

extends Remote

{

String getDescription() throws RemoteException;

}

- Cũng như trong ví dụ này tất cả các giao diện cho các remote object phải

mở rộng giao diện từ xa được xác định trong gói java.rmi. Tất cả các phương

pháp trong các giao diện cũng phải biểu thị một Remote Exception. Lý do cho việc

khai báo là cuộc gọi phương thức từ xa vốn ít tin cậy hơn cuộc gọi địa phương,

luôn luôn có thể có một cuộc gọi từ xa sẽ thất bại. Ví dụ, máy chủ hoặc kết nối

mạng có thể tạm thời không có hoặc có vấn đề mạng. Code máy client của bạn

phải được chuẩn bị để đối phó với những khả năng này. Đối với những lý do này.

Ngôn ngữ lập trình Java buộc bạn phải theo kịp Remote Exception với tất cả các

Page 10: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

9 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

cuộc gọi phương thức từ xa và để xác định các hành động thích hợp để có khi cuộc

gọi không thành công. Các khách hàng truy cập các đối tượng máy chủ thông qua

stub để thực hiện giao diện này.

Product p = . . .; // see below how the client gets a stub

reference

String d = p.getDescription();

System.out.println(d);

- Trong phần tiếp theo, bạn sẽ thấy làm thế nào client có thể có được một

tham chiếu đến loại đối tượng từ xa.

- Tiếp theo, ở phía máy chủ, bạn phải thực hiện các lớp mà thực sự thực hiện

các phương pháp quảng cáo trong giao diện từ xa.

public class ProductImpl // server

extends UnicastRemoteObject

implements Product

{

public ProductImpl(String d)

throws RemoteException

{

descr = d;

}

public String getDescription()

throws RemoteException

{

return "I am a " + descr + ". Buy me!";

}

private String descr;

}

NOTE

constructor ProductImpl được khai báo để dịch chuyển RemoteException vì

UnicastRemoteObject có thể dịch chuyển ngoại lệ nếu nó không thể kết nối

với dịch vụ mạng theo dõi các đối tượng máy chủ

- Lớp này có một phương pháp duy nhất, geTDescription ,có thể được gọi

từ các khách hàng từ xa

Page 11: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

10 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ạn có thể nói rằng class là một máy chủ cho các phương pháp điều khiển

từ xa bởi vì nó mở rộng UnicastRemoteObject, mà là một lớp Java nền tảng cho

các đối tượng truy cập từ xa.

NOTE

Lớp ProductImpl không phải là một lớp máy chủ điển hình bởi vì nó làm việc quá

ít. Thông thường, bạn chỉ muốn có máy chủ làm một số công việc nặng mà một

client không thể thực hiện. Chúng tôi chỉ sử dụng các ví dụ sản phẩm để hướng

dẫn bạn qua các cơ chế gọi các phương thức từ xa.

- Các class server thường mở rộng lớp RemoteServer từ gói

java.rmi.server. nhưng RemoteServer là một lớp trừu tượng mà chỉ xác định

các cơ chế cơ bản trong giao tiếp giữa máy chủ và các đối tượng khai từ xa Lớp

UnicastRemoteObject mà đi kèm với RMI mở rộng lớp trừu tượng và là

RemoteServer bạn có thể sử dụng nó mà không cần viết bất kỳ mã nào ."path of

least resistance "cho một lớp máy chủ là có nguồn gốc từ UnicastRemoteObject,

và tất cả các lớp máy chủ trong chương này làm như vậy.

Hình 5-5 cho thấy mối quan hệ thừa kế giữa các lớp này.

Page 12: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

11 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

- Một đối tượng UnicastRemoteObject nằm trên máy chủ. Nó còn chạy

được khi một dịch vụ được yêu cầu và phải được truy cập thông qua giao thức TCP

/ IP. Đây là lớp mà chúng tôi mở rộng cho tất cả các lớp máy chủ trong cuốn sách

này và là lớp máy chủ chỉ có trong phiên bản hiện tại của gói RMI. Sun(mặt trời)

hoặc bên thứ ba nhà cung cấp có thể, trong tương lai, thiết kế các lớp khác để sử

dụng bởi các máy chủ cho RMI.

NOTE

Thỉnh thoảng, bạn có thể không muốn có một lớp máy chủ mở rộng lớp

UnicastRemoteObject, có lẽ bởi vì nó đã được mở rộng một lớp khác. Trong tình

hình đó, bạn cần phải tự khởi tạo các đối tượng máy chủ và truyền cho phương

thức exportObject tĩnh. Thay vì mở rộng UnicastRemoteObject,ta gọi:

UnicastRemoteObject.exportObject(this, 0);

Trong xây dựng của các đối tượng máy chủ. Tham số thứ hai là 0 để chỉ ra rằng bất

kỳ cổng thích hợp có thể được sử dụng để lắng nghe các kết nối client

- Khi bạn sử dụng RMI (hoặc bất kỳ cơ chế đối tượng phân tán, cho từng

vấn đề), bạn sẽ cần phải nắm vững một chút bối rối tập các lớp. Trong chương này,

chúng tôi sử dụng một quy ước đặt tên thống nhất cho tất cả các ví dụ của chúng

tôi mà chúng tôi hy vọng làm cho nó dễ dàng hơn để nhận ra mục đích của từng

loại(xem Bảng 5-1)

Page 13: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

12 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

2/. Stub Class Generation:

- Theo JDK 5.0, tất cả các lớp stub được tạo ra tự động, sử dụng cơ chế

proxy thảo luận trong Tập 1, chương 6. Tuy nhiên, trước khi JDK 5.0, bạn phải tự

tạo ra khai với công cụ rmic, như trong ví dụ sau đây rmic -v1.2 ProductImpl

-Điều này gọi đến các công cụ rmic tạo ra một lớp tập tin ProductImpl_Stub.class

- Nếu bạn sử dụng JDK 1.1 hãy gọi: rmic -v1.1 ProductImpl

- Hai tập tin được tạo ra: các tập tin stubs và lớp một tập tin thứ hai tên là

ProductImpl_Skel.class.

NOTE

Hãy nhớ đến đầu tiên biên dịch tập tin nguồn với javac trước khi chạy rmic. Nếu

bạn đang tạo ra khai cho một lớp trong một gói, bạn phải cung cấp cho rmic tên gói

đầy đủ.

3/. Locating Server Objects:

- Để truy cập một đối tượng từ xa mà tồn tại trên máy chủ, khách hàng cần

có một đối tượng stub địa phương, Làm thế nào có thể yêu cầu client như một stub.

Phương pháp phổ biến nhất là để gọi một phương thức từ xa của một đối tượng

server và nhận được một đối tượng stub như là một giá trị trả về.

- Tuy nhiên,có một vấn đề "con gà và quả trứng” ở đây. Các đối tượng máy

chủ đầu tiên đã được đặt một cách khác. The Sun RMI thư viện cung cấp dịch vụ

đăng ký khởi động để định vị các đối tượng máy chủ đầu tiên, Một chương trình

máy chủ đăng ký các đối tượng với dịch vụ đăng ký khởi động, và client truy khai

cho các đối tượng. Bạn đăng ký một đối tượng máy chủ bằng cách cho cơ quan

đăng ký khởi động dịch vụ một tham chiếu đến các đối tượng và tên một. Tên này

là một chuỗi được (hy vọng) độc đáo

// server

ProductImpl p1 = new ProductImpl("Blackwell Toaster");

Context namingContext = new InitialContext();

namingContext.bind("rmi:toaster", p1);

Page 14: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

13 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

- Mã khách hàng nhận được một stub đối tượng để truy cập máy chủ bằng

cách chỉ định tên máy chủ và tên các đối tượng theo cách sau:

// client

Product p = (Product)

namingContext.lookup("rmi://yourserver.com/toaster");

- RMI URL bắt đầu với rmi: / / và được theo sau bởi một máy chủ, một

số cổng tùy chọn, giảm khác, và tên của các đối tượng từ xa. Một ví dụ khác là:

rmi://localhost:99/central_warehouse

- Mặc định thì server là localhost và port là 1099.

NOTE

Bởi vì nó là rất khó khăn để giữ các tên duy nhất trong một đăng ký toàn cầu, bạn

không nên sử dụng kỹ thuật này là phương pháp chung để định vị đối tượng trên

máy chủ. Thay vào đó, cần có tương đối ít đối tượng máy chủ tên đăng ký với dịch

vụ khởi động. đối tượng có thể xác định vị trí các đối tượng khác cho bạn. Trong ví

dụ của chúng tôi, chúng tôi tạm thời hành vi vi phạm quy tắc này và đăng ký các

đối tượng tương đối nhỏ để cho bạn thấy cơ chế đăng ký, định vị đối tượng.

- Vì lý do an ninh, ứng dụng có thể mơ ra ràng buộc, hoặc đăng ký tài liệu

tham khảo đối tượng rebind chỉ khi nó chạy trên máy chủ giống như đăng ký. Điều

này ngăn cản các client thù địch từ thay đổi thông tin đăng ký. Tuy nhiên, bất kỳ

client cũng có thể tra cứu các đối tượng. Các dịch vụ RMI đặt tên là tích hợp vào

trong đặt tên Java và mục thông tin (JNDI) dịch vụ. Trong JDK 1.3 và dưới đây,

bạn sử dụng một dịch vụ RMI đặt tên độc, như thế này:

Naming.bind("toaster", p1); // on the server

Product p = (Product) Naming.lookup("rmi://yourserver.com/toaster");

TIP

Nếu bạn so sánh các máy chủ của chúng tôi với các ví dụ máy chủ trong tài liệu

hướng dẫn Sun, bạn sẽ lưu ý rằng chúng tôi không cài đặt một trình quản lý bảo

mật trong máy chủ. Trái ngược với các báo cáo trong hướng dẫn này, một quản lý

an ninh là không cần thiết cho các máy chủ RMI. Bạn cần một quản lý an ninh, nếu

client gửi đến các đối tượng máy chủ thuộc về các lớp mà máy chủ không biết. Tuy

nhiên, trong dịch vụ của chúng tôi, client chỉ gửi các thông số String. Nói chung,

nó có vẻ khôn ngoan để hạn chế nạp lớp động trên các máy chủ.

Page 15: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

14 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

Example 5-1. ProductServer.java 1. import java.rmi.*;

2. import java.rmi.server.*;

3. import javax.naming.*;

4.

5. /**

6. This server program instantiates two remote objects,

7. registers them with the naming service, and waits for

8. clients to invoke methods on the remote objects.

9. */

10. public class ProductServer

11. {

12. public static void main(String args[])

13. {

14. try

15. {

16. System.out.println("Constructing server

implementations...");

17.

18. ProductImpl p1 = new ProductImpl("Blackwell

Toaster");

19. ProductImpl p2 = new ProductImpl("ZapXpress

Microwave Oven");

20.

21. System.out.println("Binding server implementations

to registry...");

22. Context namingContext = new InitialContext();

23. namingContext.bind("rmi:toaster", p1);

24. namingContext.bind("rmi:microwave", p2);

25. System.out.println("Waiting for invocations from

clients...");

26. }

27. catch (Exception e)

28. {

29. e.printStackTrace();

30. }

31. }

32. }

Example 5-2. ProductImpl.java 1. import java.rmi.*;

2. import java.rmi.server.*;

3.

4. /**

5. This is the implementation class for the remote product

Page 16: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

15 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

6. objects.

7. */

8. public class ProductImpl

9. extends UnicastRemoteObject

10. implements Product

11. {

12. /**

13. Constructs a product implementation

14. @param n the product name

15. */

16. public ProductImpl(String n) throws RemoteException

17. {

18. name = n;

19. }

20.

21. public String getDescription() throws RemoteException

22. {

23. return "I am a " + name + ". Buy me!";

24. }

25.

26. private String name;

27. }

Example 5-3. Product.java 1. import java.rmi.*;

2.

3. /**

4. The interface for remote product objects.

5. */

6. public interface Product extends Remote

7. {

8. /**

9. Gets the description of this product.

10. @return the product description

11. */

12. String getDescription() throws RemoteException;

13. }

4/. Starting the Server:

- Chương trình máy chủ của chúng tôi là không hoàn toàn sẵn sàng để chạy

được. Bởi vì nó sử dụng các chương trình khởi động RMI Registry, dịch vụ đó

phải có sẵn. Để bắt đầu đăng ký RMI theo UNIX, thực hiện các tuyên bố

rmiregistry &

Page 17: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

16 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 là Windows thì gọi: start rmiregistry

- Giờ thì bạn có thể khởi động Server. Nếu là Unix thì chạy lệnh: java ProductServer &

- Nếu là Windows thì chạy lệnh: start java ProductServer

- Nếu bạn chạy chương trình theo cách sau: java ProductServer

thì chương trình sẽ không bao giờ thoát ra bình thường.Điều này có vẻ kỳ lạ sau

khi tất cả, chương trình chỉ tạo ra hai đối tượng và đăng ký chúng.Trên thực tế,các

chức năng chính không xuất cảnh ngay lập tức sau khi đăng ký,như bạn mong đợi.

Tuy nhiên,khi bạn tạo 1 đối tượng của một lớp mở rộng UnicastRemoteObject,

một chủ đề riêng biệt để duy trì chương trình còn sống vô thời hạn được bắt đầu.

Vì vậy, chương trình tồn tại xung quanh để cho phép khách hàng để kết nối với nó.

TIP

Các phiên bản Windows của JDK bao gồm một lệnh, javaw, mà bắt đầu các phiên

dịch bytecode là một quá trình Windows riêng biệt và giữ nó chạy. Một số nguồn

khuyên bạn nên sử dụng javaw, không phải start java, để chạy một phiên Java

trong nền trong Windows cho RMI. Làm như vậy không phải là một ý tưởng tốt, vì

hai lý do. Windows không có công cụ để giết một quá trình nền javaw không hiển

thị trong danh sách công việc. Nó chỉ ra rằng bạn cần phải giết và khởi động lại

dịch vụ đăng ký khởi động khi bạn thay đổi STUB của một lớp đăng ký. Để giết

một quá trình mà bạn bắt đầu với lệnh bắt đầu, tất cả các bạn phải làm là nhấp

chuột vào cửa sổ và nhấn Ctrl + C

Còn có một lý do quan trọng để sử dụng lệnh start. Khi bạn chạy một quá trình

máy chủ bằng cách sử dụng javaw, tin nhắn gửi tới đầu ra hoặc lỗi được loại bỏ.

Đặc biệt, họ không được hiển thị ở bất cứ đâu. Nếu bạn muốn xem kết quả hoặc

thông báo lỗi, sử dụng start. Sau đó, thông báo lỗi ít nhất là hiển thị trên giao

diện điều khiển. Và tin tưởng chúng TÔI, bạn sẽ muốn nhìn thấy những tin nhắn

này. Rất nhiều những thứ có thể đi sai khi bạn thử nghiệm với RMI. Các lỗi phổ

biến nhất có lẽ là bạn quên chạy rmic. Sau đó, máy chủ than phiền về việc thiếu

STUB . Nếu bạn sử dụng javaw, bạn sẽ không thấy thông báo lỗi, và bạn sẽ gãi

đầu của bạn tự hỏi tại sao các CLIENT không có thể tìm thấy các đối tượng máy

chủ.

Page 18: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

17 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

5/. Listing Remote Objects:

- Trước khi viết chương trình client, hãy xác minh rằng chúng ta đã thành

công trong việc đăng ký các đối tượng từ xa. Ta gọi:

NamingEnumeration<NameClassPair> e = namingContext.list("rmi:");

để có được một điều tra của tất cả các đối tượng máy chủ với một rmi: URL. Việc

liệt kê sản lượng các đối tượng của loại NameClassPair, một lớp học bổ trợ có

chứa cả tên của đối tượng bị ràng buộc và tên của các lớp . Chúng tôi chỉ quan tâm

đến những cái tên: while (e.hasMore()) System.out.println(e.next().getName());

- Ví dụ 5-4 chứa chương trình đầy đủ. Output sẽ là: toaster

microwave

Example 5-4. ShowBindings.java 1. import java.rmi.*;

2. import java.rmi.server.*;

3. import javax.naming.*;

4.

5. /**

6. This programs shows all RMI bindings.

7. */

8. public class ShowBindings

9. {

10. public static void main(String[] args)

11. {

12. try

13. {

14. Context namingContext = new InitialContext();

15. NamingEnumeration<NameClassPair> e =

namingContext.list("rmi:");

16. while (e.hasMore())

17. System.out.println(e.next().getName());

18. }

19. catch (Exception e)

20. {

21. e.printStackTrace();

22. }

23. }

24. }

6/. The Client Side:

Page 19: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

18 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 có thể viết các chương trình CLIENT có yêu cầu từng

đối tượng sản phẩm mới được đăng ký để in mô tả của nó. chương trình CLIENT

có sử dụng RMI nên cài đặt một trình quản lý an ninh để kiểm soát các hoạt động

của các STUB động nạp. RMISecurityManager là như một người quản lý bảo

mật. Bạn cài đặt nó với chỉ dẫn sau:

System.setSecurityManager(new RMISecurityManager());

NOTE

Nếu tất cả các lớp (bao gồm cả stub ) có sẵn tại địa phương, sau đó bạn không thực

sự cần một người quản lý bảo mật. Nếu bạn biết tất cả các tập tin lớp của chương

trình của bạn tại thời gian triển khai, bạn có thể triển khai chúng tất cả các địa

phương. Tuy nhiên, nó thường xảy ra rằng chương trình tiến hóa máy chủ và các

lớp mới được thêm vào theo thời gian. Sau đó, bạn được hưởng lợi từ việc nạp lớp

năng động. Bất cứ lúc nào bạn mã tải từ một nguồn khác, bạn cần một người quản

lý bảo mật.

NOTE

Applet đã có một người quản lý bảo mật mà có thể kiểm soát tải của các lớp stub.

Khi sử dụng RMI từ applet, bạn không cài đặt một người quản lý bảo mật.

Example 5-5. ProductClient.java [View full width]

1. import java.rmi.*;

2. import java.rmi.server.*;

3. import javax.naming.*;

4.

5. /**

6. This program demonstrates how to call a remote method

7. on two objects that are located through the naming

service.

8. */

9. public class ProductClient

10. {

11. public static void main(String[] args)

12. {

13. System.setProperty("java.security.policy",

"client.policy");

14. System.setSecurityManager(new RMISecurityManager());

15. String url = "rmi://localhost/";

Page 20: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

19 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

16. // change to "rmi://yourserver.com/" when server

runs on remote machine

yourserver.com

17. try

18. {

19. Context namingContext = new InitialContext();

20. Product c1 = (Product) namingContext.lookup(url +

"toaster");

21. Product c2 = (Product) namingContext.lookup(url +

"microwave");

22.

23. System.out.println(c1.getDescription());

24. System.out.println(c2.getDescription());

25. }

26. catch (Exception e)

27. {

28. e.printStackTrace();

29. }

30. }

31. }

7/. Running the Client:

- Theo mặc định, RMISecurityManager những hạn chế tất cả các mã trong

chương trình từ việc thiết lập kết nối mạng. Tuy nhiên, chương trình cần để làm

cho các kết nối mạng. Để đạt được đăng ký RMI, và để liên hệ với các đối tượng

máy chủ.

- Một khi các chương trình client được triển khai, nó cũng cần sự cho phép

để tải các lớp stub của nó. Chúng tôi quyết vấn đề này sau khi chúng tôi thảo luận

triển khai.

- Để cho phép các client để kết nối đến cơ quan đăng ký RMI và đối tượng

máy chủ, bạn cung cấp một tập tin chính sách. Chúng tôi thảo luận về các tập tin

chính sách cụ thể hơn trong chương 9. Để bây giờ, chỉ cần sử dụng và sửa đổi các

mẫu mà chúng tôi cung cấp. Dưới đây là một tập tin chính sách cho phép một ứng

dụng để thực hiện bất kỳ kết nối mạng vào một cổng với số cổng ít nhất là 1024.

(Cổng RMI là 1099 theo mặc định, và các đối tượng máy chủ cũng sử dụng cổng ≥

1024.)

grant

{

permission java.net.SocketPermission

"*:1024-65535", "connect";

Page 21: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

20 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

};

NOTE

Nhiều đối tượng máy chủ trên cùng một máy chủ có thể chia sẻ một cổng. Tuy

nhiên, nếu một cuộc gọi từ xa được thực hiện và cảng bận rộn, cảng khác được mở

ra tự động. Vì vậy, bạn nên mong đợi cổng nào được sử dụng ít hơn có các đối

tượng từ xa trên máy chủ.

- Trong chương trình client, chúng tôi hướng dẫn quản lý an ninh để đọc các

file chính sách bằng cách thiết lập thuộc tính java.security.policy với tên file. (.

Chúng tôi sử dụng file client.policy trong các chương trình ví dụ của chúng

tôi)

System.setProperty ("java.security.policy", "client.policy");

- Ngoài ra, bạn có thể chỉ định thiết lập hệ thống tài sản trên dòng lệnh:

java-Djava security.policy =. client.policy ProductClient

NOTE

Trong JDK 1.1, một tập tin chính sách đã không được yêu cầu cho khách hàng

RMI. Bạn không cần một tập tin chính sách cho các applet, hoặc, cung cấp máy

chủ và đăng ký RMI RMI đều nằm trên máy chủ phục vụ các mã applet

- Nếu đăng ký RMI và máy chủ vẫn còn đang chạy, bạn có thể tiến hành để

chạy các máy khách. Hoặc, nếu bạn muốn bắt đầu từ đầu, giết RMI registry và máy

chủ. Sau đó làm theo các bước sau:

1) Compile the source files for the interface, implementation, client, and server

classes. javac Product*.java

2) If you use JDK 1.4 or below, run rmic on the implementation class.

rmic -v1.2 ProductImpl

3) Start the RMI registry.

rmiregistry &

or start rmiregistry

Page 22: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

21 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

4) Start the server.

java ProductServer &

or start java ProductServer

5) Run the client.

java ProductClient

(Make sure the client.policy file is in the current directory.)

- Chương trình đơn giản là in ra: I am a Blackwell Toaster. Buy me!

I am a ZapXpress Microwave Oven. Buy me!

- Output này không có vẻ tất cả những gì ấn tượng, nhưng xem xét những gì

diễn ra ở hậu trường khi các chương trình client thực hiện các cuộc gọi đến các

phương pháp getdescription. Chương trình client có một tham chiếu đến một

đối tượng stub rằng nó thu được từ phương pháp tra cứu. Nó gọi phương pháp

geTDescription, đó gửi một thông điệp mạng cho một đối tượng thu trên phía

máy chủ. Các đối tượng tiếp nhận viện dẫn phương thức getdescription trên đối

tượng ProductImpl nằm trên máy chủ. Đó là phương pháp tính toán một chuỗi.

Người nhận sẽ gửi chuỗi trên mạng. stub Các nhận được nó và trả về nó như là kết

quả (xem Hình 5-6).

Page 23: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

22 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

8/. Preparing for Deployment:

- Triển khai một ứng dụng sử dụng RMI có thể được khó khăn bởi vì rất

nhiều điều có thể đi sai và các thông báo lỗi mà bạn nhận được khi một cái gì đó

mơ hồ . Chúng tôi đã tìm thấy rằng nó thực sự đền đáp cho giai đoạn triển khai tại

địa phương. Trong bước chuẩn bị, riêng các lớp tập tin vào ba thư mục con:

server

download

client

- Các máy chủ thư mục chứa tất cả các file cần thiết để chạy các máy chủ.

Bạn sau đó sẽ di chuyển các tập tin này vào máy chạy quá trình máy chủ. Trong ví

dụ của chúng tôi, máy chủ thư mục chứa các tập tin sau đây:

server/

ProductServer.class

ProductImpl.class

Product.class

CAUTION

Nếu bạn sử dụng JDK 1.4 hoặc dưới đây, thêm các lớp stub (như

ProductImpl_Stub.class) vào thư mục máy chủ. Chúng là cần thiết khi máy

chủ đăng ký các đối tượng thực hiện. Trái ngược với niềm tin phổ biến, máy chủ sẽ

không xác định vị trí chúng trong thư mục tải về, ngay cả khi bạn thiết lập các cơ

sở mã. Cần :

client/

ProductClient.class

Product.class

client.policy

- Bạn sẽ triển khai những tập tin trên máy khách. Cuối cùng, các thư mục

chứa các tập tin tải về lớp cần thiết cho đăng ký RMI, khách hàng, và máy chủ,

cũng như các lớp họ phụ thuộc vào. Trong ví dụ của chúng tôi, các thư mục tải về

sẽ như thế này

download/

Product.class

CAUTION

Hãy nhớ rằng ba máy ảo sử dụng thư mục download: các khách hàng, máy chủ, và

đăng ký RMI. Việc đăng ký RMI cần các tập tin lớp học cho các giao diện từ xa

của các đối tượng mà nó liên kết. client và máy chủ cần có tập tin lớp học cho các

thông số và giá trị trả lại.

- Bạn cần phải chạy một máy chủ web để phục vụ các tập tin lớp học trên

máy tính của bạn. Nếu bạn không có một máy chủ web cài đặt, tải về từ

http://jakarta.apache.org/tomcat và cài đặt nó. Tạo một thư mục tomcat / webapps

Page 24: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

23 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

/ download, nơi tomcat là thư mục gốc cài đặt Tomcat của bạn. Tạo một thư mục

tomcat / webapps / download / WEB-INF, và để các tập tin tối thiểu sau đây

web.xml trong thư mục WEB-INF:

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web

Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

</web-app

- Sau đó copy file class từ thư mục download vào thư mục

tomcat/webapps/download.

- Kế tiếp, chỉnh sửa file client.policy. Nó cần phải cấp cho client những

quyền hạn sau:

+ Để kết nối với cổng 1024 và ở trên để đạt được đăng ký RMI và triển khai

máy chủ; Để kết nối với cổng 80 (cổng HTTP tiêu chuẩn) để tải các tập tin lớp

stub. Bạn có thể bỏ qua sự cho phép này nếu bạn sử dụng Tomcat như là một

serverit web sử dụng cổng 8080 mặc định

- Thay đổi file sao cho giống như sau: grant

{

permission java.net.SocketPermission

"*:1024-65535", "connect";

permission java.net.SocketPermission

"*:80", "connect";

};

- Cuối cùng, bạn đã sẵn sàng để thử nghiệm thiết lập của bạn.

1. Khởi động máy chủ web.

2. Điểm một trình duyệt web vào URL download

(http://localhost:8080/download/Product.class cho Tomcat) để xác minh rằng các

máy chủ web đang chạy.

3. Bắt đầu một lớp vỏ mới. Hãy chắc chắn rằng đường dẫn lớp là không

được đặt để bất cứ điều gì. Thay đổi vào một thư mục mà không chứa các tập tin

lớp. Sau đó bắt đầu đăng ký RMI.

4. Bắt đầu một lớp mới. Thay đổi vào thư mục máy chủ. Khởi động máy

chủ, cho một URL vào thư mục tải về là giá trị của tài sản

java.rmi.server.codebase:

java -Djava.rmi.server.codebase=http://localhost:8080/download/

ProductServer &

Page 25: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

24 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

5. Thay đổi vào thư mục client. Hãy chắc chắn rằng các file client.policy là

trong thư mục đó. Bắt đầu cho client

java -Djava.security.policy=client.policy ProductClient

TIP

Nếu bạn không muốn cài đặt một máy chủ web tại địa phương, bạn có thể sử dụng

một URL tập tin để kiểm tra nạp lớp. Tuy nhiên, thiết lập được một chút phức tạp

hơn. Thêm dòng

permission java.io.FilePermission "downloadDirectory", "read ";

vào tập tin chính sách client của bạn. Ở đây, các thư mục tải về là tên đường dẫn

đầy đủ đến thư mục tải về, kèm theo trong dấu ngoặc kép, và kết thúc bằng một

dấu trừ (để chỉ tất cả các file trong thư mục và thư mục con của nó). Ví dụ:

permission java.io.FilePermission "/ home/test/download/-",

"read";

Trong tên tập tin Windows, bạn phải tăng gấp đôi mỗi dấu chéo ngược. Ví dụ,

permission java.io. FilePermission "c: \ \ home \ \ test \ \

download \ \ -", "read";

Bắt đầu đăng ký RMI sau đó các bắt đầu máy chủ với

java -Djava.rmi.server.codebase=file://home/test/download/

ProductServer &

hoặc

start java -

Djava.rmi.server.codebase=file:/c:\home\test\download/

ProductServer

9./ Deploying the Program(Triển khai chương trình): - Bây giờ bạn đã kiểm tra việc triển khai các chương trình của bạn, bạn đã

sẵn sàng để phân phối nó vào thực tế khách hàng và máy chủ. Di chuyển các lớp

trong thư mục tải về vào máy chủ web.

- 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

chủ. thiết lập máy chủ của bạn bây giờ hoàn thành, nhưng bạn cần phải thực hiện

hai thay đổi trong máy khách. Đầu tiên, chỉnh sửa các tập tin chính sách và thay

thế * với tên máy chủ của bạn: grant

{

permission java.net.SocketPermission

"yourserver.com:1024-65535", "connect";

permission java.net.SocketPermission

Page 26: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

25 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

"yourserver.com:80", "connect";

};

- Cuối cùng thay thế localhost trong RMI URL của chương trình client: String url = "rmi://yourserver.com/";

Product c1 = (Product) namingContext.lookup(url + "toaster");

. . .

- Sau đó, biên dịch lại client và thử nó. Nếu công trình tất cả mọi thứ, sau đó xin

chúc mừng là theo thứ tự. Nếu không, bạn có thể tìm được danh sách kiểm tra bên

hữu ích. Nó liệt kê một số vấn đề mà thường có thể phát sinh khi bạn đang cố gắng

để có được RMI để làm việc.

10/. Logging RMI Activity:

- Việc thực thi Sun RMI được cung cấp để tạo ra logging messages, sử dụng

tiêu chuẩn Java logging API

- Để thấy được hành động logging, tạo file logging.properties với nội

dung như sau: handlers=java.util.logging.ConsoleHandler

.level=FINEST

java.util.logging.ConsoleHandler.level=FINEST

java.util.logging.ConsoleHandler.formatter=java.util.logging.Sim

pleFormatter

- Bạn có thể tinh chỉnh các thiết lập bằng cách thiết lập mức độ riêng lẽ cho

mỗi người đăng nhập hơn là thiết lập mức độ tổng thể.Bảng 5-2 danh sách logger

của RMI:

Page 27: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

26 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ắt đầu đăng ký RMI với lựa chon sau: -J-Djava.util.logging.config.file=directory/logging.properties

- Khởi động client và server với: -Djava.util.logging.config.file=directory/logging.properties

- Đó là cách tốt nhất để khởi động RMI, client, server trong môi trường khác

nhau.

- Sau đây là ví dụ của logging message cho ta thấy vấn đề của 1 lớp đang tải:

Việc đăng ký RMI không thể tìm thấy lớp Product . Nó cần để xây dựng 1 proxy

động Aug 15, 2004 10:44:07 AM sun.rmi.server.LoaderHandler

loadProxyClass

FINE: RMI TCP Connection(1)-127.0.0.1: interfaces =

[java.rmi.Remote, Product],

codebase = "http://localhost:8080/download/"

Aug 15, 2004 10:44:07 AM sun.rmi.server.LoaderHandler

loadProxyClass

FINER: RMI TCP Connection(1)-127.0.0.1: (thread context class

loader: java.net

.URLClassLoader@6ca1c)

Aug 15, 2004 10:44:07 AM sun.rmi.server.LoaderHandler

loadProxyClass

FINE: RMI TCP Connection(1)-127.0.0.1: proxy class resolution

failed

java.lang.ClassNotFoundException: Product

V/. Parameter Passing in Remote Methods(Truyền tham số

trong phương thức từ xa) :

1/. Passing Nonremote Objects (truyền các đối tượng không từ xa):

- Khi một đối tượng từ xa được truyền từ máy chủ tới máy con, máy con

nhận một stub. Sử dụng stub này, máy con có thể thao tác đối tượng máy chủ bằng

cách gọi ra phương thức từ xa.Tuy nhiên,đối tượng vẫn lưu trên máy chủ. Nó cũng

có thể truyền và trả lại bất kỳ đối tượng khi gọi một phương thức từ xa không chỉ

vậy mà còn thực hiện giao diện từ xa.

Ví dụ : phương thức geTDescription của phần trước trả về một đối tượng kiểu

String

Chuỗi đó được tạo ra trên máy chủ và đã được chuyển đến máy con. Bởi vì kiểu

String không thực hiện giao diện từ xa nên máy chủ không thể trả về đối tượng

stub kiểu chuỗi. Thay vào đó, máy con lấy một bản sao của chuỗi.Khi đó, sau khi

gọi, máy con có đối tượng String để làm việc. Điều này có nghĩa rằng không cần

Page 28: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

27 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ất kỳ kết nối nào thêm nữa cho bất kỳ đối tượng trên máy chủ để phân tán chuỗi

đó.

- Bất cứ khi nào đối tượng không phải là đối tượng từ xa thì cần được

chuyển từ -máy ảo Java đến vùng khác,máy ảo Java thực hiện sao chép và gửi bản

sao chép đó thông qua kết nối mạng.Kỹ thuật này sử dụng phương pháp cục bộ để

truyền tham số.Khi ta truyền đối tượng vào một phương thức cục bộ,hoặc trả về

đối tượng từ kết quả của phương thức này,lưu ý là chỉ có đối tượng tham chiếu

được truyền.Tuy nhiên, các đối tượng tham chiếu là những địa chỉ nhớ của các đối

tượng trong máy ảo Java cục bộ.Thông tin này là vô nghĩa với một máy ảo Java

khác.

- Không khó để tưởng tượng rằng làm thế nào để sao chép một chuỗi và

chuỗi sao chép đó có thể được chuyển qua mạng.Cơ chế RMI có thể thực hiện sao

chép nhiều đối tượng phức tạp hơn nữa, miễn là chúng được tuần tự hóa(được sắp

xếp có thứ tự). RMI sử dụng cơ chế tuần tự hóa được mô tả trong “ Tập 1 Java,

Chương 12” ,nó thực hiện gửi các đối tượng qua một kết nối mạng. Điều này có

nghĩa rằng chỉ có các thông tin trong bất kỳ lớp mà thực hiện giao diện

Serializable có thể được sao chép.

Hình 5-7: Lấy sản phẩm đề xuất từ máy chủ

*Chú ý: Hình 5-7 có một biểu ngữ "Java Applet Window". Đây là kết quả của việc

chạy chương trình với một quản lý bảo mật. Biểu ngữ cảnh báo này được cung cấp

để bảo vệ chống vi mã "phishing" (vi mã : 1 chương trình ứng dụng nhỏ thực hiện

một nhiệm vụ cụ thể). Một vi mã chống đối có lẽ bật lên một cửa sổ, nhắc nhở điền

mật khẩu hoặc số thẻ tín dụng, và sau đó gửi thông tin lại đến host của nó. Để tắt

chức năng cảnh báo, thêm những dòng sau vào file client.policy: permission java.awt.AWTPermission

Page 29: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

28 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

"showWindowWithoutWarningBanner";

- Ghi chú : phish : (máy tính) sự lợi dụng sự không hiểu biết của người dùng

để đánh cắp thông tin cá nhân của họ,bằng cách mượn tên công ty(ngân hàng,công

ty thẻ tín dụng…) và dẫn người dùng đến trang Wed giả.

- Một đối tượng loại khách hàng (customer) được gửi đến máy chủ. Bởi vì

customer không phải là đối tượng từ xa nên một sao chép đối tượng được thực

hiện trên máy chủ. Chương trình máy chủ gửi lại một danh sách mảng các sản

phẩm.Danh sách mảng chứa các sản phẩm mà phù hợp với hồ sơ khách hàng, và

nó luôn luôn chứa một mục mà sẽ thỏa đáng bất cứ ai, cụ thể như một bản sao của

cuốn sách Core Java. Một lần nữa, ArrayList không phải là một lớp từ xa, do đó,

danh sách mảng được sao chép từ máy chủ trở lại cho máy con. Như mô tả trong

“Tập 1 Java, chương 12”,cơ chế tuần tự hóa thực hiện sao chép tất cả các đối tượng

được tham chiếu bên trong một đối tượng được sao chép. Trong trường hợp của ta,

nó thực hiện một sao chép tất cả các mảng danh sách truy cập tốt. Chúng ta thêm

một điều phức tạp phụ: Các truy cập là các đối tượng product từ xa. Như vậy,

người nhận sẽ lấy một bản sao của mảng danh sách,chứa đầy các đối tượng stub

với các sản phẩm trên máy chủ .(xem Hình 5-8).

Figure 5-8. Sao chép tham số cục bộ và trả về các đối tượng

Page 30: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

29 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

- Tổng kết, các đối tượng từ xa được truyền qua mạng như là các stub. Các

đối tượng không từ xa được sao chép. Tất cả điều này là tự động và yêu cầu không

có người lập trình can thiệp.

- Bất cứ khi nào đoạn mã gọi một phương phức từ xa, stub thực hiện một gói

có chứa các bản sao chép của tất cả các giá trị tham số và gửi nó tới máy chủ, sử

dụng cơ chế tuần tự hóa đối tượng để sắp xếp có thứ tự các thông số.Máy chủ

không sắp xếp thứ tự cho chúng. Đương nhiên, tiến trình có thể khá là chậm khi

các đối tượng tham số rất lớn.

- Hãy nhìn vào các chương trình hoàn tất bên dưới. Trước tiên, chúng ta có

các giao diện cho các dịch vụ sản phẩm và nhà kho, như trong ví dụ 5-6 và 5-7.

Example 5-6. Product.java 1. import java.rmi.*;

2.

3. /**

4. The interface for remote product objects.

5. */

6. public interface Product extends Remote

7. {

8. /**

9. Gets the description of this product.

10. @return the product description

11. */

12. String getDescription() throws RemoteException;

13. }

Example 5-7. Warehouse.java 1. import java.rmi.*;

2. import java.util.*;

3.

4. /**

5. The remote interface for a warehouse with products.

6. */

7. public interface Warehouse extends Remote

8. {

9. /**

10. Gets products that are good matches for a customer.

11. @param c the customer to match

12. @return an array list of matching products

13. */

14. ArrayList<Product> find(Customer c) throws

RemoteException;

15. }

Page 31: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

30 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

- Ví dụ 5-8 bên dưới cho thấy việc thực hiện của dịch vụ sản phẩm. Sản

phẩm lưu trữ một bản mô tả gồm độ tuổi, giới tính được nhắm đến (nam, nữ, hoặc

cả hai), và sở thích phù hợp. Lưu ý rằng lớp này thực hiện các phương thức

getdescription (lấy mô tả)trong giao diện Product, và nó cũng thực hiện một

số phương thức khác,chẳng hạn như phương thức match,nhưng những phương

thức này không phải là một phần của giao diện đó. Phương thức match là một ví

dụ về phương thức cục bộ, phương thức đó có thể được được gọi chỉ từ chương

trình cục bộ, không phải từ xa. Bởi vì phương thức match là cục bộ nên nó không

cần được chuẩn bị để throw (ném) một RemoteException (ngoại lệ từ xa).

- Ví dụ 5-9 bên dưới chứa đoạn mã cho lớp Customer. Lưu ý Customer

không phải là lớp từ xa hay các phương thức của nó có thể được thực thi từ xa. Tuy

nhiên, lớp này là tuần tự. Do đó, các đối tượng của lớp này có thể được chuyển từ

máy ảo đến vùng khác.

- Ví dụ 5-10 và 5-11 bên dưới cho thấy giao diện và việc thực hiện của dịch

vụ kho hàng. Cũng giống như lớp ProductImpl, lớp WarehouseImpl có phương

pháp cục bộ và từ xa. Phương thức add là cục bộ, nó được sử dụng bởi máy chủ

để thêm sản phẩm vào kho hàng. Phương thức find là từ xa, nó được sử dụng bởi

máy con để tìm các mục(sản phẩm) trong kho hàng.

- Để minh họa cho đối tượng Customer (khác hàng)thực sự được sao chép,

phương thức find của lớp WarehouseImpl xóa đối tượng khác hàng nhận được.

Khi phương thức từ xa trả về,lớp WarehouseClient hiển thị đối tượng khác hàng

mà nó gửi đến máy chủ. Như ta thấy, đối tượng đó không được thay đổi. Máy chủ

chỉ xóa sao chép của nó. Trong trường hợp này, toán tử reset phục vụ mục đích

không có hữu ích ngoại trừ việc chứng minh rằng đối tượng cục bộ được sao chép

khi chúng được truyền như là các tham số.

- Nó có thể cho nhiều stub con để thực hiện gọi đồng thời tới một đối tượng

máy chủ, ngay cả khi một số phương thức thay đổi trạng thái của máy chủ. Trong

ví dụ 5-11, chúng ta sử dụng một đôi tượng ReadWriteLock trong lớp

WarehouseImpl vì nó hiểu được rằng phương thức add cục bộ và phươn thức find

từ xa được gọi một cách đồng thời. Ví dụ 5-12 cho thấy chương trình máy chủ tạo

ra một đối tượng kho hàng và đăng ký nó với chương trình khởi động đăng ký dịch

vụ.

Page 32: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

31 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

Chú ý: Hãy nhớ rằng bạn phải bắt đầu chương trình đăng ký và chương trình

máy chủ, và giữ cho cả hai đang chạy trước khi bạn bắt đầu máy con.

- Ví dụ 5-13 cho thấy đoạn mã của máy con. Khi người dùng nhấp nút

Submit, một đối tượng khách hàng mới được tạo ra và được truyền tới phương

thức find từ xa.Lý lịch khách hàng được hiển thị trong vùng text(để chứng minh

rằng reset gọi trong máy chủ không ảnh hưởng đến nó).Cuối cùng, mô tả sản

phẩm của các sản phẩm được trả về trong danh sách mảng được thêm vào vùng

text. Lưu ý rằng mỗi lần gọi getdescription là một lần gọi phương thức từ xa.

Đây không phải là một thiết kế tốt trong thực tiễn,bạn thường truyền các đối tượng

nhỏ như mô tả sản phẩm bởi giá trị. Tuy nhiên, chúng ta muốn chứng minh rằng

một đối tượng từ xa sẽ tự động được thay thế bằng một stub trong suốt thời gian

sắp xếp thứ tự. Tip: Nếu bạn khởi động máy chủ với java -Djava.rmi.server.logCalls=true WarehouseServer &

sau đó máy chủ ký nhận tất cả phương thức từ xa gọi trên giao diện điều khiển

của nó. Hãy thử nó,ta sẽ có được một ấn tượng tốt đẹp của vận tải RMI.

Example 5-8. ProductImpl.java 1. import java.rmi.*;

2. import java.rmi.server.*;

3.

4. /**

5. This is the implementation class for the remote product

6. objects.

7. */

8. public class ProductImpl

9. extends UnicastRemoteObject

10. implements Product

11. {

12. /**

13. Constructs a product implementation

14. @param n the product name

15. */

16. public ProductImpl(String n) throws RemoteException

17. {

18. name = n;

19. }

20.

21. public String getDescription() throws RemoteException

22. {

23. return "I am a " + name + ". Buy me!";

Page 33: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

32 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

24. }

25.

26. private String name;

27. }

Example 5-9. Customer.java 1. import java.io.*;

2.

3. /**

4. Description of a customer. Note that customer objects are

not

5. remote--the class does not implement a remote interface.

6. */

7. public class Customer implements Serializable

8. {

9. /**

10. Constructs a customer.

11. @param theAge the customer's age

12. @param theSex the customer's sex (MALE or FEMALE)

13. @param theHobbies the customer's hobbies

14. */

15. public Customer(int theAge, int theSex, String[]

theHobbies)

16. {

17. age = theAge;

18. sex = theSex;

19. hobbies = theHobbies;

20. }

21.

22. /**

23. Gets the customer's age.

24. @return the age

25. */

26. public int getAge() { return age; }

27.

28. /**

29. Gets the customer's sex

30. @return MALE or FEMALE

31. */

32. public int getSex() { return sex; }

33.

34. /**

35. Tests whether this customer has a particular hobby.

36. @param aHobby the hobby to test

37. @return true if this customer has the hobby

38. */

39. public boolean hasHobby(String aHobby)

Page 34: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

33 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

40. {

41. if (aHobby == "") return true;

42. for (int i = 0; i < hobbies.length; i++)

43. if (hobbies[i].equals(aHobby)) return true;

44.

45. return false;

46. }

47.

48. /**

49. Resets this customer record to default values.

50. */

51. public void reset()

52. {

53. age = 0;

54. sex = 0;

55. hobbies = null;

56. }

57.

58. public String toString()

59. {

60. String result = "Age: " + age + ", Sex: ";

61. if (sex == Product.MALE) result += "Male";

62. else if (sex == Product.FEMALE) result += "Female";

63. else result += "Male or Female";

64. result += ", Hobbies:";

65. for (int i = 0; i < hobbies.length; i++)

66. result += " " + hobbies[i];

67. return result;

68. }

69.

70. private int age;

71. private int sex;

72. private String[] hobbies;

73. }

Example 5-10. Warehouse.java 1. import java.rmi.*;

2. import java.util.*;

3.

4. /**

5. The remote interface for a warehouse with products.

6. */

7. public interface Warehouse extends Remote

8. {

9. /**

10. Gets products that are good matches for a customer.

11. @param c the customer to match

Page 35: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

34 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

12. @return an array list of matching products

13. */

14. ArrayList<Product> find(Customer c) throws

RemoteException;

15. }

Example 5-11. WarehouseImpl.java 1. import java.io.*;

2. import java.rmi.*;

3. import java.util.*;

4. import java.rmi.server.*;

5. import java.util.*;

6. import java.util.concurrent.locks.*;

7.

8. /**

9. This class is the implementation for the remote

10. Warehouse interface.

11. */

12. public class WarehouseImpl

13. extends UnicastRemoteObject

14. implements Warehouse

15. {

16. /**

17. Constructs a warehouse implementation.

18. */

19. public WarehouseImpl()

20. throws RemoteException

21. {

22. products = new ArrayList<ProductImpl>();

23. add(new ProductImpl("Core Java Book", 0, 200,

Product.BOTH, "Computers"));

24. }

25.

26. /**

27. Add a product to the warehouse. Note that this is a

local method.

28. @param p the product to add

29. */

30. public void add(ProductImpl p)

31. {

32. Lock wlock = rwlock.writeLock();

33. wlock.lock();

34. try

35. {

36. products.add(p);

37. }

38. finally

Page 36: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

35 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

39. {

40. wlock.unlock();

41. }

42. }

43.

44. public ArrayList<Product> find(Customer c)

45. throws RemoteException

46. {

47. Lock rlock = rwlock.readLock();

48. rlock.lock();

49. try

50. {

51. ArrayList<Product> result = new

ArrayList<Product>();

52. // add all matching products

53. for (ProductImpl p : products)

54. {

55. if (p.match(c)) result.add(p);

56. }

57. // add the product that is a good match for

everyone, a copy of Core Java

58. if (!result.contains(products.get(0)))

59. result.add(products.get(0));

60.

61. // we reset c just to show that c is a copy of the

client object

62. c.reset();

63. return result;

64. }

65. finally

66. {

67. rlock.unlock();

68. }

69. }

70.

71. private ArrayList<ProductImpl> products;

72. private ReadWriteLock rwlock = new

ReentrantReadWriteLock();

73. }

Example 5-12. WarehouseServer.java 1. import java.rmi.*;

2. import java.rmi.server.*;

3. import javax.naming.*;

4.

5. /**

6. This server program instantiates a remote warehouse

Page 37: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

36 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

7. object, registers it with the naming service, and waits

8. for clients to invoke methods.

9. */

10. public class WarehouseServer

11. {

12. public static void main(String[] args)

13. {

14. try

15. {

16. System.out.println("Constructing server

implementations...");

17. WarehouseImpl w = new WarehouseImpl();

18. w.add(new ProductImpl("Blackwell Toaster",

Product.BOTH, 18, 200, "Household"));

19. w.add(new ProductImpl("ZapXpress Microwave Oven",

Product.BOTH, 18, 200,

"Household"));

20. w.add(new ProductImpl("DirtDigger Steam Shovel",

Product.MALE, 20, 60,

"Gardening"));

21. w.add(new ProductImpl("U238 Weed Killer",

Product.BOTH, 20, 200, "Gardening"));

22. w.add(new ProductImpl("Persistent Java Fragrance",

Product.FEMALE, 15, 45,

"Beauty"));

23. w.add(new ProductImpl("Rabid Rodent Computer

Mouse", Product.BOTH, 6, 40,

"Computers"));

24. w.add(new ProductImpl("My first Espresso Maker",

Product.FEMALE, 6, 10,

"Household"));

25. w.add(new ProductImpl("JavaJungle Eau de Cologne",

Product.MALE, 15, 45,

"Beauty"));

26. w.add(new ProductImpl("FireWire Espresso Maker",

Product.BOTH, 20, 50,

"Computers"));

27. w.add(new ProductImpl("Learn Bad Java Habits in 21

Days Book", Product.BOTH,

20, 200,

28. "Computers"));

29.

30. System.out.println("Binding server implementations

to registry...");

31. Context namingContext = new InitialContext();

32. namingContext.bind("rmi:central_warehouse", w);

33.

Page 38: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

37 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

34. System.out.println("Waiting for invocations from

clients...");

35. }

36. catch (Exception e)

37. {

38. e.printStackTrace();

39. }

40. }

41. }

Example 5-13. WarehouseClient.java 1. import java.awt.*;

2. import java.awt.event.*;

3. import java.io.*;

4. import java.rmi.*;

5. import java.rmi.server.*;

6. import java.util.*;

7. import javax.naming.*;

8. import javax.swing.*;

9.

10. /**

11. The client for the warehouse program.

12. */

13. public class WarehouseClient

14. {

15. public static void main(String[] args)

16. {

17. try

18. {

19. System.setProperty("java.security.policy",

"client.policy");

20. System.setSecurityManager(new

RMISecurityManager());

21.

22. Properties props = new Properties();

23. String fileName = "WarehouseClient.properties";

24. FileInputStream in = new

FileInputStream(fileName);

25. props.load(in);

26. String url = props.getProperty("warehouse.url");

27. if (url == null)

28. url = "rmi://localhost/central_warehouse";

29.

30. Context namingContext = new InitialContext();

31. Warehouse centralWarehouse = (Warehouse)

namingContext.lookup(url);

Page 39: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

38 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

32. JFrame frame = new

WarehouseClientFrame(centralWarehouse);

33.

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

34. frame.setVisible(true);

35. }

36. catch (Exception e)

37. {

38. e.printStackTrace();

39. }

40. }

41. }

42.

43. /**

44. A frame to select the customer's age, sex, and hobbies,

and to

45. show the matching products resulting from a remote call

to the

46. warehouse.

47. */

48. class WarehouseClientFrame extends JFrame

49. {

50. public WarehouseClientFrame(Warehouse warehouse)

51. {

52. this.warehouse = warehouse;

53. setTitle("WarehouseClient");

54. setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

55.

56. JPanel panel = new JPanel();

57. panel.setLayout(new GridLayout(0, 2));

58.

59. panel.add(new JLabel("Age:"));

60. age = new JTextField(4);

61. age.setText("20");

62. panel.add(age);

63.

64. female = new JRadioButton("Female", true);

65. male = new JRadioButton("Male", true);

66. ButtonGroup group = new ButtonGroup();

67. panel.add(female); group.add(female);

68. panel.add(male); group.add(male);

69.

70. panel.add(new JLabel("Hobbies: "));

71. hobbies = new ArrayList<JCheckBox>();

72. for (String h : new String[] { "Gardening", "Beauty",

"Computers", "Household",

"Sports" })

Page 40: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

39 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

73. {

74. JCheckBox checkBox = new JCheckBox(h);

75. hobbies.add(checkBox);

76. panel.add(checkBox);

77. }

78.

79. result = new JTextArea(4, 40);

80. result.setEditable(false);

81.

82. JPanel buttonPanel = new JPanel();

83. JButton submitButton = new JButton("Submit");

84. buttonPanel.add(submitButton);

85. submitButton.addActionListener(new

86. ActionListener()

87. {

88. public void actionPerformed(ActionEvent event)

89. {

90. callWarehouse();

91. }

92. });

93.

94. add(panel, BorderLayout.NORTH);

95. add(result, BorderLayout.CENTER);

96. add(buttonPanel, BorderLayout.SOUTH);

97. }

98.

99. /**

100. Call the remote warehouse to find matching products.

101. */

102. private void callWarehouse()

103. {

104. try

105. {

106. ArrayList<String> selected = new

ArrayList<String>();

107. for (JCheckBox checkBox : hobbies)

108. if (checkBox.isSelected())

selected.add(checkBox.getText());

109. Customer c = new

Customer(Integer.parseInt(age.getText()),

110. (male.isSelected() ? Product.MALE : 0)

111. + (female.isSelected() ? Product.FEMALE : 0),

112. selected.toArray(new String[selected.size()]));

113. ArrayList<Product> recommendations =

warehouse.find(c);

114. result.setText(c + "\n");

115. for (Product p : recommendations)

Page 41: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

40 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

116. {

117. String t = p.getDescription() + "\n";

118. result.append(t);

119. }

120. }

121. catch (Exception e)

122. {

123. e.printStackTrace();

124. result.setText("Exception: " + e);

125. }

126. }

127.

128. private static final int DEFAULT_WIDTH = 300;

129. private static final int DEFAULT_HEIGHT = 300;

130.

131. private Warehouse warehouse;

132. private JTextField age;

133. private JRadioButton male;

134. private JRadioButton female;

135. private ArrayList<JCheckBox> hobbies;

136. private JTextArea result;

137. }

2/. Passing Remote Objects (Truyền đối tượng từ xa):

- Truyền các đối tượng từ xa từ máy chủ đến máy con thì đơn giản. Máy con

nhận được một đối tượng stub, sau đó lưu nó vào một biến đối tượng với cùng loại

như giao diện từ xa.Máy con có thể truy cập liền các đối tượng hiện tại trên máy

chủ thông qua biến.Máy con có thể sao chép biến này vào máy cục bộ riêng của nó

,những bản sao chép đó được tham chiếu đơn đến cùng stub. Điều quan trọng cần

lưu ý rằng chỉ có các giao diện từ xa mới có thể được truy cập thông qua stub. Một

giao thức từ xa là bất kì giao thức thực hiện mở rộng Remote. Tất cả các phương

thức cục bộ là không thể truy cập thông qua stub.(Một phương thức cục bộ là bất

kỳ phương thức mà không được xác định trong một giao diện từ xa).Các phương

thức cục bộ có thể chỉ chạy trên các máy ảo có chứa các đối tượng hiện tại.

- Tiếp theo, các stub chỉ được tạo ra từ các lớp mà thực hiện một giao diện từ

xa,và chỉ các phương thức được quy định các giao diện là được cung cấp trong các

lớp stub. Nếu một lớp con không thực hiện một giao diện từ xa nhưng một lớp cha

thực hiện điều đó, và một đối tượng của lớp con (subclass) được truyền cho một

phương thức từ xa, chỉ có các phương thức lớp cha (superclass) có thể truy cập. Để

hiểu điều này tốt hơn, xem xét ví dụ sau đây. Chúng ta nhận được một lớp

BookImpl từ ProductImpl.

Page 42: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

41 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

class BookImpl extends ProductImpl

{

public BookImpl(String title, String theISBN, int sex, int

age1, int age2, String hobby)

{

super(title + " Book", sex, age1, age2, hobby);

ISBN = theISBN;

}

public String getStockCode() { return ISBN; }

private String ISBN;

}

- Bây giờ, giả sử chúng ta truyền một đối tượng sách đến một phương thức

từ xa,cũng như truyền một tham số hoặc là một giá trị trả về. Người nhận có được

một đối tượng stub, nhưng stub đó không phải là một stub sách. Thay vào đó, nó là

một stub cho lớp cha ProductImpl bởi vì chỉ có lớp mà thực hiện một giao diện từ

xa (xem Hình 5-9). Như vậy, trong trường hợp này, phương thức getStockCode

không có sẵn từ xa.

Hình 5-9. Chỉ có phương thức ProductImpl là từ xa

Page 43: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

42 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

-Một lớp từ xa có thể thực hiện đa giao diện.Ví dụ, lớp BookImpl có thể

thực hiện giao diện thứ hai trong việc thêm vào Product. Ở đây, chúng ta định

nghĩa một giao diện từ xa StockUnit và có lớp BookImpl thực hiện nó. interface StockUnit extends Remote

{

public String getStockCode() throws RemoteException;

}

class BookImpl extends ProductImpl implements StockUnit

{

public BookImpl(String title, String theISBN, int sex, int

age1, int age2, String hobby)

throws RemoteException

{

super(title + " Book", sex, age1, age2, hobby);

ISBN = theISBN;

}

public String getStockCode() throws RemoteException

{

return ISBN;

}

private String ISBN;

}

Hình 5-10 cho thấy sơ đồ thừa kế.

và BookImpl có thêm các phương thức từ xa

Page 44: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

43 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ờ, khi một đối tượng sách được truyền đến một phương thức từ xa,

người nhận có được một stub mà đã truy cập tới các phương thức từ xa trong cả

lớp Product và StockUnit. Trong thực tế, ta có thể sử dụng toán tử instanceof

để tìm kết quả ra mà có một đối tượng từ xa cụ thể thực hiện một giao diện hay

không. Dưới đây là một tình huống điển hình mà trong đó ta sẽ sử dụng tính năng

này. Giả sử bạn nhận được một đối tượng từ xa thông qua một biến kiểu Product.

ArrayList<Product> result = centralWarehouse.find(c);

for (Product p : result)

{

. . .

}

- Đối tượng từ xa có lẽ là sách hoặc không phải. Chúng ta muốn sử dụng

instanceof để tìm kết quả ra dù nó có hay không, nhưng chúng ta không thể

kiểm tra if (p instanceof BookImpl) // wrong

{

BookImpl b = (BookImpl) p;

. . .

}

- Đối tượng p ám chỉ một đối tượng stub, và BookImpl là lớp của đối tượng

máy chủ. Thay vào đó, tìm đến giao thức thứ hai: if (p instanceof StockUnit)

Page 45: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

44 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

{

StockUnit s = (StockUnit) p;

String c = s.getStockCode();

. . .

}

- Đoạn mã này kiểm tra xem có đối tượng stub mà p ám chỉ thực hiện giao

thức StockUnit hay không.Nếu vậy, nó gọi phương thức từ xa getStockCode của

giao diện đó.

Tóm tắt:

Nếu một đối tượng thuộc về một lớp mà thực hiện một giao diện từ xa sẽ

được truyền tới một phương thức từ xa, phương thức từ xa nhận được một

đối tượng stub.

Bạn có thể bỏ đối tượng stub đó để bất kỳ giao diện từ xa mà lớp thực hiện

triển khai thực hiện.

Bạn có thể gọi tất cả các phương thức từ xa được xác định tại các giao diện

đó, nhưng bạn không thể gọi bất kỳ phương thức cục bộ thông qua stub.

3/. Remote Objects and the equals and hashCode Methods(Các đối

tượng từ xa và các phương thức so sánh bằng và mã băm):

- Trong trường hợp một tập băm hoặc bản đồ băm, phương thức hashCode

phải được xác định.Tuy nhiên, có một vấn đề khi cố gắng để so sánh các đối tượng

từ xa.Tìm kết quả ra nếu hai đối tượng từ xa có cùng một nội dung, gọi đến

equals và equals cần liên lạc với máy chủ đang chứa các đối tượng và so sánh

các nội dung đó.Nhưng việc gọi đó có thể thất bại. Tuy nhiên, phương thức

equals trong lớp Object không được mô tả để ném một RemoteException, trong

khi tất cả các phương thức trong một giao diện từ xa phải ném ngoại lệ. Bởi vì một

phương thức lớp con không thể ném nhiều ngoại lệ hơn so với phương pháp lớp

cha mà nó thay thế, ta không thể xác định một phương thức equals trong một giao

diện từ xa.Tương tự cho hashCode.

- Đáng lẽ, các phương thức equals và hashCode trên các đối tượng stub

chỉ cần nhìn vào vị trí của các đối tượng máy chủ. Phương thức equals cho rằng

hai stub bằng nhau nếu chúng chuyển đến đối tượng cùng máy chủ. Hai stub đề cập

Page 46: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

45 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

tới các đối tượng máy chủ khác nhau là không bao giờ bằng nhau, ngay cả khi

những đối tượng đó có nội dung giống hệt nhau. Tương tự như vậy, các mã băm

chỉ được tính toán từ định danh đối tượng.

Tóm tắt: ta có thể sử dụng các đối tượng stub trong các bộ và các bảng băm,

nhưng ta phải nhớ rằng kiểm tra tính bằng nhau và băm không tính đến bản kê khai

nội dung của các đối tượng từ xa.

4/. Cloning Remote Objects (Nhân bản các đối tượng từ xa):

- Các stub không có phương thức clone, vì thế ta không thể nhân bản một

đối tượng từ xa bằng cách gọi clone trên stub. Lý do là kỹ thuật có trở lại một

chút. Đó là nếu clone được thực hiện gọi từ xa kêu máy chủ nhân bản các đối

tượng thực hiện, thì phương thức clone sẽ cần được ném một

RemoteException. Tuy nhiên, phương thức clone trong lớp cha Object bảo đảm

sẽ không bao giờ ném bất kỳ ngoại lệ khác với CloneNotSupportedException.

Đó là sự hạn chế tương tự mà ta gặp phải trong phần trước: equals và hashCode

không tìm kiếm tất cả giá trị đối tượng từ xa mà chỉ so sánh các tham chiếu stub.

Tuy nhiên, nó thực hiện clone không hướng, để thực hiện một nhân bản khác của

một stub nếu bạn muốn được có một tham chiếu khác đến đối tượng remote, bạn

chỉ có thể sao chép các biến stub. Vì vậy, clone đơn giản là không được xác định

cho các stub.

V/. Server Object Activation: (Sự hoạt hóa đối tượng máy

chủ ): - Trong các chương trình mẫu trước, ta sử dụng một chương trình máy chủ

để khởi tạo và ghi nhận các đối tượng để mà các máy con có thể thực hiện gọi từ

xa trên chúng. Tuy nhiên, trong một số trường hợp, thật là lãng phí để khởi tạo rất

nhiều đối tượng máy chủ và chờ đợi các kết nối giữa chúng, mà có hoặc không có

các đối tượng máy con sử dụng chúng. Cơ chế activation cho phép bạn trì hoãn

việc xây dựng đối tượng để cho một đối tượng máy chủ chỉ được xây dựng khi có

ít nhất một máy con gọi một phương thức từ xa.

- Để tận dụng activation ,mã máy con sẽ hoàn toàn không thay đổi. Máy con

chỉ cần yêu cầu một tham chiếu từ xa và thực hiện gọi nó.

- Tuy nhiên, chương trình máy chủ được thay thế bằng một chương trình

activation mà các cấu trúc activation descriptors (mô tả sự hoạt hóa) của các đối

tượng mà sẽ được xây dựng tại một thời gian sau đó, và liên kết với người nhận từ

Page 47: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

46 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

các lần gọi phương thức từ xa với dịch vụ tên. Khi một lần gọi được thực hiện lần

đầu tiên, thông tin trong mô tả sự hoạt hóa được sử dụng để xây dựng đối tượng.

- Một đối tượng máy chủ được sử dụng theo cách này nên mở rộng lớp

Activatable và tất nhiên, thực hiện một hoặc nhiều giao diện từ xa. Ví dụ:

class ProductImpl

extends Activatable

implements Product

{

. . .

}

- Bởi vì việc xây dựng đối tượng được hoãn cho đến một thời gian sau

đó,nên nó phải xảy ra trong một hình thức tiêu chuẩn hóa. Vì vậy, ta phải cung cấp

một hàm tạo có hai tham số:

+Một ID hoạt hóa (trong đó bạn chỉ cần truyền vào cho hàm tạo lớp cha)

+Một đối tượng duy nhất đang chứa tất cả thông tin xây dựng,được bọc

trong lớp MarshalledObject.

- Nếu bạn cần nhiều tham số xây dựng, bạn phải gói chúng trong một đối

tượng duy nhất. Bạn luôn có thể sử dụng một mảng Object[] hoặc một lớp

ArrayList. Như ta sẽ sớm thấy, ta đặt một bản sao được tuần tự (hoặc sắp xếp

theo thứ tự) của thông tin xây dựng bên trong mô tả sự hoạt hóa. Hàm tạo đối

tượng máy chủ của ta nên sử dụng phương thức get của lớp MarshalledObject

để không tuần tự hóa thông tin xây dựng.

- Trong trường hợp của lớp ProductImpl, thủ tục này khá đơn giản,chỉ một

đoạn thông tin là cần thiết để xây dựng, cụ thể là, tên sản phẩm. Thông tin đó có

thể được bao bọc trong lớp MarshalledObject và không được bao bọc trong hàm

tạo: public ProductImpl(ActivationID id, MarshalledObject data)

{

super(id, 0);

name = (String) data.get();;

System.out.println("Constructed " + name);

}

- Bằng cách truyền 0 như tham số thứ hai của hàm tạo lớp cha ,chúng ta chỉ

ra rằng thư viện RMI nên chỉ định số cổng phù hợp đến cổng sự lắng

nghe(listener).

- Hàm tạo này in một tin nhắn để ta có thể thấy rằng các đối tượng sản

phẩm được hoạt hóa theo yêu cầu.

Page 48: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

47 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

Chú ý : các đối tượng máy chủ của bạn không thực sự mở rộng lớp

Activatable. Nếu chúng không làm điều đó thì đặt gọi phương thức tĩnh

Activatable.exportObject(this, id, 0) trong hàm tạo của lớp máy chủ.

- Bây giờ chúng ta chuyển sang chương trình sự hoạt hóa. Trước tiên, ta cần

phải xác định một nhóm hoạt hóa. Một nhóm hoạt hóa mô tả các thông số chung

cho việc khởi động máy ảo có chứa các đối tượng máy chủ. Thông số quan trọng

nhất là security policy (cách xử sự bảo mật).

- Cũng như với các đối tượng máy chủ khác của chúng ta, chúng ta không

kiểm tra bảo mật. (Có lẽ, các đối tượng đến từ một nguồn đáng tin cậy.) Tuy nhiên,

máy ảo (mà trong đó các đối tượng được hoạt hóa chạy) có một sự quản lý bảo mật

được cài đặt. Để kích hoạt tất cả các quyền truy cập, cung cấp một tập tin

server.policy với nội dung sau: grant

{

permission java.security.AllPermission;

};

- Xây dựng một mô tả nhóm hoạt hóa như sau: Properties props = new Properties();

props.put("java.security.policy", "/server/server.policy");

ActivationGroupDesc group = new ActivationGroupDesc(props,

null);

- Tham số thứ hai mô tả các tùy chọn lệnh đặc biệt, chúng ta không cần bất

kỳ cho ví dụ này, vì vậy chúng ta truyền một tham chiếu null.

- Tiếp theo, tạo ra một ID nhóm với việc gọi ActivationGroupID id =

ActivationGroup.getSystem().registerGroup(group);

- Bây giờ ta đã sẵn sàng để xây dựng các mô tả hoạt hóa. Đối với mỗi đối

tượng mà phải được xây dựng trên nhu cầu, bạn cần những điều sau đây:

ID nhóm hoạt hóa cho máy ảo mà trong đó đối tượng cần được xây dựng;

Tên của lớp (như "ProductImpl" hoặc "com.mycompany.MyClassImpl");

Chuỗi URL mà từ đó để tải các tập tin lớp. Điều này cần có các địa chỉ URL

cơ bản, không bao gồm các đường dẫn gói;

Thông tin xây dựng được sắp xếp theo thứ tự.

Ví dụ:

MarshalledObject param = new MarshalledObject("Blackwell

Toaster");

ActivationDesc desc = new ActivationDesc(id, "ProductImpl",

http://myserver.com/download /, param);

Page 49: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

48 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

- Truyền mô tả đến phương thức Activatable.register tĩnh. Nó trả về

một đối tượng của một số lớp mà thực hiện các giao diện từ xa của lớp thực hiện.

Bạn có thể ràng buộc các đối tượng với dịch vụ tên: Product p = (Product) Activatable.register(desc);

namingContext.bind("toaster", p);

- Không giống như các chương trình máy chủ trong những ví dụ trước,

chương trình hoạt hóa thoát sau khi ghi nhận và bắt buộc người nhận hoạt hóa. Các

đối tượng máy chủ được xây dựng chỉ khi gọi phương thức từ xa đầu tiên xảy ra.

- Ví dụ 5-14 và 5-15 cho thấy đoạn mã cho việc thực hiện sản phẩm có thể

được hoạt hóa và chương trình hoạt hóa. Giao diện sản phẩm và chương trình máy

con là không được thay đổi.

- Để khởi động chương trình này, làm theo các bước sau:

1) Biên dịch tất cả các tập tin nguồn.

2) Nếu bạn sử dụng JDK 1.4 hoặc phiên bản thấp hơn , chạy rmic để tạo ra

một stub (mạch nhánh) cho lớp ProductImpl: rmic -v1.2 ProductImpl

3) Bắt đầu đăng ký RMI.

4) Bắt đầu hoạt hóa RMI. rmid -J-Djava.security.policy=rmid.policy &

hoặc

start rmid -J-Djava.security.policy=rmid.policy

+ Chương trình rmid nghe yêu cầu hoạt hóa và hoạt hóa các đối tượng

trong một máy ảo riêng biệt. Để khởi động một máy ảo, chương trình rmid cần

quyền truy cập nhất định. Điều đó được quy định trong một tập tin xử sự (xem Ví

dụ 5-16). Sử dụng tùy chọn –J để truyền một tùy chọn đến máy ảo đang chạy hoạt

hóa.

5) Chạy chương trình hoạt hóa.Trong cài đặt này, chúng ta giả định rằng ta bắt

đầu chương trình trong bảng kiểm kê chứa các tập tin lớp và các tập tin xử

sự máy chủ. java ProductActivator

+ Chương trình thoát sau khi người nhận hoạt hóa đã được đăng ký

xong với dịch vụ tên.

6) Chạy chương trình máy con java -Djava.security.policy=client.policy ProductClient

+ Máy con sẽ in các mô tả sản phẩm quen thuộc. Khi ta chạy máy con

lần đầu tiên, ta cũng sẽ thấy các thông điệp hàm tạo trong cửa sổ vỏ máy chủ.

Page 50: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

49 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

Example 5-14. ProductImpl.java

1. import java.rmi.*; 2. import java.rmi.server.*;

3.

4. /**

5. This is the implementation class for the remote product

6. objects.

7. */

8. public class ProductImpl

9. extends UnicastRemoteObject

10. implements Product

11. {

12. /**

13. Constructs a product implementation

14. @param n the product name

15. */

16. public ProductImpl(String n) throws RemoteException

17. {

18. name = n;

19. }

20.

21. public String getDescription() throws RemoteException

22. {

23. return "I am a " + name + ". Buy me!";

24. }

25.

26. private String name;

27. }

Example 5-15. ProductActivator.java

1. import java.io.*;

2. import java.net.*;

3. import java.rmi.*;

4. import java.rmi.activation.*;

5. import java.util.*;

6. import javax.naming.*;

7.

8. /**

9. This server program activates two remote objects and

10. registers them with the naming service.

11. */

12. public class ProductActivator

13. {

14. public static void main(String args[])

15. {

16. try

Page 51: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

50 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

17. {

18. System.out.println("Constructing activation

descriptors...");

19.

20. Properties props = new Properties();

21. // use the server.policy file in the current

directory

22. props.put("java.security.policy", new

File("server.policy").getCanonicalPath());

23. ActivationGroupDesc group = new

ActivationGroupDesc(props, null);

24. ActivationGroupID id =

ActivationGroup.getSystem().registerGroup(group);

25. MarshalledObject p1param = new

MarshalledObject("Blackwell Toaster");

26. MarshalledObject p2param = new

MarshalledObject("ZapXpress Microwave

Oven");

27.

28. String classDir = ".";

29. // turn the class directory into a file URL

30. // for this demo we assume that the classes are in

the current dir

31. // we use toURI so that spaces and other special

characters in file names are

// escaped

32. String classURL = new

File(classDir).getCanonicalFile().toURI().toString();

33.

34. ActivationDesc desc1 = new ActivationDesc(id,

"ProductImpl", classURL,

p1param);

35. ActivationDesc desc2 = new ActivationDesc(id,

"ProductImpl", classURL,

p2param);

36.

37. Product p1 = (Product) Activatable.register(desc1);

38. Product p2 = (Product) Activatable.register(desc2);

39.

40. System.out.println("Binding activable

implementations to registry...");

41. Context namingContext = new InitialContext();

42. namingContext.bind("rmi:toaster", p1);

Page 52: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

51 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

43. namingContext.bind("rmi:microwave", p2);

44. System.out.println("Exiting...");

45. }

46. catch (Exception e)

47. {

48. e.printStackTrace();

49. }

50. }

51. }

Example 5-16. rmid.policy

1. grant

2. {

3. permission com.sun.rmi.rmid.ExecPermission

4. "${java.home}${/}bin${/}java";

5. permission com.sun.rmi.rmid.ExecOptionPermission

6. "-Djava.security.policy=*";

7. };

Example 5-17. server.policy

1. grant

2. {

3. permission java.security.AllPermission;

4. };

*API(Application Programming Interface)-giao diện chương trình ứng dụng :

java.rmi.activation.Activatable 1.2 protected Activatable(ActivationID id, int port)

xây dựng các đối tượng có thể hoạt hóa và thiết lập một sự lắng nghe trên

cổng đã định. Sử dụng 0 cho cổng để có một cổng được chỉ định tự động. static Remote exportObject(Remote obj, ActivationID id, int

port)

thực hiện một đối tượng từ xa có thể hoạt hóa. Trả về người nhận hoạt hóa

mà cần được làm có hiệu lực cho người gọi từ xa. Sử dụng 0 cho cổng để có

một cổng được chỉ định tự động. static Remote register(ActivationDescriptor desc)

đăng ký mô tả cho một đối tượng có thể hoạt hóa và chuẩn bị nó cho việc

nhận thao tác gọi từ xa.Trả về người nhận hoạt hóa mà cần được làm cho có

hiệu lực từ người gọi từ xa.

java.rmi.MarshalledObject 1.2 MarshalledObject(Object obj)

Page 53: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

52 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

xây dựng một đối tượng đang chứa các dữ liệu tuần tự của một đối tượng đã

cho . Object get()

Không tuần tự dữ liệu của đối tượng được lưu trữ và trả về đối tượng.

java.rmi.activation.ActivationGroupDesc 1.2 ActivationGroupDesc(Properties props,

ActivationGroupDesc.CommandEnvironment env)

xây dựng một mô tả nhóm hoạt hóa mà chỉ rõ những đặc tính máy ảo cho một

máy ảo mà máy chủ hoạt hóa các đối tượng. Thông số env chứa đường dẫn đến

máy ảo có thể thực thi và các tùy chọn lệnh- dòng, hoặc nó là null nếu không

có thiết lập đặc biệt được yêu cầu.

java.rmi.activation.ActivationGroup 1.2 static ActivationSystem getSystem()

trả về một tham chiếu đến hệ thống kích hoạt.

java.rmi.activation.ActivationSystem 1.2 ActivationGroupID registerGroup(ActivationGroupDesc group)

đăng ký một nhóm hoạt hóa và trả về ID của nhóm.

java.rmi.activation.ActivationDesc 1.2 ActivationDesc(ActivationGroupID id, String className,

String classFileURL,MarshalledObject data)

Hàm tạo một mô tả hoạt hóa.

VI/. Java IDL and CORBA: - Ở phần trước các bạn đã làm quen với khái niệm lập trình phân tán bằng kỹ

thuật RMI của Java. Phần này sẽ cung cấp cho bạn 1 khái niệm lập trình phân tán

mở rộng hơn với các đối tượng được thiết kế trên nền CORBA áp dụng cho mọi

ngôn ngữ lập trình.

- Không giống như RMI, CORBA cho phép bạn thực hiện phép gọi giữa các

đối tượng Java với những đối tượng được viết bằng ngôn ngữ khác. Để gọi được

lẫn nhau thì cần phải thông qua chương trình môi giới trung gian của CORBA gọi

là Object Request Broker-ORB(Trình môi giới các yêu cầu của đối tượng) tồn tại

cả trên sever lẫn client. Các tính năng của CORBA 2 định nghĩa 1 loạt các dịch vụ

mà ORB có thể sử dụng cho những tác vụ quản lý khác nhau.

Page 54: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

53 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

- JDK 1.2 đã giới thiệu đầy đủ 1 ORB CORBA 2-compliant, đem lại những

ứng dụng Java và applet khả năng kết nối tới những đối tượng CORBA từ xa.

- Sau đây là những bước cho việc thực thi những đối tượng CORBA:

1. Viết interface cho đối tượng và chỉ định rõ đối tượng đó thi hành như

thế nào, sử dụng IDL(interface definition language) cho việc định

nghĩa interface CORBA. IDL là 1 ngôn ngữ đặt biệt dùng để định rõ

các interface trong/bằng 1 dạng ngôn ngữ trung gian(language-

neutral).

2. Sử dụng trình biên dịch IDL cho ngôn ngữ đích(target language) tạo

ra stub cần thiết và lớp trợ giúp(helper classes).

3. Thêm code thực thi cho những đối tượng server, ngôn ngữ viết thì tùy

bạn. (Khung sườn được tạo ra bởi trình biên dịch IDL chỉ là glue

code(thành phần kết hợp thông qua các kết nối đặc biệt nối 2 interface

khác loại). Bạn vẫn cần cung cấp code thực thi cho những phương

thức server(server methods).Và biên dịch code thực thi đó.

4. Viết 1 chương trình cho server nhằm tạo và ghi nhận các đối tượng

của server. Phương thức thuận tiện nhất cho việc ghi nhận là sử dụng

dịch vụ naming của CORBA(CORBA naming service), dịch vụ này

tương tự như rmiregistry

5. Viết 1 chương trình cho client để xác định vị trí của các server object

và gọi các dịch vụ dựa và chúng.

6. Khởi động naming service và chương trình server trên server cũng

như chương trình client trên client.

- Các bước trên khá giống với những bước mà bạn dùng để xây dựng các ứng dụng

phân tán với RMI, nhưng có 2 sự khác niệt quan trọng là:

1. Bạn có thể sử dụng bất kỳ ngôn ngữ nào với 1 liên kết CORBA để

thực thi trên client và server.

2. Bạn dùng IDL để định rõ các interface.

- Phần tiếp theo mình sẽ trình bày về việc làm sao dùng IDL để định nghĩa các giao

diện CORBA(CORBA interface). Tuy nhiên, CORBA là 1 chủ đề phức tạp nên sẽ

giới thiệu vài ví dụ đơn giản để bạn biết làm sao để bắt đầu

1/. The Interface Definition Language(Ngôn ngữ đặc tả giao diện): - Để giới thiệu cú pháp IDL, chúng ta sẽ chạy thử các ví dụ minh họa mà đã

dùng cho RMI. Trong RMI, bạn bắt đầu 1 interface bằng ngôn ngữ lập trình Java.

Còn trong CORBA, thì bắt đầu 1 interface bằng cú pháp IDL như sau: interface Product

{

Page 55: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

54 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

string getDescription();

};

- Có 1 vài khác biệt khó nhận thấy giữa IDL và Java. Trong IDL thì việc kết

thúc định nghĩa interface bằng bằng dấu chấm phẩy. Để ý là string được viết

thường. Thực ra lớp string này liên quan tới khái niệm của CORBA về 1 chuỗi,

mà nó khác với 1 chuỗi trong Java. Trong ngôn ngữ lập trình Java, chuỗi bao gồm

16-bit kí tự Unicode. Còn trong CORBA thì chuỗi chỉ chứa 8-bit kí tự. Nếu bạn

gửi chuỗi 16-bit qua CORBA và chuỗi đó có những ký tự với byte cao khác

không(nonzero high byte), thì 1 ngoại lệ sẽ được đưa vào.

- Trình biên dịch “IDL sang Java” (trình biên dịch Java IDL) sẽ chuyển các

định nghĩ của IDL sang định nghĩa các interface của Java. Ví dụ, giả sử bạn đưa

định nghĩa IDL Product vào 1 file Product.idl và chạy câu lệnh idlj

Product.idl thì kết quả là 1 file ProductOperations.java với nội dung như

sau:

interface ProductOperations

{

String getDescription();

}

- Cùng với 1 file Product.java định nghĩa 1 interface như sau:

public interface Product extends

ProductOperations,

org.omg.CORBA.Object,

org.omg.CORBA.portable.IDLEntity

{

}

- Các quy tắc điều khiển việc chuyển đổi từ IDL sang ngôn ngữ lập trình

Java được gọi chung là các ràng buộc trong ngôn ngữ lập trình Java. Những ràng

buộc trong ngôn ngữ được tiêu chuẫn hóa bởi OMG. Tất cả các nhà cung cấp

CORBA đều được yêu cầu sử dụng những quy tắc chung cho việc ánh

xạ(mapping) cấu trúc IDL sang 1 ngôn ngữ lập trình cụ thể.

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ư:

Page 56: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

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;

. . .

};

Page 57: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

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

->Nó sẽ tạo ra 5 file nguồn đó là:

Page 58: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

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: class EnvImpl

Page 59: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

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: String[] services = orb.list_initial_services();

Page 60: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

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);

Page 61: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

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: java EnvClient -ORBInitialPort 2809

Page 62: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

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

Page 63: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

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.

4/. Ví dụ về server được thực thi bằng Java còn client bằng C++: Ví dụ 5-18: EnvClient.java 1. import org.omg.CosNaming.*;

2. import org.omg.CORBA.*;

3.

4. public class EnvClient

5. {

6. public static void main(String args[])

7. {

8. try

9. {

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

11. org.omg.CORBA.Object namingContextObj =

orb.resolve_initial_references

("NameService");

12. NamingContext namingContext =

NamingContextHelper.narrow(namingContextObj);

13.

14. NameComponent[] path =

15. {

16. new NameComponent("corejava", "Context"),

17. new NameComponent("Env", "Object")

18. };

19. org.omg.CORBA.Object envObj =

namingContext.resolve(path);

20. Env env = EnvHelper.narrow(envObj);

21. System.out.println(env.getenv("PATH"));

22. }

23. catch (Exception e)

24. {

25. e.printStackTrace();

26. }

27. }

28. }

Ví dụ 5-19: EnvServer.cpp 1. #include <iostream>

2. #include <cstdlib>

3.

4. #include "Env.hh"

5.

6. using namespace std;

7.

Page 64: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

63 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

8. class EnvImpl :

9. public POA_Env,

10. public PortableServer::RefCountServantBase

11. {

12. public:

13. virtual char* getenv(const char *name);

14. };

15.

16. char* EnvImpl::getenv(const char *name)

17. {

18. char* value = std::getenv(name);

19. return CORBA::string_dup(value);

20. }

21.

22. static void bindObjectToName(CORBA::ORB_ptr orb, const char

name[], CORBA::Object_ptr

objref)

23. {

24. CosNaming::NamingContext_var rootContext;

25.

26. try

27. {

28. // Obtain a reference to the root context of the name

service:

29. CORBA::Object_var obj;

30. obj = orb->resolve_initial_references("NameService");

31.

32. // Narrow the reference returned.

33. rootContext = CosNaming::NamingContext::_narrow(obj);

34. if(CORBA::is_nil(rootContext))

35. {

36. cerr << "Failed to narrow the root naming

context." << endl;

37. return;

38. }

39. }

40. catch (CORBA::ORB::InvalidName& ex)

41. {

42. // This should not happen!

43. cerr << "Service required is invalid [does not

exist]." << endl;

44. return;

45. }

46.

47. try

48. {

49. CosNaming::Name contextName;

Page 65: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

64 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

50. contextName.length(1);

51. contextName[0].id = (const char*) "corejava";

52. contextName[0].kind = (const char*) "Context";

53.

54. CosNaming::NamingContext_var corejavaContext;

55. try

56. {

57. // Bind the context to root.

58. corejavaContext = rootContext-

>bind_new_context(contextName);

59. }

60. catch (CosNaming::NamingContext::AlreadyBound& ex)

61. {

62. // If the context already exists, this exception

will be raised. In this

case, just

63. // resolve the name and assign the context to the

object returned:

64. CORBA::Object_var obj;

65. obj = rootContext->resolve(contextName);

66. corejavaContext =

CosNaming::NamingContext::_narrow(obj);

67. if( CORBA::is_nil(corejavaContext) )

68. {

69. cerr << "Failed to narrow naming context." <<

endl;

70. return;

71. }

72. }

73.

74. // Bind objref with given name to the context:

75. CosNaming::Name objectName;

76. objectName.length(1);

77. objectName[0].id = name;

78. objectName[0].kind = (const char*) "Object";

79.

80. try

81. {

82. corejavaContext->bind(objectName, objref);

83. }

84. catch (CosNaming::NamingContext::AlreadyBound& ex)

85. {

86. corejavaContext->rebind(objectName, objref);

87. }

88. }

89. catch (CORBA::COMM_FAILURE& ex)

90. {

Page 66: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

65 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

91. cerr << "Caught system exception COMM_FAILURE--unable

to contact the naming

service."

92. << endl;

93. }

94. catch (CORBA::SystemException&)

95. {

96. cerr << "Caught a CORBA::SystemException while using

the naming service." << endl;

97. }

98. }

99.

100. int main(int argc, char *argv[])

101. {

102. cout << "Creating and initializing the ORB..." << endl;

103.

104. CORBA::ORB_var orb = CORBA::ORB_init(argc, argv,

"omniORB4");

105.

106. CORBA::Object_var obj = orb-

>resolve_initial_references("RootPOA");

107. PortableServer::POA_var poa =

PortableServer::POA::_narrow(obj);

108. poa->the_POAManager()->activate();

109.

110. EnvImpl* envImpl = new EnvImpl();

111. poa->activate_object(envImpl);

112.

113. // Obtain a reference to the object, and register it in

the naming service.

114. obj = envImpl->_this();

115.

116. cout << orb->object_to_string(obj) << endl;

117. cout << "Binding server implementations to registry..."

<< endl;

118. bindObjectToName(orb, "Env", obj);

119. envImpl->_remove_ref();

120.

121. cout << "Waiting for invocations from clients..." <<

endl;

122. orb->run();

123.

124. return 0;

125. }

Page 67: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

66 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

5/. Locating Objects Through IORs(Định vị đối tượng thông qua

IORs):

- Nếu bạn không thể cấu hình cho server ORB của bạn và dịch vụ Naming

Service thì bạn vẫn có thể định vị được các đối tượng CORBA bằng cách dùng

Interoperable Object Reference . 1 IOR là 1 chuỗi dài bắt đầu bằng IOR: và tiếp

theo là rất nhiều số hexadecimal.Ví dụ như:

IOR

:012020201000000049444c3a4163636f756e743a312e300001000000000000

004e000000010100200f0000003231362e31352e3131322e3137390020350420

202e00000001504d43000000001000000049444c3a4163636f756e743a312e30

000e0000004a61636b20422e20517569636b00

- 1 IOR mô tả 1 đối tượng duy nhất. Thông thường, rất nhiều lớp server in

ra hết chuỗi IOR của tất cả các đối tượng mà chúng lưu giữ, giúp khởi động các

client để định vị chúng. Bạn có thể dán chuỗi IOR server vào trong chương trình

client. Cụ thể là dùng code sau:

String ref = "IOR:012020201000000049444c3a4163636f...";

// paste IOR from server

org.omg.CORBA.Object object = orb.string_to_object(ref);

- Sau đó, thu hẹp các đối tượng trả về tới khi phù hợp, chẳng hạn: Env env = EnvHelper.narrow(object);

Hoặc dùng: NamingContext context =

NamingContextHelper.narrow(object);

org.omg.CORBA.ORB 1.2

static ORB init(String[] commandLineArgs, Properties

orbConfigurationprops)

tạo 1 ORB mới và khởi động nó.

String[] list_initial_services()

Trả về 1 danh sách các dịch vụ tồn tại lúc đầu chẳng hạn như "NameService".

org.omg.CORBA.Object resolve_initial_references(String

initialServiceName)

trả về 1 đối tượng mà thực thi 1 trong các dịch vụ khởi đầu.

org.omg.CORBA.Object string_to_object(String ior)

định vị đối tượng với 1 IOR cho trước

Page 68: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

67 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

org.omg.CosNaming.NamingContext 1.2

org.omg.CORBA.Object resolve(NameComponent[] name)

trả về đối tượng với tên cho trước.

org.omg.CosNaming.NameComponent 1.2

NameComponent(String componentId, String componentType)

Khởi tạo 1 name component mới

6/ Implementing CORBA Servers(Thực thi Server CORBA): - Nếu bạn đang phát triển 1 cơ sở hạ tầng CORBA, bạn sẽ nhận thấy Java là

1 ngôn ngữ thực thi tốt đối với các đối tượng CORBA server. Phần này mô tả cách

thức thực thi 1 server CORBA bằng ngôn ngữ lập trình Java

- Chương trình ví dụ trong phần này thì đơn giản hơn phần trước. Giả sử ta

cung cấp 1 dịch vụ cho phép tìm kiếm 1 thuộc tính của hệ thống trên 1 máy ảo

Java. Sau đây là mô tả IDL: interface SysProp

{

string getProperty(in string name);

};

- Ví dụ, chương trình kiểm nghiệm client của ta gọi tới server bằng lệnh: CORBA::String_var key = "java.vendor";

CORBA::String_var value = sysProp->getProperty(key);

->Kết quả là 1 chuỗi mô tả nhà cung cấp máy ảo Java đang thực hiện

chương trình server. Code trình bày trong Ví dụ: 5-21

- Để thực thi server, bạn chạy lệnh idlj với lựa chọn -fall (mặc định thì

lệnh idlj chỉ tạo ra client-side stubs): idlj -fall SysProp.idl

- Sau đó bạn mở rộng lớp SysPropPOA mà bộ biên dịch idlj tạo ra từ file

IDL. Code như sau: class SysPropImpl extends SysPropPOA

{

public String getProperty(String key)

{

return System.getProperty(key);

}

Page 69: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

68 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

}

- Tiếp theo, viết 1 chương trình server thực hiện các nhiệm vụ sau:

1. Khởi động ORB.

2. Định vị và kích hoạt Portable Object Adaptor (POA).

3. Tạo lớp server thực thi

4. Sử dụng POA để chuyển tham chiếu tạm thời sang tham chiếu đối

tượng CORBA.

5. In các IOR của nó.

6. Ràng buộc lớp server thực thi với Naming service.

7. Chờ lời gọi từ client.

- Bạn sẽ hiểu rõ hơn ở Ví dụ:5-20 với code đầy đủ, sau đây là những điểm

lưu ý:

+Khởi động ORB: ORB orb = ORB.init(args, null);

+Kích hoạt POA: POA rootpoa = (POA)

orb.resolve_initial_references("RootPOA");

rootpoa.the_POAManager().activate();

+ Khởi tạo đối tượng server và chuyển nó sang đối tượng CORBA: SysPropImpl impl = new SysPropImpl();

org.omg.CORBA.Object ref =

rootpoa.servant_to_reference(impl);

+ Từ phương thức object_to_string ta thu được IOR và in nó ra: System.out.println(orb.object_to_string(impl));

+ Bạn tham chiếu tới Naming Service : org.omg.CORBA.Object namingContextObj =

orb.resolve_initial_references("NameService");

NamingContext namingContext =

NamingContextHelper.narrow(namingContextObj);

+ Sau đó bạn tạo tên mong muốn cho đối tượng, ở đây ta gọi đối tượng là SysProp NameComponent[] path =

{

new NameComponent("SysProp", "Object")

};

+ Bạn dùng phương thức rebind để ràng buộc đối tượng với 1 tên để gọi: namingContext.rebind(path, impl);

+ Cuối cùng, bạn chờ lời gọi từ client: orb.run();

- Để kiểm tra chương trình chạy, ta làm như sau:

1. Biên dịch file IDL, sử dụng cả 2 trình biên dịch C++ và Java:

Page 70: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

69 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

omniidl -bcxx SysProp.idl

idlj -fall SysProp.idl

2. Biên dịch chương trình server: javac SysPropServer.java

3. Biên dịch chương trình client C++. Trên Linux dùng lệnh: g++ -o SysPropClient -D__x86__ -D__linux__ -

D__OSVERSION__=2 -I /usr/local/include/omniORB4/

SysPropClient.cpp SysPropSK.cc -lomniORB4 -lomnithread –

lpthread

4. Khởi động dịch vụ Naming Server orbd trên server. Chương trình

này là 1 phần của bộ JDK: orbd -ORBInitialPort 2809 &

5. Khởi động server, server chạy cho tới khi bạn dừng thì thôi java SysPropServer -ORBInitialPort 2809 &

6. Chạy client, nó sẽ in ra nhà cung cấp JVM của server: ./SysPropClient -ORBInitRef

NameService=corbaname::localhost

- Bây giờ bạn đã biết được cách dùng CORBA để kết nối client và server mà

được viết bằng những ngôn ngữ lập trình khác nhau

Ví dụ:5-20 SysPropServer.java 1. import org.omg.CosNaming.*;

2. import org.omg.CORBA.*;

3. import org.omg.PortableServer.*;

4.

5. class SysPropImpl extends SysPropPOA

6. {

7. public String getProperty(String key)

8. {

9. return System.getProperty(key);

10. }

11. }

12.

13. public class SysPropServer

14. {

15. public static void main(String args[])

16. {

17. try

18. {

19. System.out.println("Creating and initializing the

ORB...");

20.

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

22.

Page 71: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

70 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

23. System.out.println("Registering server

implementation with the ORB...");

24.

25. POA rootpoa = (POA)

orb.resolve_initial_references("RootPOA");

26. rootpoa.the_POAManager().activate();

27.

28. SysPropImpl impl = new SysPropImpl();

29. org.omg.CORBA.Object ref =

rootpoa.servant_to_reference(impl);

30.

31. System.out.println(orb.object_to_string(ref));

32.

33. org.omg.CORBA.Object namingContextObj =

orb.resolve_initial_references

("NameService");

34. NamingContext namingContext =

NamingContextHelper.narrow(namingContextObj);

35. NameComponent[] path =

36. {

37. new NameComponent("SysProp", "Object")

38. };

39.

40. System.out.println("Binding server implemenation to

name service...");

41. namingContext.rebind(path, ref);

42.

43. System.out.println("Waiting for invocations from

clients...");

44. orb.run();

45. }

46. catch (Exception e)

47. {

48. e.printStackTrace(System.out);

49. }

50. }

51. }

Ví dụ:5-21 SysPropClient.cpp 1. #include <iostream>

2.

3. #include "SysProp.hh"

4.

5. using namespace std;

Page 72: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

71 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

6.

7. CORBA::Object_ptr getObjectReference(CORBA::ORB_ptr orb,

const char serviceName[])

8. {

9. CosNaming::NamingContext_var rootContext;

10.

11. try

12. {

13. // Obtain a reference to the root context of the name

service:

14. CORBA::Object_var initServ;

15. initServ = orb-

>resolve_initial_references("NameService");

16.

17. // Narrow the object returned by

resolve_initial_references() to a CosNaming:

:NamingContext

18. // object

19. rootContext =

CosNaming::NamingContext::_narrow(initServ);

20. if (CORBA::is_nil(rootContext))

21. {

22. cerr << "Failed to narrow naming context." << endl;

23. return CORBA::Object::_nil();

24. }

25. }

26. catch (CORBA::ORB::InvalidName&)

27. {

28. cerr << "Name service does not exist." << endl;

29. return CORBA::Object::_nil();

30. }

31.

32. // Create a name object, containing the name

corejava/SysProp:

33. CosNaming::Name name;

34. name.length(1);

35.

36. name[0].id = serviceName;

37. name[0].kind = "Object";

38.

39. CORBA::Object_ptr obj;

40. try

41. {

42. // Resolve the name to an object reference, and assign

the returned reference to a

43. // CORBA::Object:

44. obj = rootContext->resolve(name);

Page 73: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

72 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

45. }

46. catch (CosNaming::NamingContext::NotFound&)

47. {

48. // This exception is thrown if any of the components

of the path [contexts or

the object]

49. // aren't found:

50. cerr << "Context not found." << endl;

51. return CORBA::Object::_nil();

52. }

53. return obj;

54. }

55.

56. int main (int argc, char *argv[])

57. {

58. CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv,

"omniORB4");

59.

60. CORBA::Object_var obj = getObjectReference(orb,

"SysProp");

61. SysProp_var sysProp = SysProp::_narrow(obj);

62.

63. if (CORBA::is_nil(sysProp))

64. {

65. cerr << "Cannot invoke on a nil object reference." <<

endl;

66. return 1;

67. }

68.

69. CORBA::String_var key = "java.vendor";

70. CORBA::String_var value = sysProp->getProperty(key);

71.

72. cerr << key << "=" << value << endl;

73.

74. return 0;

75. }

org.omg.CORBA.ORB 1.2

void connect(org.omg.CORBA.Object obj)

kết nối đối tượng thực thi cho trước với ORB, kích hoạt ORB để hướng lời

gọi tới các phương thức của đối tượng

String object_to_string(org.omg.CORBA.Object obj)

Page 74: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

73 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

Trả về chuỗi IOR của đối tượng cho trước.

org.omg.CosNaming.NamingContext 1.2

void bind(NameComponent[] name, org.omg.CORBA.Object obj)

void rebind(NameComponent[] name, org.omg.CORBA.Object obj)

ràng buộc 1 đối tượng với 1 tên gọi.Phương thức bind dùng 1 ngoại lệ

AlreadyBound nếu như đối tượng trước đây đã được ràng buộc. Phương thức

rebind sẽ thay thế đối tượng đã ràng buộc trước đây

VII/. Remote Method Calls with SOAP(Gọi phương thức từ

xa qua giao thức SOAP): - Trong những năm gần đây, các dịch vụ Web đã nổi lên như 1 công nghệ

phổ biến cho cơ chế gọi phương thức từ xa. Về mặt kỹ thuật, 1 dịch vụ Web gồm

có 2 phần:

Một server có thể được truy cập bằng giao thức truyền Simple Object

Access Protocol (SOAP)

Một mô tả về dịch vụ bằng định dạng Web Service Description

Language (WSDL)

- SOAP là 1 giao thức XML, gần giống với IIOP của CORBA, cung cấp 1

giao thức cho cơ chế gọi phương thức từ xa. Cũng giống như bạn có thể lập trình

server và client trên nền CORBA mà không cần hiểu gì về IIOP, nên bạn thực sự

không cần hiểu chi tiết về SOAP để gọi 1 dịch vụ Web.

- WSDL tương tự như IDL. Nó mô tả interface của dịch vụ Web. Trong

phần này, ta chỉ thảo luận cách thực thi của 1 client kết nối tới 1 dịch vụ Web hiện

hành.

- Việc thực thi dịch vụ Web vượt quá phạm vi của cuốn sách. Để có nhiều

thông tin hơn hãy xem Chapter 8 của J2EE tutorial tại

http://java.sun.com/j2ee/1.4/docs/tutorial/doc/index.html

- Để hình dung 1 dịch vụ Web dễ hiểu, ta xét ví dụ cụ thể sau: Dịch vụ Web

của Amazon, mô tả ở địa chỉ http://www.amazon.com/gp/aws/landing.html. Dịch

vụ Web của Amazon cho phép 1 người lập trình tương tác với hệ thống của

Page 75: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

74 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

Amazon với nhiều mục tiêu đa dạng. Chẳng hạn, bạn có thể có được danh sách của

tất cả cuốn sách chỉ cần đưa ra tên tác giả hay tựa đề cuốn sách. Amazon tạo ra

dịch vụ này để các công ty có nhu cầu bán các mặt hàng của họ cho người tiêu

dùng, sử dụng hệ thống của Amazon giống như là fulfillment backend. Để chạy ví

dụ này, bạn cần đăng nhập vào Amazon và nhận thẻ miễn phí dành cho người phát

triển(developer) để có thể kết nối tới dịch vụ.

- Bạn có thể phỏng theo các kỹ thuật đã mô tả trong phần này cho bất kỳ

dịch vụ Web nào. Trang http://www.xmethods.com cung cấp rất nhiều dịch vụ

Web miễn phí cho bạn thử.

- Vì sao những dịch vụ Web lại có nhiều sức hút đến vậy?, bởi vì chúng là

ngôn ngữ trung gian. Chẳng hạn, ta có thể truy cập vào Amazon Web Services bằng

cách dùng chương trình Java, nhưng những người phát triển khác có thể truy cập

bằng C++ hay Visual Basic cũng được. The WSDL descriptor describes the

services in a language-independent manner(WSDL mô tả các dịch vụ bằng 1 ngôn

ngữ độc lập). Chẳng hạn, WSDL của Amazon Web Services (ở địa chỉ

http://soap.amazon.com/schemas3/AmazonWebServices.wsdl) mô tả 1 operation

AuthorSearchRequest như sau: <operation name="AuthorSearchRequest">

<input message="typens:AuthorSearchRequest"/>

<output message="typens:AuthorSearchResponse"/>

</operation>

. . .

<message name="AuthorSearchRequest">

<part name="AuthorSearchRequest"

type="typens:AuthorRequest"/>

</message>

<message name="AuthorSearchResponse">

<part name="return" type="typens:ProductInfo"/>

</message>

- Ngoài ra, nó định nghĩa các kiểu dữ liệu. Sau đây là định nghĩa AuthorRequest <xsd:complexType name="AuthorRequest">

<xsd:all>

<xsd:element name="author" type="xsd:string"/>

<xsd:element name="page" type="xsd:string"/>

<xsd:element name="mode" type="xsd:string"/>

<xsd:element name="tag" type="xsd:string"/>

<xsd:element name="type" type="xsd:string"/>

<xsd:element name="devtag" type="xsd:string"/>

<xsd:element name="sort" type="xsd:string" minOccurs="0"/>

Page 76: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

75 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

<xsd:element name="locale" type="xsd:string"

minOccurs="0"/>

<xsd:element name="keywords" type="xsd:string"

minOccurs="0"/>

<xsd:element name="price" type="xsd:string"

minOccurs="0"/>

</xsd:all>

</xsd:complexType>

- Khi được chuyển sang Java, AuthorRequest sẽ trở thành 1 lớp: public class AuthorRequest

{

public AuthorRequest(String author, String page, String mode,

String tag, String type,

String devtag, String sort, String locale, String keyword,

String price) { . . . }

public String getAuthor() { . . . }

public void setAuthor(String newValue) { . . . }

public String getPage() { . . . }

public void setPage(String) { . . . }

. . .

}

- Để gọi dịch vụ tìm kiếm, khởi tạo 1 đối tượng AuthorRequest và gọi

authorSearchRequest của đối tượng “port”: AmazonSearchPort port = (AmazonSearchPort) (new

AmazonSearchService_Impl()

.getAmazonSearchPort());

AuthorRequest request = new AuthorRequest(name, "1", "books",

"", "lite", "", token, "",

"", "");

ProductInfo response = port.authorSearchRequest(request);

- Đối tượng “port” sẽ biến đối tượng Java thành 1 message của SOAP,

truyền nó tới server Amazon, và biến message trả về thành 1 đối tượng ProductInfo .

Sau đó lớp port sẽ được tự động tạo ra.

- Chú ý là: File WSDL không chỉ định rõ dịch vụ phải làm gì. Nó chỉ xác định

tham số và trả về kiểu dữ liệu.

- Có thể download Java Web Services Developer Pack (JWSDP) từ

http://java.sun.com/webservices/webservicespack.html và cài đặt nó.

Page 77: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

76 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

- Để tạo ra các lớp Java theo yêu cầu, đưa file config.xml như sau vào thư

mục của chương trình client: <?xml version="1.0" encoding="UTF-8"?>

<configuration

xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">

<wsdl

location="http://soap.amazon.com/schemas3/AmazonWebServices.wsdl

"

packageName="com.amazon" />

</configuration>

- Sau đó chạy câu lệnh sau: jwsdp/jaxrpc/bin/wscompile.sh -import config.xml

jwsdp/jaxrpc/bin/wscompile.sh -gen -keep config.xml

- Ở đây jwsdp là thư mục mà bạn đã cài đặt JWSDP vào, ví dụ:

/usr/local/jwsdp-1.4 hay c:\jwsdp-1.4.

+ Câu lệnh đầu tiên sẽ import file WSDL từ vị trí cho trước. Câu lệnh thứ 2

sẽ tạo ra các lớp mà client cần. Lựa chọn -keep sẽ giữ lại những file nguồn. Kết

quả từ các câu lệnh trên là 1 số lượng lớn các lớp được tạo ra trong thư mục đã chỉ

định(ở đây là com/amazon ) như com/amazon/AuthorRequest.java và

com/amazon/Details.java . Chúng ta sẽ dùng các lớp đó cho ví dụ ứng dụng

sau.

- Ví dụ ứng dụng trong Ví dụ:5-22 , người dùng chỉ định tên của tác giả và

nhấp vào nút Search.Kết quả thể hiện trong hình 5-11 . Điều này cho thấy dịch vụ

Web hoạt động tốt

Page 78: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

77 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

- Để biên dịch ứng dụng này, ta bổ sung thêm file thư viện

jwsdp/jaxrpc/lib/jaxrpc-impl.jar cho lớp của bạn.

- Để chạy ứng dụng này, file lớp của bạn phải chứa: . (the current directory)

jwsdp/jaxrpc/lib/jaxrpc-api.jar

jwsdp/jaxrpc/lib/jaxrpc-impl.jar

jwsdp/jaxrpc/lib/jaxrpc-spi.jar

jwsdp/jwsdp-shared/lib/activation.jar

jwsdp/jwsdp-shared/lib/mail.jar

jwsdp/saaj/lib/saaj-api.jar

jwsdp/saaj/lib/saaj-impl.jar

- Ở ví dụ này sẽ cho thấy việc gọi 1 dịch vụ Web về cơ bạn giống như là

việc tạo ra lời gọi phương thức từ xa khác. Người lập trình gọi 1 phương thức cục

bộ trên 1 đối tượng proxy và proxy sẽ kết nối tới 1 server. Từ khi dịch vụ Web xuất

hiện ở mọi nơi, nó thực sự đem lại sự hứng thú cho những người lập trình ứng

dụng. Và nó trở nên dễ sử dụng khi các công cụ và thư viện được tập hợp đầy đủ

trong version mới của JDK

Ví dụ: 5-22. SOAPTest.java

1. import com.amazon.*;

2. import java.awt.*;

3. import java.awt.event.*;

4. import java.rmi.*;

Page 79: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

78 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

5. import java.util.*;

6. import javax.swing.*;

7.

8. /**

9. The client for the warehouse program.

10. */

11. public class SOAPTest

12. {

13. public static void main(String[] args)

14. {

15. JFrame frame = new SOAPTestFrame();

16. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

17. frame.setVisible(true);

18. }

19. }

20.

21. /**

22. A frame to select the book author and to display the

server response.

23. */

24. class SOAPTestFrame extends JFrame

25. {

26. public SOAPTestFrame()

27. {

28. setTitle("SOAPTest");

29. setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

30.

31. JPanel panel = new JPanel();

32.

33. panel.add(new JLabel("Author:"));

34. author = new JTextField(20);

35. panel.add(author);

36.

37. JButton searchButton = new JButton("Search");

38. panel.add(searchButton);

39. searchButton.addActionListener(new

40. ActionListener()

41. {

42. public void actionPerformed(ActionEvent event)

43. {

44. result.setText("Please wait...");

45. new Thread(new

46. Runnable()

47. {

48. public void run()

49. {

50. String name = author.getText();

Page 80: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

79 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

51. String books =

searchByAuthor(name);

52. result.setText(books);

53. }

54. }).start();

55. }

56. });

57.

58. result = new JTextArea();

59. result.setLineWrap(true);

60. result.setEditable(false);

61.

62. add(panel, BorderLayout.NORTH);

63. add(new JScrollPane(result), BorderLayout.CENTER);

64. }

65.

66. /**

67. Calls the Amazon web service to find titles that

match the author.

68. @param name the author name

69. @return a description of the matching titles

70. */

71. private String searchByAuthor(String name)

72. {

73. try

74. {

75. AmazonSearchPort port = (AmazonSearchPort)

76. (new

AmazonSearchService_Impl().getAmazonSearchPort());

77.

78. AuthorRequest request

79. = new AuthorRequest(name, "1", "books", "",

"lite", "", token, "", "", "");

80. ProductInfo response =

port.authorSearchRequest(request);

81.

82. Details[] details = response.getDetails();

83. StringBuilder r = new StringBuilder();

84. for (Details d : details)

85. {

86. r.append("authors=");

87. String[] authors = d.getAuthors();

88. if (authors == null) r.append("[]");

89. else r.append(Arrays.asList(d.getAuthors()));

90. r.append(",title=");

91. r.append(d.getProductName());

92. r.append(",publisher=");

Page 81: Báo cáo Chương 5-Core Java Volume II

Trường Đại Học Công Nghệ Thông Tin – Đại Học Quốc Gia Hồ Chí Minh 2011

80 Lập Trình Hệ Thống Với Java – Tìm hiểu lập trình phân tán trong Java

93. r.append(d.getManufacturer());

94. r.append(",pubdate=");

95. r.append(d.getReleaseDate());

96. r.append("\n");

97. }

98. return r.toString();

99. }

100. catch (RemoteException e)

101. {

102. return "Exception: " + e;

103. }

104. }

105.

106. private static final int DEFAULT_WIDTH = 450;

107. private static final int DEFAULT_HEIGHT = 300;

108.

109. private static final String token = "your token goes

here";

110.

111. private JTextField author;

112. private JTextArea result;

113. }