Cài đặt một dịch vụ phân tán trong JADE

Một phần của tài liệu Phát triển phần mềm hướng Agent (Trang 145 - 148)

Trong phần này ví dụ Logging Service được mở rộng để thể hiện tất cả các bản in lỗi trên đầu ra chuẩn mà không quan tâm đến container mà nó được sinh ra. Để đạt được điều nó, một slice của dịch vụ Logging Service phải được thực thi. Hơn nữa, OutgoingLoggingFilter được biểu diễn trong phần 6.2.3 phải được điều chỉnh để gửi một lệnh ngang tới slice của dịch vụ Logging Service ở trên container chính mỗi lần nó chắn một thông điệp.

Việc thực thi một slice cho mỗi dịch vụ là hơi phức tạp hơn so với việc thực thi một bộ lọc, vì cần phải phát triển ba lớp.

6.2.4.1 Giao diện ngang (horizontal interface)

Giao diện này khai báo tất cả các phương thức có thể được gọi từ một slice từ xa và phải mở rộng giao diện Service.Slice. Tất cả các phương thức trong giao diện ngang phải ném ra ngoại lệ jade.core.IMTPException nếu một vài vấn để mạng xảy ra tại mức IMTP, ví dụ không lấy được slice từ xa. Ví dụ giao diện ngang có thể như sau:

1: package bookTrading.logging; 2:

3: import jade.core.*; 4:

5: public interface LoggingSlice extends Service.Slice { 6: public static final String H_LOGMESSAGE = "log-message"; 7:

8: public void logMessage (String s) throws IMPException; 9: }

Giao diện ngang cũng là nơi lý tưởng để định nghĩa các hằng số biểu diễn tên của các lệnh ngang mà nó có thể được đáp ứng bởi service slice. Đặc biệt phải chỉ có một lệnh ngang cho mỗi phương thức trong giao diện ngang.

6.2.4.2 Slice Proxy

Đây là lớp mà các thể hiện của nó được trao quyền đại diện cho một remote slice. Nó mở rộng từ lớp jade.core.SliceProxy và phải thực thi giao diện ngang. Khi một dịch vụ cần tương tác với một slice trên một node từ xa, đầu tiên nó phải khôi phục lại một proxy trỏ tới slice đó và sau đó gọi phương thức đã được yêu cầu. Mục đích chính của proxy là chuyển đổi các lời gọi phương thức thành các lệnh ngang thích hợp cái mà sẽ được gửi đến remote slice. Các lớp proxy được chủ động tải về mỗi khi cần và phải tuân theo quy ước đặt tên: chúng phải được đặt tên <servicename>Proxy. Lớp bookTrading.logging.LoggingProxy được cài đặt như sau: 1: package booTrading.logging;

2:

3: import jade.core.*; 4:

5: public class LoggingProxy extends SliceProxy implements LoggingSlice {

6: public void logMessage (String s) throws IMTPException {

7: GenericCommand cmd = new GenericCommand(H_LOGMESSAGE, LoggingService.NAME, null); 8: cmd.addParam(s) ; 9: getNode().accept(cmd); 10: } 11: }

Dòng 7, lớp jade.core.GenericCommand được sử dụng để thực thi các lệnh ngang. Những lệnh này sau đó được thêm vào các tham số cần thiết và được chuyển tới các remote node. Lưu ý rằng một slice proxy được gắn vào một proxy trỏ tới node mà có proxy slice cư ngụ tại đó.

6.2.4.3 Cài đặt Slice

Đây là lớp thực thi giao diện Service.Slice. Nó chịu trách nhiệm đảm bảo dịch vụ gọi các lệnh ngang. Việc thực thi Slice không cần thực thi giao diện ngang. Lớp thực thi slice cho Logging Service được cài đặt như sau:

1: . . .

