Tải bản đầy đủ - 0 (trang)
Chương 2. Phân tích sâu mã nguồn theo công nghệ và xây dựng phụ thuộc

Chương 2. Phân tích sâu mã nguồn theo công nghệ và xây dựng phụ thuộc

Tải bản đầy đủ - 0trang

Hình 2.6. Quan hệ phụ thuộc sử dụng trường trong mã nguồn Java

thừa kế lớp cha mà lớp cha có trường được khai báo phạm vi protected hoặc default,

khi đó các phương thức trong lớp con có thể sử dụng trường đó. Ví dụ trong Hình 2.6,

lớp C thừa kế lớp A, lớp A có trường a1 với phạm vi protected và trường a2 với phạm

vi default. Khi đó, phương thức getSuperA1() và getSuperA2() của lớp C có thể sử

dụng trường a1, a2. Ngoài phạm vi protected và default, trường có phạm vi public có

thể được truy cập bởi mọi phương thức khác. Tiếp tục với Hình 2.6, phương thức

getPublicB() có thẻ sử dụng trường b của lớp B do trường b được khai báo phạm vi là

public.

Quan hệ phụ thuộc cuối cùng trong Java là quan hệ phụ thuộc gọi phương thức.

Đây là phụ thuộc giữa hai phương thức khi phương thức này được sử dụng trong

phương thức kia. Hình 2.7 là ví dụ minh họa cho một phụ thuộc gọi phương thức.

Phương thức hello() trả về một chuỗi “Hello World!”. Phương thức sayHello() sử

dụng hello() để in chuỗi “Hello World!” đó ra màn hình.



Hình 2.7. Quan hệ sử dụng phụ thuộc gọi phương thức trong mã nguồn Java

2.2.Phân tích phụ thuộc mã nguồn Struts



22



Struts là một cơng nghệ phục vụ phát triển các ứng dụng Web trên nền tảng Java.

Các ứng dụng Struts được thiết kế theo mô hình MVC7 (Model-View-Controller).

View Result thường sử dụng mã nguồn JSP đại diện cho phần View của ứng dụng. Các

yêu cầu của người dùng đều được xử lý bởi Action. Các Action chính là các lớp Java

đại diện cho phần Controller. Các Action được Struts điều hướng tự động thông qua

lớp FilterDispatcher kết hợp với tệp cấu hình là struts.xml. Phần Model gồm các lớp

Java có nhiệm vụ tương tác với các bảng trong CSDL. Các Action chịu trách nhiệm xử

lý các phần lơ-gíc nghiệp vụ của ứng dụng bằng cách sử dụng các lớp trong phần

Model. Kết quả sau khi Action xử lý là các trang JSP hoặc dữ liệu để hiển thị lại cho

người dùng.



Hình 2.8. Mơ hình thiết kế của ứng dụng Struts 2

Do Struts là một framework mã nguồn mở nên ta có thể sử dụng ngay chính bộ

xử lí được xây dựng bên trong tên là XWork để phân tích các thành phần. Cách hoạt

động của XWork được mơ tả như Hình 2.9. Đầu vào của XWork là đường dẫn của tệp

struts.xml. Sau đó, XWork sẽ tạo nên một môi trường để xử lý tệp struts.xml, goi là

XWork Emulator.



Hình 2.9. Cơ chế hoạt động của Xwork

Đầu tiên XWork Emulator sẽ khởi tạo một Dispatcher. Dispatcher có hai nhiệm

vụ chính. Thứ nhất, nó khởi tạo và chạy các providers. Trong XWork Emulator, mỗi

provider sẽ đảm nhiệm một chức năng như: quản lý tệp (File Manager Provider), quản

lý thông số ứng dụng (Properties Provider), xử lý tệp cấu hình (Xml Configuration

7 https://struts.apache.org/primer.html



23



Provider), v.v. Nhiệm vụ thứ hai của Dispatcher là điều phối các tham số cấu hình của

HttpRequest vào các provider tương ứng khi nhận yêu cầu từ giao diện. Tất cả các

providers sau khi khởi tạo sẽ được đưa vào trong một Container theo cơ chế keyvalue. Cuối cùng, ta sẽ lấy được Configuration từ Container chứa các thơng số cấu

hình của ứng dụng và các thành phần của Struts như StrutsAction, StrutsPackage,

StrutsResult, StrutsInterceptor, v.v.

Tệp struts.xml sau bước xử lý mã nguồn XML được thể hiện như là một nút với

kiểu XmlFileNode trong JDG. Sau bước phân tích sâu mã nguồn của Struts, nút này

