Khóa luận Kiểm chứng đặt tả uml cho tác tử phần mềm

Tài liệu Khóa luận Kiểm chứng đặt tả uml cho tác tử phần mềm: ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ Vũ Sỹ Vương KIỂM CHỨNG ĐẶT TẢ UML CHO TÁC TỬ PHẦN MỀM KHOÁ LUẬN TỐT NGHIỆP ĐẠI HỌC HỆ CHÍNH QUY Ngành: Công nghệ phần mềm HÀ NỘI - 2009 ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ Vũ Sỹ Vương KIỂM CHỨNG ĐẶT TẢ UML CHO TÁC TỬ PHẦN MỀM KHOÁ LUẬN TỐT NGHIỆP ĐẠI HỌC HỆ CHÍNH QUY Ngành: Công nghệ phần mềm Cán bộ hướng dẫn: Tiến sỹ Trương Anh Hoàng HÀ NỘI - 2009 Lời cám ơn Trước tiên tôi xin gửi lời cảm ơn sâu sắc tới TS. Trương Anh Hoàng, Bộ môn Công nghệ phần mềm, Khoa Công nghệ thông tin, Trường Đại học Công Nghệ, Đại Học Quốc Gia Hà Nội – người đã định hướng đề tài và tận tình hướng dẫn chỉ bảo tôi trong suốt quá trình thực hiện khóa luận tốt nghiệp này. Tôi cũng xin trân trọng cảm ơn quý th ầy cô trong Khoa Công nghệ thông tin trường Đại học Công Nghệ, Đại Học Quốc Gia Hà Nội đã tận tình giảng dạy, truyền đạt những kiến thức quý báu trong suốt bốn năm học làm nền tảng cho tôi thực hiện...

