Biểu đồ trình tự và các đoạn gộp

Một phần của tài liệu LUẬN VĂN: KIỂM CHỨNG CÀI ĐẶT BIỂU ĐỒ TƯƠNG TÁC VỚI UML 2.0 pdf (Trang 27 - 56)

1. 4 Cấu trúc khóa luận

3.1.Biểu đồ trình tự và các đoạn gộp

Trong một biểu đồ trình tự UML2.0, các đoạn gộp là một trong các thành phần quan trọng. Để xây dựng được máy trạng thái thì cần mô tả được đầy đủa các yếu tố này. Có 4 loại đoạn gộp hay được sử dụng là alt, opt, loop, break. Do đó, cần xây dựng cấu trúc dữ liệu để lưu trữ chúng.

Áp dụng phương pháp phân tích tài liệu XMI, các lớp mô tả khối gộp như sau.

Hình 4.1 Sơ đồ biểu diễn các thành phần khối gộp

Lớp CombinedFragment chịu trách nhiệm mô tả một đoạn gộp trong biểu đồ trình tự. Là một trong những thành phần quan trọng trong biểu đồ trình tự của UML2. Trong XMI một đoạn gộp được mô tả trong thành phần fragment với xmi:type="uml:CombinedFragment". Trong thành phần này, một đoạn gộp được mô tả bởi các thành phần như sau :

 Xmi.Id : cho biết id của đoạn gộp.  Name : cho biết tên của đoạn gộp.

21

Ngoài ra các thành phần xmi.id và xmi.uuid có thể giúp chúng ta tình các message thuộc vào đoạn gộp bằng cách so sánh các id của đoạn gộp với các senEvent của message.Dưới đây là mô tả về lớp CombinedFragment.

public class CombinedFragment {

String id;

Vector<Message> message;

public Message firstMessageAfterFragment;

//////

}

Lớp Loop,opt,break các một lớp con của lớp CombinedFragment về cơ bản lớp này kế thừa các thành phần của lớp CombinedFragment. Chúng không có thêm thành phần nào. Để xác định chúng, trong quá trình phần tichs tài liệu XMI chúng ta so sánh thành phần interactionOperator để xác định.

Lớp Alt là một lớp con của lớp CombinedFragment, khác với 3 lớp con trên, đôi với alse chúng ta cần quan tâm đến các thành phấn khác của nó. Alt là một mô tả điểu kiện chọn có trên hai điều kiện, chúng ta phải mô tả được điều này.Vì lý do đó, ngoài các thành phần như lớp cha lớp Alt còn có các thành phần Dưới đây là mô tả về

lớp Alt.