được chuyển đổi thành StrutsConfigurationNode bằng mẫu thiết kế Decorator [7]. Nút

kiểu StrutsConfigurationNode chứa các nút StrutsPackage theo đúng thứ tự các thẻ

XML trong mã nguồn. Ngồi ra nút StrutsConfigurationNode còn bao gồm các nút

StrutsConfigurationNode con được khai báo qua thẻ . Mối quan hệ phụ

thuộc giữa các nút đươc liệt kê trong Bảng 2.2. Ý nghĩa của từng phụ thuộc được cho

trong bảng. Tổng cộng có 10 loại phụ thuộc trong Struts.

Bảng 2.2. Danh sách phụ thuộc trong Struts

Tên phụ thuộc

UseSimpleFieldActionDependency

StrutsResultTypeConfiguration

ToJavaClassDependency

StrutsResultConfiguration

ToTilesDefinitionDependency

StrutsResultConfigurationToJsp

Dependency



Ý nghĩa của phụ thuộc

Jsp sử dụng struts-tag để gọi Action

Tệp cấu hình sử dụng Java Class để định nghĩa

Result Type

Tệp cấu hình sử dụng Tiles để định nghĩa View

Result

Tệp cấu hình sử dụng tệp Jsp để định nghĩa View

Result

Mối quan hệ thừa kế giữa hai thành phần cấu

StrutsPackageExtensionDependency

hình package

StrutsInterceptorToJavaClassDepende Tệp cấu hình sử dụng Java Class để định nghĩa

ncy

Interceptor

Các thành phần cấu hình sử dụng Interceptor

StrutsInterceptorStackRefDependency

Stack (action, package)

Các thành phần cấu hình sử dụng Interceptor

StrutsInterceptorRefDependency

(action, package, interceptor stack)

StrutsConfigurationIncludedDepende Tệp cấu hình chính struts.xml khai báo cáo tệp

ncy

cấu hình con

StrutsActionConfigurationToJavaClas Tệp cấu hình sử dụng Java Class để định nghĩa

sDependency

Action

2.3.Phân tích phụ thuộc cơ sở dữ liệu của JDBC



Các ứng dụng Java sử dụng JDBC như là một chuẩn để truy xuất cơ sở dữ liệu.

24



JDBC chịu trách nhiệm quản lí kết nối với CSDL, gửi các câu truy vấn được tạo từ

Java tới CSDL và xử lí kết quả sau truy vấn thành các đối tượng của Java. Trong ứng

dụng doanh nghiệp, các câu truy vấn thường được tạo từ trước. Sau đó, qua q trình

chỉnh sửa để phù hợp với nghiệp vụ, rồi được gửi cho CSDL bằng cách truyền vào

phương thức createQuery. Một ví dụ về sử dụng câu truy vấn được dùng trong ứng

dụng Sample như Mã nguồn 2.4.

Mã nguồn 2.4. Ví dụ một đoạn mã nguồn truy xuất CSDL bằng Java

public void printAddresses(int id) throws SQLException {

Connection con = DriverManager.getConnection("students.db");

String q = "SELECT * FROM address";

if (id!=0) q = q + "WHERE studentid=" + id;

ResultSet rs = con.createStatement().executeQuery(q);

while(rs.next()){

System.out.println(rs.getString("addr"));

}

}



Làm sao để biết được câu truy vấn cuối cùng có giá trị gì, gây ảnh hưởng đến

bảng nào của CSDL? Như ở Mã nguồn 3, để biết được điều đó ta phải xác định được

biến q trong phương thức executeQuery() có giá trị là gì. Giá trị này thực tế khơng thể

xác định chính xác hồn tồn được do bị ảnh hưởng bởi các tham số khác. Hiên nay có

một số cơng cụ hỗ trợ phân tích dự đốn giá trị của một biến kiểu String như: JSA [2],

JDBC Checker [4],… Nhưng nhược điểm của các công cụ này là chỉ phân tích được

bằng bytecode, khơng thể phân tích trực tiếp mã nguồn của chương trình. Hơn nữa,

một vấn đề trong Java cũng như mã nguồn của các ngôn ngữ khác, một phần giá trị

của câu truy vấn có thể do hàm khác tạo nên. Ví dụ như Mã nguồn 2.5, phương thức

getAllRecords() là hàm tạo và sử dụng câu truy vấn, nhưng thông tin bảng nào được

truy vấn lại là tham số truyền vào. Trong khi đó, getUsers() phương thức gọi

getAllRecords() và truyền vào tên bảng trong CSDL là User. Vậy hàm getUsers() rõ

ràng là phương thức tương tác với CSDL. Phần lớn các công cụ hiện nay chỉ tập chung

