ATM
6.2.2.1 Đặc tả giao thức
61
Giao thức mô tả tương tác giữa hai lớp Account và DBManager. Khi một đối
tượng Account gọi phương thức debit() một dãy các hàm được gọi phải tuân theo giao thức được định nghĩa để hoàn thành giao dịch:
Account.debit() -> Account.getBalance() -> DBManager.queryB() -> Account.setBalance() -> DBManager.updateB(). 6.2.2.2 Kiểm chứng Mã aspect: import java.io.File; import java.util.*; import org.aspectj.lang.JoinPoint; import readXMI_SequenceDiagram.*;
public aspect ProtocolChecker {
int NUMBER_OF_CLASSES = 2;
SharedStateManager sm = new SharedStateManager(NUMBER_OF_CLASSES);
static HashMap<String, Set<String>> fsm = null;
static HashSet<String> entrySigs, exitSigs; ProtocolChecker(){
if (fsm == null) loadProtocol(); }
pointcut pc_Account_debit(): call (void Account.debit()) ;
before(): pc_Account_debit() {
Object o = thisJoinPoint.getTarget();
if (!sm.isBinded(o))
sm.newSharedState(o); }
after(): pc_Account_debit() {
String s = thisJoinPoint.getSignature().toString(); Object o = thisJoinPoint.getTarget();
log("change state: " + sm.getSharedState(o).getState() + " ---> " + s);
sm.setSharedState(o, s);
}
pointcut pc_DBManager_updateB_String(String str): args(str) && call
(void DBManager.updateB(String));
before(String str): pc_DBManager_updateB_String(str) {
Object o = thisJoinPoint.getTarget();
if (!sm.isBinded(o)) sm.bind(o);
String s = thisJoinPoint.getSignature().toString();
if (! isValidState(o, s)) {
log("Invalid change: " + sm.getSharedState(o).getState() + " ---> " + s);
log(thisJoinPoint);
} }
after(String str): pc_DBManager_updateB_String(str){
String s = thisJoinPoint.getSignature().toString(); Object o = thisJoinPoint.getTarget();
log("change state: " + sm.getSharedState(o).getState() + " ---> " + s);
if (exitSigs.contains(s)) sm.reset(o);
62
pointcut pc_DBManager_queryB_String(String str): args(str) && call
(int DBManager.queryB(String));
before (String str): pc_DBManager_queryB_String(str) {
Object o = thisJoinPoint.getTarget();
if (!sm.isBinded(o)) sm.bind(o);
String s = thisJoinPoint.getSignature().toString();
if (! isValidState(o, s)) {
log("Invalid change: " + sm.getSharedState(o).getState() + " ---> " + s);
log(thisJoinPoint);
} }
after(String str): pc_DBManager_queryB_String(str) {
String s = thisJoinPoint.getSignature().toString(); Object o = thisJoinPoint.getTarget();
log("change state: " + sm.getSharedState(o).getState() + " ---> " + s);
sm.setSharedState(o, s); }
pointcut pc_Account_getBalance(): call (int Account.getBalance());
before (): pc_Account_getBalance() {
Object o = thisJoinPoint.getTarget();
if (!sm.isBinded(o)) sm.bind(o);
String s = thisJoinPoint.getSignature().toString();
if (! isValidState(o, s)) {
log("Invalid change: " + sm.getSharedState(o).getState() + " ---> " + s);
log(thisJoinPoint);
} }
after(): pc_Account_getBalance() {
String s = thisJoinPoint.getSignature().toString(); Object o = thisJoinPoint.getTarget();
log("change state: " + sm.getSharedState(o).getState() + " ---> " + s);
sm.setSharedState(o, s); }
pointcut pc_Account_setBalance_int(int ba): args(ba) && call (void
Account.setBalance(int));
before (int ba): pc_Account_setBalance_int(ba) {
Object o = thisJoinPoint.getTarget();
if (!sm.isBinded(o)) sm.bind(o);
String s = thisJoinPoint.getSignature().toString();
if (! isValidState(o, s)) {
log("Invalid change: " + sm.getSharedState(o).getState() + " ---> " + s);
log(thisJoinPoint);
} }
after(int ba): pc_Account_setBalance_int(ba) {
String s = thisJoinPoint.getSignature().toString(); Object o = thisJoinPoint.getTarget();
log("change state: " + sm.getSharedState(o).getState() + " ---> " + s);
sm.setSharedState(o, s); }
63 String s = "WRONG: " + jp.getSourceLocation() + ":" + jp.getSignature(); System.out.println(s); } void log(String s) { System.out.println("INF: "+ s); }
boolean isValidState(Object o, String st){
boolean b = fsm.containsKey(st);
SharedState state = sm.getSharedState(o); String objState = state.getState();
if (b)
b = fsm.get(st).contains(objState);
return b;
}
public void loadProtocol(){
try{
File xmlFile = new File ("./src/model/sequence.xml"); SequenceDiagramFSM colfsm = new
SequenceDiagramFSM(xmlFile); fsm = colfsm.fsm; entrySigs = colfsm.entrySigs; exitSigs = colfsm.exitSigs; } catch (Exception e) { e.printStackTrace(); } } }
Tương tự như với giao thức applet. Lập trình viên sẽ xây dựng hai lớp là Account
và DBManagernhư đã đặc tả. Mã aspectđược sinh ra từ công cụPVG sẽđược kết hợp với mã nguồn của chương trình. Sau đây là một sốtrường hợp kiểm chứng:
- CorrecTest1: o Lời gọi hàm: Account.debit(); ccount.getBalance(); DBManager.queryB("str"); Account.setBalance(1); DBManager.updateB("str"); o Kết quả: called debit() called getBalance() called queryB() called setBalance() called updateB()
o Nhận xét: chuỗi gọi hàm đúng với đặc tả giao thức, trong khi chạy không phát sinh lỗi.
- WrongTest1:
64 Account.debit(); DBManager.queryB("str"); Account.getBalance(); DBManager.queryB("str"); Account.setBalance(1); DBManager.updateB("str"); o Kết quả: Hình 6.8: Debit – wrongTest1
Nhật xét: Chuỗi gọi hàm sai đặc tả tại hai phương thức
DBManager.queryB("str"); Account.getBalance();vì vậy khi chạy, chương trình thông báo lỗi tại vị trí gọi hai phương thức này.
6.2.3 Kiểm chứng giao thức [A*B] n
Giả sử ta cần kiểm chứng giao thức được mô tả bằng biểu thức chính quy như
sau:
[void open() * void close()]3
Mã aspect sinh ra từ công cụPVG:
import org.aspectj.lang.JoinPoint;
public aspect ABnChecker{
int num = 0;
int count = 0;
int number = 3;
pointcut pc_open(): call (void open()); before(): pc_open() { if (num != 0){ log(thisJoinPoint); }} after(): pc_open() { count++;
65
num++;
if(count > number) log(thisJoinPoint);
}
pointcut pc_close(): call (void close()); after(): pc_close() {
num--;
if(num != 0 || count > number){ log(thisJoinPoint); }} void log(JoinPoint jp){ String s = "WRONG: " + jp.getSourceLocation() + ":" + jp.getSignature();
System.out.println(s); }
pointcut checkn() : call (void checkprotocolAnBn()); after(): checkn() {
if(count != number){
System.out.println("protocol is false"); }
}
/* copy this method to source code public static void checkprotocolAnBn(){ }
*/ }
Dưới đây là kết quả của một số ca kiểm thửđược thực hiện sau khi tích hợp mã
aspectvào chương trình chính: - WrongTest1:
o Chuỗi gọi hàm:
connectDB db = new connectDB(); db.open(); db.close(); db.open(); db.close(); o Kết quả: called open() called close() called open() called close() protocol is false - WrongTest2: o Chuỗi gọi hàm:
connectDB db = new connectDB();
db.open(); db.open(); db.close();
66 db.close(); db.open(); db.close(); o Kết quả: called open()
WRONG: CheckAxBn.java:40:void connectDB.open()
called open() called close()
WRONG: CheckAxBn.java:41:void connectDB.close()
called close() called open() called close()
- Nhận xét: Cả hai ca kiểm thử, chuỗi gọi hàm đều sai với đặc tả và trong khi chạy, chương trình đều báo lỗi.