public class Alt extends CombinedFragment{

Vector<Message> ifMessage;

Vector<Message> elseMessage;

//}

Sau đó, máy trạng thái sẽ được sinh ra như phân tích ở chương 2.

3.2. Sinh Aspect từ biểu đồ trình tự

Việc kiểm chứng giao thức trên nhiều lớp đối tượng trong biểu đồ trình tự có thể coi như việc gọi tuần tự các phương thức. Giao thức được mô tả dưới dạng một FSM. Do đó, hành vi chuyển trạng thái là đúng khi:

22

- Trạng thái trước đó có gọi hàm chuyển trạng thái không. - Điểu kiện chuyển trạng thái có thỏa mãn không.

Khi thỏa mãn các điều kiện trên, thì sự chuyển trạng thái được thực hiện đúng và sẽ chuyển qua trạng thái mới. Như vậy, các join-point được xác định các điểm chuyển trạng thái; before advice sẽ chứa các hành vi kiểm tra sự chuyển trạng thái này là đúng hay sai. Sau đó, mã trạng thái được thay đổi; after advice chứa các hành vi kiểm tra điều kiện loop,alt, break, opt và kiểm tra điều kiện dừng.

Để tiện cho việc kiểm tra, Trạng thái ban đầu của máy trạng thái ta đặt là “0”, dùng một biến Id để xác định tên các trạng thái hiện tại(ArrayList<String> Id).

Tại before, kiểm tra xem phương thức gây biến đổi trạng thái có phải bắt đầu từ một trạng thái có thể hiện tại hay không? Nếu vi phạm thì thông báo lỗi. Sau đó cập nhật lại trạng thái hiện tại. Trạng thái hiện tại được đặt mặc định ban đầu là “0”.

Tại after advice. Khi này trạng thái hiện tại đã là trạng thái mới. Khi đó ta kiểm tra xem trạng thái này có thuộc alt, loop, opt hay break không, để đưa ra các hướng giải quyết tương ứng. Nếu nó là một trong các trạng thái kết thúc thì đưa ra thông báo tổng quát về qua trình thực hiện.

Thuật toán sinh mã Aspect như sau : Bảng 3.2: Thuật toán sinh mã Aspect

Bước Nội dung (adsbygoogle = window.adsbygoogle || []).push({});

1 Duyệt danh sách các trạng thái FSM, lấy các trạng thái rồi lấy tập các thông điệp gây ra biến đổi trạng thái. Dùng các hàm để xử lý các thông điệp này và đưa nó về dạng @Implement * ten_ham(<danh sach doi so>). Sau đó đưa chúng vào pointcut. Việc này giúp chúng ta chỉ cần một pointcut.

2 Duyệt danh sách các trạng thái trong FSM lấy các trạng thái nguồn và các trạng thái đích tương ứng để tạo ra các điều kiện kiểm tra. 3 Tạo các pointcut, advice bằng cách thay thế các xâu tương ứng

vừa được tạo ra ở trên vào vị trí cần thiết.

23

Việc kiểm chứng cho từng thành phần đoạn gộp của biểu đồ trình tự lại có điểm khác nhau.

Đối với break, opt khi trạng thại của chúng được kích hoạt thì ta đưa ra thông báo. Trạng thái kích hoạt một đoạn gộp break hoặc opt là trạng thái đầu tiên cuả nó. Do đó, khi một phương thức nào đó, kích hoạt sự chuyển trạng thái đến trạng thái này thì ta thông báo sự chuyển trạng thái đó.

Đối với loop, nó cũng có trạng thái kích hoạt như trên. Nhưng với loop ta cần đếm số lần xuất hiện của nó. Do đó, ta dùng biến có tên dạng loop+<tên trạng thái> để đếm số lấn. Tại before, khi một trạng thái loop được kích hoạt thì ta tăng số lần đếm nó lên.Ví dụ: ta có một trạng thái kích hoạt loop là “2”. Ta đặt tên cho biến đếm lad loop2 và khởi tạo nó ban đầu là 0.

Đối với alt, Tương tự nó có các trạng thái kích hoạt, nhưng khác với loop, break, opt. Với alt có nhiều trạng thái kích hoạt, do đó ta cần chỉ ra nó kích hoạt theo hướng nào.

3.3. Kết luận

Trong chương này, tôi đã trình bày về cách xây dựng cấu trúc dữ liệu để mô tả các đoạn gộp. Từ đó, đưa các thông tin về các đoạn gộp vào máy trạng thái.

Tại chương này, tôi đã trình bày về phương pháp sinh Aspect từ máy trạng thái để kiểm tra giao thức sinh ra từ biểu đồ tuần tự. Nội dung chính của phương pháp là duyệt qua các trạng thái của FSM, tìm các thành phần tương ứng và đưa vào Aspect dưới dạng các pointcut và các advice. Aspect được đưa ra kiểm chứng được hầu hết các giao thức mô tả bằng biều đồ trình tự UML như vòng lặp loop, lựa chọn một thành phần(opt), lựa chọn nhiều thành phần(đoạn gộp alt) và đoạn gộp break. Đây là mở rộng của UML 2.

Aspect được sinh ra sẽ đan vào chương trình nguồn giúp cho việc kiểm chứng cho chương trình Java được thiết kế theo đặc tả của biểu đồ trình tự tương ứng.

24

Chương 4. Thực nghiệm

Để minh hoạ cho phương pháp xây dựng công cụ sinh Aspect được giới thiệu trong 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ả kiểm chứng trên một số giao thức thực tế.

4.1. Xây dựng công cụ

Sau khi đặc tả giao thức kiểm chứng bằng UML, công cụ altova Umodel2 hỗ trợ xuất biểu đồ ra dạng XMI và đây chính là đầu vào cho công cụ của tôi.

Áp dụng phương pháp đã giới thiệu ở các chương trước, tôi đã cái đặt thành công công cụ tự động sinh Aspect từ tài liệu XMI. Trong phương pháp này tối sử dụng công cụ eclipse3 và framework JDK để cài đặt công cụ. Giao diện làm việc của eclipse được minh họa như sau :

Hình 5.1a : Cài đặt bằng công cụ eclipse

Thuật toán cơ bản của phương pháp là việc phân tích tài liệu XMI, xây dựng cấu trúc mô tả các thành phần của biểu đồ trình tự UML. Từ đó, xây dựng máy trạng thái mô tả biểu đồ. Qua việc duyệt danh sách các trạng thái, phân tích tìm vị trí thích

2http://www.altova.com/umodel.html

25

hợp của sinh ra xâu chứa nội dung Aspect, xâu Aspect chứa các nội dung tuân theo cấu trúc của Aspect. Về thực chất quá trình này thông qua các thông điệp để xác định nguồn và đích tương ứng mới phương thức được gọi, để sinh ra Aspect.

Cài đặt công cụ thông qua các bước :

- Bước 1 : Tạo ra cấu trúc dữ liệu lưu các thông tin về biểu đồ trình tự. - Bước 2 : Cài đặt thuật toán sinh ra máy trạng thái (FSM).

- Bước 3 : Cài đặt thuật toán sinh tự động Aspect.

Hoàn tất quá trình cài đặt trên, tôi thu được công cụ tự động sinh mã kiểm chứng. Về công cụ của tôi, sau khi cài đặt như trên, tôi cài đặt dưới dạng một plugin dành cho eclipse. Với tên “org.eclipse.adj.creattoxmi”, để hoạt động được công cụ, đầu tiên phải copy file “org.eclipse.adj.creattoxmi.jar” vào thư mục “plugins” của eclipse. Khi đó, công cụ của tôi sẽ là một plugin dành cho eclipse, dưới đây là hình mô tả hoạt động của công cụ.

Hình 5.1b : mô tả hoạt động của công cụ.

Để hoạt động công của của tôi cài đặt, có một số yêu cầu như sau :

- Thứ nhất : copy file org.eclipse.adj.creattoxmi.jar vào thư mục plugins của eclipse. (adsbygoogle = window.adsbygoogle || []).push({});

26

- Thứ hai : import file Implement-Java.jar vào thư viện của project.

- Các file xmi được để trong một package của project.Mặc định, Aspect được sinh ra sẽ nằm trong package này.

- Hoạt động:

o Chọn file xmi cần chuyển qua Aspect.

o Nhấn ctrl + N

o Chọn Create Aspect from Xmi

Hình 5.1.c : Lựa chọn chức năng

o Đặt lại tên và địa điểm để aspect nếu cần. Nếu không Aspect được sinh ra có tên trùng với tên của file XMI được chọn và ở trong package chứa file XMI đó.

27

Hình 5.1d: Giao diện đặt tên cho aspect sinh ra

Nếu không có file XMI nào được chọn hoặc Aspect không sinh ra được thì sẽ tạo ra một Aspect mặc định không có nội dung bên trong.

4.2. Kiểm chứng một số giao thức thực tế

4.2.1. Kiểm chứng biểu đồ truy cập thông tin cơ bản của một máy ATM 4.2.1.1. Đặc tả giao thức 4.2.1.1. Đặc tả giao thức

28

Hình 4.2.1.1.Giao thức truy cập thông tin cơ bản ATM

Giao thức mô tả mối quan hệ giữa các lớp User, ATM, Consortium và Branch. Khi một đối tượng User gọi một phương thức getCashOnHand() một dãy các hàm được gọi phải tuân theo giao thức để hoàn thành quá trình. Quá trình được mô tả qua các thứ tự các hàm được gọi như sau :

getCashOnHand() -> validateAccoutinfo() -> verifyCardWithBank(int stringCardStrinp) -> getConnected().

4.2.1.2. Kiểm chứng

Sử dụng công cụ altova Umodel tôi vẽ lại giao thức trên. Sau đó, xuất ra dưới dạng tài liệu XMI làm đầu vào cho công cụ. File XMI sinh ra được để trong fackage xmi của project.

Khi chạy chương trình mã Aspect được sinh ra như sau :

public Aspect ATM{

29

private int numError = 0; // xác địn số lỗi hiện tại

private ArrayList<String> Id = new ArrayList<String>();//trạng thái hiện tại

ArrayList<String> listEnd = new ArrayList<String>();// các trạng thái kết thúc ////////////

Pointcut ATMChecked():call(@Implement * getConnected(char)) ||

call(@Implement * verifyCardWithBank(int)) || call(@Implement * validateAccoutinfo())|| call(@Implement * getCashOnhand());

before() : ATMChecked(){

String nameThisAspect = this.getClass().toString(); (adsbygoogle = window.adsbygoogle || []).push({});

nameThisAspect = nameThisAspect.substring( nameThisAspect.lastIndexOf(".") + 1, nameThisAspect.length());

String CallMethod = getNameMethod( thisJoin-pointStaticPart);

String AnnotationOfMethod = getAnnotationOfMethod(thisJoin-pointStaticPart); // kiem tra xem phuong thuc duoc goi co duoc dinh nghia de su dung aspect nay //khong

if(isPart(nameThisAspect,AnnotationOfMethod) == false)

return;

if(Id.isEmpty()) Id.add("0"); // khoi tao trang thai ban dau // Dua cac trang thai ket thuc vao danh sach listEnd

if(listEnd.isEmpty()){ listEnd.add("4"); }

isError = true; // mac dinh la goi thu tu phuong thuc sai ArrayList<String> l = new ArrayList<String>();

ArrayList<String> target = new ArrayList<String>();

// dua cac trang thai co the la trang thai nguon khi goi phuong thuc vao l // dua cac trang thai co the la trang thai ket thuc vao danh sach target if( CallMethod.equals("* getConnected(char)")){

l.add("3"); target.add("4"); }

else if( CallMethod.equals("* voidverifyCardWithBank(int)")){ l.add("2");

target.add("3"); }

30

l.add("1"); target.add("2"); }

else if( CallMethod.equals("* getCashOnhand()")){ l.add("0");

target.add("1"); }

setIdIfTrue(l,target);

/* kiem tra tinh dung sai cua viec goi phuong thuc, dat lai trạng thai hien tai*/

if(isError == true){ numError ++;

System.out.println("goi sai o dong phuong thuc "+ CallMethod +" o dong thu : "+thisJoin-pointStaticPart.getSourceLocation().getLine());

System.out.println("so loi hien tai : " + numError); Id.clear(); Id = target ;

} }

