Luận văn Nghiên cứu và cài đặt một công cụ trên nền tảng Eclipse để hỗ trợ phát triển các ứng dụng Java - Vũ Thanh Hà

Trong phát triển phần mềm, phương phát tiếp cận phát triển hướng miền được sử dụng cho những nhu cầu phức tạp, kết nối cài đặt với một mô hình đang phát triển của các khái niệm nghiệp vụ. DDD bao gồm một ngôn ngữ chung, các kỹ thuật và mô hình cũng như một kiến trúc; tập trung vào mô hình hóa các vấn đề cần giải quyết. Với DDD, các nhà phát triển có được những kỹ thuật giúp tối thiểu hóa sự phức tạp và thúc đẩy sự cộng tác với các chuyên gia miền. Với những ưu điểm vượt trội của mình, DDD thực sự là một phương pháp phát triển phần mềm hiện đại và hữu ích. Công cụ hỗ trợ phát triển phần mềm hướng miền được thiết kế dựa trên các nguyên tắc DDD, giúp tự động sinh ra phần mềm từ các mô hình lớp miền. Nhờ đó, mà người dùng chỉ cần tập trung vào miền vấn đề và mô hình miền, toàn bộ phần mềm (bao gồm giao diện và lưu trữ đối tượng) sẽ được sinh ra một cách tự động và nâng cao hiệu xuất sản xuất phần mềm. Mặc dù, chức năng các phần mềm được tạo ra bởi công cụ, còn đơn giản nhưng công cụ đã giúp cho thiết kế hướng miền DDD lại gần hơn với các nhà phát triển phần mềm. Một trong những hạn chế của công cụ là không có giao diện trực quan, dẫn đến những khó khăn cho người dùng cũng như tốn nhiều thời gian trong quá trình sử dụng. Luận văn này đã giải quyết được hạn chế này bằng việc xây dựng một ứng dụng Eclipse plug-in. Về mặt lý thuyết, ứng dụng này được xây dựng từ ba thuật toán là thuật toán sinh phương thức cho phần mềm, thuật toán sinh cấu hình mô-đun phần mềm và cuối cùng là thuật toán sinh cấu hình phần mềm. Ứng dụng này là một phần của Eclipse và được tích hợp trực tiếp vào Eclipse. Qua đó, bất kì người dùng nào sử dụng công cụ có thể tải về và cài đặt vào Eclipse của mình để sử dụng. Điều này có ý nghĩa quan trọng giúp cho công cụ hỗ trợ phát triển phần mềm hướng miền được sử dụng rộng rãi hơn. Tuy nhiên, trong luận văn mới chỉ dừng lại ở việc xây dựng được ứng dụng Eclipse plug-in giúp trực quan hóa việc sử dụng công cụ hỗ trợ phát triển phần mềm hướng miền. Khi miền vấn đề lớn lên, mô hình miền trở nên phức tạp hơn, làm sao biết được mô hình miền được sinh ra bởi công cụ là đúng. Vì vậy, hướng phát triển tiếp theo của luận văn là xây dựng phương pháp kiểm tra tính đúng đắn của mô hình miền sử dụng các ánh xạ cấu trúc lớp miền được định nghĩa cho DCSL. Hy vọng, trong thời gian tới, tôi có thể phát triển và hoàn thiện nội dung này. Qua việc thực hiện luận văn, tôi đã thu được rất nhiều kiến thức bổ ích về một kiến thức phát triển phần mềm hiện đại là thiết kế hướng miền cũng như kiến thức về xây dựng ứng dụng một ứng dụng Eclipse plug-in. Tuy nhiên, do kiến thức có hạn nên trong luận văn không thể tránh khỏi những sai sót, khuyết điểm, tôi rất mong thầy nhận được sự đóng góp của quý thầy cô để luận văn được hoàn thiện hơn.

