Cách tiếp cận dựa trên truy xuất (Visitor-based) [19] là cách tiếp cận đơn giản nhất để sinh mã nguồn, bao gồm việc cung cấp một số kỹ thuật truy xuất để
duyệt cấu trúc biểu diễn của mô hình và ghi mã nguồn vào chuỗi văn bản. Một
ví dụ của phương pháp là Jamda, đây là một framework hướng đối tượng cung
cấp một tập các lớp đại diện cho mô hình UML, tập các API để thao tác trên mô hình và một kỹ thuật truy xuất (gọi là CodeWriters) để sinh mã. Mặc dù Jamda không hỗ trợ chuẩn MOF để định nghĩa các metamodel mới, nhưng các loại phần tử mô hình mới có thểđược đưa ra bằng các phân chia các lớp Java hiện có cho các loại phần tử mô hình được định nghĩa trước.
Hình 2.1- Sinh mã nguồn Java trong JAMDA 2.1.2 Sinh mã dựa trên Template
MDA đặt mô hình tại trung tâm của quá trình phát triển phần mềm hướng
mô hình. Có nhiều loại mô hình được sử dụng để mô tả các khía cạnh khác nhau của hệ thống trong khía cạnh độc lập với nền tảng. Cùng với đó là tập các phép
biến đổi được áp dụng chuyển đổi PIM sang PSM. Những mô hình PSM đó cần
được chuyển sang mã nguồn, các đặc tả triển khai, báo cáo, tài liệu, vv. Chuẩn QVT được đưa ra cho chuyển đổi mô hình tới mô hình (ví dụ: PIM tới PIM,
PIM tới PSM và PSM tới PSM). Còn chuẩn MOF Model to Text (mof2text)
được đưa ra để giải quyết bài toán chuyển đổi mô hình tới các yếu tố mang tính chất văn bản như mã nguồn, đặc tả triển khai, báo cáo… Thực chất chuẩn mof2text giải quyết bài toán chuyển đổi mô hình sang dạng thể hiện văn bản tuyến tính. Một con đường trực quan cho yêu cầu này là cách tiếp cận dựa trên template nơi mà văn bản được sinh ra tử mô hình được quy định như là một tập các template dạng văn bản mà được tham số hóa với các phần tử mô hình.
Một cách tiếp cận dựa trên template được sử dụng trong đó, một Template xác định một template văn bản cùng với các điểm mốc (placeholders) cho dữ
liệu được trích xuất ra từ mô hình. Những điểm mốc đó về bản chất là các biểu thức quy định các thành phần metamodel cùng với các truy vấn là cơ chế chính cho việc lựa chọn và trích xuất giá trị từ mô hình. Giá trị đó được chuyển đổi qua văn bản bằng cách sử dụng ngôn ngữ biểu thức dựa trên các thư viện xử lý chuỗi. Template có thể được sử dụng để giải quyết các yêu cầu chuyển đổi phức
tạp. Các chuyển đổi lớn hơn có thể được đưa vào thành mô đun với các phần
public và private [1].
Ví dụ, đặc tả Template dưới đây sinh mã nguồn Java từ một lớp UML
Hình 2.2- Đặc tả Template sinh mã nguồn Java [1] 2.1.3 Sinh mã từ mô hình biểu diễn Java
Mục tiêu cuối cùng của tiến trình MDSD là sinh mã nguồn chương trình từ
mô hình của hệ thống. Để đạt mục tiêu này thì có thể mô hình hóa ngôn ngữ lập
trình thành ngôn ngữ mô hình hóa. Khi đó một ngôn ngữ lập trình như Java có
thể xử lý như một ngôn ngữ mô hình khác, bằng cách áp dụng các kỹ thuật chuyển đổi mô hình thì có thể chuyển đổi qua lại giữa các mô hình sang mô hình Java. Hơn nữa các công cụ mô hình hiện nay có thể xử lý các chương trình Java
như xử lý các mô hình khác - cấu trúc và kiểu - thay vì xử lý chúng như văn bản. Khi đó tại bước chuyển đổi cuối cùng PIM sang PSM, ta thu được mô hình biểu diễn trên Java và có thể kết xuất ra mã nguồn chương trình.
Hình 2.3- Kết xuất mã nguồn Java từ mô hình Java
2.2 Mô hình JaMoPP biểu diễn Java
Chúng ta sẽ xem xét cụ thể Java metamodel và các chức năng của JoMoPP
trong phần dưới đây.
2.2.1 Java Metamodel
Như mô tả ở trên, hầu hết các chuyển đổi trong một tiến trình MDSD làm
giảm cấu trúc và kiểu của dữ liệu, thậm chí ở cấp độ mô hình hệ thống trừu
tượng (ví dụ: mô hình hóa Use Case). Tuy nhiên, việc chuyển đổi cuối cùng, từ
các mô hình tới mã nguồn thường được thực hiện một cách có cấu trúc yếu và không định kiểu sử dụng engine mẫu xử lý chuỗi. Đây là một nghịch lý từ kiểm tra kiểu và lỗi là quan trọng nhất khi tạo ra các mã nguồn biên dịch được.
Ngoài ra, nhiều nhà mô hình đặc biệt là những người tham gia vào công
đoạn cuối của một tiến trình MDSD cũng là lập trình viên. Thực tiễn phổ biến hiện nay, chẳng hạn như chú thích các mô hình với (định lại kiểu) mã nguồn
Java, cho thấy sự tích hợp chặt chẽ hơn giữa mô hình và ngôn ngữ lập trình
thường được mong muốn.
Có một khoảng cách giữa mô hình hóa và ngôn ngữ lập trình cần phải thu
hẹp để giải quyết nhiều vấn đề ngày nay trong những bước cuối cùng của tiến
trình MDSD. Khoảng cách là do thực tế là mô hình hóa và ngôn ngữ lập trình
thường được coi là những thứ khác nhau. Nếu một ngôn ngữ lập trình như Java có thể xử lý như một ngôn ngữ mô hình khác, các vấn đề thảo luận ở trên có thể được giải quyết như sau: các công cụ mô hình hiện nay có thể xử lý các chương
trình Java như xử lý các mô hình khác - cấu trúc và kiểu - thay vì xử lý chúng
như văn bản. Bằng cách sử dụng các công cụ metamodeling để mở rộng và tái sử dụng các đặc tả ngôn ngữ, Java (hoặc các thành phần của Java) có thể được sử dụng như bất kỳ ngôn ngữ mô hình khác. Kết quả là Java có thể được sử
dụng như bất kỳ ngôn ngữ mô hình khác.
Để thu hẹp khoảng cách cho ngôn ngữ lập trình Java và ngôn ngữ mô hình
hóa, nhóm nghiên cứu tại đại học Dresde, Đức đề xuất bộ công cụ JaMoPP [6]. Bộ công cụ này sử dụng Java như một ngôn ngữ mô hình bằng cách như sau:
JaMoPP định nghĩa metamodel hoàn chỉnh bao phủ toàn bộ ngôn ngữ
Java. Các metamodel được định nghĩa trong ngôn ngữ metamodelling
thường được sử dụng eCore cho phép nó được xử lý bởi công cụ
metamodelling để sửa đổi, mở rộng hoặc tái sử dụng.
JaMoPP định nghĩa cú pháp văn bản phù hợp với đặc tả của ngôn ngữ
Java và từ đó một parser tạo một thể hiện của metamodel từ mã nguồn Java và printer dùng để kết xuất mã nguồn Java từ Java metamodel.
Tương tự như metamodel, cú pháp văn bản cũng là một model và có thể
thay đổi, mở rộng, tái sử dụng và các công cụ (ví dụ: paser và printer) có thể được tạo lại.
Metamodel Java của JaMoPP phản ánh ngữ nghĩa tĩnh của Java thông qua tham chiếu chéo giữa các phần tử mô hình. Những tham chiếu đó
được thiết lập sau khi phân tích bằng một cơ chế phân tích mà triển khai cụ thể ngữ nghĩa tĩnh của Java. Cơ chế này được cài đặt trong một mô
Hình 2.4- Minh họa chuyển đổi Java Class sang EMF Object Model và kết xuất ra Java
Cùng với JaMoPP, các công cụ mô hình hóa dựa trên Ecore có thể xử lý các
tệp Java giống như xử lý các mô hình. Thêm vào đó, những công cụ tương tự có
thể áp dụng Java metamodel vào trong nó.
Hiện nay có một số lượng lớn các công cụ hoạt động trên các chương trình Java, có nghĩa là hoạt động trên thể hiện của các metamodel Java dù là minh
bạch hay ngầm định. Tuy nhiên bản thân đặc tả của Java (JLS) [6] không cung
cấp một metamodel hình thức của Java. Các trình phân tích Java (ví dụ: javac
hay Eclipse Java Development Tools (JDT)) cũng có những metamodel nội bộ
được viết bằng Java. Một cài đặt mà gần với giải pháp được chuẩn hóa là Java 5 của hệ thống Stratego/XT. Tuy nhiên không cài đặt nào ở trên tích hợp được với
các công cụ metamodeling chuẩn.
Ngoài ra, Java metamodel cung cấp bởi tổ chức OMG, dự án MoDisco hay
dự án SPOON dựa trên ngôn ngữ metamodeling chuẩn hóa (cụ thể là Ecore), tuy
nhiên không metamodel nào cung cấp một cách đầy đủ. Do đó, nhóm nghiên
cứu JaMoPP tiến hành so sánh các metamodel hiện có, trích xuất ra các điểm
chung và mở rộng để hỗ trợ JLS đầy đủ. Metamodel hoàn chỉnh có thể tìm hiểu
tại website JaMoPP. Trong JaMoPP, Java metamodel được định nghĩa trong 80
lớp trừu tượng và 153 lớp cụ thể và phân chia thành 18 gói. Metamodel này chứa tất cả các thành phần của ngôn ngữ Java (ví dụ: classifiers, imports, types, modifiers, members, statements, variables, expressions và literals).
Hình 2.5- Metalmodel cho ngôn ngữ Java [6]
Khi Java được biểu diễn trên metamodel thì bản thân nó trở thành một ngôn
ngữ mô hình hóa. Do đó việc chuyển đổi mô hình sang mô hình Java là hoàn
toàn có thể thực hiện được bằng các kỹ thuật chuyển đổi mô hình. Khi có được
mô hình Java thì mã nguồn Java có thể được kết xuất ra từ đó nhờ bộ công cụ
JaMoPP.
2.2.2 Chức năng JaMoPP
Để Java metamodel trên sử dụng được trong thực tế thì phải có một đặc tả cú pháp văn bản để các công cụ có thể được tạo ra. Bước tạo ra này sử dụng các
quy tắc cú pháp văn bản được đinh nghĩa trong ngôn ngữ đặc tả CS của
EMFText như là một đầu vào (mỗi một quy tắc cú pháp được định nghĩa cho
một metaclass). Kết quả và cài đặt các thành phần của công cụ (ví dụ: parser, printer và tập các reference resolvers) như sau:
Parsing: dựa trên Context-free Grammar (CFG) được sinh ra từ đặc tả
CS và được cài đặt sử dụng chiến lược phân tích giảm dần đệ quy mô tả.
Mặc dù Java không hoàn toàn là context-free.
Reference Resolving: tương ứng với phân tích ngữ nghĩa tĩnh trong mô
hình Java. EMFText tạo ra reference resolvers cho các tham chiếu
(references) không bị giới hạn (non-containment) bằng cách thay các tên
tượng trưng trong mô hình phân tích cấu trúc cây bằng các liên kết rõ ràng đến phần tử tương ứng. Bởi vì sự phân mảnh cao của các mô hình Java trong các tệp khác nhau, cho nên sẽ có rât nhiều các tham chiếu không bị giới hạn (non-containment). JaMoPP sử dụng global registry (tương ứng với Java classpath) để quản lý tài nguyên và vị trí vật lý.
Registry được sử dụng để tìm các tài nguyên mô hình liên kết chéo theo
yêu cầu và cho phép tham chiếu được giải quyết trong nhiều tệp. Thêm
vào đó, các tham chiếu có thể trỏ đến lớp trong thư viện mà ở dạng mã nhị phân. Để giải quyết vấn đề này, JaMoPP sử dụng bộ phân tích BCEL (Byte Code Engineering Library) và dịch đầu ra thành thể hiện của JaMoPP metamodel.
Printing Java Source Files: là đảo ngược của tiến trình phân tích.
EMFText tạo ra một printer từ đặc tả CS mà chứa phương thức print riêng cho từng metaclass. Theo từng quy tắc CS thuộc về một class, printer sinh ra từ khóa cho các phần tử của model, giá trị thuộc tính của phần tử và gọi đệ quy các phương thức để in ra các thành phần.
Tool Integration: công cụ tích hợp với ngôn ngữ mô hình hóa dựa trên
Ecore và công cụ được tích hợp vào nền tảng Eclipse bằng Eclips Modelling Framework (EMF) [11]. Các ngôn ngữ mới có thể tích hợp trong suốt vào nền tảng này bằng cách phát triển giao diện EMF
Resource. Do đó, JaMoPP cung cấp JavaResource cho các tệp *.java và
nguồn nhị phân để nạp và chứa các mô hình Java. Do đó, mặc dù là cú pháp văn bản, nhưng Java models có thể được xử lý bằng các công cụ
dựa trên EMF như bắt kỳ mô hình khác.
2.3 Ngôn ngữ chuyển mô hình ATL
Để phục vụ cho việc chuyển đổi mô hình trong MDA thì cần phải có các công cụ hỗ trợ quá trình chuyển đổi. Phần này chúng ta sẽ tìm hiểu về ATL, một trong những ngôn ngữ hỗ trợ chuyển đổi mô hình phổ biến nhất hiện nay.
2.3.1 Giới thiệu ATL
ATL [12] là bản cài đặt phù hợp với chuẩn OMG MOF/QVT RFP do nhóm
nghiên cứu AtlanMod thực hiện. ATL là ngôn ngữ chuyển đổi mô hình được đặc tả bằng cả metamodel và cú pháp cụ thể văn bản. Trong lĩnh vực (MDE), ATL cung cấp cho các nhà phát triển một con đường để tạo ra một tập các mô hình
đích từ một tập các mô hình nguồn. ATL là ngôn ngữ lai tạo giữa ngôn ngữ khai
báo và bắt buộc (declarative and imperative programming). Thông thường khi
viết các luật chuyển đổi thì ATL sử dụng kiểu khai báo: nó cho phép đơn giản
hóa việc thể hiện ánh xạ giữa mô hình nguồn và mô hình đích. Tuy nhiên ATL
cũng cung cấp cấu trúc bắt buộc (imperative constructs) để dễ dàng đặc tả ánh xạ khó thể hiện khi dùng kiểu khai báo.
Một chương trình chuyển đổi ATL bao gồm các luật xác định cách thức các phần tử mô hình nguồn được kết hợp và chuyển hướng đển các phần tử của mô hình đích. Bên cạnh chuyển đổi mô hình cơ bản, ATL định nghĩa một cơ sở truy
vấn mô hình cho phép xác định các yêu cầu đầu của vào mô hình.
Phát triển trên nền tảng Eclipse, môi trường phát triển tích hợp ATL cung
cấp một số công cụ phát triển tiêu chuẩn (đánh dấu cú pháp, sửa lỗi...) nhằm mục đích dễ dàng thiết kế các chuyển đổi ATL. Môi trường phát triển ATL còn cung cấp một số công cụ bổ xung dành riêng cho việc xử lý các mô hình và siêu mô hình. Những tính năng này bao gồm một hệ thống ký hiệu văn bản đơn giản dành riêng cho đặc tả siêu mô hình, nhưng cũng có một số cầu nối tiêu chuẩn giữa cú pháp văn bản thông thường và biểu diễn mô hình tương ứng.
Hình dưới đây cung cấp tổng quan quá trình chuyển đổi ATL
(Author2Person) sinh ra mô hình Person từ mô hình nguồn Author.
Hình 2.6- Tổng quan chuyển đổi mô hình trong ATL7 2.3.2 Cú pháp và ngữ nghĩa ATL
Ngôn ngữ ATL cho phép các nhà phát triển ATL thiết kế nhiều loại đơn vị
ATL khác nhau. Một đơn vị ATL (ATL unit) được định nghĩa trong tệp ATL
của nó. Các tệp ATL được phân biệt bởi phần mở rộng .atl.
ATL chủ yếu tập trung vào chuyển đổi mô hình. Những hoạt động chuyển
đổi đó được đóng gói thành một mô đun ATL. Ngoài mô đun ra, ngôn ngữ ATL
còn cho phép các nhà phát triển tạo ra các mô hình cho các chương trình có kiểu
dữ liệu cơ bản. Những đơn vị (unit) đó gọi là truy vấn ATL (ATL queries). Mục
đích của truy vấn là tính toán các giá trị nguyên thủy, ví dụ như là kiểu string
hay kiểu interger từ mô hình nguồn. Hơn nữa, ATL còn cho phép phát triển các
thư viện độc lập mà có thể import từ các đơn vị ATL khác, bao gồm cả bản thân các thư viện đó. Điều này cung cấp một con đường thuận tiện để tái sử dụng mã nguồn ATL được sử dụng trong nhiều đơn vị ATL. Hiện có 3 đơn vị ATL đều cùng sử dụng phần mở rộng .atl.
Phần dưới đây sẽ trình bày về 3 đơn vị ATL, sẽ giải thích mục đích sử dụng từng loại đơn vị và cung cấp tổng quan nội dung của 3 đơn vị.
ATL mô đun
a)
Một mô đun ATL tương ứng với một chuyển đổi một mô hình sang mô hình. Loại đơn vị ATL này cho phép các nhà phát triển ATL xác định cách thức để tạo ra một tập các mô hình mục tiêu từ một tập hợp các mô hình nguồn. Cả mô hình nguồn và mục tiêu của một mô đun ATL phải được “định kiểu” bởi metamodels tương ứng. Hơn nữa, một mô đun ATL chấp nhận một số cố định của các mô hình như là đầu vào, và trả về một số cố định của các mô hình mục tiêu. Như
vậy một mô đun ATL không thể tạo ra một số lượng không rõ các mô hình mục tiêu tương tự (ví dụ mô hình phù hợp với một cùng một metamodel).
Một mô đun ATL định nghĩa một chuyển đổi từ mô hình đến mô hình. Nó
bao gồm các thành phần: Header định nghĩa một số thuộc tính có liên quan đến các mô đun chuyển đổi, Import cho phép nhập khẩu một số thư viện ATL hiện