xây dựng giá trị chuỗi mà không tập trung vào vấn đề này.

Do vậy cần thiết phải có một phương pháp để có thể dự đốn chính xác nhất các

giá trị có thể xảy ra của câu truy vấn và phương thức sử dụng chúng ngay từ mã

nguồn. Khóa luận này đề xuất một phương pháp phân tích khơng những dự đốn chính

xác câu truy vấn mà còn xây dựng một bộ dữ liệu để lưu trữ và quản lý các DAO

(phương thức thực hiện các câu truy vấn để truy cập và xử lý dữ liệu).

25



Mã nguồn 2.5. Mã nguồn thể hiện sử dụng phương thức tương tác CSDL

public ResultSet getAllRecords(String tbl) {

String query = “Select * from ” + tbl;

ResultSet rs = session.createQuery(query);

return rs;

}

public User getUsers() {

ResultSet rs = getAllRecords(“User”);

List users = new ArrayList<>();

// chuyển dữ liệu của đối tượng rs về dữ liệu của users

return users;

}



Bộ phân tích câu truy vấn được xây dựng dựa trên mẫu thiết kế Visitor [7]. Cấu

trúc bộ phân tích được minh họa như Hình 2.10, gồm bốn phần chính: JDBC Import

Filter, Hotspot Finder, Query Analyzer và Value Tracer.



Hình 2.10. Cơ chế phân tích và xây dựng câu truy vấn từ mã nguồn

Hotspot là những vị trí trong mã nguồn Java, nơi mà mã nguồn Java thực hiện

câu truy vấn CSDL. Đối với JDBC, hotspot là nơi sử dụng phương thức createQuery().

Để tìm các hotspot này, đầu tiên, JDBC Import Filter sẽ lọc ra những mã nguồn Java

có khả năng là DAO. Quá trình lọc này dựa trên ba tiêu chí.

• Mã nguồn có import java.sql.*,

• Mã nguồn có import lớp java.sql.Connection,

• Mã nguồn có import lớp java.sql.Statement, java.sql.Statement hoặc



26



java.sql.Statement.

Nếu mã nguồn của một tệp Java chỉ cần đảm bảo được một trong ba tiêu chí này,

tệp đó đó sẽ được đưa vào một tập tiềm năng. Tiếp theo, mã nguồn của tất cả các tệp

tiềm năng này được quét bằng AST Visitor. AST Visitor sẽ đi vào từng thành phần trong

mã nguồn, vào sâu đến tận thành phần nhỏ nhất như các biến của các câu lệnh trong

phương thức. Bất cứ khi nào phát hiện có sự sử dụng phương thức createQuery(), AST

Visitor sẽ thông báo cho Hotspot Finder. Nhiệm vụ của Hotspot Finder lúc này là

kiểm tra xem phương thức có thực sự là dùng để tương tác CSDL hay không bằng

cách kiểm tra tham số. Nếu phương thức này sử dụng duy nhất một tham số, và tham

số đó ở dạng String hoặc một đối tượng khác như sử dụng phương thức toString(),

phương thức sẽ được chấp nhận và tham số sẽ được đưa vào bộ Query Analyzer. Nếu

khơng thỏa mãn điều kiện đó, phương thức sẽ bị bỏ qua và AST Visitor tiếp tục quá

trình quét.

Với mỗi một hotspot, bộ quản lý DAO sẽ tạo ra một bộ mô tả tương tác dữ liệu

(Data Access Descriptor) để lưu trữ các thơng tin trong q trình phân tích như là tập

câu truy vấn, danh sách các bảng trong CSDL được sử dụng, phương thức sử dụng,

v.v. Bộ quản lý DAO sẽ đảm bảo trong suốt quá trình phân tích truy vấn của một

phương thức, chỉ có một bộ mơ tả được tạo ra và có thể sử dụng mọi lúc trong q

trình phân tích. Nếu kết thúc q trình phân tích khơng xảy ra lỗi và phát hiện được

bảng có tham gia vào câu truy vấn, việc phân tích được coi là thành cơng, bộ mơ tả

hiện tại sẽ chứa đầy đủ thông tin về việc tương tác dữ liệu và được lưu trữ vào danh

sách của bộ quản lý DAO. Một bộ mô tả mới tiếp tục được tạo ra để lưu trữ thông tin

cho hotspot tiếp theo.

Query Analyzer đảm nhận nhiệm vụ phân tích cụ thể tham số của createQuery(),

kết hợp với bộ Value Tracer để xây dựng giá trị của chuỗi theo thứ tự xử lý câu lệnh

