3 Thực nghiệm, đánh giá
1.12 Máy trạng thái giao thức DBaccessor
ràng buộc mơ tả trong đặc tả PSM.
Ví dụ, khi một thực thi sử dụng giao diện thành phần DBaccess và tuân theo đặc tả PSM DBaccessor thì các hành động open, close, query, fetch, cancel, create và kikll phải được thực thi theo đúng thứ tự được chỉ ra bởi giao thức của giao diện DBaccess (xem Hình 1.12). Nghĩa là nếu một thực thi nào đó xảy ra chuỗi sự kiện open → query → close → query là vi phạm đặc tả vì sự kiện truy vấn (query) xảy ra ngay liền sau sự kiện đóng cơ sở dữ liệu (close).
1.4.3 Một số nghiên cứu liên quan
Kiểm tra sự tuân theo giữa thực thi và đặc tả
Có nhiều cách tiếp cận để kiểm tra sự tuân theo giữa thực thi và đặc tả đã được nghiên cứu và công bố.
Trong [4], các tác giả đã mở rộng JML (Java Modelling Language), một ngơn ngữ đặc giả hình thức giao diện hành vi, để mơ tả một cách hình thức những tính chất giao thức của những module chương trình Java như các lớp hay giao diện theo kiểu trực quan và ngắn gọn. Sự mở rộng cho phép ta tách riêng những phụ thuộc về thứ tự giữa các lời gọi phương thức và đặc tả chúng một cách tường minh. Việc tách riêng những tính chất giao thức cũng giúp mang lại những đặc tả tính chất về chức năng một cách rõ ràng và dễ đọc. Bên cạnh việc mở rộng JML, các tác giả còn mở rộng trình bên dịch JML để nhận biết được những mệnh đề về chuỗi lời gọi phương thức và dịch nó sang mã lệnh kiểm tra lúc chạy chương trình.
Bài báo [8], các tác giả mô tả giao thức sử dụng máy trạng thái. Sau đó, những phân tích của họ đảm bảo chuỗi các lời gọi phương thức tương ứng với máy trạng thái. Máy trạng thái đưa ra trong bài báo cho phép tùy biến các trạng thái và thêm vào các tiền điều kiện và hậu điều kiện, vì vậy lập trình viên có thể thêm vào những kiểm tra bổ sung.
Các tác giả bài báo [26] đề xuất một cách tiếp cận cho việc đặc tả và kiểm tra các giao thức sử dụng lập trình hướng khía cạnh (Aspect Oriented Programming – AOP). Trong bài báo này, chuỗi các lời gọi phương thức, hay giao thức, là thứ tự mà các hành vi của các đối tượng phải được gọi. Các giao thức có thể được đặc tả bằng nhiều cách khác nhau như sử dụng biểu thức chính quy, automata hay hay trạng thái. Các tác giả cung cấp một ngôn ngữ đặc tả giao thức dựa trên biểu thức AspectJ[14, 13]. Mã lệnh AspectJ được sinh ra từ đặc tả của lớp, có thể kiểm tra tính vi phạm giao thức khi chạy chương trình. Các khía cạnh được sinh ra sau đó được trộn với mã nguồn chương trình để sinh ra được chương trình cuối cùng hợp thành từ những chức năng ban đầu cùng với những kiểm tra tuân theo giao thức trong lúc chạy chương trình. Tuy nhiên, cách tiếp cận này chỉ áp dụng với chương trình hướng đối tượng và khơng thể áp dụng vào phát triển dựa trên thành phần vì AOP chỉ làm việc với lập trình hướng đối tượng.
Kiểm tra tính chất của mã lệnh bytecode
Một số phương pháp kiểm tra mã bytecode sử dụng kiểm thử mơ hình (model checking) cũng đã được đề xuất.
Trong bài báo [2], các tác giả sử dụng kỹ thuật kiểm thử mơ hình [11] để kiểm tra những tính chất an tồn của chương trình Java. Đầu tiên, phương thức được trừu tượng hóa thành một hệ chuyển trạng thái mô tả việc thực hiện phương thức trên một máy trừu tượng. Sau đó, các tính chất được sinh ra dưới dụng các tính chất an tồn theo thời gian. Cuối cùng, những mô tả này được chuyển dịch sang ngôn ngữ đầu vào của cơng cụ kiểm thử mơ hình sẵn có như SPIN [10], SMV. Cơng cụ kiểm thử mơ hình sau đó sẽ báo cáo kết quả kiểm tra, nếu hoạt động của phương thức khơng thỏa tính chất nó sẽ đưa ra một phản ví dụ cho tình huống dẫn đến lỗi. Cách tiếp cận này có thể thực hiện đơn giản hơn bằng cách sử dụng cơng cụ có sẵn Java PathFinder (JPF) để dịch chương trình Java sang Promela để làm đầu vào cho cơng cụ SPIN. Tuy nhiên, SPIN chỉ kiểm tra các tính chất được đặc tả bằng logic thời gian hoặc những tính chất ở mức thấp như deadlock, an tồn,. . . , nó khơng hỗ trợ kiểm tra
những thành phần phần mềm với những tính chất đặc tả hành vi ở mức cao.
Trong bài báo [19], các tác giả trình bày cách tiếp cận kiểm thử mơ hình cho các thành phần phần mềm được cài đặt bằng Java cùng với những đặc tả ở mức cao hành vi của chúng, được định nghĩa thông qua các giao thức hành vi [20], sử dụng cơng cụ kiểm thử mơ hình JPF và cơng cụ kiểm thử giao thức. Tính chất được kiểm tra nhờ sự cộng tác giữa hai cơng cụ này. Vì hai cơng cụ này làm việc trên hai mức trừu tượng khác nhau, JPF làm việc với lệnh bytecode trong khi đó cơng cụ kiểm thử giao thức làm việc ở mức giao thức hành vi, nên cần có một phép ánh xạ từ khơng gian trạng thái của JPF vào không gian trạng thái của cơng cụ cịn lại. Các tác giả đã điều chỉnh JPF để hỗ trợ việc ánh xạ này và điều chỉnh bộ kiểm thử giao thức để chấp nhận những thông báo từ JPF cũng như điều hướng việc duyệt không gian trạng thái giao thức tùy theo những sự kiện nhận được từ JPF.
Xây dựng đồ thị luồng điều khiển
Ngoài những nghiên cứu về việc kiểm tra sự tuân theo giữa thực thi và đặc tả cũng như kiểm tra tính chất của mã lệnh bytecode, một số phương pháp xây dựng đồ thị luồng điều khiển cho Java bytecode cũng được công bố.
Trong các bài báo [29, 6, 18], các tác giả trình bày phương pháp xây dựng đồ thị luồng điều khiển cho Java bytecode. Đầu tiên, tác giả chia các lệnh của phương thức thành những khối cơ bản ở những chỗ luồng điều khiển có thể thay đổi, như sau cách lệnhif hay goto,
hay trước những lệnh là địa chỉ đích đến của lệnh if và goto. Sau đó, tác giả xây dựng đồ
thị luồng CFG với các đỉnh là các khói lệnh cơ bản đã xác định trước đó và các cung biểu diễn luồng điều khiển giữa những khối lệnh cơ bản trên. Trong cách tiếp cận của luận văn này, chúng tôi chỉ quan tâm đến các lệnh là lời gọi phương thức và các lệnh rẽ nhánh nên cách tiếp cận này sẽ có nhiều dữ thừa trong đồ thị CFG. Giải pháp của chúng tôi là giản lược CFG để được đồ thị CG như trong thuật toán Algorithm 3 trình bày ở Chương 2.
Bài báo [12] trình bày đề xuất phương pháp xây dựng đồ thị luồng điều khiển bằng cách tách riêng luồng ngoại lệ và luồng bình thường. Tác giả đưa ra cách phân tích luồng ngoại lệ để đánh giá luồng điều khiển ngoại lệ. Đồng thời tác giả cũng đề xuất đồ thị luồng ngoại lệ biểu diễn để biểu diễn luồng điều khiển ngoại lệ. Đồ thị luồng điều khiển CFG biểu diễn cả hai loại luồng điều khiển được xây dựng bằng cách trộn hai loại đồ thị với nhau. Ưu điểm của việc tách riêng hai loại luồng điều khiển là có thể xây dựng riêng đồ thị luồng ngoại lệ khi cần, thay vì phải tính tốn cả hai. Hơn nữa, phương pháp này có thể sử dụng lại kỹ thuật xây dựng đồ thị luồng điều khiển đã có để áp dụng vào trường hợp luồng điều khiển bình thường.
Tổng kết chương
Thành phần phần mềm là một phần tử phần mềm tn theo một mơ hình chuẩn, có thể triển khai độc lập và hợp thành với các thành phần khác mà không cần bất kỳ thay đổi nào theo chuẩn hợp thành. Một thành phần phần mềm có các tính chất: độc lập, hợp thành được, triển khai được và có tài liệu đầy đủ. Giao diện của nó phản ánh những dịch vụ mà nó cung cấp (giao diện “cung”) và những dịch vụ nó yêu cầu phải có để hoạt động đúng (giao diện “cầu”).
các phần tử cơ bản: các giao diện, cách sử dụng và cách triển khai. Với những thành phần được thực thi như những đơn vị chương trình hơn là các dịch vụ ra bên ngồi, mơ hình thành phần đặt ra những dịch vụ được cung cấp bởi middleware hỗ trợ thực hiện các thành phần, gồm cách dịch vụ nền và dịch vụ hỗ trợ.
Quy trình phần mềm dựa trên thành phần có hai loại: quy trình phát triển để sửa dụng lại và phát triển bằng cách sử dụng lại. Quy trình phát triển để sử dụng lại quan tâm đến việc phát triển các thành phần hoặc các dịch vụ sẽ được sử dụng lại trong các ứng dụng khác. Quy trình phát triển bằng cách sử dụng lại là quy trình phát triển các ứng dụng mới sử dụng lại những thành phần và dịch vụ đã có.
Hợp thành các thành phần là q trình tích hợp các thành phần với những thành phần khác, đặc biệt là viết những đoạn mã lệnh có vai trị kết nối để dựng nên hệ thống hay thành phần khác. Có nhiều cách hợp thành khác nhau: hợp thành tuần tự, hợp thành có phân cấp và hợp thành tổng. Trong các kiểu hợp thành thì vấn đề tương thích giao diện là vấn đề quan trọng. Ngoài ra, vấn đề nhất quán giữa thực thi và đặc tả PSM của thành phần cũng là vấn đề quan trọng làm ảnh hưởng đến chất lượng của hệ thống phần mềm phát triển theo cách tiếp cận dựa trên thành phần.
Chương 2
Kiểm tra sự tuân theo đặc tả PSM
Để kiểm tra sự tuân theo giữa thực thi và đặc tả PSM, chúng ta sẽ chuyển đặc tả PSM thành một đồ thị và thực thi của thành phần thành một đồ thị khác. Sau đó, ta kiểm tra sự tuân theo trên hai đồ thị trung gian. Chương này trình bày thuật tốn chuyển đổi và kiểm tra sự tuân theo cùng những định nghĩa và tính chất liên quan.
2.1 Chuyển PSM về dạng đồ thị
Để đơn giản, ta xét một đặc tả PSM đơn giản như trong Hình 2.1. Với DB (DataBase). Connected Opened Updated Closed connect( ) open( ) close( ) update( ) DB close( ) Hình 2.1: Một PSM đơn giản
Đặc tả PSM được mô tả sử dụng ký hiệu trực quan của UML. Một PSM có thể xem như một đồ thị có hướng trong đó các đỉnh là các trạng thái trước và sau khi thực thi một phương thức, cạnh nối các trạng thái mô tả thứ tự thực thi các phương thức của giao diện (như trong Hình 2.1). Chúng ta muốn chuyển đồ thị của PSM (G) sang một dạng khác trong đó hành vi trên cạnh trở thành đỉnh trong một đồ thị dẫn xuất, gọi là G’.
2.1.1 Đồ thị luồng, đồ thị dẫn xuất
Chúng tôi đưa ra định nghĩa về đồ thị luồng và đồ thị dẫn xuất tương ứng trong Định nghĩa 1 và Định nghĩa 2.
Định nghĩa 1. Một đồ thị luồngG là một bộ G= (V, E, s, à, ), trong ú
ã V l tp cỏc nh,
ã EV ìV l tp cnh cú hng,
ã s∈V là đỉnh biểu diễn điểm xuất phát của đồ thị luồng, • t∈V là đỉnh biểu diễn điểm kết thúc của đồ thị luồng, ã à:V →LV là hàm gán nhãn cho đỉnh,
• ν:E →LE là hàm gán nhãn cho cạnh.
Định nghĩa 2. Đồ thị G0 là đồ thị dẫn xuất của đồ thị luồng G nếu
• V0 =E là tập đỉnh,
• E0 là tập cạnh, (vi0, vj0)∈E0 nếu∃v∈V ∧tail(vi0) =v∧head(vj0) =v
Trong đó,head(e) và tail(e) tương ứng là đỉnh đầu và cuối của cạnhe.
Trong một mơ hình thực, chúng ta khơng để đọc trực tiếp các ký hiệu UML từ công cụ hỗ trợ UML. Chúng ta phải lưu đặc tả PSM dưới dạng file XMI (XML Meta Data Interchange)[9]. Biểu diễn XMI của đặc tả PSM trong Hình 2.1 được mơ tả trong Listing 2.1.
2.1.2 Thuật toán chuyển đổi
Từ định nghĩa về đồ thị dẫn xuất và cấu trúc file XMI mô tả đặc tả PSM, chúng tơi đưa ra thuật tốn chuyển đổi đặc tả PSM sang đồ thị như trong thuật tốn Algorith 1. Thuật tốn này có độ phức tạpO(n2), trong đón là số phương thức của giao diện trong PSM.
Đặc tả PSM của một thành phần không mô tả tường minh tất cả các khả năng của ngơn ngữ lập trình. Ví dụ, trong ngơn ngữ lập trình, các chương trình có thể kết thúc sau khi thực hiện một phương thức bất kỳ, điều này không được mô tả trong PSM. Một ví dụ khác, trong ngơn ngữ lập trình, một phương thức có thể được gọi lặp lại, quy tắc này khơng được mơ tả trong PSM. Vì vậy, chúng ta phải thêm những đặc tả không tường minh này vào đồ thị được chuyển đổi từ đặc tả PSM. Câu lệnh ở dịng 20 của thuật tốn Algorithm 1 giải quyết vấn đề này.
Để đảm bảo thứ tự lời gọi thực hiện phương thức trong đồ thị được chuyển đổi như trong thuật toán Algorithm 1 được giữ nguyên như trong đặc tả PSM, chúng tơi chứng minh tính chất nêu trong Định lý 1.
Định lý 1. Nếu đồ thị có hướng G0 = (V0, E0) là đồ thị dẫn xuất của G= (V, E) thì thứ tự tuyến tính của các đỉnh trong G0 đảm bảo được giữ nguyên như thứ tự các cạnh trongG.
Listing 2.1: Biểu diễn XMI của PSM
<?xml version=" 1 . 0 " e n c o d i n g="UTF−8" standalone=" no " ?>
<psm>
<component>DataBase</ component> < !−−The l i s t o f s t a t e s .−−>
< s t a t e i d=" 0 "> <x>−39.0</ x> <y>4 9 . 0</ y> < i n i t i a l /> </ s t a t e> < s t a t e i d=" 1 "> <x>9 4 . 0</ x> <y>4 8 . 0</ y> </ s t a t e>
< s t a t e i d=" 2 "> <x>9 6 . 0</ x> <y>2 0 0 . 0</ y> </ s t a t e> < s t a t e i d=" 3 "> <x>9 8 . 0</ x> <y>3 5 5 . 0</ y> </ s t a t e> < s t a t e i d=" 4 "> <x>3 7 2 . 0</ x> <y>3 5 5 . 0</ y> </ s t a t e>
< s t a t e i d=" 5 "> <x>3 7 3 . 0</ x> <y>2 7 2 . 0</ y> < f i n a l /> </ s t a t e> < !−−The l i s t o f t r a n s i t i o n s .−−>
< t r a n s i t i o n> <from>2</ from> <t o>3</ t o> < t r i g g e r>u p d a t e</ t r i g g e r> </ t r a n s i t i o n>
< t r a n s i t i o n> <from>2</ from> <t o>4</ t o> < t r i g g e r> c l o s e</ t r i g g e r> </ t r a n s i t i o n>
< t r a n s i t i o n> <from>3</ from> <t o>4</ t o> < t r i g g e r> c l o s e</ t r i g g e r> </ t r a n s i t i o n>
< t r a n s i t i o n> <from>0</ from> <t o>1</ t o> < t r i g g e r>c o n n e c t</ t r i g g e r> </ t r a n s i t i o n>
< t r a n s i t i o n> <from>4</ from> <t o>5</ t o> < t r i g g e r />
</ t r a n s i t i o n>
< t r a n s i t i o n> <from>1</ from> <t o>2</ t o> < t r i g g e r>open</ t r i g g e r>
</ t r a n s i t i o n> </psm>
Algorithm 1 Chuyển PSM sang đồ thị Transforming():
1: Đọc file XMI để được đồ thịG={V, E}
2: InitializeV0=∅,E0=∅
3: foreach i <|E|do 4: V0 ←trigger(ei) 5: end for
6: foreach i <|E|do 7: if head(ei) =sthen 8: E0 ←(s0, trigger(ei)) 9: end if 10: if tail(ei) =tthen 11: E0 ←(trigger(ei), t0) 12: continue 13: end if
14: foreach j <|E|do
15: if tail(ei) =head(ej) then 16: E0←(trigger(ei), trigger(ej))
17: end if
18: end for
19: end for
20: Thêm các quy tắc không được đặc tả tường minh.
Chứng minh. Với mỗi cặp đỉnh liền kềvi0, vj0 ∈V0, ta chứng minh rằng tồn tại các cạnh liên tiếp nhau tương ứngei vàej sao cho(ei, ej)∈E. Nếu vi0, vj0 là các đỉnh trong V0 thì cạnh (vi0, vj0)∈E0. Theo Định nghĩa 2,∃vk∈V ∧(vi, vk)∈E∧(vk, vj)∈E.
Ngược lại, với mỗi cặp cạnh liên tiếp ei và ej sao cho (ei, ej) ∈ E, ta chứng minh rằng các đỉnh tương ứng(vi0, vj0)∈V0 là kề nhau. Nếu(ei, ej) là hai cạnh liên tiếp thìtail(ei) = head(ej). Nghĩa là∃vk∈V∧(vi, vk)∈E∧(vk, vj)∈E. Giả sử(vi, vk)được chuyển đổi thành vi0 và(vk, vj) được chuyển đổi thànhvj0. Theo Định nghĩa 2,(vi0, vj0)∈E0 hoặcvi0, vj0 là các đỉnh kề nhau trongV0. Vì vậy, thứ tự tuyến tính của các đỉnh trongG0 được giữ nguyên như trongG.
2.2 Biểu diễn thực thi qua CFG
2.2.1 Mã lệnh thực thi bytecode
Bytecode là dạng biểu diễn trung gian của chương trình, ở mức cao hơn mã lệnh nhị phân và thấp hơn mã nguồn của một ngơn ngữ lập trình. Mỗi câu lệnh bytecode gồm một opcode