持久化(Persistence)
EMF拥有一个强大的模型持久化框架。通过一个高度可定制资源实现(resource implementation)来支持XML序列化。
EMF不要求持久化是基于XML或者是基于流(stream)。这个框架提供的API灵活到足以支持任何种类的存储,甚至在不同类型的存储中保存对象,其中包含引用。
持久化框架的概述
EMF中持久化的基本单元叫做资源(resource),它是一个或多个与其内容一起持久化的对象的容器。
EMF对象由Resource接口来进行持久化,方法是将对象添加到资源的内容列表中,然后调用save()方法,例子如下:
PurchaseOrder po = ...
Resource resource = ...
resource.getContents().add(po);
resource.save(null);
这个例子中,save()方法的参数,一个Map,如果指定了保存操作的选项,那么这个参数将非空(non-null)。EMF的XML资源支持的选项详细介绍在15.3.3。
持久化的逆操作,从持久化形式中在内存中重建活动(actiive)的对象。使用load()方法从资源的内容列表中访问对象:
Resource resource = ...
resource.load(null);
PurchaseOrder po = (PurchaseOrder)resource.getContents().get(0);
Resource接口的详细说明在15.2.3。
上面的代码带来了以下问题:XML序列化写到哪里?从哪里读入?开始的时候如何获取资源?
为了管理不同资源中对象之间的引用,EMF持久化框架包含了另一种接口,称作ResourceSet,作用相当于资源的容器。getResources()方法返回的是资源的列表,以一个集合(set)的形式。
通常而言,资源是由资源集合创建的,或者是加载的。如下:
ResourceSet resourceSet = new ResourceSetImpl();
URI uri = URI.createURI("file:/c:/data/out.epo2");
Resource resource = resourceSet.createResource(uri);
这里我们创建了一个资源集合,调用createResource()来创建特定的资源。这个方法的参数是URI,它被用来指定资源,在资源集合中识别出这个资源。然后,我们调用save()和load()方法,资源可以使用这个URI来决定写出和读入的位置。这里的URI是文件模式(file-scheme),其他支持的URI类型详见15.2.1。
EMF不会向资源集合提供工厂。由用户来决定实例化合适的实现。ResourceSetImpl是一个功能灵活的实现,通常应该是足够的。如果有必要的话,它也可以被扩展以及定制。
传给createResource()的URI还有另外的用途。资源集合维持(maintain)资源工厂的注册表。为了创建一个资源,需要查询(consult)它的注册表,以根据特定的URI来获取一个合适的工厂。这个工厂实际上创建了对应的资源,并且决定对象如何被持久化。
注册表根据模式(scheme)或者文件扩展名(file extension)来选择资源工厂。我们可以对.epo2文件扩展名注册EMF的默认XMI资源工厂:
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().
put("epo2", new XMIResourceFactoryImpl());
当使用Eclipse里生成的模型时,这种注册不是必要的,因为相似的注册会通过模型插件(model plug-in)的清单文件(manifest file)中指定的扩展名来自动地执行。然而,当独立运行时,注册必须被明确地执行。否则,createResource()将无法创建资源并且会返回null。详见15.2.4的Resource的嵌套工厂和Registry接口以及15.2.5的ResourceSet
现在已经有了对持久化框架的足够理解,来编写简单但有效的程序来保存采购清单:
PurchaseOrder po = createPurchaseOrder();
ResourceSet resourceSet = new ResourceSetImpl();
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().
put("epo2", new XMIResourceFactoryImpl());
URI uri = URI.createURI("file:/c:/data/out.epo2");
Resource resource = resourceSet.createResource(uri);
resource.getContents().add(po);
try
{
resource.save(null);
System.out.println("saved");
}
catch (IOException e)
{
System.out.println("failed to write " + uri);
}
这里的createPurchaseOrder()返回的是我们想要持久化的采购清单。我们可以设想它创建了PurchaseOrder的实例并且向其中加入一组Items,在out.epo2的最终的序列化结果如下:
<?xml version="1.0" encoding="ASCII"?>
<epo2:PurchaseOrder xmi:version="2.0"
xmlns:xmi="http://www.omg.org/XMI"
xmlns:epo2="http://www.example.com/epo2.ecore"
comment=