của mã nguồn. Tham số truyền vào sẽ thuộc một trong bốn nhãn như sau.











Infix: Tham số là một biểu thức trung tố, dạng “select * ” + “from Table”

Method: Tham số là một phương thức

Variable: Tham số là một biến

Raw Statement: Tham số là một câu truy vấn đầy đủ



Tương ứng với bốn nhãn là bốn kiểu phân tích tương ứng: Infix Analyzer, Method

Analyzer, Variable Analyzer, Raw Statement Analyzer. Chi tiết nhiệm việc phân loại

tham số và các kiểu phân tích tương ứng được cho trong Bảng 2.3. Do đặc thù mỗi

27



một kiểu tham số là khác nhau, nên một kiểu tham số tương ứng với một nhãn sẽ được

phân tích bởi bộ phân tích khác nhau. Với nhãn Infix tương ứng với biểu thức, bộ phân

tích biểu thức Infix Analyzer được sử dung. Với nhãn Variable tương ứng với một biến,

bộ phân tích biến Variable Analyzer được sử dụng. Tương tự như vậy với tham số là

phương thức, hoặc một giá trị chuỗi cụ thể, các bộ phân tích Method Analyzer hoặc

Raw Statement Analyzer được sử dụng.

Trong các bộ phân tích, bộ phân tích phương thức là đơn giản nhất. Do giá trị

thay thế của phương thức trong Java chính là biểu thức trong câu lệnh return. Với một

phương thức như Mã nguồn 2.6, khi sử dụng trong biểu thức

“from”+getTableName(), thì giá trị của biểu thức đó sẽ tương đương

“from”+“Table”.



Mã nguồn 2.6. Mã nguồn của một phương thức trong Java

public String getTableName() {

String tbl = “Table”;

return tbl;

}



Bảng 2.3: Thứ tự bộ phân tích truy vấn tùy theo các kiểu mã nguồn

Câu lệnh truy vấn

createQuery(“select *”

+ “from Table”)

createQuery(func())

createQuery(query)

createQuery(“from…”);



Kiểu của tham

số (theo AST)

InfixExpression

MethodInvocatio

n

SimpleName

StringLiteral



Nhãn tham số



Bộ phân tích



Infix



Infix Analyzer



Method



Method Analyzer



Variable

Variable Analyzer

Raw Statement Raw Statement

Analyzer



Như vậy, thay vì phân tích cả phương thức, ta chỉ cần phân tích câu lệnh return.

Tương tự như tham số của phương thức createQuery(), câu lệnh return có thể chứa

biểu thức thuộc cả bốn kiểu nhãn. Do đó, bộ phân tích phương thức phải xác định xem

biểu thức trong câu lệnh return sử dụng kiểu biểu thức nào. Sau đó, tùy vào kiểu biểu

thức là biểu thức trung tố, biến, phương thức hay là chuỗi để sử dụng bộ phân tích hợp

lý. Ví dụ như Mã nguồn 2.6, biểu thức trong câu lệnh return là một biến có tên tbl. Do

đó, bộ phân tích phương thức phải sử dụng bộ phân tích biến để đốn nhận giá trị chỗi

của biến này.



28



1 Phân tích câu truy vấn dưới dạng biến

Theo AST, biến trong mã nguồn Java được thể hiện là kiểu SimpleName. Để tìm

giá trị chuỗi mà biến này lưu trữ, ta cần phải “giả lập” đoạn mã nguồn có thao tác với

biến, nghĩa là xây dựng giá trị của chuỗi bằng cách thực hiện lại cách thức giá trị của

biến được thay đổi trong mã nguồn. Bộ phân tích sẽ truy ngược lại nơi mà biến được

khởi tạo, và bắt đầu thực hiện việc truy vết. Mỗi một vết là một vị trí trong mã nguồn,

nơi giá trị của biến bị thay đổi. Sau đó, tùy vào câu lệnh, bộ phân tích sẽ thực hiện lại

giống hệt cách thức mà giá trị của biến bị thay đổi. Sau q trình này, giá trị tính tốn

của biến được lưu lại trong bộ phân tích. Có hai cách thức thay đổi của giá trị chuỗi

của một biến: cơng gộp (sử dụng tốn tử “+”) và sử dụng các phương thức xây dựng

sẵn (replace, trim, insert, v.v.).

Trong trường hợp gặp một vết kiểu cộng gộp chuỗi đơn giản (ví dụ var + “b”),

chuỗi “b” sẽ được gộp trực tiếp vào giá trị của biến var mà đang bộ phân tích đang

đốn nhận. Trong trường hợp thành phần được cộng gộp là một biến khác hoặc một