2: private class LoggingSlicelmpl implements Service.Slice { 3:

4: public Service getService() { 5: return LoggingService.this; 6: }

7:

8: public Node getNode() throws ServiceException { 9: try {

10: return LoggingService.this.getLocalNode() ; 11: }

12: catch (IMTPException imtpe) {

13: // Should never happen as this is a local call

14: throw new ServiceException("Unexpected error retrieving local node") ;

15: } 16: } 17:

18: public VerticalCommand serve (HorizontalCommand cmd) { 19: String cmdName = cmd.getName() ;

20: if (cmd.getName().equals (LoggingSlice.H_LOGMESSAGE)) { 21: Object[] params = cmd.getParams () ;

22: System.out.println (params [0]) ; 23: }

24: } 25: } 26: . . .

Các phương thức getService() và getNode() khá đơn giản và phần thân của nó khá rõ ràng trong tất cả các lớp thực thi slice. Phương thức serve() là điểm trung tâm của lớp thực thi slice và được gọi đến mỗi lần một lệnh ngang được nhận. Một slice có thể phục vụ trực tiếp một lệnh ngang như trong ví dụ trên, hoặc như đã đề cập trong phần 6.1.3.2, nếu các nhà phát triển muốn các dịch vụ khác phản ứng lại việc nhận một lệnh ngang, họ có thể cài đặt phương thức serve() để trả về đối tượng VerticalCommand, đối tượng này sẽ di chuyển qua mắt xích của bộ lọc incoming filter và tới service sink. Một dịch vụ tuyên bố nó có khả năng để thực hiện việc phối hợp giữa các

node bằng cách thực thi các phương thức getHorizontalInterface() và the getLocalSlice(). Để làm được điều đó, lớp LoggingService phải được cài đặt như sau:

1: . . .

2: private ServiceSlice localSlice = new LoggingSliceImpl() ; 3: . . .

4: public Class getHorizontalInterface() { 5: return LoggingSlice.class;

6: } 7:

8: public Service.Slice getLocalSlice() { 9: return localSlice;

10: } 11: . . .

Tại thời điểm này, LoggingService đã sẵn sàng để chuyển tiếp các ghi chép lỗi tới các nút của platform. Việc cuối cùng phải làm là sửa đổi OutgoingLoggingFilter như trong phần 6.2.3 để chuyển tiếp các ghi chép lỗi đến logging slice trên main container. Việc thực thi các dòng code như sau:

1: . . .

2: private class OutgoingLoggingFilter extends Filter { 3: public boolean accept (VerticalCommand cmd) {

4: if (cmd.getName().equals (MessagingSlice.SEND_MESSAGE)) { 5: Object[] params = cmd.getParams() ;

6: AID sender = (AID) params [0] ;

7: GenericMessage gMsg = (GenericMessage) params[1] ; 8: ACLMessage msg = gMsg.getACLMessage() ;

9: AID receiver = (AID) params[2] ; 10: // Prepare the log record

11: String logRecord = "Message from "+sender+" to "+receiver+": \n" ; 12: if (verbose) { 13: logRecord = logRecord+msg; 14: } 15: else { 16: logRecord = logRecord+ACLMessage.getPerformative (msg.getPerformative()); 17: } 18:

19: // Send the log record to the logging slice on the Main Container

20: try {

21: LoggingSlice mainSlice = (LoggingSlice) getSlice(MAIN_SLICE) ;

22: mainSlice.logMessage(logRecord) ; 23: }

24: catch (ServiceException se) {

25: System.out.println("Error retrieving Main Logging Slice") ;

26: se.printStackTrace() ; 27: }

28: catch (IMTPException impte) {

29: System.out.println ("Error contacting Main Logging Slice") ;

30: se.printStacktrace() ; 31: }

32: }

33: // Never block a command 34: return true;

35: } 36: }

Phương thức getSlice() của dịch vụ Service được sử dụng để phục hồi một proxy để đưa đến một remote slice. Phương thức này lấy tên của node mà chứa remote slice đó. Hằng MAIN_SLICE được đinh nghĩa trong lớp BaseService luôn báo đến slice trong container chính.

Một phần của tài liệu Phát triển phần mềm hướng Agent (Trang 145 - 148)