pdf93 trang | Chia sẻ: haohao | Lượt xem: 1133 | Lượt tải: 0download
Bạn đang xem trước 20 trang mẫu tài liệu Khóa luận Kiểm chứng đặt tả uml cho tác tử phần mềm, để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên
ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ Vũ Sỹ Vương KIỂM CHỨNG ĐẶT TẢ UML CHO TÁC TỬ PHẦN MỀM KHOÁ LUẬN TỐT NGHIỆP ĐẠI HỌC HỆ CHÍNH QUY Ngành: Công nghệ phần mềm HÀ NỘI - 2009 ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ Vũ Sỹ Vương KIỂM CHỨNG ĐẶT TẢ UML CHO TÁC TỬ PHẦN MỀM KHOÁ LUẬN TỐT NGHIỆP ĐẠI HỌC HỆ CHÍNH QUY Ngành: Công nghệ phần mềm Cán bộ hướng dẫn: Tiến sỹ Trương Anh Hoàng HÀ NỘI - 2009 Lời cám ơn Trước tiên tôi xin gửi lời cảm ơn sâu sắc tới TS. Trương Anh Hoàng, Bộ môn Công nghệ phần mềm, Khoa Công nghệ thông tin, Trường Đại học Công Nghệ, Đại Học Quốc Gia Hà Nội – người đã định hướng đề tài và tận tình hướng dẫn chỉ bảo tôi trong suốt quá trình thực hiện khóa luận tốt nghiệp này. Tôi cũng xin trân trọng cảm ơn quý th ầy cô trong Khoa Công nghệ thông tin trường Đại học Công Nghệ, Đại Học Quốc Gia Hà Nội đã tận tình giảng dạy, truyền đạt những kiến thức quý báu trong suốt bốn năm học làm nền tảng cho tôi thực hiện khóa luận tốt nghiệp này. Con xin cảm ơn cha mẹ và gia đình đã sinh ra và nuôi d ạy con khôn lớn, luôn bên cạnh động viên và ủng hộ con trên con đường mà con đã yêu thích và lựa chọn. Cảm ơn các bạn sinh viên Khoa Công nghệ thông tin khóa 2005 – 2009. Các bạn đã giúp đỡ và ủng hộ tôi rất nhiều cũng như đóng góp nhiều ý kiến quý báu, qua đó, giúp tôi hoàn thiện khóa luận tốt hơn. Mặc dù đã r ất nỗ lực, cố gắng nhưng chắc hẳn khóa luận của tôi vẫn còn nhiều thiếu sót. Tôi rất mong nhận được nhiều những ý kiến đánh giá, phê bình của quý thầy cô, của các anh chị và các bạn. Một lần nữa, tôi xin chân thành cảm ơn. Hà Nội, tháng 5 năm 2009 Vũ Sỹ Vương Tóm tắt nội dung Trong quy trình phát triển phần mềm, kiểm chứng phần mềm đóng vai trò quan trọng trong việc đảm bảo tính đúng đắn của hệ thống trong suốt quá trình thực thi. Nó có nhiệm vụ phát hiện và dò tìm lỗi cho giai đoạn kiểm thử phần mềm. Phương pháp lập trình hướng khía cạnh (AOP) cùng với công nghệ AspectJ ra đời đã tạo ra hướng phát triển mới cho kiểm chứng phần mềm, giúp nâng cao chức năng dò tìm, s ửa lỗi phần mềm mà không ảnh hưởng tới mã nguồn hệ thống. Từ yêu cầu thực tế, khi mà mô hình UML đang là sự lựa chọn phổ biến cho việc mô hình hóa hệ thống phần mềm ở giai đoạn thiết kế, việc kiểm chứng các giao thức ràng buộc đối tượng, giao thức ràng buộc giữa các tác tử trong hệ đa tác tử được mô tả trong biểu đồ trạng thái và biểu đồ trình tự UML, AUML là rất cần thiết trong thời gian chạy. Dựa vào yêu cầu thực tế đặt ra cùng với việc lựa chọn AOP làm giải pháp giải quyết vấn đề, trong phạm vi khóa luận, tôi xin trình bày phương pháp sinh mã aspect phục vụ cho mục đích kiểm chứng phần mềm và xây dựng công cụ Protocol Verification Generator (PVG) tự động sinh mã aspect dựa trên phương pháp này. Nội dung chính của phương pháp là dựa vào các kiến thức về AOP và UML, XML, AUML, JADE framework để chuyển đổi các giao thức ràng buộc đối tượng được đặc tả bởi biểu đồ UML, giao thức tương tác giữa các tác tử trong hệ đa tác tử được đặc tả bởi biểu đổ AUML sang các mô-đun aspect phục vụ quá trình kiểm chứng. Ý nghĩa thực tiễn của bài toán là việc sử dụng mã aspect vừa được tạo ra đan vào chương trình chính thông qua b ộ đan (aspect weaver) của AspectJ để thực hiện nhiệm vụ kiểm chứng các giao thức ràng buộc giữa các đối tượng, các tác tử trong thời gian chạy. Mục lục Chương 1. Mở đầu .................................................................................................. 1 1.1 Đặt vấn đề ................................................................................................ 1 1.2 Nội dung bài toán ..................................................................................... 2 1.3 Tổng quan phương pháp “Kiểm chứng đặc tả UML cho tác tử phần mềm” ................................................................................................................. 3 1.4 Cấu trúc khóa luận ................................................................................... 4 Chương 2. Giới thiệu lập trình hướng khía cạnh (Aspect-Oriented Programming) và AspectJ ............................................................................................................... 6 2.1 Phương pháp lập trình hướng khía cạnh .................................................. 6 2.1.1 Sự hạn chế của lập trình hướng đối tượng (OOP) ............................... 6 2.1.2 Lập trình hướng khía cạnh (AOP) ....................................................... 9 2.2 AspectJ ................................................................................................... 12 2.2.1 Join point ........................................................................................... 12 2.2.2 Pointcut .............................................................................................. 12 2.2.3 Advice ............................................................................................... 13 2.2.4 Aspect ................................................................................................ 14 2.2.5 Cơ chế họa động của AspectJ ............................................................ 15 2.3 Sử dụng AOP Phát triển ứng dụng và phương pháp kiểm chứng dựa trên AOP ............................................................................................................. 15 2.4 Kết luận .................................................................................................. 17 Chương 3. Agent UML và JADE framework ....................................................... 18 3.1 Ngôn ngữ mô hình hóa UML ................................................................ 18 3.1.1 Khái niệm .......................................................................................... 18 3.1.2 Biểu đồ trạng thái (State Diagram) ................................................... 18 3.1.3 Biểu đồ trình tự (Sequence Diagram) ............................................... 19 3.2 XML (eXtensible Markup Language) ................................................... 20 3.2.1 Cơ bản về XML ................................................................................. 20 3.2.2 XML DOM ........................................................................................ 22 3.3 XMI (XML Metadata Interchange) ....................................................... 24 3.4 AUML (Agent UML) ............................................................................ 25 3.4.1 Tác tử phần mềm là gì? ..................................................................... 25 3.4.2 Phần mềm hướng Agent .................................................................... 26 3.4.3 AUML (Agent Unified Modeling Language) ................................... 28 3.5 Java Agent DEvelopment Framework (JADE) ..................................... 31 3.5.1 Khái niệm về JADE ........................................................................... 31 3.5.2 Cấu trúc của JADE platform ............................................................. 32 3.5.3 Một số lớp quan trọng trong thư viện JADE ..................................... 33 3.6 Kết luận .................................................................................................. 34 Chương 4. Xây dựng máy trạng thái từ biểu đồ UML ......................................... 35 4.1 Biểu đồ trạng thái ................................................................................... 35 4.1.1 Quy tắc biểu diễn giao thức bằng biểu đồ trạng thái ......................... 35 4.1.2 Xây dựng cấu trúc dữ liệu mô tả biểu đồ trạng thái UML ................ 36 4.1.3 Xây dựng FSM mô tả biểu đồ trạng thái UML ................................. 40 4.2 Biểu đồ trình tự UML ............................................................................ 42 4.2.1 Cách biểu diễn giao thức giữa nhiều đối tượng bằng biểu đồ trình tự UML ........................................................................................................... 42 4.2.2 Xây dựng cấu trúc dữ liệu mô tả biểu đồ trình tự UML ................... 43 4.2.3 Xây dựng FSM mô tả biểu đồ trình tự UML .................................... 46 4.3 Kết luận .................................................................................................. 47 Chương 5. Xây dựng công cụ tự động sinh aspect từ máy trạng thái................... 48 5.1 Đặt vấn đề .............................................................................................. 48 5.2 Sinh aspect từ FSM mô tả biểu đồ trạng thái UML ............................... 49 5.3 Sinh aspect từ FSM mô tả biểu đồ trình tự UML .................................. 50 5.4 Mở rộng ................................................................................................. 51 5.5 Sinh mã aspect kiểm chứng giao thức (AB)n ......................................... 52 5.5.1 Giao thức (AB)n là gì? ....................................................................... 52 5.5.2 Thuật toán kiểm chứng giao thức (AB)n ........................................... 53 5.5.3 Sinh mã aspect kiểm chứng giao thức (AB)n .................................... 54 5.6 Kết luận .................................................................................................. 54 Chương 6. Thực nghiệm ....................................................................................... 55 6.1 Xây dựng công cụ PVG ......................................................................... 55 6.2 Kiểm chứng một số giao thức thực tế .................................................... 56 6.2.1 Giao thức của các ứng dụng Applet .................................................. 56 6.2.2 Kiểm chứng giao thức biểu diễn giao thức ghi nợ ở một máy ATM 60 6.2.3 Kiểm chứng giao thức [A*B] n .......................................................... 64 6.2.4 Kiểm chứng giao thức tương tác tác tử ............................................. 66 6.3 Kết luận .................................................................................................. 70 Chương 7. Kết luận ............................................................................................... 71 7.1 Kết luận về khóa luận ............................................................................ 71 7.2 Hướng phát triển trong tương lai ........................................................... 72 Phụ lục .................................................................................................................. 73 Phụ lục A: Tài liệu XMI mô tả biểu đồ trạng thái UML .................................. 73 Phụ lục B: Tài liệu XMI mô tả biểu đồ trình tự UML ...................................... 75 Phụ lục C: Agent Customer (Customer.java) ................................................... 78 Phụ lục D: Agent ShoppingCart (ShoppingCart.java) ...................................... 81 Phụ lục E: Aspect Template ............................................................................. 83 Danh mục ký hiệu, từ viết tắt AOP Aspect-Oriented Programming FSM Finite State Machine JADE Java Agent DEvelopment Framework OOP Object Oriented Programming PVG Protocol Verification Generator XMI XML Metadata Interchange XML eXtensible Markup Language UML Unified Modeling Language 1 Chương 1. Mở đầu 1.1 Đặt vấn đề Ngày nay công nghệ thông tin đã được ứng dụng vào tất cả các lĩnh vực của đời sống xã hội. Nó đã tạo ra một diện mạo mới cho xã hội và nhờ đó nền văn minh nhân loại đã được nâng lên một tầm cao mới. Nói đến công nghệ thông tin là nói đến công nghệ phần mềm – một phần không thể tách rời của công nghệ thông tin. Hiện nay ngành công nghệ phần mềm trên thế giới đã và đang phát triển như vũ bão. Những tiến bộ vượt bậc của khoa học kỹ thuật phần cứng đã tạo điều kiện thuận lợi cho công nghệ phần mềm ngày càng phát triển không ngừng. Phần mềm được coi là sản phẩm chính của công nghệ phần mềm, được phát triển theo các mô hình, quy trình phát triển đặc biệt. Quá trình phát triển phần mềm bao gồm rất nhiều giai đoạn: Thu thập yêu cầu, phân tích, thiết kế, xây dựng, kiểm tra, triển khai và bảo trì phần mềm. Trong các giai đoạn đó giai đoạn kiểm tra, phát hiện, xác định và sửa các lỗi phần mềm là rất quan trọng để đảm bảo chất lượng của một phần mềm. Các lỗi phần mềm có thể gây thiệt hại to lớn về tiền bạc, thời gian và công sức của con người. Lỗi phần mềm được phát hiện càng muộn thì càng gây hậu quả nghiêm trọng, tốn rất nhiều thời gian và công sức để sửa chữa lỗi, thậm chí có thể phải xây dựng lại toàn bộ hệ thống từ đầu. Chính ví vậy cần có các phương pháp phát hiện lỗi sớm nhằm giảm thiểu công sức để sửa chúng. Để phát hiện ra những lỗi phần mềm, phần mềm cần phải được kiểm chứng (Verification) và thẩm định (Valication) [13]. Kiểm chứng phần mềm là kiểm tra xem phần mềm có được thiết kế đúng và thực thi đúng như đặc tả yêu cầu hay không. Thẩm định phần mềm là giai đoạn có sự hỗ trợ của khách hàng nhằm kiểm tra xem phần mềm có đáp ứng được các yêu cầu của họ hay không. Mục đích chính của kiểm chứng phần mềm là làm giảm thiểu lỗi phần mềm tới mức có thể chấp nhận được. Chính vì vậy, nó có vai trò vô cùng quan trọng trong toàn bộ quy trình phát triển phần mềm và trong ngành công nghệ phần mềm hiện nay. Nó đã và đang thu hút được mối quan tâm của rất nhiều nhà nghiên cứu. Giai đoạn kiểm thử trong quy trình phát triển phần mềm có mục đích kiểm tra tính đúng đắn của sản phầm phần mềm. Trên thực tế, các thao tác kiểm thử đơn vị chỉ đánh giá được tính đúng sai của đầu vào và đầu ra của chương trình, không ki ểm tra được quá trình hoạt động logic của chương trình có theo đúng đ ặc tả ban đầu hay 2 không. Những đơn vị chương trình nhỏ này nếu không được kiểm tra kỹ sẽ có thể gây ra thiệt hại nặng nề khi tích hợp chúng để tạo thành chương trình hoàn ch ỉnh. Vấn đề đặt ra là cần có phương pháp kiểm chứng các đặc tả giao thức giữa các đối tượng, các tác tử ngay trong thời gian chạy, đánh giá xem trong thời gian chạy đối tượng hay tác tử phần mềm có vi phạm các giao thức ràng buộc đã được đặc tả hay không, và từ đó đảm bảo chắc chắn hơn tính đúng đắn của sản phầm phần mềm. Trong khóa luận này, tôi xin giới thiệu phương pháp tự động sinh mã aspect kiểm chứng đặc tả giao thức trong thời gian chạy, dựa trên phương pháp lập trình hư ớng khía cạnh (Aspect – Oriented Programming). 1.2 Nội dung bài toán Hiện nay có rất nhiều phương pháp kiểm chứng phần mềm như giả lập hay kiểm chứng mô hình. Trong phạm vi bài toán được đặt ra ở đây, tôi muốn đề cập tới phương pháp kiểm chứng phần mềm dựa trên phương pháp lập trình hướng khía cạnh (AOP) [7, 12]. Lĩnh vực kiểm chứng cụ thể trong phạm vi bài toán là kiểm chứng giao thức đặc tả hoạt động của các đối tượng Java và kiểm chứng giao thức giữa các tác tử trong hệ đa tác tử (giao thức được mô tả bằng biểu đồ trạng thái và biểu đồ trình tự UML, AUML) trong thời gian chạy. Trong cách tiếp cận này, một ứng dụng hướng đối tượng được đặc tả bằng mô hình UML và được cài đặt bằng ngôn ngữ Java; một hệ đa tác tử được đặc tả bằng các biểu đồ AUML và được cài đặt dựa trên JADE framework. Các aspect sau đó sẽ được đan vào khung mã Java đ ể kiểm tra tại bất kỳ thời điểm nào trong thời gian chạy, các đối tượng Java, các tác tử phần mềm hoạt động vi phạm giao thức đã đặc tả (aspect là mô-đun cắt ngang hệ thống). Bài toán có nhiệm vụ là tạo ra được các aspect từ biểu đồ trạng thái và biểu đồ trình tự UML; dùng công cụ AspectJ để đan các aspect này vào khung chương trình Java chính . Khi đó, trong quá trình ch ạy của chương trình, các đoạn mã aspect sẽ tự động kiểm tra các đặc tả giao thức và đưa ra thông báo lỗi khi có bất kỳ vi phạm nào xảy ra. Trong khi phương pháp kiểm thử đơn vị chỉ xác định được tính đúng đắn của đầu vào và đầu ra của chương trình, không kiểm tra được những lỗi logic thì phương pháp kiểm tra tính đúng đắn ngay tại thời gian chạy của chương trình sẽ đem lại hiệu quả rất lớn. Nhiệm vụ chính của bài toán là xây dựng phương pháp tạo ra các đoạn mã aspect để kiểm chứng, xây dựng công cụ Protocol Verification Generator(PVG) tự động sinh mã aspect kiểm chứng từ đặc tả giao thức bằng biểu đồ trạng thái và biểu đồ trình tự UML, AUML. Tôi xin đề cập hướng nghiên cứu kiểm chứng đặc tả UML cho tác tử 3 phần mềm để kiểm chứng giao thức giữa các đối tượng Java trong thời gian chạy và kiểm chứng giao thức giữa các tác tử trong hệ đa tác tử được xây dựng trên JADE framework. Từ một biểu đồ trạng thái hay biểu đồ trình tự UML, AUML xuất ra tài liệu XMI đặc tả các biểu đồ này. Các tài liệu XMI chính là đầu vào cho công cụ cần xây dựng. Dựa vào các kiến thức về UML, XML tôi sẽ phân tích tài liệu XMI, xây dựng máy trạng thái (FSM) mô tả các biểu đồ UML, AUML. Sử dụng máy trạng thái vừa tạo để sinh ra mã aspect phục vụ cho việc kiểm chứng sau này. Mã aspect chính là đầu ra cuối cùng của công cụ. 1.3 Tổng quan phương pháp “Kiểm chứng đặc tả UML cho tác tử phần mềm” Bài toán bắt đầu với đầu vào là một biểu đồ trạng thái hay biểu đồ trình tự UML, các biểu đồ này sẽ được xuất ra dạng XMI. Sau đó, lấy ra các thông tin cần thiết mô tả các đối tượng của biểu đồ và chuyển thành một máy trạng thái (FSM). Lập trình viên sẽ phát triển các mô-đun nghiệp vụ chính từ hai biểu đồ này và các biểu đồ UML khác còn lại. Song song với nó là quá trình xây dựng các mô-đun cắt ngang hệ thống thành các aspect từ máy trạng thái. Bài báo “Checking Interface Interaction Protocols Using Aspect-oriented Programming” [5] đã xây dựng phương pháp kiểm chứng giao thức xử dụng AOP. Dựa vào nội dung phương pháp này tôi đã xây d ựng công cụ tự động hóa việc sinh các mô-đun aspect với đầu vào là tài liệu XMI mô tả biểu đồ trạng thái hay biểu đồ trình tự UML. Phương pháp xây dựng công cụ Protocol Verification Generator của tôi gồm hai bước: - Bước1: Phân tích tài liệu XMI, lấy các thông tin cần thiết mô tả biểu đồ UML để xây dựng máy trạng thái. Đầu tiên, tôi sẽ phân tích tài liệu XMI, xây dựng các cấu trúc dữ liệu mô tả các thành phần của biểu đồ UML bằng ngôn ngữ Java, sau đó sử dụng thư viện XML DOM đọc tài liệu XMI này, lấy dữ liệu theo cấu trúc đã định nghĩa trước, tạo ra FSM. - Bước 2: Xây dựng bộ sinh tự động aspect từ FSM: Sử dụng FSM vừa được sinh ra, duyệt từng trạng thái trong FSM, áp dụng phương pháp cài đặt aspect trong bài báo nói trên, tôi sẽ tạo ra các join point, pointcut và advice từ các trạng thái đó để hình thành mô-đun aspect. Trong hình minh họa dưới đây, tôi sẽ xây dựng công cụ Protocol Verification Generator. Kết quả thu được là các đoạn mã aspect sẽ được đan vào chương trình Java thông qua trình biên dịch AspectJ. Kết quả cuối cùng của quá trình này chính là hệ 4 thống có chứa những đoạn mã kiểm chứng. Trong quá trình thực thi, kể cả trong thời gian chạy, bất cứ khi nào xảy ra vi phạm ràng buộc đã định nghĩa trong biểu đồ UML thì chương trình đều báo thông báo lỗi cho lập trình viên, chỉ ra vị trí dòng mã nguồn sai đặc tả trong mã nguồn của chương trình. Nhờ đó, lập trình viên có thể kiểm soát được hệ thống và làm cho hệ thống chạy ổn định và đúng đắn hơn. Use Case Diagram Class Diagram Sequence Diagram State Diagram ……. UML XMI File (*.xmi, *.xml) Protocol Specification AspectJ Generator Java code AspectJ codeAspectJ Weaver Bytecode with Protocol checking Hình 1.1: Quy trình kiểm chứng phần mềm dựa vào AOP 1.4 Cấu trúc khóa luận Các phần còn lại của khóa luận được phân bố như sau: Chương 2: Giới thiệu về phương pháp lập trình hướng khía cạnh. Trong chương này tôi sẽ đưa ra những so sánh giữa hai phương pháp OOP và AOP, từ đó nêu bật những ưu điểm của AOP; vai trò và ý nghĩa c ủa AOP đối với công nghệ phần mềm hiện nay. Đồng thời, tôi cũng gi ới thiệu công cụ AspectJ – một cài đặt của AOP cho ngôn ngữ lập trình Java. Chương 3: Trình bày sơ qua v ề các kiến thức về: UML, XML, XMI; trình bày một số khái niệm về tác tử phần mềm, phần mềm hướng agent và AUML – mở rộng từ UML để mô tả các hệ thống dựa tác tử. Giới thiệu JADE – một framework hỗ trợ xây dựng hệ đa tác tử trên ngôn ngữ Java. Đây là nền tảng kiến thức căn bản để xây dựng công cụ tự sinh mã aspect trong khóa luận của tôi. Chương 4: Trình bày phương pháp xây dựng máy trạng thái mô tả biểu đồ trạng thái và biểu đồ trình tự UML. Trong chương này, tôi sẽ trình bày cách phân tích tài 5 liệu XMI mô tả các biểu đồ UML, từ đó xây dựng các cấu trúc dữ liệu cần thiết để lấy dữ liệu từ tài liệu XMI hình thành nên máy trạng thái. Chương 5: Xây dựng công cụ tự sinh mã aspect từ máy trạng thái. Trong chương này, tôi sẽ trình bày chi tiết thuật toán sinh mã aspect từ máy trạng thái mô tả biểu đồ UML. Đồng thời tôi trình bày phương pháp sinh mã aspect kiểm chứng giao thức (AB)n – một mở rộng cho công cụ Protocol Verification Generator. Chương 6: Cài đặt công cụ Protocol Verification Generator tự sinh aspect. Sau đó, tiến hành kiểm chứng một số giao thức thực tế. Chương 7: Đưa ra các kết luận của khóa luận và hướng nghiên cứu tiếp theo trong tương lai. 6 Chương 2. Giới thiệu lập trình hư ớng khía cạnh (Aspect-Oriented Programming) và AspectJ 2.1 Phương pháp lập trình hướng khía cạnh Có lẽ các khái niệm về lập trình hướng khía cạnh (AOP) hiện nay đã được nhiều người biết đến, vì vậy ở đây tôi sẽ chỉ trình bày lại ngắn gọn các khái niệm cơ bản và đặc điểm chính của AOP. Để trả lời được câu hỏi AOP là gì? Tại sao phải có AOP? chúng ta sẽ bắt đầu tìm hiểu sự hạn chế của các phương pháp lập trình hiện tại trong việc đáp ứng các yêu cầu ngày càng phức tạp của các hệ thống phần mềm. 2.1.1 Sự hạn chế của lập trình hướng đối tượng (OOP) Như chúng ta đã bi ết trong OOP người ta cố gắng mô tả thế giới thực thành các đối tượng với các thuộc tính và phương thức; cùng với các tính chất của lập trình hướng đối tượng như: tính trừu tượng, tính đóng gói, tính kế thừa và đa hình đã làm thay đổi hoàn toàn ngành công nghiệp phần mềm. Hình 2.1: OOP Ta xét một bài toán cụ thể: Cần xây dựng một chương trình vẽ hình đơn giản như hình vẽ mô tả dưới đây: 7 Hình 2.2: Mô tả chương trình vẽ hình đơn giản Một phân tích đơn giản cho yêu cầu của bài toán: - Các hình học cơ bản: điểm, đoạn thẳng, hình chữ nhật, hình tròn… - Hiển thị các hình ở các vị trí khác nhau trong khung vẽ. - Phải cập nhật lại hình tại vị trí mới mỗi khi di chuyển, co giãn hình. Sử dụng OOP ta sẽ mô hình hóa yêu cầu thành các đối tượng như sau: - Lớp Shape: là một lớp Abstract chứa phương thức moveBy(int, int) – di chuyển hình. - Lớp Display: hiển thị hình ảnh. - Lớp Point: mô tả một điểm hình học. Chứa hai thuộc tính là hai tọa độ x, y và được kế thừa từ lớp Shape. - Lớp Line: mô tả đoạn thẳng, chứa hai thuộc tính là hai điểm mút của đoan thẳng và cũng được kế thừa từ lớp Shape. Ở đây tôi không đi quá sâu vào đặc tả bài toán, chỉ mô tả một số lớp đơn giản nhất. Dưới đây là sơ đồ lớp cho bài toán vẽ hình: 8 Hình 2.3: Sơ đồ lớp cho bài toán vẽ hình Mô hình hóa thành các lớp như vậy ta thấy bài toán đã tương đối ổn. Bây giờ vấn đề đặt ra là mỗi khi ta thay đổi tọa độ của một điểm hay co giãn hình, di chuyển hình ta lại phải vẽ lại hình ở vị trí mới – tức là phải update lại Display. Xét lớp đơn giản nhất là lớp Point, Khi đặt lại tọa độ x, tọa độ y, hay di chuyển Point từ vị trí này sang vị trí khác, ta đều phải update lại Display thông qua phương thức display.update(this). Như vậy, cùng một phương thức display.update(this), ta phải gõ lại ở ba vị trí khác nhau ứng với ba sự thay đổi. Hãy thử tưởng tượng xem nếu chương trình của chúng ta đủ lớn và có khoảng vài ngàn sự thay đổi kiểu như thế thì dòng mã nguồn display.update(this) sẽ phải xuất hiện ở hàng ngàn chỗ khác nhau. Đối với lớp Line hay các lớp khác cũng vậy. Mỗi khi có sự thay đổi hình thì ngay sau sự thay đổi đó sẽ có dòng mã nguồn display.update(this) đi kèm theo nó. Hình 2.4: Cập nhật hình khi có sự thay đổi 9 Giả sử chương trình vẽ hình của chúng ta đã hoàn thành mỹ mãn với đầy đủ các chức năng cơ bản. Đột nhiên, khách hàng yêu cầu cần phải ghi lại những sự thay đổi khi vẽ hình ra một file log.txt. Ôi! Điều này thực sự là rất khổ sở cho lập trình viên khi phải dò lại toàn bộ mã nguồn, xem đoạn nào có sự thay đổi hình, chèn thêm vào đó một dòng mã nguồn có chức năng lưu vết ra file log.txt. Ta có thể chia các chức năng của một phần mềm ra làm hai loại chính: - Thứ nhất là các chức năng thực hiện các nghiệp vụ chính, nghiệp vụ cơ bản của hệ thống (ví dụ như chức năng vẽ điểm, vẽ đoạn thẳng, vẽ hình khối trong bài toán vẽ hình ở trên). - Thứ hai, những chức năng dàn trải trên rất nhiều các mô-đun nghiệp vụ chính – được gọi là các chức năng cắt ngang hệ thống (ví dụ: cập nhật hình, lưu vết, bảo mật) hay được gọi là crosscutting concern. OOP có thể giải quết rất tốt những chức năng chính của hệ thống, nhưng lại gặp rất nhiều khó khăn trong việc giải quyết các chức năng cắt ngang hệ thống. Khi sử dụng OOP để thực hiện các chức năng cắt ngang hệ thống, hệ thống sẽ gặp phải hai vấn đề chính, đó là: chồng chéo mã nguồn (Code tangling) và dàn trải mã nguồn (Code scattering) [12]. - Chồng chéo mã nguồn: Mô-đun chính của hệ thống ngoài việc thực hiện các yêu cầu chính, nó còn phải thực hiện các yêu cầu khác như: tính đồng bộ, bảo mật, lưu vết, lưu trữ. Như vậy, trong một mô-đun có rất nhiều loại mã khác nhau, hiện tượng này gọi là chồng chéo mã nguồn. Điều này làm cho tính mô-đun hóa của hệ thống giảm đi, khả năng sử dụng lại mã nguồn thấp, khó bảo trì hệ thống. - Dàn trải mã nguồn: Cùng một mã nguồn của các chức năng cắt ngang hệ thống được cài đặt lặp đi lặp lại rất nhiều lần ở nhiều mô-đun chính của hệ thống. Ví dụ như trong chương trình vẽ hình ở trên, mã nguồn của chức năng cập nhật hình, lưu v ết xuất hiện ở tất cả các mô-đun của hệ thống. Hiện tượng này gọi là dàn trải mã nguồn. 2.1.2 Lập trình hướng khía cạnh (AOP) Lập trình hướng khía cạnh được xây dựng trên các phương pháp lập trình hiện tại như lập trình hướng đối tượng, lập trình có cấu trúc, bổ sung thêm các khái niệm và cấu trúc để mô-đun hóa các chức năng cắt ngang hệ thống (crosscutting concern). Với AOP, các quan hệ cơ bản sử dụng các phương pháp cơ bản. Nếu sử dụng OOP, sẽ thực 10 thi các quan hệ cơ bản dưới hình thức lớp (class). Các aspect trong hệ thống đóng gói các chức năng cắt ngang hệ thống lại với nhau. Chúng sẽ quy định cách các mô-đun khác nhau gắn kết với nhau để hình thành lên hệ thống cuối cùng. Nền tảng cơ bản của AOP khác với OOP là cách quản lý các chức năng cắt ngang hệ thống. Việc thực thi của từng chức năng cắt ngang AOP bỏ qua các hành vi được tích hợp vào nó. Ví dụ một mô-đun nghiệp vụ sẽ không quan tâm nó cần được lưu vết hoặc được xác thực như thế nào, kết quả là việc thực thi của từng concern tiến triển một cách độc lập. Quay trở lại với ví dụ về chương trình vẽ hình đơn giản ở phần trên. Nếu sử dụng AOP, các chức năng cắt ngang hệ thống: cập nhật hình, lưu vết sẽ được giải quyết theo cách sau: Thay vì tích hợp chức năng các mô-đun cắt ngang hệ thống (cập nhật hình, lưu vết) ngay trong mô-đun nghiệp vụ chính; lập trình viên sẽ tách chúng ra thành các mô- đun mới, gọi là aspect. Hình 2.5 minh họa cho việc thực thi chức năng cập nhật hình bằng AOP và dưới đây là mã nguồn của aspect đó public aspect UpdateSignaling { pointcut updateDisplay(): execution(void *.setX(int)) || execution(void *.setY(int)) || execution(void *.moveBy(int,int)); after(): updateDisplay() { display.update(this); } } Hình 2.5: Dùng AOP giải quyết bài toán vẽ hình 11 Sau khi định nghĩa một aspect như vậy thì bất cứ khi nào có sự thay đổi về hình (setX, setY, moveBy) chương trình s ẽ tự động gọi chức năng cập nhật hình, cụ thể ở đây là phương thức display.update(this) mà ta không cần phải lục lọi lại các đoạn mã nguồn để thêm nó dòng mã nguồn này vào. (các khái niệm cơ bản của aspect như: advice, join point, pointcut, aspect tôi sẽ trình bày cụ thể trong phần 2.2 nói về AspectJ). 2.1.2.1 Phương pháp luận của AOP Vấn đề cốt lõi của AOP là cho phép chúng ta thực hiện các vấn đề riêng biệt một cách linh hoạt và kết nối chúng lại để tạo nên hệ thống cuối cùng. AOP bổ xung cho OOP bằng việc hỗ trợ một dạng mô-đun khác, cho phép kéo theo thể hiện chung của các vấn đề đan nhau vào một khối. Khối này gọi là ‘aspect’ (tạm dịch là ‘lát’ – hàm ý cắt ngang qua nhiều lớp đối tượng). Từ chữ ‘aspect’ này chúng ta có mội phương pháp lập trình mới: Aspect-Oriented Programming. Nhờ mã được tách riêng biệt, các vấn đề đan xen nhau trở nên dễ kiểm soát hơn. Các aspect của hệ thống có thể thay đổi, thêm hoặc xóa lúc biên dịch và có thể tái sử dụng. Một dạng biên dịch đặc biệt có tên là Aspect Weaver thực hiện việc kết hợp các thành phần riêng lẻ thành một hệ thống thống nhất. 2.1.2.2 Ưu điểm của AOP AOP là một kỹ thuật mới đầy triển vọng, hứa hẹn đem lại nhiều lợi ích cho việc phát triển phần mềm, dưới đây là một số lợi ích cụ thể của AOP [12]: - Mô-đun hóa những vấn đề đan xen nhau: AOP xác định vấn đề một cách riêng biệt, cho phép mô-đun hóa những vấn đề liên quan đến nhiều lớp đối tượng. - Tái sử dụng mã nguồn tốt hơn: Các aspect là những mô-đun riêng biệt, được kết hợp linh động – đây chính là yếu tố quan trọng để tái sử dụng mã nguồn. - Cho phép mở rộng hệ thống dễ dàng hơn: Một thiết kế tốt phải tính đến cả những yêu cầu hiện tại và tương lai, việc xác định các yêu cầu trong tương lai là một công việc khó khăn. Nhưng nếu bỏ qua các yêu cầu trong tương lai, có thể bạn sẽ phải thay đổi hay thực hiện lại nhiều phần của hệ thống. Với AOP, người thiết kế hệ thống có thể để lại quyết định thiết kế cho những yêu cầu trong tương lai nhờ thực hiện các aspect riêng biệt. 12 2.2 AspectJ AspectJ là sự mở rộng theo mô hình AOP của ngôn ngữ Java, với sự mở rộng này mã chương trình viết bằng Java sẽ tương thích với chương trình viết bằng AspectJ. AspectJ gồm hai phần cơ bản là: - Đặc tả ngôn ngữ: Chỉ ra cách viết mã, với AspectJ các chức năng cơ bản của hệ thống sẽ được viết bằng Java còn các chức năng cắt ngang hệ thống sẽ được thực hiện bởi AspectJ. - Phần thực thi: Cung cấp các công cụ biên dịch, gỡ lỗi. AspectJ đã đư ợc plugin vào công cụ phát triển Eclipse ( và được đánh giá là sản phẩm tốt nhất hiện nay về AOP. Một số khái niệm cơ bản trong AspectJ: 2.2.1 Join point Join point là bất kỳ điểm nào có thể xác định được khi thực hiện chương trình [7, 12]. Ví dụ: lời gọi hàm, khởi tạo đối tượng. Join point chính là vị trí mà các hành động thực thi cắt ngang được đan vào. Trong AspectJ mọi thứ đều xoay quanh join point. Một số loại join point chính trong AspectJ: - Join point tại hàm khởi tạo (constructor). - Join point tại các phương thức. - Join point tại các điểm truy cập thuộc tính. - Join point tại các điểm điều khiển ngoại lệ: Được điều khiển trong khối điều khiển ngoại lệ. 2.2.2 Pointcut Pointcut là một cấu trúc chương trình mà nó chọn các join point và ngữ cảnh tại các join point đó [7, 12]. Ví dụ một pointcut có thể chọn một join point là lời gọi đến một phương thức và lấy thông tin ngữ cảnh của phương thức đó như đối tượng chứa phương thức đó, các tham số của phương thức đó. Cú pháp của pointcut được khai báo như sau: [access specifier] pointcut pointcut-name([args]) : pointcut- definition; Ví dụ: public pointcut test(): call(void Line.setP1(Point)); 13 Bảng 2.1: Ánh xạ giữa các loại join point và pointcut tương ứng: Loại join point Cú pháp pointcut Thực hiện phương thức execution(MethodSignature) Gọi phương thức call(MethodSignature) Thực hiện hàm dựng execution(ConstructorSignature) Gọi hàm dựng call(ConstructorSignature) Khởi tạo lớp staticinitialization(TypeSignature) Đọc thuộc tính get(FieldSignature) Ghi thuộc tính set(FieldSignature) Thực hiện điều khiển ngoại lệ execution handler(TypeSignature) Khởi tạo đối tượng initialization(ConstructorSignature) Tiền khởi tạo đối tượng preinitialization(ConstructorSignature) Thực hiện advice adviceexecution() 2.2.3 Advice Advice là mã thực hiện tại một join point mà được chọn bởi pointcut [7, 12]. Hay nói cách khác, nếu ta coi pointcut là khai báo tên phương thức, thì advice là phần thân của phương thức đó. Pointcut và advice sẽ hình thành nên các luật đan kết các quan hệ đan xen. Advice được chia ra làm ba loại sau: - Before: Được thực hiện trước join point. - After: Được thực hiện sau join point. - Around: Thực thi xung quanh join point. Giả sử ta có pointcut được khai báo như sau: pointcut updateDisplay(): execution(void *.moveBy(int,int)) Ta có thể xây dựng các advice như sau: - Before advice thự hiện lưu vết before() : updateDisplay() { 14 // logging } - After advice thực hiện cập nhật hình after() : updateDisplay() { display.update(this); } Ví dụ về around advice dùng để kiểm tra thuộc tính age của lớp Person trong phương thức setAge() có vi phạm điều khiện không (điều kiện: age > 0). void around(Person person, int age):setAge(person, age) { if(age > 0) Process(person,age); else System.out.println("Invalid Age!"); } 2.2.4 Aspect Aspect là phần tử trung tâm của AspectJ, giống như class trong Java. Aspect chứa mã thể hiện các luật đan kết cho các concern. Join point, pointcut, advice được kết hợp trong aspect [7, 12]. Aspect được khai báo theo mẫu sau: [access specification] aspect [extends class-or-aspect-name] [implements interface-list] [(Pointcut)] { ... aspect body } Ví dụ: public abstract aspect AbstractLogging { public abstract pointcut logPoints(); public abstract Loger getLogger(); before():logPoints() { getLogger().log(Level.INFO, “Before” + thisJoinPoint); } } Tuy có gần giống các đặc điểm của class trong Java như: chứa thuộc tính, phương thức, có thể khai báo trừu tượng, có thể kế thừa… Tuy nhiên, Aspect có một số khác biệt cơ bản sau: 15 - Aspect không thể khởi tạo trực tiếp. - Aspect không thể kế thừa từ một aspect cụ thể (không phải trừu tượng) Aspect có thể được đánh dấu là có quyền bằng định danh privileged. Nhờ đó nó có thể truy cập đến các thành viên của lớp mà chúng cắt ngang. 2.2.5 Cơ chế họa động của AspectJ Aspect compiler là thành phần trung tâm của AspectJ, nó có nhiệm vụ kết hợp các file mã nguồn Java với các aspect lại với nhau để tạo ra chương trình cu ối cùng. Quá trình dệt có thể xảy ra ở các thời điểm khác nhau: compile – time, link – time và load – time [7]: - Compile – time: Dệt trong thời gian biên dịch là cách đơn giản nhất. Mã nguồn Java và các aspect sẽ được kết hợp với nhau trước khi trình biên dịch dịch mã nguồn ra dạng byte code. Hay nói cách khác, trước khi biên dịch, các mã aspect sẽ được phân tích, chuyển đổi sang dạng mã Java và được chèn chính xác vào các vị trí đã định nghĩa sẵn trong mã nguồn Java chính của chương trình. Sau đó trình biên dịch sẽ dịch mã đã được dệt này ra dạng byte code. AspectJ 1.0.x sử dụng cách này để dệt chương trình. - Link – time: Quá trình dệt được thực hiện sau khi mã nguồn Java và các aspect được biên dịch ra dạng byte code. Một bộ xử lý tĩnh được sử dụng để đánh dấu các điểm gọi hàm trong mã được viết bằng java. Khi một hàm được thực thi. Runtime system sẽ phát hiện ra điểm nào cần gọi đến mã aspect để thực thi và khi đó mã aspect sẽ được gọi để đan vào chương trình chính. AspectJ 1.1.x sử dụng cách này để dệt chương trình. - Load – time: Quá trình dệt được thực hiện khi máy ảo Java tải một class vào để chạy. Theo cách này, mã nguồn Java và các aspect được biên dịch ra dạng byte code. Quá trình dệt diễn ra khi classloader nạp một class. AspectJ 1.5.x sử dụng cách này để dệt chương trình. 2.3 Sử dụng AOP Phát triển ứng dụng và phương pháp kiểm chứng dựa trên AOP Ngày nay, AOP được ứng dụng rộng rãi trong việc phát triển phần mềm. Phát triển hệ thống sử dụng AOP tương tự như phát triển hệ thống sử dụng các phương pháp khác, cũng g ồm các bước như: xác định concern, cài đặt concern và kết hợp 16 chúng lại tạo thành hệ thống cuối cùng. Cộng đồng nghiên cứu AOP đề xuất ba bước [12] thực hiện như sau: - Phân tích bài toán theo khía cạnh (Aspectual decomposition): Trong bước này chúng ta phân tích các yêu cầu nhằm xác định các chức năng chính của hệ thống và các chức năng cắt ngang hệ thống. Các phương thức cắt ngang hệ thống được tách ra khỏi các chức năng chính. - Xây dựng các chức năng (Concern Implementation): Cài đặt các chức năng một cách độc lập. - Kết hợp các khía cạnh lại để tạo nên hệ thống hoàn chỉnh (Aspectual Recompositon): Trong bước này chúng ta chỉ ra các quy luật kết hợp bằng cách tạo ra các aspect. Quá trình này gọi là quá trình dệt mã, sử dụng các thông tin trong aspect để cấu thành hệ thống cuối cùng. Hình 2.6: Các giai đoạn phát triển ứng dụng sử dụng AOP AOP đã được nghiên cứu và áp dụng vào rất nhiều ngôn ngữ lập trình như: Java, C, C#, PHP. Một số dự án được liệt kê trong bảng dưới đây: Bảng 2.2: Các dự án nghiên cứu AOP Tên dự án Địa chỉ 1. AspectJ 1. AspectWerkz 2. Jboss AOP 3. Sping AOP 4. Aspect# 5. AspectC++ 6. JAC 17 Từ khả năng mô-đun hóa các quan hệ đan xen, các chức năng cắt ngang hệ thống; tách rời sự hoạt động của các mô-đun cũng như nhiều ưu điểm khác của AOP so với OOP mà hiện nay AOP đã trở thành sự lựa chọn phù hợp cho rất nhiều hệ thống phần mềm; đặc biệt là trong các chức năng lưu vết, bảo mật, xác thực của hệ thống phần mềm. Ngoài ra, do các mã aspect độc lập với mã nguồn chính của chương trình, có thể sửa đổi tùy theo ý muốn của lập trình viên, chính vì vậy AOP còn đư ợc ứng dụng rất lớn vào các loại kiểm chứng trong quá trình thiết kế phần mềm. Ví dụ như: kiểm chứng giao thức [5], kiểm tra việc gọi tuần tự các hàm trong chương trình [15]… Nội dung chính của các phương pháp kiểm chứng dựa trên AOP là dựa vào những kiến khái niệm cơ bản của AOP như: join point, pointcut, advice, aspect để xây dựng nên các mô-đun kiểm chứng (các aspect) từ các chức năng cắt ngang hệ thống. Các aspect này sẽ được đan vào khung mã ngu ồn chương trình thông qua trình biên dịch AspectJ để thực hiện chức năng kiểm chứng. 2.4 Kết luận Trong chương 2 này, tôi trình bày tất cả những khái niệm cơ bản về phương pháp lập trình hướng khía cạnh AOP và AspectJ – sự mở rộng của AOP cho Java. Ứng dụng của AOP vào phát triển và kiểm chứng phần mềm. AOP vẫn là một ý tưởng mới, vẫn cần có thời gian để đánh giá, tìm hiểu các kỹ thuật hiện có và để phát triển, ứng dụng rộng rãi 18 Chương 3. Agent UML và JADE framework 3.1 Ngôn ngữ mô hình hóa UML 3.1.1 Khái niệm UML (Unified Modeling Language) là ngôn ngữ mô hình hóa đư ợc sử dụng để biểu diễn, đặc tả và xây dựng các thành phần của hệ thống phần mềm. Nó là một chuẩn của tổ chức OMG (Object management Group) [11]. UML giúp người sử dụng mô tả được các tài liệu đặc tả yêu cầu, tài liệu phân tích và tài liệu thiết kế ứng dụng. Hiện nay, nó được dùng để mô tả hình hóa gần như toàn bộ các hệ thống phần mềm từ nhỏ tới lớn, từ đơn giản tới phức tạp trên thế giới. UML sử dụng một hệ thống ký hiệu thống nhất để biểu diễn các phần tử mô hình. Tập các phần tử mô hình tạo nên các biểu đồ UML. Có nhiều loại biểu đồ UML như: biểu đồ ca sử dụng, biểu đồ lớp, biểu đồ tuần tự, biểu đồ trạng thái, biểu đồ hoạt động… Ở đây tôi chỉ trình bày hai loại biểu đồ được sử dụng làm đầu vào cho nghiên cứu của tôi; đó là: biểu đồ trạng thái (State Diagram) và biểu đồ trình tự (Sequence Diagram). 3.1.2 Biểu đồ trạng thái (State Diagram) Biểu đồ trạng thái là một sự bổ sung cho lời miêu tả biểu đồ lớp. Nó mô tả chu kỳ tồn tại của đối tương từ khi sinh ra đến khi bị phá hủy. Nó chỉ ra tất cả các trạng thái mà đối tượng của lớp này có thể có, các hành vi của đối tượng và những sự kiện tác động làm thay đổi trạng thái. Ví dụ: Hình 3.1: Biểu đồ trạng thái thực hiện hóa đơn Một trạng thái có thể có ba phần sau: - Name: Tên của trạng thái, Ví dụ: Paid, Unpaid. 19 - State variables (các biến trạng thái – không bắt buộc): đây là những thuộc tính của lớp được thể hiện qua biểu đồ trạng thái - Activities (sự kiện – không bắt buộc): Đây là phần dành cho hoạt động nơi mà các sự kiện và hành động và liệt kê. Có ba loại sự kiện chuẩn hóa có thể được sử dụng cho hành động: o Entry: Xác định các hành động tạo trạng thái. o Exit: Xác định các hành động khi rời bỏ trạng thái. o Do: Xác định các hành động cần phải thực hiện trong trạng thái. Sự kiện là nguyên nhân của chuyển trạng thái. Một sự kiện có thể kích hoạt một hoặc nhiều hành động bởi một tác nhân. Trong UML, có các kiểu sư kiện: - Change events: Xuất hiện khi điều kiện thỏa mãn. - Signal events: Chỉ ra việc nhận một tín hiệu ngoài từ một đối tượng sang đối tượng khác. - Call events: Chỉ ra việc nhận một lời gọi hàm bởi một đối tượng hoặc tác nhân. - Time events: Đánh dấu việc chuyển trạng thái sau một khoảng thời gian. 3.1.3 Biểu đồ trình tự (Sequence Diagram) Biểu đồ trình tự minh họa các đối tượng tương tác với nhau ra sao. Chúng tập trung vào các chuỗi thông điệp, có nghĩa là các thông điệp gửi và nhận giữa một loạt các đối tượng như thế nào. Biểu đồ tuần tự có hai trục: trục dọc chỉ thời gian, trục nằm ngang chỉ ra một tập các đối tượng. Ví dụ: Hình 3.2: Biểu đồ tuần tự rút tiền từ máy ATM Một biểu đồ tuần tự cũng nêu bật sự tương tác giữa các đối tượng trong một kịch bản – một tương tác sẽ xảy ra tại một thời điểm nào đó trong quá trình thực thi hệ thống. 20 Biểu đồ tuần tự gồm hai thành phần chính: - Các đối tượng. - Các thông điệp trao đổi giữa các đối tượng. 3.2 XML (eXtensible Markup Language) 3.2.1 Cơ bản về XML XML kết hợp những ưu điểm của các ngôn ngữ trước đó (sự đơn giản của HTML và cấu trúc mô tả tài liệu của SGML), có khả năng mô tả nhiều loại dữ liệu khác nhau với mục đích là đơn giản hóa việc chia sẻ dữ liệu giữa các hệ thống khác nhau, đặc biệt là các hệ thống được kết nối với Internet. XML là ngôn ngữ đánh dấu với mục đích chung cho W3C đề nghị [6]. XML là một ngôn ngữ đánh dấu, nó gần giống với HTML (Hypertext markup Language). Nó cung cấp một phương tiện dùng văn bản để mô tả thông tin và áp dụng một cấu trúc kiểu cây cho thông tin đó. Mọi thông tin đều hiển thị dưới dạng văn bản (text), chen giữa các thẻ đánh dấu (markup) với nhiệm vụ ký hiệu sự phân chia thông tin thành một cấu trúc có thứ bậc của các dữ liệu ký tự [6]. Nội dung của một tài liệu XML gồm hai phần chính: - Nội dung chính: Hệ thống các thẻ đánh dấu tương ứng với các thông tin cần biểu diễn và có một node gốc. - Nội dung phụ: Bổ sung thông tin cho tài liệu XML, một số thẻ phụ: o Thẻ khai báo tham số: Một số tham số thường dùng như: tham số version (phiên bản chỉ định của XML), tham số encoding (cách mã hóa các ký tự), tham số standalone (liên kết với tài liệu xml khác). o Thẻ chỉ thị xử lý: Mô tả một số thông tin cho tài liệu XML nhưng có ý nghĩa riêng đối với một vài công cụ xử lý nào đó. C ấu trúc: <? Bo_Xu_Ly_Du_Lieu > Ví dụ: Định dạng thể hiện tài liệu XML với “chương trình đ ịnh dạng” theo ngôn ngữ CSS được lưu trữ bên trong tệp tin a.css. Thẻ này có ý nghĩa với một số trình duyệt như IE5, Netscape. o Thẻ ghi chú: Không ảnh hưởng đến tài liệu XML. 21 Cấu trúc: o Thẻ CDATA: Yêu cầu các bộ phân tích tài liệu XML bỏ qua không phân tích vào nội dung bên trong của thẻ này. Mục đích chính của thẻ này là cho phép sử dụng trực tiếp bên trong thẻ một số ký hiệu không được phép sử dụng bên ngoài. Ví dụ các ký tự ‘’. Cấu trúc: . o Thẻ khai báo thực thể: cho phép tài liệu XML tham chiếu đến một tập hợp các giá trị đã chuẩn bị trước dưới dạng một tên gợi nhớ (tên thực thể). Khai báo: <!DOCTYPE Ten_goc[ Khai báo thực thể tên X Khai báo thực thể tên Y] o Thẻ khai báo cấu trúc. Các thẻ XML không được định nghĩa trước trong cú pháp XML, người sử dụng có thể tự định nghĩa theo các thẻ theo ý thích khi sử dụng XML. XML sử dụng DTD hoặc XML schema để mô tả dữ liệu. XML biểu diễn dữ liệu bằng cách sử dụng các thành phần XML, trong đó chứa một trong các thành phần sau đây: - Thẻ bắt đầu: Chứa tên của thành phần. - XML attributes: Các thuộc tính, mỗi thuộc tính có tên và giá trị - Nội dung: Có thể chứa một đoạn văn bản hoặc thuộc tính, cũng có th ể chứa cả hai. - Thẻ kết thúc, giống với tên của thẻ bắt đầu. Ví dụ về một tài liệu XML: <?xml XML đã trở thành một công cụ rất mạnh và đơn giản để lưu trữ dữ liệu trên các file. Nó cho phép bạn lưu trữ dữ liệu theo mẫu và có thể truy xuất được bằng các ứng version="1.0" encoding="UTF-8"?> An edge of one graph Có 6 thành phần XML trong tài liệu này. Đầu tiên là chỉ thị xử lý, Phần tử edge chứa thuộc tính có tên là type và giá trị là directed. Phần tử edge chứa hai phần tử con là from và to chúng có hai thuộc tính là id. Phần tử comment chứa nội dung là một đoạn văn bản (text). 22 dụng khác nhau, nhưng nó không thể tạo ra dữ liệu. Bằng cách sử dụng các API như DOM, SAX, bạn có thể truy xuất dữ liệu từ một tài liệu XML rất dễ dàng. 3.2.2 XML DOM 3.2.2.1 DOM “The W3C Document Object Model (DOM) is a platform and language-neutral interfacethat allows programs and scripts to dynamically access and update the content, structure, and style of a document” []. DOM gồm ba phần riêng biệt: - Core DOM: Định nghĩa các đối tượng chuẩn cho các tài liệu có cấu trúc. - XML DOM: Định nghĩa tập hợp các đối tượng chuẩn cho tài liệu XML - HTML DOM: Định nghĩa tập các đối tượng chuẩn cho tài liệu HTML. 3.2.2.2 XML DOM XML DOM định nghĩa các đối tượng và thuộc tính của tất cả các thẻ của tài liệu XML và các phương thức (giao diện) để truy xuất chúng. Nó là một chuẩn để truy xuất, thêm, xóa, sửa các thẻ XML. Trong DOM, mọi thứ trong tài liệu đều là nút (node): - Toàn bộ tài liệu là một nút tài liệu (document node) – cây node o Một cây gồm nhiều node. o Node cao nhất gọi là root. o Mỗi node, trừ root ra có chính xác một node cha. o Một node có nhiều node con. o Node lá là node không có node con. - Mọi thẻ XML là một nút thẻ (element node). - Text trong các thẻ XML là nút text (text node). - Mọi thuộc tính là nút thuộc tính (attribute node). - Ghi chú là nút ghi chú (comment node). 3.2.2.3 XML DOM Parser Để đọc, cập nhật và thao tác trên một tài liệu XML ta cần một XML Parser. Có nhiều XML Parser được hỗ trợ trong hầu hết các ngôn ngữ (Java, .Net…). Parser nạp tài liệu XML vào trong bộ nhớ của máy tính và được xem dưới dạng cây node. Sau đó dữ liệu sẽ được thao tác và xử lý thông qua tập hàm XML DOM API. 23 Hình 3.3: XML DOM Parser 3.2.2.4 XML DOM API Cung cấp các phương thức xử lý tài liệu XML. Trong XML DOM API có rất nhiều phương thức để có thể thao tác với tài liệu XML, ở đây tôi xin chỉ ra một số phương thức thường sử dụng nhất để thao tác với tài liệu XML: - Duyệt node: o ParentNode: Lấy node cha của node hiện tại o ChildNodes: Lấy các node con của node hiện tại o firstChild: Lấy node con đầu tiên của node hiện tại o lastChild: Lấy node con cuối cùng của node hiện tại o nextSibling: Lấy node kết tiếp node hiện tại. o previousSibling: Lấy node trước node hiện tại. - Thao tác trên các node: o getElementsByTagName(String tagname): Trả về một tập các node có thuộc tính tên là: tagname. o getElementById(String id): Trả về một node có thuộc tính id là: id o setAttribute(String name, String value): Đặt thuộc tính cho node với tên thuộc tính là name, giá trị là value. o getAttribute(String name): lấy giá trị của thuộc tính có tên là name o removeChild: Xóa node con của node hiện tại o removeAttribute: Xóa bỏ thuộc tính của node hiện tại 24 o replaceChild: Thay thế node con của node hiện tại bằng một node mới. o createNode: Dùng để tạo ra tất cả các loại node. o createElement: = createNode với loại element node. o createTextNode: = createNode với loại text node o createAttribute: = createNode với loại attribute node. o nodeCha.appendChild: thêm vào phần tử cuối cùng của danh sách các node con của nodeCha. o nodeCha.insertBefore: thêm node mới vào trước node nào đó trong danh sách node con của nodeCha. 3.3 XMI (XML Metadata Interchange) XMI là một chuẩn OMG cho việc trao đổi siêu dữ liệu (metadata) giữa các công cụ, các kho dữ liệu và các ứng dụng. Nó là một chuẩn cho phép người dùng mô tả đối tượng bằng cách sử dụng XML. Nó làm việc dựa trên các chuẩn như W3C XML, OMG UML và MOF [14]. Mặc dù XML có rất nhiều ưu điểm, nhưng vẫn có một khoảng cách nhất định giữa XML với các đối tượng (objects). XML định nghĩa các phần tử XML, các thuộc tính, không phải là đối tượng. Nó không cung cấp các đặc điểm của hướng đối tượng như đa thừa kế và nó không chứa mô hình đối tượng. Tồn tại nhiều cách khác nhau để lưu trữ dữ liệu XML và nếu sử dụng các công cụ khác nhau để lưu trữ XML thì sẽ gây ra khó khăn trong việc trao đổi dữ liệu. Khi ta lưu trữ đối tượng bằng XML cũng vậy, nếu đối tượng được lưu trữ khác nhau trong XML thì rất khó khăn để trao đổi giữa các công cụ. Tuy nhiên, XMI ra chính là cầu nối liền khoảng cách giữa đối tượng và XML. Nó cung cấp một chuẩn để tạo ra một ánh xạ từ một đối tượng được định nghĩa bằng UML đến XML. 25 Hình 3.4: Sử dụng XMI trao đổi thông tin giữa các công cụ khác nhau. XMI được xây dựng dựa trên XML, vì vậy chúng ta hoàn toàn có thể sử dụng các API chuẩn thao tác với XML như DOM, SAX để thao tác với tài liệu XMI. Trong nghiên cứu của tôi, tôi sử dụng DOM XML cho ngôn ngữ Java để thao tác với tài liệu XMI. 3.4 AUML (Agent UML) Trước khi đi vào tìm hi ểu về AUML, tôi xin giới thiệu qua một số khái niệm cơ bản về tác tử phần mềm (agent) và phần mềm hướng tác tử để ta có một cái nhìn tổng quan nhất về một phần mềm hướng tác tử. 3.4.1 Tác tử phần mềm là gì? Theo từ điển Heritage của Mỹ: “Agent là một đối tượng mà có ảnh hưởng hay có khả năng và có quyền tác động hay đại diện cho một đối tượng khác”. Theo Ressel và Norvig: “Một agent có thể được xét tới bởi khả năng nhận thức về môi trườn nó đang tồn tại qua bộ cảm biến (sensor) và khả năng tác động lên môi trường đó qua cơ quan phản ứng (effector)”. Theo Pattie Maes: “Agent tự chủ là các hệ tính toán tồn tại trong môi trường động phức tạp, tri giác và hành động tự chủ trong môi trường này, qua đó hình dung được nhiệm vụ hoặc mục đích của mình”. Theo như các định nghĩa trên thì agent có thể là hệ thống phần cứng (điều nhiệt, tàu vũ trụ, xe tự hành…) hoặc phần mềm (kiểm tra thư, Antivirus, …) Ở đây ta đi vào một vấn đề nhỏ hơn, đó là tác tử phần mềm. Vậy tác tử phần mềm là gì? 26 Tác tử phần mềm là một chương trình máy tính t ồn tại trong môi trường nhất định, tự động hành động phản ứng lại sự thay đổi của môi trường nhằm đáp ứng mục tiêu đã được thiết kế trước []. Và có các tính chất như: - Antonomy (Tính tự chủ): Một agent có khả năng kiểm soát hành vi của mình độc lập với các thực thể khác. - Reactivity (Tính phản xạ): Agent có khả năng phản ứng lại các tác động từ môi trường theo một cơ chế nào đó. - Pro-activeness (Tính chủ động): Agent không chỉ phản ứng lại môi trường, chúng có thể hành động có mục đích và chủ động để tranh thủ thời cơ đạt được mục đích đó. Từ một mục tiêu, agent có khả năng xác định các hành động cần thiết và nó thực hiện một cách linh hoạt các hành vi đó để đạt được mục tiêu đề ra. - Social Ability (Tính cộng đồng): Agent có thể tương tác với những agent khác hay con người để hoàn thành công việc riêng của mình hay trợ giúp các agent khác trong những hoạt động nào đó. Dựa vào mức độ thông minh, tính di động hay số lượng agent, người ta phân agent ra một số loại như: agent cộng tác, agent giao diện, agent di dộng, agent thông tin, agent phản xạ, agent thông minh. 3.4.2 Phần mềm hướng Agent Công nghệ phần mềm hướng Agent phân rã bài toán thành nhiều thành phần tương tác và tự trị (agents) mà có các mục tiêu cụ thể để đạt tới. Phần mềm hướng agent là một phương pháp luận mới hỗ trợ cách tiếp cận được công nghệ hóa: phân tích và thiết kế hệ thống. - Phân tích hướng agent: Cũng giống như các phương pháp phân tích hệ thống khác, phân tích hướng agent cũng bắt đầu từ việc định nghĩa các yêu cầu và mục đích của hệ thống. Các mục đích toàn thể của ứng dụng được phân rã thành những mục tiêu con, nhỏ hơn; cho tới khi nào có thể quản lý được chúng. Việc phân tích hướng agent phải nhận ra được nhiệm vụ của một agent. - Thiết kế phần mềm hướng agent: Mỗi agent trong hệ thống được giao cho một hoặc một số nhiệm vụ riêng biệt. Các agent phải nắm được đầy đủ trách nhiệm đối với việc hoàn thành các nhiệm vụ được giao. Các nhiệm vụ cộng đồng biểu diễn các chức năng toàn cục của hệ thống agent. 27 Phát triển phần mềm hướng agent dựa vào các hệ đa agent – là một cộng đồng các agent, nơi mà tương tác qua lại giữa các agent và với môi trường của chúng tạo ra một hành vi toàn thể, hữu ích. Một hệ đa agent bao gồm các thành phần: - Các agent được xem như là các cá thể. - Tương tác giữa các agent - Sự phụ thuộc qua lại giữa agent và các quan hệ cộng đồng. Để hiểu rõ hơn phương pháp phân tích thi ết kế phần mềm hướng agent, tôi xin trình bày qua một số khái niệm cơ bản trong lý thuyết Gaia [10] – một lý thuyết dùng trong phân tích và thiết kế phần mềm hướng agent. Hình 3.5: Các khái niệm cơ bản của lý thuyết Gaia Trong pha phân tích: - Xác định các vai trò trong hệ thống và định nghĩa một dãy các vai trò chính bằng ngôn ngữ miêu tả phi hình thức. Với mỗi vai trò cần xác định các giao thức liên kết. - Đầu ra của pha phân tích là mô hình hoàn thiện của các vai trò – mô tả về trách nhiệm, quyền hạn, các giao thức tương tác, hoạt động và mô hình tương tác. Mỗi giao thức mô tả về sự chuyển đổi dữ liệu và các thành phần có liên quan. Pha thiết kế: Tập trung vào việc định nghĩa h ệ thống agent để nó có thể hoạt động. Nó bao gồm một số giai đoạn như sau: - Thứ nhất: Xác định mô hình agent, kết hợp vai trò vào các loại agent từ đó xây dựng hệ thống phân cấp các loại agent và ước lượng số lượng các thể hiện (instance) được yêu cầu đối với mỗi lớp. 28 - Thứ hai: Xác định các dịch vụ mà agent phải cung cấp để hoàn thành các nhiệm vụ mà chúng được giao bằng cách phân tích các nhiệm vụ và hoạt động. Đó chính là các giao thức được định nghĩa cho mỗi vai trò. - Thứ ba: Xác định các mô hình tích hợp để xác định các khả năng thiếu sót trong thiết kế. Kết quả đầu ra của pha thiết kế chính là kiến trúc thực tế của hệ thống agent. Nói đến agent cũng như phần mềm hướng agent còn rất nhiều vấn đề cần bàn như: kiến trúc agent, hệ đa agent, liên lạc/truyền thông trong hệ agent… trong phạm vi khóa luận của tôi, tôi không đề cập tới tất cả các kiến thức về agent, cách thức phân tích thiết kế, xây dựng phần mềm hướng agent; mà ở đây tôi chỉ trình bày một số khái niêm cơ bản nhất, đưa ra một cái nhìn tổng quan nhất về agent và phần mềm hướng agent. Các vấn đề này được trình bày kỹ trong [1, 3, 10]. 3.4.3 AUML (Agent Unified Modeling Language) Như ta đã biết UML là ngôn ngữ rất mạnh để mô hình hóa các đối tượng và thao tác của các đối tượng. Nó cung cấp các mô hình tĩnh (các bi ểu đồ lớp và gói) và các mô hình động (biểu đồ tương tác, biểu đồ trạng thái, biểu đồ hoạt động) để mô tả hệ thống phần mềm. Quá trình xây dựng các hệ thống dựa tác tử cũng đòi hỏi tất cả các quá trình của công nghệ phần mềm như: phân tích, thiết kế, đanh giá, bảo trì… Tuy nhiên, agent có nhiều điểm khác biệt so với các đối tượng nên có nhiều lúc UML không thể hỗ trợ toàn bộ để mô hình hóa hệ thống dựa agent. Vì vậy, để đặc tả cho hệ thống dựa tác tử, FIFA (Foundation for Intelligent Physical Agents) sử dụng UML mở rộng, gọi là AUML (Agent Unified Modeling Language) để mô hình hóa các hệ dựa tác tử, đặc tả giao thức tương tác tác tử (AIP – Agent Interaction Protocols). AUML là một hướng tiếp cận giao thức phân mức. Một giao thức tương tác tác tử (AIP) mô tả các mẫu truyền thông như một dãy các thông đi ệp giữa các agent và ràng buộc nội dung của các thông điệp này. AIP được mô tả gồm ba mức [8, 9]: - Mức 1: Mô tả giao thức liên lạc (UML Package and Template). - Mức 2: Mô tả tương tác giữa các agent (các biểu đồ tuần tự, cộng tác, hoạt động biểu đồ trạng thái). - Mức 3: Mô tả quá trình xử lý bên trong agent (activity diagram và statechart) 29 3.4.3.1 Mức 1 – biểu diễn giao thức liên lạc ở mức tổng quan UML cung cấp hai kỹ thuật nhằm biểu diễn các giải pháp cho giao thức, đó là package và template. - Package: Là tập các nhân tố mô hình hóa ở mức khái niệm Ví dụ sau được lấy trong [8] Hình 3.6: Ví dụ package Các gói cung cấp một kỹ thuật chung cho việc phân chia các mô hình và nhóm các thành phần mô hình. Mỗi gói được biểu diễn như sau: o Mỗi gói đóng là nhóm thành phần có quan hệ logic với nhau. o Kiến trúc của hệ thống được biểu diễn nhờ mô hình liên kết giữa các gói đóng o Một gói đóng có thể chứa các gói đóng khác. o Dùng một gói mô tả giao thức lồng nhau. - Template: là một thành phần mô hình được tham số hóa có các tham số bị ràng buộc. Ví dụ sau được lấy trong [8] 30 Hình 3.7: Một kịch bản giữa người mua hàn và ngời bán hàng 3.4.3.2 Mức 2 – biểu diễn tương tác giữa các agent Ở mức này, ta sử dụng các biểu đồ trong UML để biểu diễn các giao thức: - Biểu đồ tuần tự - Biểu đồ cộng tác - Biểu đồ hoạt động - Biểu đồ trạng thái Trong đó, biểu đồ tuần tự và biểu đồ cộng tác mô tả tương tác giữa các agent; còn biểu đồ hoạt động và biểu đồ trạng thái biểu diễn các luông xử lý. Các biểu đồ này biểu diễn các agent gần giống với UML biểu diễn các đối tượng, và mở rộng ra một chút cho phù hợp với agent. Như: AUML thêm các phần biểu diễn tương tác đa luồng ví dụ [8]: Hình 3.8 Tương tác đa luồng trong AUML Hình (a) biểu diễn các luồng được gửi đi song song (phép AND). Hình (b) bao gồm một hộp quyết định xác định xem luồng nào sẽ được gửi đi tiếp (phép OR). Hình (c) xác định trong một thời điểm chỉ có một luồng được phép gửi đi (phép XOR). 31 3.4.3.3 Mức 3 – biểu diễn xử lý bên trong Agent Tại mức thấp nhất, đặc tả về một giao thức. Agent yêu cầu giải thích rõ ràng những xử lý chi tiết bên trong agent để tiến hành giao thức. Các mô hình mức cao hơn (gọi là holon) bao gồm tập các agent ở mức thấp hơn. Các hành vi bên trong có thể được biểu diễn bằng việc sử dụng đệ quy các cách biểu diễn ở mức 2. Ví dụ: Hình 3.9: Các hành vi bên trong của agent Initiator (a) và Participant(b) 3.5 Java Agent DEvelopment Framework (JADE) 3.5.1 Khái niệm về JADE “JADE (Java Agent DEvelopment Framework) is a software Framework fully implemented in Java language. It simplifies the implementation of multi-agent systems through a middle-ware that complies with the FIPA specifications and through a set of graphical tools that supports the debugging and deployment phases” [3]. Ta có thể tóm tắt lại định nghĩ trên như sau: - JADE là phần mềm dạng middle-ware phục vụ cho việc phát triển hệ đa tác tử. Nó hỗ trợ việc xây dựng từng agent trong hệ đa agent. Cung cấp các dịch vụ cho từng hoạt động của agent, các công cụ phục vụ cho việc debug và agent xây dựng dựa trên chuẩn FIFA. - JADE là một hệ thống mã nguồn mở, được xây dựng trên ngôn ngữ Java. 32 3.5.2 Cấu trúc của JADE platform Platform JADE là môi trường hỗ trợ agent hoạt động, trao đổi thông tin. Platform JADE chứa nhiều container, các container có thể hoạt động độc lập trên các host khác nhau. Có hai loại container chính: - JADE main-container: Mỗi platform chỉ có một main-container. Container này được khở tạo và hủy cùng với platform. Nó chứa một số agent quan trọng của JADE platform như: o RMA (Remote Management Agent): Hoạt động như màn hình đi ều khiển, phục vụ việc quản lý platform. o DF (Directory Facilitator): Là một agent cung cấp dịch vụ trang vàng (yellow-page) trong platform.  Trang vàng (Yellow-page): Là một dịch vụ cung cấp chức năng quản lý việc giao tiếp giữa các agent, đối chiếu thông tin trao đổi. o AMS (Agent Management System): Là agent theo dõi quản lý sự truy cập và sử dụng agent platform. Cung cấp dịch vụ trang trắng (white- page).  Trang trắng (White-page) cung cấp chức năng quản lý việc đăng ký của agent, quản lý ID của các agent đã đăng ký và quản lý vòng đời của agent. - JADE agent-container: Chứa các agent của người sử dụng, nó có thể nằm trên các host khác nhau. Hình 3.10: Cấu trúc phân tán của JADE 33 3.5.3 Một số lớp quan trọng trong thư viện JADE - Gói jade.core: Cài đặt các thành phần cơ bản của hệ thống. Nó chứa lớp Agent, các agent được tạo ra bắt buộc phải kế thừa từ lớp này. Ngoài ra nó còn chứa gói jade.core.behavior: cung cấp các hàm cài đặt nhiệm vụ cho agent. o Lớp jade.core.Agent: cung cấp các phương thức đăng ký với platform, các phương thức xác định trạng thái của agent, quản lý trạng thái và các phương thức hoạt động của agent. Cách tạo agent: public class MyAgent extends Agent { // some attributes public void setup() { // registry with AMS.. // other activities addBehaviour(myBehaviour) } // other methods } o Gói jade.core.behavior: Chứa các lớp cho phép tạo ra các hoạt động của agent từ đơn giản đến phức tạp. Ta có thể tạo ra các hành động cho agent bằng việc kế thừa từ các lớp này. Cách tạo behavior: public class MyBehaviour extends Behaviour { // some attributes public MyBehaviour(Agent agent){super(agent)} public void action() { // agent action } // other methods } - Gói jade.lang.acl: cung cấp các phương thức xử lý giao tiếp giữa các agent theo chuẩn FIFA. - Gói jade.domain: mô tả các thực thể quản lý agent theo chuẩn FIFA. Nó cung cấp một số dịch vụ như: life-cycle, yellow-page, white-page. Ngoài ra còn một số gói khác như: jade.wrapper, jade.content, jade.tools… Hoạt động của một agent: 34 Hình 3.11: Hoạt động của agent 3.6 Kết luận Các kiến thức về UML, XML, XMI, AUML mà tôi trình bày trong chương này không phải quá mới mẻ và cũng không thật sự đầy đủ. Nhưng đó là những nền tảng kiến thức cơ bản tôi sử dụng trong khóa luận để xây dựng công cụ tự động sinh mô- đun aspect kiểm chứng. Để giải quyết bài toán “kiểm chứng đặc tả UML cho tác tử phần mềm”, tôi chia bài toán ra làm hai bước nhỏ: Bước thứ nhất là xây dựng FSM từ tài liệu XMI mô tả các biểu đồ UML. Bước thứ hai là xây dựng bộ sinh aspect tự động từ FSM. Hai bước này sẽ được trình bày cụ thể ở các chương sau. 35 Chương 4. Xây dựng máy trạng thái từ biểu đồ UML Trong chương 2 và 3 tôi đã trình bày các ki ến thức nền tảng cơ bản để xây dựng công cụ Protocol Verification Generator(PVG). Trong chương này, tôi sẽ trình bày bước thứ nhất trong phương pháp xây dựng công cụ tự động sinh mô-đun aspect, đó là phân tích tài liệu XMI được xuất ra từ một biểu đồ UML, từ đó xây dựng máy trạng thái. Như vậy, trong bước này ta có: - Input: Một tài liệu XMI mô tả biểu đồ trạng thái hoặc biểu đồ trình tự UML. - Output: Máy trạng thái nếu xây dựng được, nếu không sẽ báo lỗi. Để xây dựng được máy trạng thái, trước tiên tôi sẽ xây dựng các cấu trúc dữ liệu để đặc tả các thành phần của biểu đồ UML bằng các đối tượng trong Java, cấu trúc dữ liệu của máy trạng thái mà tôi sử dụng. Tiếp theo, tôi sẽ trình bày cách thức tạo ra máy trạng thái từ tài liệu XMI và các cấu trúc dữ liệu đã xây dựng trước đó. 4.1 Biểu đồ trạng thái 4.1.1 Quy tắc biểu diễn giao thức bằng biểu đồ trạng thái Ngoài cách vẽ biểu đồ trạng thái như trong UML đề cập, tôi xin đưa ra thêm một số quy tắc dùng biểu đồ trạng thái để biểu diễn giao thức. Công cụ PVG mà tôi xây dựng sẽ sử dụng các quy tắc này như là một chuẩn để nó có thể hiểu được giao thức mà người dùng đặc tả bằng UML. Nếu người dùng không tuân thủ các quy tắc này, chương trình sẽ không đưa ra được kết quả như ý. Một số quy tắc: - Trong một tài liệu UML, chỉ có một biểu đồ trạng thái thể hiện giao thức cần kiểm tra. - Biểu đồ trạng thái bắt buộc phải có trạng thái bắt đầu và trạng thái kết thúc. - Trạng thái bắt đẩu có tên bắt đầu bằng “Initial”, và chỉ có các cạnh đi ra chứ không có cạnh đi vào trạng thái này. - Trạng thái kết thúc có tên bắt đầu bằng “FinalState” và chỉ có cạnh đi vào, không có cạnh đi ra từ trạng thái này. 36 - Các trạng thái khác phải có ít nhất một cạnh đi vào và một cạnh đi ra. Tên của các trạng thái này không bắt đầu bằng “Initial” hoặc “FinalState”. - Các cạnh là chữ ký (signature) của các hàm, phương thức sẽ được gọi dùng để thay đổi trạng thái. Chữ ký này được định nghĩa gi ống như tên hàm trong mã nguồn của chương trình cần kiểm chứng, bao gồm cả kiểu giá trị trả về, tên hàm, danh sách các tham số truyền vào. Ví dụ: o Trong mã nguồn, ta gọi hàm init() không có tham số truyền vào, kiểu trả về là void thì tên của cạnh trong biểu đồ UML sẽ là: void init(). o Hàm int setAge(int age) được gọi trong mã nguồn thì tên của cạnh tương ứng sẽ là: int setAge(int age). Đối số age là không bỏ được. - Chú ý rằng tên của tham số truyền vào phải giống với tên biến đã khai báo trong mã nguồn của chương trình cần kiểm chứng. - Điều kiện tiên quyết (precondition) để hàm được gọi sẽ được mô tả trong “GuardCondition” của cạnh. Điều kiện này cũng phải giống với điều kiện trong mã nguồn của chương trình. Hoặc nó là đoạn code trả về giá trị boolean (ví dụ như một phương thức tĩnh (static) boolean isTrue()) Sau đây là ví dụ mô tả một cạnh trong biểu đồ trạng thái UML: - Đoạn mã trong chương trình: if(temp.isTrue()) { init(); ..... } - Ta sẽ mô tả cạnh của biểu đồ trạng thái UML như sau: Hình 4.1: UMLTransition o Tên của cạnh (Name): void init(). o Điều kiện tiên quyết (GủadCondition): temp.isTrue() 4.1.2 Xây dựng cấu trúc dữ liệu mô tả biểu đồ trạng thái UML Ta có thể thấy một biểu đồ trạng thái UML gồm hai thành phần chính: Các trạng thái (State) và các cạnh (Transition). Tôi sẽ xây dựng hai lớp để mô tả hai thành này phần của biểu đồ trạng thái UML. 37 4.1.2.1 Lớp State – mô tả các trạng thái (các đỉnh) Trong biểu đồ trạng thái UML, đỉnh được mô tả gồm có tên của đỉnh, các cạnh đi vào đỉnh và các cạnh đi ra từ đỉnh. Trạng thái bắt đầu chỉ có cạnh đi ra, không có cạnh đi vào. Trạng thái kết thúc, chỉ có các cạnh đi vào đỉnh, không có các cạnh đi ra từ đỉnh. Như vậy, để mô tả một trạng thái ít nhất ta cần mô tả ba dữ liệu: tên đỉnh, các cạnh đi vào và các cạnh đi ra. Để xét xem còn dữ liệu nào cần mô tả nữa không, ta xem cách tài liệu XMI mô tả một trạng thái của biểu đồ trạng thái UML (Phụ lục A). <UML:SimpleState xmi.id="UMLCompositeState.17" name="State1" visibility="public" isSpecification="false" container="UMLCompositeState.15" outgoing="UMLTransition.22" incoming="UMLTransition.21" 4.1.2.2 Lớp Transition – mô tả các cạnh của biểu đồ trạng thái UML /> Nhìn vào cách tài liệu XMI mô tả một trạng thái, ta thấy cần mô tả thêm một dữ liệu nữa về một trạng thái, đó là id của trạng thái (xmi.id). Tài liệu XMI dùng id của trạng thái để đại diện cho một trạng thái bất kỳ trong các liên kết của trạng thái đó với các thành phần khác của biểu dồ, vì vậy dữ liệu về id của trạng thái là rất quan trọng, không thể bỏ qua. Tóm lại, ta cần bốn dữ liệu để mô tả một trạng thái: id của trạng thái, tên trạng thái, các cạnh đi vào và các cạnh đi ra. Và lớp State mô tả trạng thái được xây dựng cơ bản như sau: public class State { private String xmiId; private String name; private String[] incoming; private String[] outgoing; // các phương thức khác. } Một cạnh được mô tả gồm có tên của cạnh và là một đường liên kết giữa hai đỉnh trong biểu đồ trạng thái UML, bắt đầu từ một đỉnh (trạng thái) của biểu đồ và kết thúc ở một đỉnh khác. Vì vậy, để mô tả một cạnh của biểu đồ, ta phải mô tả tên của cạnh, đỉnh bắt đầu của cạnh và đỉnh kết thúc của cạnh. Ngoài ra, tài liệu XMI dùng id để mô tả các thành phần của biểu đồ, như vậy đỉnh bắt đầu và đỉnh kết thúc của cạnh sẽ là id của đỉnh bắt đầu và kết thúc. Mặt khác ta cũng cần thêm id để mô tả id của cạnh. Như vậy, ta đã có 4 dữ liệu cần thiết phải mô tả một cạnh, đó là: id của cạnh, tên của cạnh, 38 id của đỉnh bắt đầu, id của đỉnh kết thúc. Ta xét xem XMI mô tả biểu cạnh của biểu đồ trạng thái như thế nào: <UML:Transition xmi.id="UMLTransition.11" name="void init()" visibility="public" isSpecification="false" stateMachine="UMLStateMachine.4" source="UMLPseudostate.6" target="UMLCompositeState.7"> <UML:BooleanExpression xmi.id="X.17" body="a >= b" - Id của cạnh: xmi.id /> Như vậy sau khi xét tài liệu XMI, ta thấy: Ngoài bốn dữ liệu cần thiết đã chỉ ra ở trên, tài liệu XMI còn mô tả điều kiện tiên quyết để phương thức được thực hiện trong phần tử là phần tử con của . Tóm lại, để mô tả một cạnh, ta cần năm dữ liệu sau: - Tên cạnh: name - Id của đỉnh mà từ đó cạnh đi ra: source - Id của đỉnh mà cạnh đi vào: target - Điều kiện tiên quyết: guard.expression. Lớp Transition được xây dựng như sau: public class Transition { private String xmiId; // ID của cạnh private String name; // Tên cạnh private String source; // ID của đỉnh mà cạnh đi ra private String target; // ID của đỉnh mà cạnh đi vào private String preCondition; // điều kiện để chuyển trạng thái ..... } 4.1.2.3 Mô tả biểu đồ trạng thái bằng các đối tượng trong Java Hai lớp State và Transition mô tả hai thành phần chính của biểu đồ trạng thái UML. Tuy nhiên, một biểu đồ trạng thái thường có nhiều State và nhiều Transition, vì vậy để tiện cho việc truy xuất dữ liệu về các thành phần này tôi xây dựng thêm hai lớp nữa mô tả danh sách các State (ListStates) và danh sách các Transition (ListTransitions) có trong biểu đồ trạng thái UML. Hai lớp này 39 có nhiệm vụ duyệt tài liệu XMI và lấy dữ liệu về các State, các Transition. Sơ đồ lớp mô tả các đối tượng được minh họa như hình vẽ dưới đây: Hình 4.2: Sơ đồ lớp biểu diễn biểu đồ trạng thái bằng các đối tượng trong Java Trong hai lớp ListStates và ListTransitions, tôi xây dựng thêm một số phương thức khác để lấy các thành phần dữ liệu của một State và Transition một cách dễ dàng như: lấy dữ liệu về một State khi biết id của State hay lấy dữ liệu về một Transition khi biết id của Transition đó. Cách xây dựng các hàm này hết sức đơn giản, khi ta đã có m ột danh sách các State và Transition, ta chỉ việc duyệt trong danh sách này, so sánh id của State hoặc Transition với tham số id truyền vào, nếu đúng thì ta xuất dữ liệu ra theo ý muốn. Như đã trình bày ở chương 3, tôi sử dụng thư viện XML DOM trong Java để đọc thông tin từ tài liệu XMI. Cấu trúc của tài liệu XMI này tôi chỉ rõ ở phụ lục A; Ở đây, tôi sẽ chỉ ra các node (thẻ XML) cần đọc để lấy dữ liệu. - Các trạng thái: o Trạng thái bắt đầu: : . o Trạng thái kết thúc: . o Trạng thái trung gian: . o Với mỗi trạng thái, các thuộc tính (attribute) cần đọc để lấy dữ liệu là:  xmi.id  name  incoming  outgoing 40  điều kiện sẽ được lấy thông qua thuộc tính body của phần tử con: . - Các cạnh (Transition) o Các node cần duyệt: . o Các thuộc tính cần đọc để lấy dữ liệu:  xmi.id  name  source  target Khi đã xác đ ịnh được các node, các thuộc tính cần đọc để lấy dữ liệu, công việc còn lại là đọc tài liệu XMI và tạo ra danh sách các trạng thái và danh sách các Transition là hết sức đơn giản như sau: - Khởi tạo ListState, ListTransition - Lấy danh sách các node (NodeList) của Transition và State. - Duyệt từng node trong NodeList - Tạo ra một Transition và một State mới, thêm vào danh sách. Sau bước này, ta sẽ có một danh sách mô tả các State và Transition có trong biểu đồ UML. Bước tiếp theo, tôi sẽ trình bày cách tạo ra FSM từ hai danh sách này. 4.1.3 Xây dựng FSM mô tả biểu đồ trạng thái UML Như ta đã bi ết, để chuyển từ trạng thái này, sang trạng thái kia thì cần có hàm chuyển trạng thái. Trong nghiên cứu của tôi, hàm chuyển trạng thái được mô tả trong các cạnh của biểu đồ trạng thái. Tập hợp các hàm chuyển trạng thái sẽ tạo thành giao thức mô tả hoạt động của đối tượng. FSM được xây dựng cần phải mô tả được giao thức này. Mặt khác, trong mã nguồn của chương trình, các tr ạng thái hầu như không có ý nghĩa, các đoạn mã chỉ mô tả các phương thức được thực hiện – chính là các cạnh của biểu đồ, và mục đích của việc kiểm chứng ở đây chính là kiểm tra xem các phương thức trong mã nguồn của chương trình có được gọi theo đúng giao thức đã được chỉ ra hay không. Để kiểm tra việc này, công cụ tự sinh aspect cần phải biết phương thức nào được gọi trước, phương thức nào được gọi sau từ đó sẽ kiểm tra được các vi phạm các giao thức ràng buộc đối tượng. FSM được xây dựng cần phải mô tả được điều này. Dựa vào bài báo [5] tôi xây dựng FSM gồm các thành phần dữ liệu sau: HashMap> fsm = null; HashSet entrySigs, exitSigs; 41 HashMap> stateMap = null; Trong đó: - entrySigs: Mô tả các cạnh đi ra từ trạng thái bắt đầu. - exitSigs: Mô tả các cạnh đi vào trạng thái kết thúc. - fsm: Là một HashMap, với key chính là một cạnh đi ra từ một trạng thái trung gian. Value chính là các cạnh đi vào trạng thái này. - stateMap: Biểu diễn các trạng thái và các cạnh đi vào trạng thái. Hashmap này sẽ được dùng để đánh số các trạng thái của biểu đồ. Thuật toán xây dựng FSM như sau: - Input: tài liệu XMI mô tả biểu đồ trạng thái UML - Output: FSM nếu xây dựng được, nếu không sẽ báo lỗi. - Các bước thực hiện: o Khởi tạo fsm, entrySigs, exitSigs, stateMap. o Đọc file XMI, lấy ListStates và ListTransitions. o Duyệt từng State trong ListStates  Tạo giá trị cho stateMap: • Nếu nó là trạng thái bắt đầu: thêm một phần tử mới với key là “START”, value = null. • Ngược lại thêm vào stateMap một phần tử với với key là tên trạng thái hiện tại, value là tên của các cạnh đi vào đỉnh.  Nếu nó là trạng thái bắt đầu, lấy tên + precondition cho vào entrySigs và cho vào fsm (biến fsm) với key là tên + precondition còn value là: “START”.  Nếu nó là trạng thái kết thúc, lấy tên + precondition cho vào exitSigs.  Nếu nó là trạng thái trung gian. • Lấy tên của tất cả các cạnh đi vào trạng thái cho vào cấu trúc dữ liệu dạng “Set” trong Java. • Duyệt từng cạnh đi ra từ trạng thái. Lấy tên + precondition. Thêm vào fsm key là tên + precondition của cạnh đi ra và value là “Set” chứa các cạnh đi vào ở trên. 42 4.2 Biểu đồ trình tự UML 4.2.1 Cách biểu diễn giao thức giữa nhiều đối tượng bằng biểu đồ trình tự UML Một biểu đồ trình tự bao gồm hai thành phần chính, đó là các đối tượng và các thông điệp trao đổi giữa các đối tượng. Các đối tượng ở đây, chính là tên của các lớp trong mã nguồn của chương trình. Các thông điệp trao đổi giữa các đối tượng chính là các phương thức của các lớp trong mã nguồn mà ta cần kiểm chứng. Khi mô tả giao thức giữa các lớp bằng biểu đồ trình tự UML, ta sẽ mô tả như sau: - Tên của lớp trong mã nguồn – cũng chính là tên của đối tượng (UMLObject) trong biểu đồ. Và đối với lớp, ta chỉ cần mô tả tên của lớp đó. - Các thông điệp trao đổi giữa các đối tượng được (UMLStimulus) mô tả đầy đủ các thành phần giống như mô tả phương thức của các lớp trong mã nguồn. Cũng gồm có tên phương thức, các tham số truyền vào, kiểu giá trị trả về và thông điệp là phương thức của lớp nào thì nó đư ợc bắt đầu đi ra từ lớp đó. o Tên phương thức mô tả thông qua thuộc tính name. o Các tham số truyền vào được mô tả thông qua thuộc tính Arguments. Các tham số truyền vào, được mô tả bao gồm cả kiểu dữ liệu và tên của tham số. Tên tham số giống như tên của tham số truyền vào trong lời gọi phương thức ở mã nguồn chính của chương trình. o Kiểu giá trị trả về được mô tả bằng thuộc tính Return. Cụ thể các thành phần này được mô tả chi tiết như hình dưới đây: 43 Hình 4.3: StarUML mô tả các thành phần trong biểu đồ trình tự Hoàn toàn tương tự cách xây dựng FSM từ biểu đồ trạng thái, FSM mô tả biểu đồ trình tự UML cũng được xây dựng hoàn toàn tương tự như vậy. Cũng gồm hai bước nhỏ: Thứ nhất là xây dựng cấu trúc dữ liệu mô tả các thành phần của biểu đồ, cách mô tả biểu đồ bằng các thành phần này. Thứ hai là xây dựng FSM từ các thành phần dữ liệu đã được cấu trúc hóa thành các đối tượng được định nghĩa ở bước thứ nhất. Biểu đồ trình tự UML gồm hai thành phần chính: Các đối tượng (Object) và các thông điệp trao đổi giữa các đối tượng (Stimulus). Tôi cũng xây dựng cấu trúc dữ liệu mô tả hai thành phần này như sau: 4.2.2 Xây dựng cấu trúc dữ liệu mô tả biểu đồ trình tự UML Phương pháp xây dựng cấu trúc dữ liệu mô tả biểu đồ trình tự UML hoàn toàn tương tự với cách xây dựng cấu trúc dữ liệu mô tả biểu đồ trạng thái mà tôi đã trình bày ở phần trước. Đầu tiên là tôi xem xét các thành phần chính của biểu đồ, ta sẽ mô tả dữ liệu gì thông qua các thành phần này. Tiếp theo là phân tích tài liệu XMI được xuất ra từ một biểu đồ trình tự UML, xem xét xem tài liệu XMI dùng các thẻ gì để mô tả các thành phần chính này, các thành phần dữ liệu trong thẻ (thuộc tính) gồm những gì. Cuối cùng, tôi sẽ lọc ra các dữ liệu cần thiết nhất và xây dựng các lớp Java để mô tả các thành phần chính của biểu đồ. Đây cũng chính là phương pháp phân tích tài li ệu XMI mà tôi sử dụng trong khóa luận. Áp dụng phương pháp phân tích tài liệu XMI ở trên, tôi xây dựng các lớp mô tả biểu đồ trình tự UML theo như biểu đồ lớp được mô tả trong hình vẽ dưới đây: 44 Hình 4.4: Sơ đồ lớp biểu diễn các thành phần của biểu đồ trình tự UML 4.2.2.1 Lớp ClassifierRole mô tả các đối tượng Mô tả các lớp trong biểu đồ trạng thái, ta chỉ mô tả tên của lớp, ngoài ra XMI mô tả thêm id của lớp, như vậy để mô tả một ClassifierRole, ta chỉ cần mô tả hai thành phần dữ liệu, đó là: id của lớp và tên của lớp: public class ClassifierRole { private String id; // ID cua lop private String name; // Ten lop } Tài liệu XMI, mô tả các lớp thông qua thành phần (thẻ) <UML: ClassifierRole>, trong đó: - xmi.id: Mô tả id của ClassifierRole. - name: Mô tả tên của ClassifierRole. Đây cũng chính là tên thẻ và tên các thuộc tính của thẻ khi ta duyệt tài liệu UML và lấy dữ liệu mô tả các ClassifierRole. 4.2.2.2 Lớp Message mô tả thông điệp trao đổi giữa các đối tượng Thông điệp – hay chính là tên của phương thức được gọi trong mã nguồn. Mà như ta đã biết, một phương thức được mô tả bởi các thành phần như: tên phương thức, các tham số truyền vào, kiểu giá trị trả về của phương thức và một thành phần quan trọng không kém là ta cần xác định xem phương thức đó thuộc lớp (class) nào. Nhưng khi phân tích tài liệu XMI ta thấy: Không giống như các thành phần khác của biểu đồ UML, các dữ liệu mô tả một thành phần đều là các thuộc tính của một loại thẻ nào đó. Ví dụ như thẻ mô tả các cạnh của biểu đồ trạng thái, thẻ <UML: 45 ClassifierRole> mô tả các đối tượng của biểu đồ trình tự. Dữ liệu mô tả về một thông điệp của biểu đồ trình tự UML được thể hiện qua hai loại thẻ khác nhau: - Thẻ chứa các dữ liệu mô tả tên phương thức, lớp chứa phương thức đó. - Thẻ mô tả các tham số, kiểu giá trị trả về của phương thức. Vì vậy, tôi xây dựng hai lớp độc lập nhau để lưu trữ những thành phần dữ liệu khác nhau của một thông điệp được mô tả trên hai loại thẻ XML khác nhau. Đó là lớp Message và lớp TaggedValue. Lớp Message mô tả hai dữ liệu về thông điệp được mô tả trong thẻ đó là tên phương thức và id của lớp chứa phương thức đó. Lớp TaggedValue đại diện cho thẻ mô tả về tên các tham số và kiểu giá trị trả về của phương thức: - Class Message: public class Message { private String id; //ID cua message private String name; // Ten cua message private String sender; // ID cua lop } - Class TaggedValue: public class TaggedValue { private String value; // gia tri cua TaggedValue private String ID; // ID cua Message } Một thông điệp sẽ là sự kết hợp của Message và TagedValue. Thông qua thuộc tính id của thông điệp. 4.2.2.3 Mô tả biểu đồ trình tự UML bằng các đối tượng trong Java Ta đã có ba lớp cơ bản: ClassifierRole, Message, TagedValue để mô tả hai thành phần quan trọng của biểu đồ trạng thái UML, đó là đối tượng và thông điệp trao đổi giữa các đối tượng. Trong một biểu đồ trình tự, không chỉ có một đối tượng hay một thông điệp, mà nó chứa mỗi chuỗi các đối tượng và các thông điệp trao đổi giữa các đối tượng, tạo nên giao thức trao đổi thông điệp giữa các đối tượng. Do đó, cũng giống như mô tả biểu đồ trình tự, để mô tả các thành phần có trong biểu đồ trình tự, tôi cũng dùng một danh sách các ClassifierRole để lưu trữ tất cả các đối tượng có trong biểu đồ. Danh sách các Message và danh sách các TagedValue để lưu trữ tất cả các thông điệp trao đổi giữa các đối tượng trong biểu đồ. Các lớp này được mô tả trong hình 4.3. 46 Ngoài ra tôi cũng xây dựng thêm các phương thức giúp truy xuất dữ liệu về từng thành phần trong danh sách các đối tượng trong lớp được dễ dàng hơn thông qua id của đối tượng đó. 4.2.3 Xây dựng FSM mô tả biểu đồ trình tự UML Giao thức được mô tả bằng biểu đồ trình tự là giao thức liên quan đến nhiều lớp đối tượng khác nhau, nhưng xét cho cùng, nó cũng g ần giống với giao thức trên một lớp đối tượng được mô tả bằng biểu đồ trạng thái. Nó cũng quy đ ịnh dãy các phương thức sẽ được gọi trong chương trình và l ập trình viên sẽ phải gọi các phương thức trong các lớp khác nhau đúng theo trình tự như vậy. Việc kiểm chứng, xét cho cùng cũng chính là để kiểm tra xem lập trình viên gọi các phương thức có đúng như giao thức đặc tả ban đầu không. Do đó, Máy trạng thái mô tả biểu đồ trình tự tôi xây dựng cũng tương tự với máy trạng thái mô tả biểu đồ trạng thái. Gồm ba thành phần dữ liệu: HashMap> fsm = null; HashSet entrySigs, exitSigs; - entrySigs: Mô tả phương thức bắt đầu của giao thức - exitSigs: Mô tả phương thức kết thúc giao thức - fsm: Là một HashMap, với key một phương thức bất kỳ khác phương thức mở đầu và phương thức kết thúc giao thức. Value chính là phương thức ngay trước nó trong giao thức. Một câu hỏi đặt ra là: Trong biểu đồ trình tự, các phương thức (thông điệp) được mô tả theo một dãy và đư ợc đánh số thứ tự tự động bắt đầu từ 1, như vậy thì cần ba thành phần dữ liệu để mô tả một dãy gọi phương thức như vậy có phải là thừa không? Tôi xin trả lời là không hề thừa chút nào. Vì trong khi kiểm chứng, theo như bài báo [5] đề cập, không phải trong chương trì nh, mỗi lớp đối tượng được đặc tả ở đây chỉ được khởi tạo và thực hiện một lần. Lập trình viên có thể thực hiện giao thức nhiều lần bằng cách khai báo các biến khác nhau của các lớp đối tượng này. Ví dụ: Ta mô tả giao thức giữa hai đối tượng A và B với hai thông điệp A -> B và B -> A. Ta có thể khai báo hai đối tượng của lớp A: là a1, a2 và hai đối tượng của lớp B là b1, b2 cùng thực hiện giao thức này. Cụ thể việc tự động ánh xạ giao thức cho từng đối tượng của lớp như thế nào, tôi sẽ trình bày ở phần sau. Phần này tôi chỉ tập trung vào việc mô tả thuật toán xây dựng máy trạng thái mô tả biểu đồ trình tự UML dựa vào tài liệu XMI đặc tả biểu đồ trình tự và các cấu trúc dữ liệu đã được xây dựng ở phần trước. Thuật toán xây dựng FSM mô tả biểu đồ trình tự UML: 47 - Input: tài liệu XMI - Output: FSM nếu xây dựng được, nếu không sẽ báo lỗi. - Các bước thực hiện: o Khởi tạo fsm, entrySigs, exitSigs. o Đọc file XMI, lấy ListMessage, ListClasfierRoles, ListReturn, ListArgument và ListTransitions. o Duyệt từng Message trong ListMessage.  Nếu nó là message đầu tiên, lấy các dữ liệu về tên lớp, kiểu trả về, các tham số truyền vào cho vào entrySigs và cho vào fsm với key là tên thông điệp hoàn chỉnh, value là “START”.  Nếu nó là message kết thúc, lấy dữ liệu tạo thành message hoàn chỉnh (bao gồm tên lớp, kiểu trả về…), lưu vào exitSigs. Lưu vào fsm với key là message hoàn chỉnh vừa lưu vào exitSigs và value là Set chứa hàm ngay hoàn chỉnh ngay trước đó.  Nếu nó là message trung gian, lấy dữ liệu hoàn chỉnh về message hiện thời và message ngay trước đó. Lưu vào fsm với key là message hiện thời, value là Set chứa message ngay trước đó. 4.3 Kết luận Trong chương này, tôi đã trình bày phương pháp xây d ựng FSM từ một tài liệu XMI đặc tả biểu đồ UML. Nó gồm một số bước cơ bản như: phân tích tài liệu XMI, đánh dấu các thẻ cần lấy dữ liệu, chọn ra các thuộc tính cần lấy dữ liệu, từ đó xây dựng các cấu trúc dữ liệu mô tả các thành phần cơ bản của biểu đồ. Tiếp theo, xây dựng các cấu trúc dữ liệu mở rộng để có thể lưu trữ được toàn bộ các dữ liệu quan trọng về các thành phần của biểu đồ. Cuối cùng là xây dựng FSM từ các dữ liệu mô tả biểu đồ UML bằng các đối tượng trong Java. Kết quả của bước này chính là FSM mô tả giao thức mà biểu đồ UML đã đ ặc tả. Đây cũng chính là đ ầu vào cho bộ sinh mô-đun aspect tự động trong công cụ PVG của tôi. 48 Chương 5. Xây dựng công cụ tự động sinh aspect từ máy trạng thái Xây dựng công cụ tự động sinh aspect từ máy trạng thái chính là bước thứ hai trong nghiên cứu của tôi về “phương pháp kiểm chứng đặc tả UML cho tác tử phần mềm”. Mục tiêu của bước này là tạo dựng được công cụ tự sinh aspect từ máy trạng thái đã được tạo ra theo phương pháp đã trình bày ở chương 4. Aspect này sẽ được đan vào chương trình chính thông qua trình biên d ịch AspectJ nhằm thực thi nhiệm vụ kiểm chứng. 5.1 Đặt vấn đề Trong chương 2 nói về lập trình hư ớng khía cạnh, tôi đã trình bày chi ti ết về aspect và cấu trúc của nó. Một aspect phải có đầy đủ các thông tin về các quy tắc đan (join point và pointcut) và mã kiểm chứng (được cài đặt trong advice). Từ đó trình biên dịch AspectJ mới có thể đan chúng vào chương trình chính ph ục vụ quá trình kiểm chứng. Từ nội dung nghiên cứu của bài báo “Checking Interface Interaction Protocols Using Aspect-Oriented Programming” [5] và khóa luận của tôi, phương pháp cài đặt aspect từ máy trạng thái bao gồm các bước cơ bản sau: Bước 1: Xác định quy tắc đan – căn cứ vào các giao thức cần kiểm chứng để xác định các join point sẽ cần theo dõi xem có vi phạm hay không trong thời gian chạy. Từ các join point này sẽ xây dựng các pointcut trong aspect. Bước 2: Xây dựng hành vi đan – đây chính là bước viết mã kiểm chứng trong phần advice. Ta cần xác định các hành vi mà hệ thống cần thực thi và những điều kiện làm cho ràng buộc về giao thức bị vi phạm. Bước 3: Tổng hợp aspect – Khi đã xác đ ịnh được pointcut và advice, aspect sẽ được hình thành theo mẫu sau: aspect { Vùng pointcut; Vùng advice; } 49 5.2 Sinh aspect từ FSM mô tả biểu đồ trạng thái UML Mô tả giao thức bằng biểu đồ trạng thái, ta quan tâm tới các trạng thái và các hành vi chuyển trạng thái. Hành vi chuyển trạng thái chỉ được thực hiện khi nó thỏa mãn hai điều kiện: - Trạng thái trước đó có gọi được hàm chuyển trạng thái hay không. - Điểu kiện chuyển trạng thái được thỏa mãn. Khi thỏa mãn hai điều kiện này, hàm chuyển trạng thái được thực thi và trạng thái của chương trình s ẽ thay đổi sang một trạng thái mới. Như vậy, các join point được xác định chính là điểm gọi các hàm chuyển trạng thái; before advice sẽ chứa mã kiểm tra vi phạm hai điều kiện chuyển trạng thái; after advice chứa mã thay đổi trạng thái. Cấu trúc tổng quát sẽ có dạng: pointcut pc_METHOD: ARGS && call (METHOD_RETURN METHOD_NAME(METHOD_ARG_TYPE)) before(METHOD_ARG): pc_METHOD_NAME(METHOD_ARG_NAME) { if (PRE-CONDITIONS){ // Định nghĩa các hành động khi vi phạm điều kiện } } after(METHOD_ARG): pc_METHOD_NAME(METHOD_ARG_NAME) { // Thay đổi trạng thái } Để tiện cho việc quản lý các trạng thái, ta đặt giá trị cho các trạng thái đặc tả trong giao thức bằng các số tự nhiên bắt đầu từ 0 – HashMap stateMap sẽ được dùng vào việc này. Và dùng một biến khác để lưu giá trị của trạng thái hiện thời (int state). Before advice sẽ kiểm tra xem giá trị của biến state hiện thời có bằng giá trị của các trạng thái trước đó có thể sẽ được chuyển trạng thái khi gọi phương thức hiện thời hay không? Nếu vi phạm, sẽ báo lỗi. Giá trị của biến state sẽ được đặt bằng 0 khi trạng thái hiện tại là “START”. After advice sẽ đặt lại giá trị mới cho biến state sau khi hàm thay đổi trạng thái được gọi. giá trị của biến state sẽ được đặt bằng 0 nếu sau khi thay đổi trạng thái, trạng thái mới là “FINAL”. Thuật toán sinh mã aspect sẽ được cài đặt như sau: - Duyệt lần lượt các key trong FSM – đây chính là các hàm chuyển trạng thái - Nếu key không phải là “START” hay “FINAL” 50 o Dùng các hàm xử lý xâu, cắt chuỗi key thành các phần như: tên hàm, kiểu trả về, kiểu tham số truyền vào, tên tham số truyền vào, điều kiện chuyển trạng thái. o Duyệt từng thành phần trong value của FSM, tạo ra các điều kiện kiểm tra vi phạm. o Tạo ra các pointcut, advice bằng cách thay thế các xâu vừa được tạo ra ở trên vào các vị trí đã được định nghĩa sẵn trong mẫu pointcut và advice được định nghĩa trước đó. - Kết hợp các pointcut, advice lại thành aspect. 5.3 Sinh aspect từ FSM mô tả biểu đồ trình tự UML Kiểm chứng giao thức trên nhiều lớp đối tượng giống như việc gọi tuần tự các phương thức trong biểu đồ trình tự được đề cập rất rõ trong bài báo [5]. Ở đây, tác giả của bài báo dùng hai lớp là SharedState và SharedStateManager để kiểm chứng giao thức trên nhiều lớp đối tượng. SharedState để ràng buộc các đối tượng của các lớp trong giao thức và SharedStateManager cung cấp một vài phương thức để tạo ra SharedState, liên kết SharedState với các đối tượng. Các pointcut trong aspect này được chia ra làm ba loại: - pc_entry: pointcut dùng để bắt phương thức đầu tiên trong giao thức - pc_exit: pointcut dùng để bắt phương thức cuối cùng trong giao thức - pc: pointcut dùng để bắt các phương thức khác. Before advice của pc_entry sẽ tạo ra một đối tượng SharedState mới nếu nó chưa có ràng buộc với bất kỳ đối tượng SharedState nào. Before advice của pc và pc_exit dùng để kiểm tra đối tượng khi nó còn ràng buộc với bất kỳ đối tượng SharedState nào đó. Nó kiểm tra xem có vi phạm các ràng buộc không và đưa ra các thông báo khi có vi phạm xảy ra. After advice của pc_entry và pc pointcut là giống nhau, chúng được sử dụng để lưu lại trạng thái và đặt giá trị mới cho biến trạng thai sau khi mỗi phương thức được gọi. After advice của pc_exit ngoài việc lưu lại trạng thái, nó xóa bỏ đối tượng SharedState đã được tạo ra trong before advice của pc_entry. Thuật toán sinh mã aspect được cài đặt như sau: 51 - Duyệt lần lượt các hàm trong entrySigs tạo ra loại pointcut pc_entry và các advice. - Duyệt lần lượt các hàm trong exitSigs tạo ra loại pointcut pc_exit và các advice. - Duyệt lần lượt các hàm trong key của fsm, tạo ra loại pointcut pc và các advice - Ba loại pointcut này đều được tạo ra bằng cách xử lý các xâu ký tự, tách chuỗi thành tên hàm, kiểu trả về, tên tham số truyền vào, kiểu tham số truyền vào… - Kết hợp các pointcut và advice đã tạo ra ở trên thành aspect kiểm chứng hoàn chỉnh. - Thêm nữa, để quản lý trạng thái của SharedState, ta cần phải có dữ liệu của FSM mô tả biểu đồ trình tự UML. Vì vậy, trong aspect này sẽ chứa thêm phần mã nguồn tạo ra FSM từ biểu đồ trình tự UML như trong chương 4 đã trình bày. 5.4 Mở rộng Trong bài báo “Checking Interface Interaction Protocols Using Aspect-oriented Programming” [5] chưa xử lý các hàm trùng tên nhưng có các tham s ố truyền vào khác nhau hay kiểu dữ liệu trả về khác nhau và không kiểm tra điều kiện tiên quyết cần thiết trước khi hàm được gọi (precondition của hàm). Trong khóa luận của tôi, tôi đã mở rộng thêm hai phần này: - Kiểm tra precondition được mô tả trong biểu đồ trạng thái UML: Như trong phần 4.1.1, tôi có nói đến các quy tắc biểu diễn giao thức bằng biểu đồ trạng thái UML. Biểu thức điều kiện ở đây giống với biểu thức điều kiện trong mã nguồn của chương trình. Như v ậy, để kiểm tra xem có vi phạm điểu kiện hay không, tôi sẽ quy về một đoạn mã nguồn có thể là biểu thức, có thể chứa các lời gọi hàm và trả về kiểu boolean. Như vậy ta sẽ kiểm tra được vi phạm. Tuy nhiên, do việc mô tả precondition bằng cách rất hạn chế mà công cụ PVG chỉ tạo ra aspect với các mô tả có trong biểu đồ, do đó đôi khi precondition sẽ không kiểm tra được trong thực tế (ví dụ: precondition liên quan đến dữ liệu của nhiều lớp khác nhau chẳng hạn). Điều này có thể khắc phục bằng cách sửa lại mô-đun aspect do công cụ PVG tạo ra, thêm một số các đoạn mã để có thể kiểm tra được precondition trong mô-đun aspect. 52 - Thêm tham số truyền vào cho hàm: ở đây tôi sử dụng các thao tác với xâu khí tự trong Java, cắt chuỗi phương thức thành các phần nhỏ như: các chuỗi lưu tên hàm, tên tham số truyền vào, tên kiểu dữ liệu của tham số, tên tham số, kiểu giá trị trả về từ đó tạo ra các advice bằng cách thay thế các chuỗi con này vào trong các phần của aspect mẫu đã được định nghĩa từ trước. Khi cắt xâu ký tự mô tả phương thức thành nhiều phần nhỏ như vậy, việc tạo ra hai pointcut cho hai hàm trùng tên nhưng khác tham số truyền vào rất đơn giản, tôi chỉ cần thêm chuỗi mô tả kiểu của các tham số vào ngay sau xâu định nghĩa tên pointcut; như vậy sẽ giải quyết được mọi vấn đề của các hàm trùng tên, khác tham số truyền vào. 5.5 Sinh mã aspect kiểm chứng giao thức (AB)n Trong phần tìm hiểu của tôi, tôi sử dụng phương pháp tạo ra mã kiểm chứng ở trên để xây dựng thêm một chức năng khác cho công cụ “PVG”, đó là sinh mã aspect kiểm chứng giao thức (AB)n. Trong phần này tôi sẽ trình bày phần mở rộng này. 5.5.1 Giao thức (AB)n là gì? A và B là tên của các phương thức còn n là số lần các phương thức được gọi trong chương trình. Nói một cách đơn giản, (AB)n mô tả việc hàm A và B phải được gọi n lần trong mã nguồn của chương trình. Giao thức (AB)n được mô tả bằng biểu thức chính quy như sau: [A*B] n. Ở đây, * có thể là rỗng (null) hoặc là một dãy các phương thức khác. Ví dụ: - Giao thức: [void open() void close()]3 - mô tả việc gọi 3 cặp phương thức void open(), void close() trong chương trình; gi ữa hai phương thức này không có bất kỳ phương thức nào khác được gọi: - …open() close()…open() close()…open() close()… - Giao thức: [void open() * void close()]3 – mô tả việc gọi cặp hàm void open() và void close() trong chương trình như sau: - …open()…close()…open()…close()…open()…close(). Ở đây “…” đại diện cho một phương thức hay một chuỗi phương thức bất kỳ. Công cụ PVG chỉ hiểu giao thức (AB)n được định nghĩa theo đúng như biểu thức chính quy mô tả ở trên. 53 5.5.2 Thuật toán kiểm chứng giao thức (AB)n 5.5.2.1 [A * B] n Việc kiểm chứng giao thức [A * B] n nảy sinh hai vấn đề lớn: - Thứ nhất: phương thức A và B được gọi liên tiếp nhau (), tức là việc gọi hai phương thức A B phải tạo thành một dãy: A … B … A … B… Vấn đề này được giải quyết bằng một biến đếm kiểu nguyên num như sau: o Ban đầu đặt num = 0. o Trước khi gọi A, kiểm tra num, nếu num != 0 -> báo lỗi o Sau khi gọi A, tăng num lên 1. o Sau khi gọi B, giảm num đi 1. Và sau khi giảm n đi 1 kiểm tra num, nếu num != 0 -> báo lỗi. - Thứ hai: cặp (A B) được gọi đúng n lần. Việc gọi cặp (A B) đúng n lần nảy sinh ra hai trường hợp: gọi lớn hơn n lần và gọi nhỏ hơn n lần. Kiểm tra cặp A, B gọi đúng lớn hơn n lần rất đơn giản, ta cũng dùng một biến kiểu nguyên khác để kiểm tra (ví dụ: biến int count): o Sau khi gọi A, tăng biến count lên 1 và kiểm tra, nếu count > n thì báo lỗi. o Ở đây ta chỉ cần kiểm tra A có được gọi > n lần hay không mà không cần kiểm tra B vì nếu A đã được gọi > n lần thì ta đã bắt được lỗi và nếu A và B được gọi với số lần khác nhau, ta cũng đã b ắt được lỗi bằng biến num ở trên. Như vậy chỉ cần kiểm tra A là đủ. Kiểm tra (A B) được gọi < n lần khó khăn hơn, ta không thể dùng các join point tại các phương thức A và B kiểm tra được mà phải dùng một join point khác là điểm mà sau khi tất cả các hàm A, B được gọi. Để đơn giản, tôi tạo ra một phương thức mới trong mã nguồn của chương trình (void checkAnBn()). Phương thức này không ảnh hưởng gì đ ến chương trình, nó đư ợc gọi ở điểm kết thúc của chương trình. Sau khi tạo được một join point tại điểm kết thúc của chương trình thì vi ệc kiểm tra A có được gọi n lần hay không tôi cũng dùng chính ngay biến count ở trên để kiểm tra. Before advice sẽ kiểm tra xem, nếu count != n thì sẽ báo lỗi. Quay trở lại, ta có thể thấy việc tạo ra một phương thức mới làm điểm đánh dấu kết thúc chương trình sẽ giải quyết được tất cả vấn đề 54 liên quan tới việc gọi hàm A đúng n lần. Trong công cụ PVG tôi sử dụng cả hai cách đã được chỉ ra ở trên. 5.5.2.2 [A B] n [A B] n là mở trường hợp đặc biệt của [A * B] n khi * = null. Ở đây, ta phải gọi hai phương thức A, B theo một cặp (A B). Để kiểm chứng giao thức [A B] n ta cũng kế thừa từ thuật toán kiểm chứng giao thức [A * B] n, và mở rộng thêm một phần kiểm tra gọi hai phương thức A, B theo cặp (A B). Để làm được điều này, ta phải bắt được tất cả các điểm gọi hàm khác. Khi bắt được tất cả các điểm gọi hàm khác thì việc kiểm tra vi phạm sẽ rất đơn giản, ta chỉ cần dùng một biến check kiểu nguyên. Mỗi khi chương trình g ọi hàm, biến check được tăng lên 1. Sau khi chương trình gọi hàm A, biến check được đặt lại giá trị = 0. Và ta sẽ kiểm tra sau khi gọi hàm B, nếu biến check != 1 thì chương trình sẽ báo lỗi. Vì nếu check != 1 thì tức là đã có một hàm khác được gọi ở giữa A và B. 5.5.3 Sinh mã aspect kiểm chứng giao thức (AB)n Phương pháp này có ý tưởng hoàn toàn giống với phương pháp sinh aspect kiểm chứng từ biểu đồ UML, nó chỉ khác nhau ở các mẫu aspect được định nghĩa khác nhau. Đầu tiên là phân tích chuỗi [A * B] n lấy ra các phương thức A, B và biến n. Sau đó dùng các phương thức xử lý xâu ký tự, tách các hàm A, B này ra thành các phần: tên hàm, kiểu giá trị trả về, tham số… giống như khi xử lý tạo ra aspect từ biểu đồ UML. Sau đó tạo ra các aspect theo mẫu đã định nghĩa trước. 5.6 Kết luận Trong chương này, tôi đã trình bày phương pháp tự động sinh mô-đun aspect từ FSM mô tả biểu đồ UML. Nội dung chính của phương pháp chính là duyệt các trạng thái trong FSM, phân tích vào các vị trí thích hợp trong xâu aspect mẫu được khai báo từ trước. Xâu aspect mẫu sẽ tuân theo cú pháp của một aspect cơ bản, bao gồm tên aspect, vùng pointcut và vùng advice. Thuật toán duyệt các trạng thái trong máy trạng thái thực chất là việc duyệt các key của FSM, lấy dữ liệu của từng trạng thái, sử dụng các phương thức thao tác với xâu ký tự để tạo ra các aspect. Đồng thời, tôi đưa ra phương pháp kiểm chứng giao thức (AB)n – một mở rộng cho công cụ PVG có thể kiểm chứng giao thức (AB)n. Kết quả thu được sau bước này là mã aspect. Mã aspect này sẽ được đan vào chương trình chính để thực hiện chức năng kiểm chứng chương trình. 55 Chương 6. Thực nghiệm Để minh họa cho phương pháp xây dựng công cụ sinh aspect được giới thiệu trong các chương trước, chương này sẽ mô tả chi tiết các bước cài đặt mà tôi đã thực hiện và kết quả thực hiện kiểm chứng trên một số giao thức thực tế.

Các file đính kèm theo tài liệu này:

  • pdfLUẬN VĂN-KIỂM CHỨNG ĐẶT TẢ UML CHO TÁC TỬ PHẦN MỀM.pdf