phương thức, tương ứng Variable Analyzer hoặc một Method Analyzer khác sẽ được sử

dụng và phân tích giá trị chuỗi cho biến hoặc phương thức mới đó, giá trị sau khi phân

tích sẽ được thêm vào giá trị chuỗi đang được đoán nhận hiện tại .

Trong trường hợp gặp vết là một phương thức xây dựng sẵn, bộ phân tích phải sử

dụng thêm bộ String Manipulation để cập nhật lại chuỗi theo từng phương thức. Đầu

vào của String Manipulation là tập truy vấn đang được đự đoán ở hiện tại, cùng với

các thông tin của phương thức như: tên, tham số đi kèm, v.v. Như hiện tại bộ String

Manipulation mới xử lý được cho các phương thức cơ bản như: replace (Replace

Operation), trim (Trim Operation), insert (Insert Operation), v.v.

Ngoài đối tượng String, trong Java, có một kiểu đối tượng dùng để lưu giá trị

chuỗi như StringBuilder, StringBuffer. Các lớp của đối tượng này đều kế thừa lớp

Appendable. Lớp Appendable định nghĩa cách thức cộng gộp giá trị chuỗi bằng

phương thức append(). Do có tính chất tương tự một biến đơn giản, nên các đối tượng

này được coi như là một biến. Để sử dụng giá trị chuỗi được lưu bên trong, các đối

tượng này phải sử dụng phương thức toString(). Như vậy, bộ phân tích phải xác định

những vị trí mà biến sử dụng phương thức toString(). Sau đó, truy ngược lại vị trí biến

được khởi tạo để kiểm tra biến có thuộc các đối tượng loại Appendable hay khơng.

Nếu có, bộ phân tích sẽ tìm các vị trí thay đổi giá trị của biến là phương thức append()

và các phương thức xây dựng sẵn khác để thực hiện việc đoán nhận giá trị.

29



2 Phân tích câu truy vấn dưới dạng biểu thức trung tố

Như đã nêu ở mục trước, tham số của biểu thức trung tố có dạng: a1+a2+a3+…

trong đó ai (i ∈ N) có thể là một hàm, biến, chuỗi String hoặc có thể là một biểu thức

trung tố khác. Thực chất, ai có thể là bất kỳ đối tượng nào, kể cả số, nhưng phiên bản

này chỉ xét đến những đối tượng có thể quy về chuỗi, và bỏ qua các kiểu dữ liệu khác.

Do biểu thức không thể có tốn tử nào khác ngồi tốn tử “+”, nên cấu trúc AST chia

biểu thức thành bốn phần:











Tốn hạng trái: Toán hạng đầu tiên của biểu thức (a1)

Toán tử: Toán tử “+”

Toán hạng phải: Toán hạng thứ hai của biểu thức (a2)

Tập toán tử mở rộng: Tập các toán hạng tiếp theo (a3, a4, a5,…).



Hình 2.11. Mơ tả cấu trúc AST của mã nguồn: “select ”+ “ * ” +“from ”+“Table”

Ví dụ với mã nguồn “select ” + “* ” + “from ” + “Table” , cấu trúc AST sẽ được

xây dựng như Hình 2.11. Đại diện của biểu thức trung tố trong AST là đối tượng

InfixExpression. Toán hạng trái của biểu thức là chuỗi “select”. Toán tử sử dụng trong

biểu thức là phép “+”. Toán hạng phải của biểu thức là chuỗi “*”. Còn lại, tập tốn tử

mở rộng có hai phần tử: chuỗi “from” và chuỗi “Table”.

Cần lưu ý rằng, vị trí của cặp đóng mở ngoặc “()” gây ảnh hưởng đến thứ tự các

toán tử. Với biểu thức (a1 + a2)+ a3 + a4 + …, toán hạng trái là a1 + a2, toán hạng phải

là a3 còn tập tốn tử mở rộng là a4, a5, … Còn với biểu thức a1 + (a2+ a3) + a4 + … thì

tốn hạng trái lại là a1, tốn hạng phải là a2 + a3 và tập toán tử mở rộng là a4, a5, …

Từng toán hạng trong biểu thức trung tố sẽ được đưa đoán nhận giá trị theo đúng

thứ tự từ trái sang phải. Tùy theo mỗi kiểu thể hiện của từng tốn hạng, bộ phân tích

biểu thức trung tố sẽ sử dụng một bộ phân tích khác nhau:

30



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Chương 2. Phân tích sâu mã nguồn theo công nghệ và xây dựng phụ thuộc

Tải bản đầy đủ ngay(0 tr)

×