after():ATMChecked(){

/*Neu goi moi trang thai ket thuc nao do thi hien thi cac thong tin*/

for(int i = 0; i < listEnd.size(); i ++) if(Id.lastIndexOf(listEnd.get(i)) >=0){

System.out.println("so loi hien tai : " + numError); }

} }

Lập trình viên phải xây dựng các lớp User, AMT, Consortium với các phương thức cần thiết. Lớp User gồm các phương thức float getCashOnhand()

public class User { (adsbygoogle = window.adsbygoogle || []).push({});

@Implement("ATM.xmi")

float getCashOnhand(){

//do something

} }

31

Lớp ATM chứa phương thức : void validateAccoutinfo() và phương thức char getConnected(). Được mô tả như dưới đây.

public class ATM {

@Implement("ATM.xmi")

public char getConnected(){

//do something

}

@Implement("ATM.xmi")

public void validateAccoutinfo() {

// do somthing }

}

Lớp Consortium chứa phương thức void verifyCardWithBank(int stringCardStrinp) .Được cài đặt như dưới đây :

public class Consortium {

@Implement("ATM.xmi")

public void verifyCardWithBank(int stringCardStrinp){

// do something }

}

Aspect sinh ra được tích hợp vào mã nguồn tự động tại package xmi của project. Tôi được kết quả kiểm thử của một số đầu vào như sau:

 Test1 :

o chuỗi gọi hàm:

getCashOnhand();validateAccoutinfo(); verifyCardWithBank(0); getConnected();

o kết quả : hiển thị thông báo so loi hien tai : 0

o Nhận xét : Chuỗi gọi hàm đúng với đặc tả trong giao thức. Chương trình không báo lỗi.

32 o Chuỗi gọi hàm :

getCashOnhand();validateAccoutinfo(); getConnected(); o Kết quả :

Hình 4.2.1.2b. kết quả Test2 (adsbygoogle = window.adsbygoogle || []).push({});

o Nhận xét : Chuỗi gọi hàm sai với đặc tả, không chứa phương thức getConnected(). Chương trình báo lỗi và hiện ra thông báo lỗi. Chương trình hoạt động đúng.  Test3 : o Chuỗi gọi hàm : getCashOnhand();verifyCardWithBank(0); validateAccoutinfo();verifyCardWithBank(0); verifyCardWithBank(0); getConnected(); o Kết quả Hình 4.2.1.2c Kết quả Test3

o Nhận xét : Chuỗi gọi hàm sai đặc tả : Phương thức verifyCardWithBank(int) gọi trước phương thức validateAccoutinfo(). Chương trình hoạt động chính xác.

Như vậy, mới chỉ qua 3 ca kiểm thử đã có thể chứng minh Aspect do công cụ của tôi sinh ra có thể kiểm tra được chính xác giao thức được mô tả trên.

4.2.2. Kiểm chứng biểu đồ loop 4.2.2.1. Đặc tả giao thức 4.2.2.1. Đặc tả giao thức

Để minh chứng cho việc dùng Aspect sinh ra để kiểm chứng cho biều đồ dùng loop. Tôi lấy một ví dụ đơn giản. với biểu đồ trình tự được xây dựng như dưới đây.

33

Hình 4.2.2.1.Biểu đồ trình tự dùng loop đơn giản.

Phương thức m1() có thể được lặp lại nhiều lần.

4.2.2.2. Kiểm chứng giao thức

Aspect được sinh ra.

public Aspect Loop{

int loop2 = 0 ;

private boolean isError = false ;

private int numError = 0;

private ArrayList<String> Id = new ArrayList<String>();

ArrayList<String> listEnd = new ArrayList<String>(); ////////////////////

pointcut LoopChecked():call(@Implement * m2() )||call( @Implement * m1() )||

call(@Implement * m1())||call(@Implement * m2())||call(@Implement * m());

before() : LoopChecked(){

String nameThisAspect = this.getClass().toString();

nameThisAspect=nameThisAspect.substring(nameThisAspect.lastIndexOf(".") + 1, nameThisAspect.length());

String CallMethod = getNameMethod(thisJoin-pointStaticPart);

String AnnotationOfMethod= getAnnotationOfMethod( thisJoin-pointStaticPart ); if(isPart(nameThisAspect,AnnotationOfMethod) == false)

34 if(Id.isEmpty()) Id.add("0"); if(listEnd.isEmpty()){ listEnd.add("3"); } isError = true;

ArrayList<String> l = new ArrayList<String>(); ArrayList<String> target = new ArrayList<String>(); if( CallMethod.equals("* m2()")){ l.add("2"); target.add("3"); l.add("1"); target.add("3"); } else if( CallMethod.equals("* m1()")){ l.add("2"); target.add("2"); l.add("1"); target.add("2"); } else if( CallMethod.equals("* m()")){ l.add("0"); target.add("1"); } setIdIfTrue(l,target); if(isError == true){ numError ++;

System.out.println("goi sai o dong phuong thuc "+ CallMethod +" o dong thu : "+thisJoin-pointStaticPart.getSourceLocation().getLine());

Id.clear(); Id = target ; }

}

after():LoopChecked(){

/*Neu trang thai vua den la trang thai loop thi tang bien loop tuong ung them*/ if(Id.lastIndexOf("2")>=0) (adsbygoogle = window.adsbygoogle || []).push({});

35

for(int i = 0; i < listEnd.size(); i ++) if(Id.lastIndexOf(listEnd.get(i)) >=0){

System.out.println("vong loop thu 1bat dau bang phuong thuc* m1() duong goi "+loop2+ "lan");

if(numError > 0) System.out.println("so loi hien tai : " + numError); }

} }

Tiếp theo đây tôi sẽ đưa ra một số test để kiểm tra gia thức này.  Test1 :

o Đầu vào : m() -> m2() o Kết quả

Hình 4.2.2.2a : kết quả test1

o Nhận xét :

Đoạn gộp loop không được sử dụng, nó được gọi 0 lần, giao thức đặc tả đúng, không có lỗi. Kết quả đúng.

 Test2 o Đầu vào : m() -> m1() -> m1() -> m2() o Kết quả : Hình 4.2.2.2b: kết quả test2 o Nhận xét :

Trong test này, đoạn gộp loop được kích hoạt, nó được gọi 2 lần, giao thức miêu tả đúng, không có lỗi. Kết quả đúng.

 Test3

36 m1() -> m2() -> m1() -> m1() ->m2() o Kết quả :

Hình 4.2.2.2c: Kết quả test3

Một phần của tài liệu LUẬN VĂN: KIỂM CHỨNG CÀI ĐẶT BIỂU ĐỒ TƯƠNG TÁC VỚI UML 2.0 pdf (Trang 27 - 56)