1. ATL简介
ATL是ATLAS转换语言的简称,它是ATLAS研究组开发出来的一种符合OMG的一个QVT提案的模型转换语言。目前ATL已经实现为ADT的一个组成部分,ADT是一个Eclipse插件,他是著名的Eclipse项目GMT的子项目。ATL是基于EMF(Eclipse模型框架)的,其元模型、模型都是用EMF来描述的。
从本质上来说,ATL属于基于规则的模型转换语言,其中使用了OCL作为约束描述语言。ATL是一种混合语言,既有描述性语言的特征,又含有命令式语言的内容。作为一种基于规则的语言,描述性是其最主要特征,但是为了完成某些复杂的转换,命令式的内容也被加进去了。
目前ATL属于三个组织,ATLAS研究组、LINA & INRIA(这应该是一个法国的研究机构,主页上是法文,看不懂)和法国Nantes大学。
2. ATL安装简介
在ADT的文档页面上面有关于ATL和ADT的大部分文档,包括安装手册、初学者手册和用户手册等等。2,3,4节简要的说明了其中的内容。
安装步骤如下:
首先安装Eclipse3.1和EMF2.1.0:
Eclipse is available at http://www.eclipse.org/downloads/index.php. Select the release 3.1(eclipse-SDK-3.1-win32.zip).
EMF can be downloaded from http://download.eclipse.org/tools/emf/scripts/downloads.php.
Select the release 2.1.0 (emf-sdo-runtime-2.1.0.zip).
然后安装ADT,它在http://www.eclipse.org/gmt/atl/download/,选择adt-20051102.zip包下载。然后按照Eclipse插件的安装方法安装插件。
最后还要安装两个其它的java包:
ANTLR can be downloaded from http://www.antlr.org/download.html. Select the “jar file only”(tool and Java runtime) archive (antlr-2.7.5.jar).将这个jar包改名为antlr.jar,然后拷贝到\eclipse\plugins\org.atl.eclipse.engine_version\lib。
MDR is available at http://mdr.netbeans.org/download/. Select the “MDR zip” archive (mdrstandalone.zip).将这个zip包解压缩后得到jmi.jar, jmiutils.jar, mdrapi.jar, mof.jar, nbmdr.jar and openide-util.jar,将这些jar文件拷贝到\eclipse\plugins\org.atl.engine.repositories.mdr4atl_version\lib。
至此ADT才算安装完成,过程有点复杂,所以记下来。
3. ATL的Helloworld
ATL的框架结构
ATL的helloworld可不是那么简单,首先要弄清楚一个ATL程序需要包含哪些内容。而要弄清这些内容,最好还是先看看ATL的整个框架结构。以下就是ATL的模型转换的层次结构:
其中Ma是源模型,而Mb是目标模型。Ma符合其元模型MMa,而Mb符合其元模型MMb。同时MMa和MMb都符合唯一的元元模型MMM。Mt是一个模型转换实例,它也是一种模型,它符合模型转换的元模型MMt。MMt也符合唯一的元元模型MMM。
在ATL当中,唯一的元元模型就是Ecore,其地位等同于MOF。而MMa和MMb则是Ecore创建出来的元模型。Ma和Mb则是符合这些元模型的模型实例。MMt已经被ATL定义好了,Mt则是使用者自己要定义的模型转换模型,也就是模型转换程序。
所以,一个完整的ATL模型转换程序,需要四个内容:MMa、MMb、Ma、Mt。而生成的目标模型则是Mb。
ATL的helloworld
这个例子出现在ATL Starter’s Guide中。
首先打开Eclipse创建一个ATL项目,然后依次创建文件Author.km3,Person.km3, Authors.ecore和Author2Person.atl。它们分别代表元源模型、元目标模型、源模型和转换程序。
元模型其实都可以使用EMF来直接创建,但是ATL提供了一个类似java的语言km3,使用km3定义的元模型可以生成基于EMF的元模型Author.ecore、Person.ecore。
代码内容如下:
Author.km3:
package Author{
class Author{
attribute name : String;
attribute surname: String;
}
}
package PrimitiveTypes{
datatype String;
}
Person.km3:
package Person{
class Person{
attribute name : String;
attribute surname: String;
}
}
package PrimitiveTypes{
datatype String;
}
这两个元模型经过转换后都成为基于XMI格式的Ecore模型Author.ecore和Person.ecore。
然后给出一个源模型,它是符合Author.ecore的:
Authors.ecore:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns="Author">
<Author name="David" surname="Touzet"/>
<Author name="Freddy" surname="Allilaire"/>
</xmi:XMI>
最后是转换程序代码:
Author2Person.atl
module Author2Person; -- Module Template
create OUT : Person from IN : Author;
uses strings;
rule Author{
from
a: Author!Author
to
p: Person!Person (
name<-a.name,
surname<-a.surname
)
}
代码的含义可以参考相关文献,可以看出来,这种基于规则的代码简单的定义了两个模型之间的名称映射。如果要定义更加复杂的约束,则需要用到更多ATL的知识,这些约束一般都是使用OCL来定义的。
在Eclipse中运行这个程序需要在run as…中进行详细的配置。也可以参考相关文献。运行的结果是一个目标模型Persons.ecore,其内容如下:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns="Person">
<Person name="Freddy" surname="Allilaire"/>
<Person name="David" surname="Touzet"/>
</xmi:XMI>
当然,ecore模型都是可以用EMF的编辑器来进行可视化察看的,并不是都使用XMI格式来察看。而且,在熟悉了之后可以使用EMF来直接创建元模型,我觉得比学习和使用KM3语言要稍微快一点。
至此我们完成了ATL的这个helloworld,看起来有一点复杂,需要的知识面也比较广泛。如果对于相关的知识都有一定程度的了解,可能会比较轻松上手。
4. 另一个ATL例子代码
这个例子出现在ATL User Manual中,但是只有转换程序代码,其它的三个代码都没有,因此我补全了其它代码,使之可以运行。
这个例子的目的如下:MMa描述了一本书的模型,这本书含有许多章节,每个章节都有页数、名称和作者。MMb描述了一个出版物的模型,这个出版物只包括了一个总的名称、作者和页数。那么转换程序的目的是将书的所有章节作者合并到出版物的作者字符串,将书的所有章节的字数相加得到出版物的字数。
MMa的代码如下(我使用EMF直接创建了它,但是这里列出的是文本内容)Book.ecore
<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore">
<ecore:EPackage xmi:version="2.0"
xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="Book">
<eClassifiers xsi:type="ecore:EClass" name="Book">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="title" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="chapters" upperBound="-1"
eType="#//Chapter"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="Chapter">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="nbPages" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="title" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="author" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eClassifiers>
</ecore:EPackage>
</xmi:XMI>
MMb的代码如下Publication.ecore
<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore">
<ecore:EPackage xmi:version="2.0"
xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="Publication">
<eClassifiers xsi:type="ecore:EClass" name="Publication">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="title" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="nbPages" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="authors" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eClassifiers>
</ecore:EPackage>
</xmi:XMI>
Ma的代码如下Books.ecore
<?xml version="1.0" encoding="ISO-8859-1"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns="Book">
<Book title="WxbBook">
<chapters nbPages="12" title="chapter1" author="author1"/>
<chapters nbPages="15" title="chapter2" author="author2"/>
<chapters nbPages="20" title="chapter3" author="author3"/>
</Book>
</xmi:XMI>
Mt的代码如下Book2Publication.atl,这个代码是手册中提供的,我还是列在这里:
module Book2Publication; -- Module Template
create OUT : Publication from IN : Book;
helper context Book!Book def : getAuthors() : String =
self.chapters->collect(e | e.author)->asSet()
->iterate(authorName; acc : String = '' |
acc +
if acc = ''
then authorName
else ' and ' + authorName
endif
);
helper context Book!Book def : getNbPages() : Integer =
self.chapters->collect(f|f.nbPages)
->iterate(pages; acc : Integer = 0 |
acc + pages
);
rule Book2Publication {
from
b : Book!Book (
b.getNbPages() > 2
)
to
out : Publication!Publication (
title <- b.title,
authors <- b.getAuthors(),
nbPages <- b.getNbPages()
)
}
从Mt的代码可以看出,为了实现转换中的约束,定义了两个helper函数,函数都是使用OCL来定义的。并且在转换规则中调用了这些函数。在规则开头的限定条件中也调用了这些函数。
那么进行转换后得到的代码如下,Publications.ecore
<?xml version="1.0" encoding="ISO-8859-1"?>
<Publication xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns="Publication" title="WxbBook" nbPages="47" authors="author3 and author1 and author2"/>
本节的内容主要是想把用户手册中没有提供的代码补全,让初学者可以直接运行这个例子,可以了解ATL的一部分功能。
5. ATL使用感想
通过这一天的对ATL的了解和使用,有一点点心得。
ATL和MTF的比较
在目前能够run的模型转换语言中,MTF和ATL都是比较著名的。MTF是IBM开发的模型转换框架,而ATL则是Eclipse的GMT中包含的模型转换语言。从影响力来看,旗鼓相当。使用者的人数不好统计,况且目前好像都还没有商业化,也看不出市场占有率。不过从纯技术的角度来比较这两个语言,也是很有意义的。
从上手的难易度来看,无疑MTF是比ATL容易得多。MTF作为一个准商业化的软件,遵循了简单易用的原则。而ATL作为一个研究者团体开发的开源软件,上手则比较困难。从安装上来看,MTF是一个标准的Eclipse插件,基于EMF插件,安装一步到位。而ATL则需要另外安装两个其它的jar包。从提供的例子程序来看,MTF提供了完整的例子程序包,由易到难循序渐进,在运行helloworld的时候仅仅需要一个规则文件即可凭空构造一个目标模型,再以这个目标模型作为源模型构造更多的目标模型。而ATL在运行第一个Helloworld例子时则需要手工输入源元模型、目标元模型、源模型和规则文件。导致复杂性大幅度增加。而且,除了转换语言ATL以外,还引入了元模型描述语言KM3,而不是直接使用EMF。这样也增加了上手的困难程度。
从技术路线来看,MTF和ATL都是基于Eclipse平台和EMF。而且,它们都是基于规则的转换语言。不同之处在于,MTF更加倾向于构造一个完全描述性的语言,而ATL则倾向于构造一个描述性和命令行共存的混合语言。这就导致了MTF可以更多的用来描述双向转换规则,即源模型和目标模型可以对等转换。而ATL则一般用来描述单向转换规则。但是有得必有失,我认为MTF描述复杂规则的能力要比ATL弱。因为ATL使用了OCL作为约束描述语言,它基本上实现了OCL(有些地方略为有更改),从上文就可以看出,使用OCL定义的ATL函数功能是比较强大的。而MTF则没有使用OCL来定义约束,而是使用一种中庸的简单比较功能来限定转换的条件。这样在写转换规则的时候就有一种便秘的感觉,明明我非常了解这个约束,但是不能够痛快的写出来。而且,如果在源模型中使用OCL定义了某种约束,那么在MTF的转换中必然不能直接的使用或者体现这个约束。相比之下,ATL的功能更加强大一些。
另外有一点值得注意的是,MTF和ATL的作者对于模型层次的理解显然有点差别。在MTF中,模型层次和MOF中的四层模型是一致的。MTF在M2层定义转换规则,进行转换的是M1层的模型。例如,定义了简化的UML和简化的RDBMS之间的转换规则,可以将UML中的类转换为关系数据库中的表。但是ATL的模型层次则大部分时候是在M1层定义转换,而进行转换的是M0层的模型,即对象模型。例如第4节的例子。当然,所谓的“元”只是一个相互对应的概念,更抽象的便可称之为“元”。MTF和ATL都可以用处转换各个模型层次的模型,只是从它们提供的例子可以看出它们作者的偏好。从这个角度来看,MTF更加符合大众的口味。
总而言之,MTF是易于上手的,容易理解的,双向的描述性模型转换语言,其描述规则的能力一般,往往要绕圈子来定义规则。而ATL是开源的,难于上手和掌握的,单向的混合型(描述性和命令行并存)模型转换语言,使用OCL来描述约束,描述规则的能力较好,使用范围较广。
ATL的前景
MDA是一个较新的概念,也是一个争议很大的技术。但是模型转换作为MDA的核心技术却是毫无疑问的。广义的模型转换技术其实和XSLT一样,将一种格式化的模型(文档)转换为另一种格式化的模型(文档)。所以它是有着广泛的用途和强大的生命力的。
ATL作为模型转换语言中的一个出色的实现,依托于Eclipse这个平台,应该是有着比较光明的背景的。遗憾的是,学习和使用ATL所需的背景知识比较多,使用起来也不是很容易上手。我可以看见ATLAS已经在努力克服这些问题,最近他们实现了模型编织的工具,用来生成ATL的模型转换代码。从模型编织的理论上来看,是比较优秀和完美的,但是ModelWeaver我还没有体验过,因此并不知道是否可以克服ATL目前的缺点。
6. 小结
我很遗憾的发现关于ATL网上似乎没有任何的中文文献,包括MDA技术也大多是泛泛而谈,涉及到具体的工具、理论的很少。愿这篇文章,可以给那些有志于了解模型转换技术的人一个引路石。