pdf73 trang | Chia sẻ: yenxoi77 | Lượt xem: 419 | Lượt tải: 0download
Bạn đang xem trước 20 trang tài liệu Luận văn Nghiên cứu và cài đặt một công cụ trên nền tảng Eclipse để hỗ trợ phát triển các ứng dụng Java - Vũ Thanh Hà, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
u không có lỗi xảy ra thì lớp miền đầy đủ và kết quả thành công sẽ được trả về lần lượt cho “Plug-in Handler”, “Plug-in UI” để hiển thị thông báo lên cho người dùng. Trường hợp có lỗi thì thông báo thất bại sẽ được trả về. 35 Quá trình được thực hiện tương tự cho việc sinh cấu hình mô-đun phần mềm, sinh cấu hình phần mềm. Biểu đồ lớp Hình 2.3: Biểu đồ lớp cho plug-in Có ba lớp chính được sử dụng trong plug-in là lớp quản lý và xử lý các sự kiện “Plug-in Handler”. Khi nhận được một sự kiện nào đó, lớp này sẽ phân tích và gọi đến các hệ thống con tương ứng để xử lý. Có ba hệ thống con được đóng gói trong ba thư viện được sử dụng là sinh phương thức cho lớp miền (BspaceGenToo), sinh cấu hình mô-đun phần mềm (MCCGenTool) và sinh cấu hình phần mềm (SWCGenTool). Biểu đồ triển khai Hình 2.4: Biểu đồ triển khai cho plug-in Máy chủ update-site của Eclipse quản lý tất cả các update-site của người dùng. Plug-in sau khi hoàn thành, nếu muốn trở thành một phần của Eclipse và người dùng khác có thể tải về và sử dụng, thì plug-in phải được đóng gói dưới dạng một “deployable feature” và một trang cập nhật “update-site”. Người dùng đăng ký trang cập nhật plug-in của mình với máy chủ update-site của Eclipse. Người dùng khác muốn cài đặt và cập nhật plug-in đó, có thể vào Help > Install New Software > điền tên plug-in > Install. 36 2.3.2. Thuật toán sinh phương thức và Thuật toán sinh cấu hình mô-đun Các thuật toán được đóng gói trong các thư viện tương ứng và được plug-in sử dụng. Thuật toán sinh phương thức Mô hình lớp miền được xây dựng sử dụng các annotation đính kèm trên lớp và các thành phần của lớp. Ban đầu, lớp miền chưa đầy đủ, nó chỉ chứa các thuộc tính phản ánh miền vấn đề và cần phải xây dựng các phương thức cho nó. Công việc này chính là ánh xạ cấu trúc giữa không gian trạng thái và hành vi của một lớp miền. Về mặt lý thuyết, các quy tắc ánh xạ cấu trúc được sử dụng [6] là: TT Thành phần không gian trạng thái SSEP (thuộc tính) Thành phần không gian hành vi BSEP (phương thức) DAtrr DAssoc DOpt Property Stateful func. Property Stateful func. Property Stateful func. 1 auto isNotAuto - - type isObjectFormContructorType type isNotCollection Type - - 2 auto isNotAuto - - type isRequiredContructorType type isNotCollection Type - - type optional isNotOptional - - type 3 mutable isMutable - - type isSetterType 4 auto isAuto - unassign type isAutoValueGenType 5 type isCollectionType ascType isOneMany Asc type isLinkAdderNewType type isLinkAdderType type isLinkUpdaterType endType isOneEnd type isLinkRemoverType type isLinkGetterType type isLinkSetterType 6 type isDomainType ascType isOneOne Asc type isLinkAdderNewType Mỗi dòng của bảng định nghĩa một quy tắc ánh xạ cấu trúc. Không gian trạng thái liên quan đến hai meta-attribute là DAtrr và DAssoc. Mỗi meta-attribute có các thuộc tính con trong cột “property” và các hàm trạng thái “stateful func.” kết hợp với nó, giá trị của thuộc tính con bị rằng buộc bởi hàm trạng thái tương ứng. Cụ thể, tên của mỗi hàm trạng thái mới trong không gian hành vi là một giá trị OptType. Ví dụ, hàm isAuto có nghĩa là kiểm tra xem DAttr.auto=true; tương tự, hàm isSetterType có nghĩa là kiểm tra DOpt.type=Setter. Các quy tắc này quy định các phương thức gì sẽ được sinh ra từ các mô tả trong lớp miền. Quy tắc 3 ánh xạ SSEP(DAttr, isMutable) thành BSEP(DOpt, isSetterType). 37 Quy tắc 2 ánh xạ SSEP(DAttr, isMutable ∩ isNotOptional ∩ isNotCollectionType) thành BSEP(DOpt, isRequiredConstructorType), không gian trạng thái liên quan đến ba thuộc tính con và hàm trạng thái của nó được cấu thành bởi phép toán logic AND ba hàm trạng thái của ba thuộc tính con. Quy tắc 4 ánh xạ SSEP(DAttr, isAuto), (DAssoc, unassign) thành BSEP(DOpt, isAutoValueGenType). Quy tắc 5 ánh xạ 1 SSEP(DAttr, isCollectionType), (DAssoc, isOneManyAsc ∩ isOneEnd) thành 6 BSEP: (DOpt, isLinkAdderNewType), (DOpt, isLinkAdderType), (DOpt, isLinkUpdateType), (DOpt, isLinkRemoverType), (DOpt, isLinkGetterType), (DOpt, isLinkSetterType). Về mặt kỹ thuật lập trình, thuật toán Bspace được sử dụng để ánh xạ cấu trúc để tự động sinh ra đặc tả hành vi của một lớp miền [6]. Đầu vào: c là một lớp miền có không gian trạng thái xác định Đầu ra: c được cập nhật các phương thức //tạo các hàm khởi tạo 1. Đặt FU = { f | f ∈ cF , ¬ isAuto (DAttr ( f )), ¬ isCollectionType (DAttr ( f ))} 2. Đặt FR = { f | f ∈ FU , ¬ isOptional (DAttr ( f ))} 3. if FU ≠ ∅ then 4. Tạo trong c hàm khởi tạo đối tượng c1 (u1,, um ) (uj ∈ FU ) //quy tắc 1 5. if FR ≠ ∅ then 6. Tạo/cập nhật trong c hàm khởi tạo được yêu cầu c2(r1,, rm ) (rk ∈ FR ) //quy tắc 2 //tạo các hàm khác 7. for all f ∈ cF do 8. Tạo trong c hàm getter cho f 9. if isMutable (DAttr ( f )) then 10. Tạo trong c hàm setter cho f //quy tắc 3 11. if def(DAssoc ( f )) then 12. if isOneManyAsc (DAssoc ( f )) AND isOneEnd (DAssoc ( f )) then 13. Tạo trong c các hàm liên quan đến liên kết cho f //quy tắc 5 14. else if isOneOneAsc (DAssoc ( f )) then 15. Tạo trong c hàm thêm liên kết mới cho f //quy tắc 6 16. if isAuto (DAttr ( f )) AND undef (DAssoc ( f )) then 17. Tạo trong c hàm tự động sinh giá trị cho thuộc tính cho f //quy tắc 4 Thuật toán lấy đầu vào là một lớp miền c có không gian trạng thái xác định, đầu ra tự động sinh trong c tập các định nghĩa phương thức. Giả sử mỗi loại phương thức có một mẫu có sẵn trong một ngôn ngữ lập trình hướng đối tượng đích. Hai tập FU và FR là các tập thuộc tính thỏa mãn không gian trạng thái của hai quy tắc 1 và 2. Mỗi tập hình thành các tham số của một hàm khởi tạo tương ứng, các hàm khởi tạo được tạo ra ở dòng 3-4 và 5-6. Câu lệnh tạo/ cập nhật trong dòng 6 cho phép trường hợp tập thuộc tính FU = FR thì hàm khởi tạo đối tượng ObjectFormContructor (c1) giống hàm khởi tạo được yêu cầu RequiredContructor (c2) và (c2) không cần tạo nữa. Thay vào đó, (c1) được gán bổ sung thêm một DOpt có kiểu RequiredContructor. 38 Vòng lặp for tại dòng 7-17 thực hiện các quy tắc ánh xạ 3-6, được áp dụng cho từng thuộc tính riêng của lớp. Quy tắc 3 được áp dụng tại dòng 10 để tạo một hàm setter cho thuộc tính miền f nếu nó là mutable. Quy tắc 4 được áp dụng tại dòng 17 để tạo một hàm tự động sinh giá trị cho thuộc tính f nếu nó là một trường tự động và không liên kết. Nếu f là một trường liên kết thì quy tắc 5 và 6 được sử dụng tại dòng 13-15 để tạo các hàm bắt buộc liên quan đến liên kết đó cho hai trường hợp là liên kết một-một và liên kết một-nhiều. Thuật toán sinh cấu hình mô-đun phần mềm Mô hình kiến trúc của phần mềm COURSMAN, được sinh ra từ DomainAppTool như sau: Hình 2.5: Mô hình kiến trúc phần mềm COURSEMAN Mô hình kiến trúc trên định vị mô hình miền tại lõi và hiện đang tập trung vào việc xây dựng giao diện người dùng trong một lớp xung quanh lõi này. Nó được xây dựng trên hai khái niệm chính [9]: lớp mô-đun dựa trên MVC (các đặc tả về mô-đun phần mềm) và lớp chứa các mô-đun (các đặc tả về phần mềm) . Một lớp mô-đun là một lớp có cấu trúc dựa trên MVC được sử dụng để tạo ra mô-đun. Lớp này bao gồm 3 thành phần: 1 mô hình (một lớp miền), 1 lớp View và 1 lớp Controller. Với một lớp miền C, các lớp View và Controller là các lớp tham số hóa nghĩa là chúng là hai lớp mẫu, có sẵn; lớp miền C có thể coi chúng như một tham số cấu hình. Tập trung chính của một lớp mô-đun là cấu hình ba thành phần của nó. Cấu hình này được gọi là lớp cấu hình mô-đun (MCC), cấu trúc MCC gồm 4 khái niệm: lớp mô-đun ModuleClass, trường giao diện ViewField, mô tả về mô-đun ModuleDesc và mô tả về thuộc tính AttributeDesc. ModuleClass được dẫn xuất từ lớp có tên Class và phản ánh lớp miền. ViewField được dẫn xuất từ các trường trong lớp miền và đại diện cho các trường trên giao diện hiển thị. ModuleDesc và AttributeDesc là các annotation được gắn cho ModuleClass và ViewField. Ví dụ về một ModuleStudent của lớp Student. 39 @ModuleDescriptor(name = "ModuleStudent", modelDesc = @ModelDesc( model = Student.class), viewDesc = @ViewDesc(formTitle = "Form: Student", imageIcon = "Student.png", domainClassLabel = "Student",parent=RegionName.Tools, viewType=Region.Type.Data, view = View.class), controllerDesc = @ ControllerDesc()) public class ModuleStudent { @AttributeDesc(label = "title") private String title; @AttributeDesc(label = "id") private int id; @AttributeDesc(label = "name") private String name; @AttributeDesc(label = "address") private Address address; @AttributeDesc(label = "enrolments") private Collection enrolments; } Thuật toán MCC [9] được sử dụng để sinh cấu hình mô-đun phần mềm trên: Đầu vào: c: Lớp miền Đầu ra: m: lớp cấu hình mô đun phần mềm MCC //tạo tiêu đề cho m 1. Đặt nc = c.name, nm = “Module” + nc 2. Đặt m = Class (visibility = “public”, name = nm ) // tạo ModuleDesc cho m 3. Đặt do = ModelDesc (model = c) 4. Đặt dv = ViewDesc(formTitle= “Form:” + nc, domainClassLabel = nc) 5. Đặt dc = ControllerDesc () 6. Đặt dm = ModuleDesc(m): modelDesc = do, viewDesc = dv, controllerDesc= dc // tạo các ViewField cho m 7. Đặt fd = Field( class = m, visibility = “private”, name = “title”, type = String) 8. Tạo AttributeDesc ( fd ): label = nc 9. Đặt cF = { f | f : Domain Field, f ∈ c.fields} // các trường của lớp miền c // tạo một ViewField để phản ánh mỗi trường của lớp miền c 10. AddViewFields (m, cF ) 11. return m 12. Function AddViewFields (Class m, Set F): 13. for all f in F do 14. Đặt nf = f.name, tf = f.type 15. Đặt fd = Field (class = m, visibility = “private”, name = nf, type = tf ) 16. Tạo AttributeDesc (fd ): label = nf 40 MCC được tạo ra hoàn toàn tự động. Tuy nhiên, một số phần (dòng 4, 6, 8,16) chứa các thuộc tính có thể tùy chỉnh được. Chúng bao gồm các thuộc tính liên quan đến khung nhìn như tiêu đề, nhãn, icon và các thuộc tính liên quan đến các quy tắc cấu hình, ví dụ như nếu MCC là không có giao diện người dùng thì thuộc tính ViewDesc (view = View ) cần được thay đổi sang ViewDesc (view = null). Thuật toán này giúp sinh ra cấu hình mô-đun phần mềm theo cách biểu diễn các thông tin đặc tả về mô hình, giao diện, controller dưới dạng các annotation. Nhờ đó, công cụ hỗ trợ phát triển phần mềm DomainAppTool có thể giải mã được, và tạo ra mô-đun phần mềm tương ứng. 2.3.3 Thuật toán sinh cấu hình phần mềm SWC Nếu như lớp cấu hình mô-đun MCC tập trung vào mô tả cấu hình ba thành phần chính MVC của nó thì cấu hình phần mềm SWC tập trung vào mô tả cấu hình toàn hệ thống. Cấu trúc SWC chứa 3 khái niệm: lớp cấu hình SWC, lớp cấu hình mô-đun ModuleClass và mô tả về hệ thống SystemDesc. Lớp cấu hình SWC được dẫn xuất từ thứ tự vòng lặp phát triển do trong mỗi vòng lặp, một lớp cấu hình SWC cần được tạo thành để sinh ra nguyên mẫu phần mềm. ModuleClass được dẫn xuất từ lớp có tên Class và phản ánh lớp miền. Trong mỗi vòng lặp phát triển, SWC có thể chứa một số lớp cấu hình mô-đun khác nhau. Các mô tả SystemDesc bao gồm : thông tin chung về hệ thống (tên ứng dụng, logo, ngôn ngữ sử dụng), thông tin về tổ chức OrgDesc (tên tổ chức, logo, trang web), thông tin về cơ sở dữ liệu của hệ hệ thống DSDesc (loại cơ sở dữ liệu, url, user/password, loại kết nối,), thông tin các MCC được sử dụng Modules, mô tả về cài đặt SetUpDesc, mô tả về bảo mật SecurityDesc. ModuleDesc là annotation được gắn cho lớp SWC . Ví dụ về một SWC trong vòng lặp phát triển thứ nhất: @SystemDesc( appName = "Courseman", splashScreenLogo = "coursemanapplogo.jpg", language = Language.English, orgDesc = @OrgDesc(name = "Faculty of IT", address = "K1m9 Nguyen Trai Street, Thanh Xuan District", logo = "hanu.gif", url = ""), dsDesc = @DSDesc(type = "postgresql", dsUrl = "//localhost:5432/domainds", user = "admin", password = "password", dsmType = DSM.class, domType = DOM.class, osmType = PostgreSQLOSM.class, connType = ConnectionType.Client), modules = { ModuleMain.class, ModuleAddress.class, ModuleStudent.class, ModuleEnrollment.class }, sysModules = {}, setUpDesc = @SysSetUpDesc(setUpConfigType = SetUpConfig.class), securityDesc = @SecurityDesc(isEnabled = false)) public class SWC1 { } Thuật toán SWC được sử dụng để sinh cấu hình phần mềm: 41 Đầu vào: c1,cN: các lớp cấu hình mô-đun (MCCs), m: ModuleMain.class, p: tên dự án, i: số thứ tự vòng lặp phát triển Đầu ra: s: lớp cấu hình phần mềm //tạo tiêu đề cho s 1. Đặt ns= “SWC” + i 2. Đặt s = Class (visibility = “public”, name = ns ) 3. Đặt da = AppName(p) 4. Đặt dlo = ScreenLogo(p + “logo.png” ) 5. Đặt dla = Language(Language.English) 6. Đặt dm = Modules (c1,c2,cN, m) 7. Đặt do = OrgDesc(name = “name”, address = “address”, logo = “logo”, url = “url”) 8. Đặt dd = DSDesc(type = “postgresql”, dsUrl = “”, user = “”, password = “”, dsmType = DSM.class, domType = DOM.class, omsType = postgreSQL.class, connType = ConnectionType.client 9. Đặt dsp = SysSetUpDesc( setUpConfigType = setUpConfig.class) 10. Đặt dsc = SecurityDesc( isEnable = false) 11. Đặt ds = SystemDesc(s) : appName = da , screenLogo = dlo , language = dla , orgDesc = do , dsDesc = dd , setUpDesc = dsp , securityDesc = dsc Đầu vào là các lớp cấu hình mô-đun MCC đã chọn trong vòng lặp phát triển thứ i, tên dự án, và một ModuleMain.class là mô-đun cấu hình cho lớp main khi chạy phần mềm. Đầu tiên, dòng : đặt tên của cấu hình phần mềm được đặt theo cú pháp “SWC” + số thứ tự vòng lặp phát triển. Các dòng từ 3-5 thiết lập các mô tả chung của hệ thống. Dòng 6 là các lớp mô-đun được sử dụng trong vòng lặp thứ i để tạo ra cấu hình phần mềm. Trong khi, dòng 7 mô tả về tổ chức thì dòng 8 mô tả về cơ sở dữ liệu của hệ thống. Dòng cuối cùng chuyển tất cả các mô tả về hệ thống ở trên thành các thuộc tính con cho metta-attribute SystemDesc của lớp SWCi. Như vậy, lớp SWCi là một lớp rỗng chỉ chứa các cấu hình mô tả về hệ thống. Trong các mô tả đó, một số phần (dòng 4- 8) chứa các thuộc tính có thể tùy chỉnh được. Chúng bao gồm các thuộc tính liên quan thông tin về tổ chức, về cơ sở dữ liệu sử dụng và các thuộc tính liên quan đến các quy tắc cấu hình, ví dụ nếu hệ thống không sử dụng chính sách bảo mật thì thuộc tính isEnable trong SecurityDesc sẽ có giá trị là true. Tương tự như thuật toán MCC, thuật toán SWC giúp sinh ra cấu hình phần mềm theo cách biểu diễn các thông tin mô tả hệ thống dưới dạng annotation gắn với lớp. Sau đó, công cụ hỗ trợ phát triển phần mềm DomainAppTool sử dụng cấu hình này để tự động sinh ra nguyên mẫu phần mềm tương ứng. Hiểu một cách đơn giản, đây là quá trình mã hóa và giải mã. Quá trình mã hóa là cấu hình phần mềm phải được xây dựng dựa trên các quy tắc nhất định để công cụ DomainAppTool có thể hiểu được, các mô tả được biểu diễn dưới dạng thuộc tính con của các meta-attribute. Quá trình giải mã: công cụ DomainAppTool tạo ra phần mềm tương ứng dựa trên cấu hình phần mềm. Việc sinh cấu hình phần mềm từ cấu hình mô-đun phần mềm làm tăng tính mô-đun hóa cũng như khả năng tái sử dụng mô-đun của hệ thống. 42 2.4. Cài đặt chi tiết thiết kế plug-in Các bước thực hiện xây dựng plug-in như sau: Hình 2.6: Các bước xây dựng Plug-in Bước 1: Tạo dự án plug-in mới Vào File > New > Other > Plug-in Development > Plug-in Project để tạo tạo plug-in mới. Nhập tên dự án “DomainAppEclipsePlugin” . Màn hình tiếp theo hiển thị các thông tin được yêu cầu để tạo ra plug-in: Hình 2.7: Màn hình nhập thông tin ban đầu Plug-in mới 43 Tiếp theo chọn loại Template cho plug-in. Eclipse đã cung cấp rất nhiều loại Template nhưng đối với dự án này, “Hello, World Command” sẽ được sử dụng. Mẫu này giúp tạo ra các item mới trên Menu hoặc Context Menu, thêm các button mới vào thanh công cụ, Hình 2.8: Màn hình chọn Template cho Plug-in mới Cuối cùng, hoàn thành dự án mới được tạo ra sử dụng Template đã chọn. Đối với mẫu “Hello, World Command”, eclipse sẽ mặc định import bốn plug-in khác được yêu cầu cho Template và mặc định tạo package có tên theo cú pháp “ID + handlers”. Giao diện dự án mới như sau: Hình 2.9: Màn hình dự án Plug-in mới đã tạo Một dự án Eclipse plug-in sẽ chứa một vài tệp được sinh một cách tự động dựa trên nội dung đã điền khi tạo dự án. Các tệp chính trong một Eclipse plug-in là: 44  META-INF/MANIFEST.MF: mô tả tên, phiên bản và các dependencies của plug-in. Nếu dự án, có sử dụng thư viện bên ngoài thì cần phải được khai báo trong tệp này.  plugin.xml: khai báo những thành phần mở rộng mà plug-in cung cấp cho Eclipse runtime. Các nhãn biểu diễn cho lệnh/hành động/menu đều được khai báo trong tệp plugin.xml chứ không phải trong mã nguồn lập trình cho phép Eclipse hiển thị các menu trước khi cần tải hoặc thực thi bất kì mã nguồn nào. Đây cũng là lý do Eclipse khởi tạo rất nhất nhờ không cần tải hay thực thi các lớp. Tại thời điểm chạy, tùy vào hành động của người dùng mà các lớp yêu cầu sẽ được tải.  build.properties: được sử dụng khi build dự án. Nói chung, nó có thể được bỏ qua nhưng nếu plug-in cần thêm vào các nguồn tài nguyên mới như ảnh, tệp thuộc tính, nội dung HTML, thì cần được khai báo ở đây, nếu không nó sẽ không được tìm thấy. Bước 2: Thêm vào các thư viện cần thiết cho plug-in  Tạo thư mục /lib và import các thư viện .jar : dcsl.jar, mccl.jar, swcl.jar domainapp.jar và javaparser-core-3.2.5.jar.  Khai báo các thư viện ngoài trong tệp META-INF/MANIFEST.MF: Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: MCCsGenerator Bundle-SymbolicName: DomainAppEclipsePlugin;singleton:=true Bundle-Version: 1.0.0.qualifier Require-Bundle: org.eclipse.ui, org.eclipse.jdt.core;bundle-version="3.13.50", org.eclipse.core.runtime;bundle-version="3.13.0", org.eclipse.core.resources;bundle-version="3.12.0", org.eclipse.core.expressions;bundle-version="3.6.0", org.eclipse.e4.core.di.annotations;bundle-version="1.6.0", org.eclipse.e4.core.services;bundle-version="2.1.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ClassPath: ., lib/domainapp.jar, lib/javaparser-core-3.2.5.jar, lib/dcsl.jar, lib/mccl.jar, lib/swcl.jar Bước 3: Tạo ba lớp handlers tương ứng với ba item trên Context Menu “Source” Plug-in này sẽ bổ sung ba item mới cho Menu “Source” là:  Generate Bspace: Khi người dùng chọn các lớp miền > Source > Generate Bspace. Handler “GenerateBspace” sẽ sinh ra các phương thức cho các lớp miền đã chọn. 45  Generate MCC: Khi người dùng chọn các lớp miền > Source > Generate MCC. Handler “GenerateMCC” sẽ sinh ra các cấu hình mô-đun phần mềm chứa các lớp miền đã chọn.  Generate SWC: Khi người dùng chọn các mô đun cấu hình phần mềm > Source > Generate SWC. Handler “GenerateSWC” sẽ sinh ra cấu hình phần mềm chứa các mô đun cấu hình phần mềm đã chọn. Ba lớp handers “GenerateBspace”, “GenerateMCC” và “GenerateSWC” có cấu tạo tương tự nhau, chỉ khác gọi đến các thư viện khác nhau khi sinh ra các tệp đâu ra. Ví dụ, “GenerateBspace” gọi đến thư viện sinh phương thức dcsl.jar, “GenerateMCC” gọi đến thư viện sinh cấu hình mô-đun phần mềm mccl.jar, còn “GenerateSWC” gọi đến thư viện sinh cấu hình phần mềm swcl.jar. Mã nguồn handlers “GenerateBspace” như sau: public class GenerateBSpace extends AbstractHandler{ private String rootSrcPath=""; @Override public Object execute(ExecutionEvent event) throws ExecutionException { Shell shell = HandlerUtil.getActiveShell(event); IStructuredSelection selections = HandlerUtil.getCurrentStructuredSelection(event); ICompilationUnit firstCu = (ICompilationUnit) selections.getFirstElement(); Iterator selectedElements = selections.iterator(); Object selectedElement; while (selectedElements.hasNext()) { selectedElement= selectedElements.next(); generateBSpaces(shell, selectedElement); } try { firstCu.getJavaProject().getProject().refreshLocal(IResource.FOLDER, null); } catch (CoreException e) { e.printStackTrace(); } MessageDialog.openInformation(shell, "Info", "Finish !!!"); return null; } private void generateBSpaces(Shell shell, Object firstElement) { ICompilationUnit cu = (ICompilationUnit) firstElement; String[] domainClsNameStr = new String[]{cu.getElementName().split("\\.")[0]}; try { String pkgName = cu.getPackageDeclarations()[0].getElementName(); BSpaceGenTool bSpaceGenTool = new BSpaceGenTool(rootSrcPath, pkgName, domainClsNameStr) ; bSpaceGenTool.exec(); } catch (JavaModelException e) { e.printStackTrace(); MessageDialog.openInformation(shell, "Error", e.getMessage()); } } 46 Khi người dùng nhấn vào “Generate Bspace”, phương thức execute của handler này được kích hoạt. Đầu tiên, lớp HandlerUtil sẽ xác định các lớp được lựa chọn (chính là các lớp miền) cho sự kiện nhấn chuột vừa xảy ra là gì. Sau đó, vòng lặp sinh phương thức gọi đến hàm generateBSpaces cho mỗi lớp miền được thực hiện. Hàm generateBSpaces sẽ đọc đường dẫn đến các lớp miền và sử dụng thư viện dcsl.jar để thực thi sinh ra các phương thức cho các lớp miền. Các handler còn lại được xây dựng một cách tương tự. Bước 4:Tạo các điểm mở rộng trong plug-in.xml Mở tệp plug-in.xml > chọn tab Extensions > hiện thị mặc định bốn điểm mở rộng cần được thiết lập : Hình 2.10: Màn hình Extensions  Tạo các command: Chọn org.eclipse.ui.commands > New > Generic > Sửa các thông tin: catagoryId, id, name. Hình 2.11: Màn hình tạo các command  Khai báo các lớp hander: Chọn org.eclipse.ui.handlers > New > Generic > Sửa các thông tin: class,commandId. Trong đó, thuộc tính class phải được trỏ đến 47 lớp handler đã tạo ở bước 3 còn commandId thì trỏ đến command tương ứng trong org.eclipse.ui.commands. Hình 2.12: Màn hình khai báo các handlers  Tạo các bindings: Chọn org.eclipse.ui.bindings > New > Generic > Sửa các thông tin: commandId, contextId và sequence. Trong đó, commandId được khai báo với command tương ứng trong org.eclipse.ui.commands; contextId thể hiện loại component nào được sử dụng (context menu, menu, button,), mỗi component có id mặc định khác nhau và được tra cứu trên các hướng dẫn của PDE; cuối cùng sequence hiển thị phím tắt cho component đã tạo. Hình 2.13: Màn hình khai báo các bindings  Thiết lập vị trí cho component mới: Chọn org.eclipse.ui.menu > New > Generic > Sửa các thông tin locationURI bằng “popup:org.eclipse.jdt.ui.source.menu?after=DPSeparator”: thêm thành phần mới này vào contextmenu “Source” sau một dòng ngăn cách. Tiếp tục, chọn “popup:org.eclipse.jdt.ui.source.menu?after=DPSeparator” vừa tạo > New > Generic > Sửa các thông tin: commandId, id, label. Trong đó, commandId chỉ đến command tương ứng đã tạo trong org.eclipse.ui.commands và label sẽ hiển thị tên item mới. 48 Hình 2.14: Màn hình khai báo vị trí của các item mới trên menu Bước 5: Chạy dự án Chọn dự án PDE đã tạo > Run As > Eclipse Plugin 2.5. Tổng kết chương Chương này đã mô tả chi tiết các bước thực hiện xây dựng plug-in từ thuật toán sử dụng, mô hình thiết kế plug-in cho đến cài đặt mã nguồn. Plug-in được tạo ra đáp ứng các yêu cầu đầu vào, hứa hẹn sẽ giúp cho công cụ hỗ trợ phát triển phần mềm hướng miền của nhóm tác giả [5] được sử dụng rộng rãi. Ở chương tiếp theo, plug-in sẽ được cài đặt và chạy thử nghiệm trên một ví dụ thực nghiệm. Từ đó, đánh giá được những điểm hạn chế và đề xuất các hướng phát triển. 49 CHƯƠNG 3. CÀI ĐẶT VÀ THỰC NGHIỆM 3.1. Giới thiệu chương Tính thực tiễn và hiệu quả của plug-in sẽ được đánh giá thông qua việc sử dụng một ví dụ phần mềm thực tế. Cụ thể, nội dung chính của chương bao gồm đưa ra một mô hình miền điển hình của một phần mềm thực tế để vận dụng plug-in vào việc sinh cấu hình phần mềm, kết quả thu được là phần mềm tự động được sinh ra theo cấu hình phần mềm đó. 3.2. Môi trường cài đặt Plug-in tương thích với Java phiên bản 1.8 và Eclipse phiên bản Oxygen.1a Release 4.7.1a . 3.3. Bài toán quản lý khóa học Như đã giới thiệu trong 1.4.3, CourseMan là ví dụ điển hình được sử dụng xuyên suốt để minh họa phương pháp thiết kế phần mềm hướng miền DDSDM cũng như ứng dụng của công cụ DomainAppTool. Trước đây, phần mềm được tự động sinh ra nhờ việc thực hiện một loạt các dòng lệnh command-line, gây khó khăn cho người dùng trong việc sử dụng công cụ DomainAppTool để thiết kế mô hình miền hoàn chỉnh. Trong chương này, luận văn cũng xin sử dụng CourseMan làm ví dụ thực nghiệm nhưng nhờ có plug-in, việc tạo ra CourseMan trở nên dễ dàng hơn. CourseMan là một phần mềm quản lý khóa học đơn giản bao gồm các chức năng quản lý sinh viên, quản lý lớp, quản lý mô-đun học, quản lý sinh viên đăng ký mô-đun học và báo cáo sinh viên theo tên. Sơ đồ ca sử dụng của CourseMan như sau: Hình 3.1. Mô hình ca sử dụng của CourseMan Áp dụng phương pháp phát triển phần mềm hướng miền DDSDM để xây dựng phần mềm CourseMan: 50 Phát triển một mô hình miền khái niệm Hình 3.2: Mô hình miền khái niệm và các mô hình con của CourseMan Bên phải hình 3.2 là mô hình miền khái niệm của CourseMan. Mô hình này được tạo nên bởi năm mô hình con. Các mô hình con được biểu diễn bởi hình ô-van điền đầy và được kết nối tới một ca sử dụng ở phía bên trái. Hai mô hình con đầu tiên chứa các lớp miền Student và Module tương ứng, mô hình con thứ ba chưa cả hai lớp miền Student, Module và liên kết giữa chúng. Liên kết này đại diện cho sự đăng ký của sinh viên vào các môn học. Định nghĩa các vòng lặp phát triển CourseMan có năm ca sử dụng tương ứng năm vòng lặp phát triển là: STT Ca sử dụng Các mô hình con 1 Manage students Student 2 Manage course modules CourseModule 3 Manage enrollments Student, CourseModule 4 Manage student classes SClass, Student 5 Manage student-by-name reports StudentByNameReport, Student Thực hiện các vòng lặp phát triển Các hoạt động được thực hiện trong vòng lặp thứ nhất : Hoạt động Mô tả Kết quả Phân tích Phân tích ca sử dụng “Manage students” để phát hiện ra một lớp mới tên là Address, đại diện cho Mô hình con với hai lớp miền Student và Address . 51 địa chỉ của mỗi Student . Thiết kế Áp dụng các quy luật thiết kế để thiết kế lớp miền Student và Address. Một mô hình con thiết kế được thiết kế chi tiết. Lập trình  Tự động sinh các phương thức cho lớp miền Student và Address sử dụng BspaceGen.  Tự động sinh cấu hình mô- đun phần mềm từ lớp miền sử dụng MCC  Tự động sinh cấu hình phần mềm từ mô-đun ModuleMain và các mô-đun vừa sinh sử dụng SWC.  Mã nguồn hoàn chỉnh của lớp miền Student và Address: đầy đủ các thuộc tính và phương thức.  Mã nguồn cho cấu hình mô-đun phần mềm là ModuleStudent và ModuleAddress.  Mã nguồn cấu hình nguyên mẫu phần mềm cho vòng lặp thứ nhất bao gồm ModuleMain, ModuleStudent và ModuleAddress Kiểm thử  Sử dụng thư viện của công cụ DomainAppTool với cấu hình phần mềm đã sinh để tạo ra nguyên mẫu phần mềm  Tạo mới/chỉnh sửa/xóa các đối tượng miền của mỗi lớp miền để kiểm tra thiết kế của lớp đó.  Kiểm tra bảng dữ liệu cho mỗi lớp bao gồm: test-case, kết quả mong đợi và kết quả thực tế. Thực hiện một cách tương tự cho các vòng lặp sau để thu được các nguyên mẫu phần mềm. Tích hợp các nguyên mẫu phần mềm Mặc dù các mô hình con của các vòng lặp có thể liên quan đến các tập con khác nhau của các lớp miền nhưng các lớp miền cùng với nhau tạo thành cây mã nguồn chung của mô hình miền CourseMan. Khi làm việc trên cùng một lớp miền trong các vòng lặp khác nhau thì lớp miền cần nhận ra yêu cầu của từng lần lặp. Giả các lần lặp không xung đột với nhau hoặc xung đột có thể giải quyết được thì một mô hình miền hoàn chỉnh của CourseMan sẽ được xây dựng. Tuy nhiên trong phạm vi của mình, luận văn chỉ tập trung vào việc xây dựng thuật toán tự động sinh cấu hình phần mềm cho các vòng lặp phát triển và cài đặt các thuật toán đó trên thành phần mở rộng Eclipse Plug-in. Phần sau sẽ mô tả chi tiết các bước thực hiện sinh nguyên mẫu phần mềm CourseMan sử dụng plug-in và đánh giá kết quả đạt được. 52 3.4. Kết quả thực nghiệm Bước 1: Chuẩn bị đầu vào Đầu vào của thực nghiệm là mô hình miền của CourseMan và lớp ModuleMain. Mô hình miền có thể là một mô hình miền chưa hoàn chỉnh, thông qua việc thực hiện các vòng lặp phát triển, mô hình miền sẽ được làm phong phú và hoàn thiện. Hình 3.3. Đầu vào của thực nghiệm Lớp ModuleMain là một lớp cấu hình mô-đun, chứa các cấu hình chung về lớp điều khiển, giao diện hiển thị, môi trường cài đặt, của phần mềm được khởi tạo. @ModuleDescriptor( name = "ModuleMain", viewDesc = @ViewDesc( formTitle = "Course Management App: CourseMan", imageIcon = "courseman.jpg", view = View.class, viewType = Type.Main, topX = 0.5, topY = 0.0, widthRatio = 0.75f, heightRatio = 1f, children = { RegionName.Desktop, RegionName.MenuBar, RegionName.ToolBar, RegionName.StatusBar }, excludeComponents = { Add }, props = { @PropertyDesc(name = PropertyName.view_toolBar_buttonIconDisplay, valueAsString = "true", valueType = Boolean.class), @PropertyDesc(name = PropertyName.view_toolBar_buttonTextDisplay, valueAsString = "false", valueType = Boolean.class), @PropertyDesc(name=PropertyName.view_searchToolBar_buttonIconDisplay, valueAsString = "true", valueType = Boolean.class), @PropertyDesc(name=PropertyName.view_searchToolBar_buttonTextDisplay, valueAsString = "false", valueType = Boolean.class), @PropertyDesc(name = PropertyName.view_lang_international, valueAsString = "true", valueType = Boolean.class), } ), controllerDesc = @ControllerDesc(controller = Controller.class), type = ModuleType.DomainMain, setUpDesc = @SetUpDesc(postSetUp = CopyResourceFilesCommand.class) ) public class ModuleMain { } 53 Mô hình miền của của CourseMain chứa bốn lớp miền. Mã nguồn lớp miền Student : @DClass(schema=”courseman”) public class Student{ /*** STATE SPACE **/ @DAttr(name = “id”, type = Type.Integer, id = true, auto = true, mutable = false, optional = false, min = 1.0) private int id; @DAttr(name = “name”, type = Type.String, length =30 , optional = false) private String name; @DAttr(name = “address”, type = Type.Domain, length = 20, optional = true) @DAssoc(ascName = “student-has-address”, role = “student”, ascType = AssocType.One2One, endType = AssocEndType.One, associate = @Associate(type= Address.class, cardMin = 1, cardMax= 1)) private Address address; @DAttr(name = “enrolments”, type = Type.Collection, optional = false, serialisable = false, filter = @Select(clazz = Enrolment.class)) @DAssoc(ascName = “std-has-enrols”, role = “student”, ascType = AssocType.One2Many, endType = AssocEndType.One, associate= @Associate(type= Enrolment.class, cardMin=0, cardMax= 30)) private Collection enrolments; /*** BEHAVIOUR SPACE **/ } Và mã nguồn lớp Address : @DClass(schema = "courseman") public class Address { /*** STATE SPACE **/ @DAttr(name= "id", id= true, auto= true, length= 3, mutable = false, optional = false, type = Type.Integer) private int id; @DAttr(name = "cityName", type = Type.String, length = 20, optional = false) private String cityName; @DAttr(name="student", type=Type.Domain, optional=true, serialisable=false) @DAssoc(ascName = "student-has-address", role = "address", ascType = AssocType.One2One, endType = AssocEndType.One, associate = @Associate(type= Student.class, cardMin = 1, cardMax = 1, determinant = true)) private Student student; /*** BEHAVIOUR SPACE **/ } Các lớp miền được thiết kế chứa các thông tin hướng miền và được mô hình hóa dưới dạng tập các meta-attribute gắn vào lớp và các thành viên của lớp. Ví dụ đối với lớp Address, DClass xác định schema lưu trữ các đối tượng miền là “courseman”, các thuộc tính khác có giá trị mặc định: serialisable = true : các đối tượng miền có thể được lưu trữ trong không gian lưu trữ có tên schema là “courseman”; mutable = true : 54 các đối tượng miền được hiển thị dưới dạng chỉ xem nên người dùng không được phép thay đổi trạng thái của chúng; singleton = false : có một vài đối tượng miền được tạo ra trong thời gian chạy của phần mềm Các lớp miền đầu vào có cấu trúc chưa hoàn thiện, thiếu các phương thức hoạt động. Các phương thức này sẽ được tự động sinh ra trong bước tiếp theo. Bước 2: Sinh phương thức cho lớp miền nhờ BspaceGen Các phương thức của lớp miền được sinh ra bằng cách thực hiện: Chọn các lớp miền > chuột phải, chọn Source > chọn Generate BSpace Hình 3.4: Giao diện menu sinh phương thức cho lớp miền Kết quả thu được hai lớp miền hoàn chỉnh. Mã nguồn lớp Address thu được như sau: @DClass(schema = “courseman”) public class Address { /*** STATE SPACE **/ @DAttr(name = "id", id = true, auto = true, length = 3, mutable = false, optional = false, type = Type.Integer) private int id; @DAttr(name = "cityName", type = Type.String, length = 20, optional = false) private String cityName; @DAttr(name= "student", type= Type.Domain, optional=true, serialisable= false) @DAssoc(ascName = "student-has-address", role = "address", ascType = AssocType.One2One, endType = AssocEndType.One, associate = @Associate(type = Student.class, cardMin = 1, cardMax = 1, determinant = true)) private Student student; 55 /*** BEHAVIOUR SPACE **/ private static int idCounter; @DOpt(type = DOpt.Type.Getter) @AttrRef(value = "id") public int getId() {} @DOpt(type = DOpt.Type.AutoAttributeValueGen) @AttrRef(value = "id") private static int genId(Integer id) {...} @DOpt(type = DOpt.Type.Getter) @AttrRef(value = "cityName") public String getCityName() {...} @DOpt(type = DOpt.Type.Setter) @AttrRef(value = "cityName") public void setCityName(String cityName) {...} @DOpt(type = DOpt.Type.Getter) @AttrRef(value = "student") public Student getStudent() {...} @DOpt(type = DOpt.Type.Setter) @AttrRef(value = "student") public void setStudent(Student student) {...} @DOpt(type = DOpt.Type.LinkAdderNew) @AttrRef(value = "student") public boolean setNewStudent(Student obj) { setStudent(obj); return false; } @DOpt(type = DOpt.Type.DataSourceConstructor) public Address(Integer id, String cityName) throws ConstraintViolationException { this.id = genId(id); this.cityName = cityName; this.student = null; } @DOpt(type = DOpt.Type.ObjectFormConstructor) public Address(String cityName, Student student) throws ConstraintViolationException { this.id = genId(null); this.cityName = cityName; this.student = student; } @DOpt(type = DOpt.Type.RequiredConstructor) public Address(String cityName) throws ConstraintViolationException { this.id = genId(null); this.cityName = cityName; this.student = null; } } Lớp miền Address mới có ba hàm khởi tạo, một hàm getter và hàm tự động sinh giá trị cho thuộc tính id; các hàm getter và setter cho thuộc tính cityName; và ba phương thức liên quan đến thuộc tính student. Trong ba phương thức này, hai phương 56 thức đầu là hàm getter và setter, phương thức cuối liên quan đến việc thêm mới các đối tượng Student kết hợp với Address. Các phương thức tạo có chứa meta-attribute tên là Dopt xác định loại phương thức. Loại tham số được sử dụng trong mỗi hàm khởi tạo phải là kiểu đối tượng. Hàm khởi tạo sử dụng hàm gentID, tự động tạo ra giá trị tiếp theo cho thuộc tính id. Hàm genID này sử dụng một thuộc tính tĩnh khác là idCounter để giữ giá trị lớn nhất đến thời điểm hiện tại của id. Thuộc tính id, không có hàm setter bởi vì nó có DAttr.mutable = false nghĩa là giá trị của nó không được thay đổi bởi người dùng. Phương thức setNewStudent thuộc loại Dopt.Type.LinkAdderNew đặc tả cho liên kết 1:1 giữa Student và Address nghĩa là thêm một liên kết mới từ đối tượng Student tới đối tượng Address đã tồn tại hoặc vừa tạo. Bước 3: Sinh tập cấu hình mô-đun phần mềm, được xây dựng từ mô hình lớp miền. Cách thực hiện: chọn các lớp miền sinh ra từ bước 2 > chuột phải, chọn Source > chọn Generate MCC : Hình 3.5: Giao diện menu sinh cấu hình mô-đun phần mềm Các cấu hình mô-đun phần mềm được sinh ra sẽ nằm trong gói modules và có tên được đặt theo nguyên tắc Module + Tên miền : 57 Hình 3.6: Cấu hình mô-đun phần mềm được sinh ra Mã nguồn cấu hình mô-đun phần mềm ModuleAddress, được xây dựng từ lớp miền Address. ModuleAddress là một lớp có kiến trúc dựa trên mô hình MVC bao gồm ba thành phần: một mô hình (lớp miền), một khung nhìn hiển thị giao diện người dùng và một lớp điều khiển. Mỗi lớp mô-đun có phạm vi trạng thái là một tập con của các thuộc tính của lớp miền được định nghĩa trong đặc tả mô-đun, ở đây là lớp Address. @ModuleDescriptor( name = "ModuleAddress", modelDesc = @ModelDesc(model = Address.class), viewDesc = @ViewDesc( formTitle = "Form: Address", imageIcon = "Address.png", domainClassLabel = "Address", parent=RegionName.Tools, view = View.class, viewType=Region.Type.Data), controllerDesc = @ControllerDesc()) public class ModuleAddress { @AttributeDesc(label = "title") private String title; @AttributeDesc(label = "id") private int id; @AttributeDesc(label = "cityName") private String cityName; @AttributeDesc(label = "student") private Student student; } Bước 4: Sinh tập cấu hình phần mềm từ tập cấu hình mô-đun phần mềm. Cách thực hiện: chọn ModuleMain và các cấu hình mô-đun phần mềm sinh ra từ bước 3 > chuột phải, chọn Source > chọn Generate SWC. Đối với vòng lặp thứ nhất 58 sử dụng 3 cấu hình mô-đun: ModuleAddress, ModuleEnrollment, ModuleStudent. Hình 3.7: Giao diện menu sinh cấu hình phần mềm Cấu hình phần mềm được sinh ra sẽ nằm trong gói software.config và có tên được đặt theo nguyên tắc SWC + Số thứ tự. Mỗi vòng lặp phát triển sử dụng các lớp cấu hình mô-đun phần mềm khác nhau để tạo ra cấu hình riêng cho mỗi nguyên mẫu phần mềm. Một biến tự động tăng sinh số thứ tự cho các cấu hình phần mềm. Ví du, trong vòng lặp thứ nhất, cấu hình phần mềm có tên là SWC1, vòng lặp thứ hai là SWC2. Hình 3.8: Cấu hình phần mềm SWC1 được sinh ra 59 Mã nguồn cấu hình phần mềm SWC1 là một lớp rỗng, có chứa các meta-attriubute mô tả chi tiết thông tin nguyên mẫu phần mềm được tạo ra như tên ứng dụng, ngôn ngữ sử dụng, thông tin về tổ chức, Lớp cấu hình phần mềm SWC1 cũng có kiến trúc dựa trên mô hình MVC với ba thành phần chính là một mô hình (các lớp mô-đun chứa lớp miền), một khung nhìn mô tả giao diện người dùng và một lớp điều khiển. Phần mô hình chứa các lớp mô-đun sử dụng: ModuleMain, ModuleAddress, ModuleStudent, ModuleEnrollment. @SystemDesc( appName = "Courseman", splashScreenLogo = "coursemanapplogo.jpg", language = Language.English, orgDesc = @OrgDesc(name = "Faculty of IT", address = "K1m9 Nguyen Trai Street, Thanh Xuan District", logo = "hanu.gif", url = ""), dsDesc = @DSDesc(type = "postgresql", dsUrl = "//localhost:5432/domainds", user = "admin", password = "password", dsmType = DSM.class, domType = DOM.class, osmType = PostgreSQLOSM.class, connType = ConnectionType.Client), modules = { ModuleMain.class, ModuleAddress.class, ModuleStudent.class, ModuleEnrollment.class }, sysModules = {}, setUpDesc = @SysSetUpDesc(setUpConfigType = SetUpConfig.class), securityDesc = @SecurityDesc(isEnabled = false)) public class SWC1 {} Làm tương tự đối với vòng lặp phát triển thứ hai, sử dụng cấu hình mô-đun phần mềm ModuleAddress, thu được cấu hình phần mềm SWC2: Hình 3.9: Cấu hình phần mềm SWC2 được sinh ra Cấu hình phần mềm SWC2 có mã nguồn chỉ sử dụng cấu hình mô-đun ModuleMain và ModuleAddress : 60 @SystemDesc( appName = "Courseman", splashScreenLogo = "coursemanapplogo.jpg", language = Language.English, orgDesc = @OrgDesc( name = "Faculty of IT", address = "K1m9 Nguyen Trai Street, Thanh Xuan District", logo = "hanu.gif", url = ""), dsDesc = @DSDesc( type = "postgresql", dsUrl = "//localhost:5432/domains", user = "admin", password = "password", dsmType = DSM.class, domType = DOM.class, osmType = PostgreSQLOSM.class, connType = ConnectionType.Client), modules = { ModuleMain.class, ModuleAddress.class }, sysModules = {}, setUpDesc = @SysSetUpDesc(setUpConfigType = SetUpConfig.class), securityDesc = @SecurityDesc(isEnabled = false)) public class SWC2 { } Thực hiện một cách tương tự cho các vòng lặp phát triển khác, sẽ thu được các cấu hình phần mềm riêng cho các nguyên mẫu phần mềm. Bước tiếp theo sẽ là sử dụng công cụ DomainAppTool để sinh ra nguyên mẫu phần mềm. Bước 5: Sinh phần mềm từ tập cấu hình phần mềm Tạo lớp CourseMan có hàm main khai báo lớp cấu hình phần mềm SWC1.class đã sinh và lớp thiết lập môi trường cài đặt mặc định SetupGen.class. public class CourseMan { public static void main(String[] args) { final Class SwCfgCls = SWC1.class; final Class SetUpCls = SetUpGen.class; SoftwareAio sw = new SoftwareStandardAio(SetUpCls, SwCfgCls); try { sw.exec(args); } catch (NotPossibleException e) { e.printStackTrace(); System.exit(1); } } } Tạo cấu hình JVM mặc định khi chạy mã nguồn: chuột phải CourseMan > RunAs > Run Configurations. Màn hình Run Configurations hiện ra. Trong panel bên trái, nhấn chuột vào Java Application > chọn biểu tượng thêm cấu hình mới : 61 Hình 3.10: Cấu hình Run Configurations để chạy mã nguồn Trong Arguments của panel chính, khai báo hai tham số: -Dlogging=true kích hoạt chức năng log hệ thống, tham số thứ hai thiết lập đối tượng miền sinh ra sẽ được lưu trong bộ nhớ chạy thay vì lưu trong cơ sở dữ liệu. Chạy chương trình: chuột phải CourseMan > Run As > Run Configurations. Màn hình Run Configurations hiện ra > chọn cấu hình CourseMan vừa tạo > cuối cùng chọn Run. Giao diện phần mềm CourseMan được sinh ra như sau: Hình 3.11: Giao diện phần mềm CourseMan 62 Vòng lặp phát triển đầu tiên sử dụng ba mô-đun cấu hình phần mềm, tương ứng với nó là ba form giao diện được sinh ra. Ba form này nằm ở trên menu Tools. Nhấn chuột vào từng form, giao diện hiển thị các thông tin về lớp miền tương ứng hiện ra. Trong mỗi form, các thuộc tính được cấu hình mặc định, ví dụ tiêu đề của form vẫn để là “title” hay tên các thuộc tính vẫn giữ nguyên như trong lớp miền. Nguyên nhân là do hiện tại các cấu hình mô-đun chứa các meta-attribute đính kèm với lớp hoặc thành viên của lớp dưới dạng các annotation, nếu không được thay đổi thủ công bằng tay thì phần mềm sẽ lấy các giá trị mặc định của cấu hình mô-đun. Hình 3.12: Giao diện các form của CourseMan trong vòng lặp đầu tiên Thay đổi cấu hình mô-đun của lớp Address bằng cách sửa giá thuộc tính label trong mã nguồn ModuleAddress : @ModuleDescriptor( name = "ModuleAddress", modelDesc = @ModelDesc(model = Address.class), viewDesc = @ViewDesc( formTitle = "Form: Address", imageIcon = "Address.png", domainClassLabel = "Address", parent=RegionName.Tools, view = View.class, viewType=Region.Type.Data), controllerDesc = @ControllerDesc()) public class ModuleAddress { @AttributeDesc(label = "Địa chỉ") private String title; 63 @AttributeDesc(label = "Mã thành phố") private int id; @AttributeDesc(label = "Tên thành phố") private String cityName; @AttributeDesc(label = "Sinh viên") private Student student; } Chạy lại phần mềm, giao diện CourseMan chứa form Address có các nhãn thuộc tính bằng tiếng Việt: Hình 3.13: Giao diện các form của CourseMan sau khi sửa cấu hình mô-đun Làm tương tự đối với các vòng lặp phát triển tiếp theo, các nguyên mẫu phần mềm CourseMan mới được sinh ra. Kiểm thử trên từng nguyên mẫu phần mềm, nhà phát triển phát hiện các lỗi xảy ra, các thuộc tính thiếu và quay trở lại thay đổi lớp miền. Thông qua các vòng lặp, kết quả cuối cùng thu được một lớp miền tối ưu nhất cho phần mềm. Trước đây, sau khi chỉnh sửa, các lớp miền phải được đóng gói dưới dạng .jar và phải sử dụng các lệnh command line trong terminal để thực hiện sinh ra nguyên mẫu phần mềm. Cứ như thế, mỗi lần thay đổi lớp miền, công việc này lại được lặp lại gây khó khăn cho các nhà phát triển phần mềm. Như vậy, nhờ có plug-in việc thực hiện các vòng lặp không những đơn giản hơn mà còn rất hữu ích trong việc xem và thay đổi cấu hình mô-đun phần mềm. 64 3.5. Tổng kết chương Kết quả thực nghiệm đã chứng minh công cụ plug-in giúp cho việc phát triển phần mềm hướng miền trở nên dễ dàng hơn. Các vòng lặp phát triển được thực hiện đơn giản thông qua nhấn chuột thay vì thực hiện một loạt các lệnh command line. Tuy nhiên, hệ thống vẫn còn ba hạn chế chính: một là phần mềm được thêm ra mới chỉ dừng lại ở các chức năng cơ bản là thêm, sửa, xóa; hai là việc thay đổi cấu hình mô- đun phần mềm hiện tại vẫn phải thực hiện thủ công bằng cách thay đổi trực tiếp mã nguồn mà số lượng thuộc tính nhiều, sẽ gây không ít khó khăn cho nhà phát triển; ba là chưa kiểm tra tính đúng đắn của lớp miền, cấu hình mô-đun phần mềm và cấu hình phần mềm (hiện tại, chủ yếu thực hiện kiểm thử phần mềm sinh ra có lỗi không). 65 KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN Trong phát triển phần mềm, phương phát tiếp cận phát triển hướng miền được sử dụng cho những nhu cầu phức tạp, kết nối cài đặt với một mô hình đang phát triển của các khái niệm nghiệp vụ. DDD bao gồm một ngôn ngữ chung, các kỹ thuật và mô hình cũng như một kiến trúc; tập trung vào mô hình hóa các vấn đề cần giải quyết. Với DDD, các nhà phát triển có được những kỹ thuật giúp tối thiểu hóa sự phức tạp và thúc đẩy sự cộng tác với các chuyên gia miền. Với những ưu điểm vượt trội của mình, DDD thực sự là một phương pháp phát triển phần mềm hiện đại và hữu ích. Công cụ hỗ trợ phát triển phần mềm hướng miền được thiết kế dựa trên các nguyên tắc DDD, giúp tự động sinh ra phần mềm từ các mô hình lớp miền. Nhờ đó, mà người dùng chỉ cần tập trung vào miền vấn đề và mô hình miền, toàn bộ phần mềm (bao gồm giao diện và lưu trữ đối tượng) sẽ được sinh ra một cách tự động và nâng cao hiệu xuất sản xuất phần mềm. Mặc dù, chức năng các phần mềm được tạo ra bởi công cụ, còn đơn giản nhưng công cụ đã giúp cho thiết kế hướng miền DDD lại gần hơn với các nhà phát triển phần mềm. Một trong những hạn chế của công cụ là không có giao diện trực quan, dẫn đến những khó khăn cho người dùng cũng như tốn nhiều thời gian trong quá trình sử dụng. Luận văn này đã giải quyết được hạn chế này bằng việc xây dựng một ứng dụng Eclipse plug-in. Về mặt lý thuyết, ứng dụng này được xây dựng từ ba thuật toán là thuật toán sinh phương thức cho phần mềm, thuật toán sinh cấu hình mô-đun phần mềm và cuối cùng là thuật toán sinh cấu hình phần mềm. Ứng dụng này là một phần của Eclipse và được tích hợp trực tiếp vào Eclipse. Qua đó, bất kì người dùng nào sử dụng công cụ có thể tải về và cài đặt vào Eclipse của mình để sử dụng. Điều này có ý nghĩa quan trọng giúp cho công cụ hỗ trợ phát triển phần mềm hướng miền được sử dụng rộng rãi hơn. Tuy nhiên, trong luận văn mới chỉ dừng lại ở việc xây dựng được ứng dụng Eclipse plug-in giúp trực quan hóa việc sử dụng công cụ hỗ trợ phát triển phần mềm hướng miền. Khi miền vấn đề lớn lên, mô hình miền trở nên phức tạp hơn, làm sao biết được mô hình miền được sinh ra bởi công cụ là đúng. Vì vậy, hướng phát triển tiếp theo của luận văn là xây dựng phương pháp kiểm tra tính đúng đắn của mô hình miền sử dụng các ánh xạ cấu trúc lớp miền được định nghĩa cho DCSL. Hy vọng, trong thời gian tới, tôi có thể phát triển và hoàn thiện nội dung này. Qua việc thực hiện luận văn, tôi đã thu được rất nhiều kiến thức bổ ích về một kiến thức phát triển phần mềm hiện đại là thiết kế hướng miền cũng như kiến thức về xây dựng ứng dụng một ứng dụng Eclipse plug-in. Tuy nhiên, do kiến thức có hạn nên trong luận văn không thể tránh khỏi những sai sót, khuyết điểm, tôi rất mong thầy nhận được sự đóng góp của quý thầy cô để luận văn được hoàn thiện hơn. 66 TÀI LIỆU THAM KHẢO Tiếng Việt 1. Septeni Technology, 2015, “Domain-Driven Design Quickly bản tiếng Việt” được dịch từ Abel Avram & Floyd Marinescu, (2006), “Domain-Driven Design Quickly”. Tiếng Anh 2. Eric Evans, (2013), “Domain-Driven Design: Tackling Complexity in the Heart of Software”, pp.4-99 3. Alex Blewitt, (2014), “Mastering Eclipse Plug-in Development”, pp. 7-77. 4. Eclipse, (2018), “https://help.eclipse.org/photon/index.jsp”, last visit was on 12/11/2018. 5. Duc Minh Le, Duc-Hanh Dang. (2017), “DomainAppTool: A Domain-Driven Software Development Tool”, Hanoi University. 6. Duc Minh Le, Duc-Hanh Dang, Viet-Ha Nguyen. (2016), “Domain-Driven Design Using Meta-Attributes: A DSL-Based Approach”, in KSE 2016, pp.67-72. 7. Duc Minh Le, Duc-Hanh Dang, Viet-Ha Nguyen. (2018), “On Domain Driven Design Using Annotation-Based Domain Specific Language”, 8. K. Czarnecki, (2004),“Overview of Generative Software Development,” in Unconventional Programming Paradigms 2004, no. 3566, pp. 326–341. 9. Duc Minh Le, Duc-Hanh Dang, Viet-Ha Nguyen. (2017), “Generative Software Module Development: A Domain-Driven Design Perspective”, in KSE 2017, pp.85-90. 10. B.Liskov and J.Guttag, 2000, “Program development in Java: abstraction, specification, and object-oriented design”, Pearson Education

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

  • pdfluan_van_nghien_cuu_va_cai_dat_mot_cong_cu_tren_nen_tang_ecl.pdf
Luận văn liên quan