关于EMF的序列化
对于EMF的序列化有几个比较重要的接口:Resource,ResourceSet,Resource.Factory,URIConverter。这些接口的主要作用就是保存模型到持久化存储介质,或者从持久化存储介质加载模型。
1.关于URI(Uniform Resource Identifier)
在EMF 中是通过URI来标识package的,并且同过URI来唯一的确定resources。URI包括三个部分:a scheme, a scheme-specific part和an optional fragment。scheme主要决定了访问资源的协议;比如:Platform:/resource/……中的platform。scheme- specific part 包含一些authority,device和一些segments,如file:/c:/dir1/dir2/myfile.xml,file是协议,没有authority,c:是device,剩下的3个是segments。URI fregment标识了resource内部的某个具体的内容。如:file:/c:/dir1/dir2/myfile.xml#loc中的#loc。 EMF通过带有fregment的URI来访问资源中的EObjects。
2.关于URIConverter
URIConverter的作用是normalize一个输入URI,使之成为一个实际的针对某个resource的URI。它可以把namespace URIs(比如:
http:///com/example/epo2.ecore)映射到物理文件的URIs, 或者重定向旧的(或别名)的URI参考到一个具体的实际的location。
一个URIConverter维护一个URI到URI的映射集合。比如,把一个命名空间URI映射到物理文件:
URIConverter converter
=
new
URIConverterImpl();
URI uri1
=
URI.createURI(
"
http:///somemodel.ecore
"
);
URI uri2
=
URI.createURI(
"
platform:/resource/project/somemodel.ecore
"
);
converter.getURIMap().put(uri1, uri2);
在如下面代码:
URI normalized
=
converter.normalize(uri1);
System.out.println(normalized);
打印的结果是:platform:/resource/project/somemodel.ecore
URIConverter.normalize()方法只是简单的同过映射的map把key替换成了相应的value。
URIConverter的最原始是应用在resource sets,用来定位resources.
3.关于Resource和ResourceSet
Resource 表示一个持久化的EOjbects的容器;ResourceSet表示一组Resource的集合,集合中的Resource同时创建或加载。 Resource中比较重要的就是save和load方法,还有通过URI fregments访问资源中的Object的机制,如:
Resource resource
=
Item item
=
(Item)resource.getEObject(
"
//@orders.0/@items.2
"
);
Item item
=
String fragment
=
resource.getURIFragment(item);
上面代码中的两个方法,getEObject通过带有fregment的URI获得一个EObject,与之相反的方法getURIFragment()通过EObject获得相应的fragment path。
ResourceSet中有些重要的方法:
createResource()创建一个空的Resource;
getResource()通过resource的URI来创建Resource;
getEObject(),通过URI中的fregment来获得具体的EObject对象。
4.关于Resource.Factory
用来创建Resource,resource factory 要注册到Registry实例中。一个factory 可以通过多种方式的URIs来注册,包括URI scheme或者URI的extension。在插件方式的应用中,通过扩展点的方式在插件加载的时候注册descriptor。
下面是Resource的源代码
public
interface
Resource
extends
Notifier
{
interface Factory
{
Resource createResource(URI uri);
interface Descriptor
{
Factory createFactory();
}
interface Registry
{
Factory getFactory(URI uri);
Map getProtocolToFactoryMap();
String DEFAULT_EXTENSION = "*";
Map getExtensionToFactoryMap();
Registry INSTANCE = new ResourceFactoryRegistryImpl();
}
}
}
下面是Registry中的getFactory()方法的算法(引用原文):
-
Check for a factory in the protocolToFactoryMap, using the scheme of the URI.
-
If nothing was found, check the extensionToFactoryMap using the file extension of the URI.
-
If still nothing was found, check the extensionToFactoryMap using the DEFAULT_EXTENSION (that is, the wildcard character "*").
-
If no extension match was found, call the delegatedGetFactory() method. This allows you to supply your own factory registry, with its own lookup criteria.
-
If a descriptor was found, instead of an actual factory, call the createFactory() method on the descriptor to create the factory.
-
Finally, return the factory if one was found, or null.
tip:emf缺省的序列化方式是XMI。因此,如果没有找到相应注册的factory缺省的就会返回以*注册的缺省的factory,这个factory是针对XMI的factory,即XMIResourceFactoryImpl。如,对于 XMIResourceFactoryImpl的扩展点声明:
<
extension
point
= "org.eclipse.emf.ecore.extension_parser"
>
<
parser
type
="*"
class
="org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl"
/>
</
extension
>
当非插件应用的时候,可以通过手工的方式来注册factory,如:
Resource.Factory.Registry.INSTANCE.
getExtensionToFactoryMap().put(
"
*
"
,
new
XMIResourceFactoryImpl());