国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

EMF學習筆記(三)——使用EMF編程——持久化

villainhr / 2037人閱讀

摘要:生成的包首次被訪問時,在全局包注冊表中自動地注冊。然而,類似于資源工廠注冊表,這種顯式注冊的過程僅當獨立運行時被要求,在下運行時通過擴展指針來自動地完成。通過使用合適的資源工廠,就可以確定被產生的和被使用的持久化形式。

持久化(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的最終的序列化結果如下:





  從其持久化形式中加載采購清單的程序如下:

EPO2Package epo2Package = EPO2Package.eINSTANCE;
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);
try
{
    resource.load(null);
    PurchaseOrder po = (PurchaseOrder)resource.getContents().get(0);
    System.out.println("loaded: " + po);
}
catch (IOException e)
{
    System.out.println("failed to read " + uri);
}

  程序的第一行,訪問采購清單模型的,另一種作用是注冊包。生成的包首次被訪問時,在全局包注冊表中自動地注冊。資源取決于能夠找到注冊的包,以反射式地實例化其描述的。然而,類似于資源工廠注冊表,這種顯式(explicit)注冊的過程僅當獨立運行時被要求,在Eclipse下運行時通過擴展指針(extension point)來自動地完成。

EMF持久化API

  EMF持久化框架以個基礎接口為中心:Resource,ResourceSet, Resource.Factory, URIConverter

URI

  URI是一個字符串,包含三個基本的部分:schemescheme-specific部分、可選片段。

URIConverter

  這個接口用來規范化 URIs:將一個URI轉換為另一個訪問資源的URI。

Resource

  前面已經說過,EMF中持久化的基本單元叫做資源(resource)。盡管資源直接關系EObjects,但是不像從第5章描述的元模型中生成的各種Ecore接口,Resource接口事實上不會來描述模型化的類。然而,它表現的像重要的方式之一:

public interface Resource extends Notifier
{
    int RESOURCE__RESOURCE_SET = 0;
    int RESOURCE__URI = 1;
    int RESOURCE__CONTENTS = 2;
    ...
    ResourceSet getResourceSet();
    URI getURI();
    void setURI(URI uri);
    EList getContents();
    ...
}

  首先,資源是通知器(notifier):多個適配器(adapter)可以被附加于一個資源,當資源改變時,將會給適配器們發送通知。可以看到,接口定義了“虛擬特征(virtual features)”,比如resourceSetURI內容,它們都被使用于通知中。
  其次,getContents()返回的列表,描繪了資源的內容,表現的十分像一個模型化雙向的引用,相反的引用由EObject中的eResource()方法實現。需要注意的是,這種關系實際上并不是真正的模式化,而是概念上的,情況如下圖:

  值得強調的是,當內容虛擬特征(contents virtual feature)期望getContents()訪問器時,其相反的訪問器的名字,eResource(),毫無疑問是非常規的(unconventional)。這是因為它反而遵循EObject中所有其他方法使用的模式,被選擇以避免與在模型化子類中生成的訪問器的名稱相沖突。還值得注意的是,對于eResource()沒有相應的設置(set)方法,所以這個虛擬特征只能從Resource end來設置,通過將對象加入到內容列表。
  在URI這一節,資源默認地包含其內容列表中每個對象所包含的整個對象樹。這影響到eResource()的返回值。
  內容虛擬特征表現的像一個普通雙向特征,相反的是multiplicity-one。這就是說,如果一個對象已經存在于一個資源的內容中,將其添加到另一個則會自動地從第一個中移除
  此外,內容虛擬特征展示了遏制(contaiment)語義,但僅涉及不是代理解析(proxy resolving)的模型化的遏制引用。換句話說,如果一個對象已經存在于任一模式化的非代理解析的遏制引用,把它添加到一個資源的內容中則會自動的將其從它的容器中移除。回顧第10章中遏制語義默認不是代理解析。因此,它就表現出默認阻止跨資源(cross-resource)遏制:一個對象只可以被直接放置在一個容器對象中,或者直接放置在一個資源內容中,而不能兩者都放置。
  “遏制代理”詳見13.8.2。
  一個資源通常被一個資源集合所包含,getResourceSet()來獲取。資源在集合中通過URI來唯一標識。通常在資源創建時指定URI,但是只能分別通過getURI()setURI訪問設置URI通常決定資源的持久化形式將要存貯的位置。

  save()load()方法將資源從活動的內存形式復制到持久化存儲,反之亦然。每個都有兩種形式:

void save(Map options) throws IOException;
void load(Map options) throws IOException;

void save(OutputStream outputStream, Map options) throws IOException;
void load(InputStream inputStream, Map options) throws IOException;

  EMF為資源提供了一個基礎類,ResourceImpl,它通過從資源集合中獲取一個URIConverter來實現每個單參數的方法,這個URIConverter用來打開資源的URI的輸出或輸入流,還能將流傳到對應的雙參數方法。因此,特定子類的作用是提供有意義的,特定于存儲(storage-specific)保存加載實現。
  通過調用unload()方法可以卸載資源。卸載會將資源中所有的對象變為代理(proxy),這樣的結果是,下次這些對象中之一從其他資源通過跨引用(cross-reference)被訪問時,資源的請求重新加載(通過EcoreUtil.resolve())。這就可以把一個資源更新,比如自上次加載以來,底層文件( underlying file )發生了變化。isLoaded() 方法表明資源當前是否被加載。
  資源可以通過isModified(),來跟蹤對其完整內容的任何更改,并且返回自從最近保存和加載后的變更。默認情況下,這個特性是無效的,因為它的實現昂貴而且對撤銷命令是無效的,由于撤銷看起來像變更。適當時候,setTrackingModification() 可以使其生效

  URI Fragments,是資源基于ResourceImpl使用類似XPath的方式來定位對象。Resource接口定義getEObject() 方法,可以根據給出的段路徑(fragment path)來檢索對象:

Resource resource = ...
Item item = (Item)resource.getEObject("http://@orders.0/@items.2");

  相反,也可以獲取段路徑:

Item item = ...
String fragment = resource.getURIFragment(item);
Resource.Factory和Resource.Factory.Registry

  嵌套在Resource接口中的是Factory接口,它定義了資源如何被創建:

public interface Resource extends Notifier
{
    ...
    interface Factory
    {
        Resource createResource(URI uri);
        interface Descriptor
        {
            Factory createFactory();
        }
    
        interface Registry
        {
            Factory getFactory(URI uri);
            Map getProtocolToFactoryMap();
            Map getExtensionToFactoryMap();
            String DEFAULT_EXTENSION = "*";
            Registry INSTANCE = new ResourceFactoryRegistryImpl();
        }
    }
}

  正如這個接口建議的那樣,資源工廠只是簡單地知道如何去創建資源的一種類型。通過使用合適的資源工廠,就可以確定被產生的和被使用的持久化形式。
  嵌套在Factory中的是Registry接口,它基于特定URI,提供了選擇合適資源工廠的機制。資源工廠注冊表維護著兩個可以注冊資源工廠的map。這些map被getFactory方法咨詢,以獲取適合于給定URI的工廠。
  ResourceFactoryRegistryImpl(),按照以下步驟來獲取資源工廠:

檢查getProtocolToFactoryMap()返回的map,使用URI模式作為關鍵字。

如果沒有找到任何東西,檢查getExtensionToFactoryMap()返回的map,使用URI文件擴展名作為關鍵字。

如果仍然沒有找到,就檢查getExtensionToFactoryMap()返回的map默認值,使用DEFAULT_EXTENSION*作為關鍵字。

如果沒有找到相應的匹配,調用受保護的(protected)delegatedGetFactory()方法。默認情況下,它沒有做任何事,但可以被重寫(override)

  資源集合維護(maintain)著資源工廠注冊表,當其需要創建資源時,就要咨詢(consult)來獲取工廠。此外,有一個可用的全局注冊表Resource.Factory.Registry.INSTANCE,它可以注冊系統中的所有資源集合。默認資源集合中注冊表的實現重寫了delegatedGetFactory() 來委托給全局注冊表。所以僅當根據URI的模式,在局部沒有找到合適的工廠時,才會根據文件擴展名(file extension)來咨詢全局注冊表。
  在持久化框架概述中說道,在Eclipse環境下運行時,資源工廠可以通過Eclipse的擴展指針機制,來被自動地注冊。這樣的注冊是在全局注冊表中完成的。
  org.eclipse.emf.ecore.xmi 插件清單文件包含以下擴展:


    

  它默認注冊了XMIResoureFactoryImpl資源工廠實現。這就是為什么EMF的XMI序列化作為默認持久化格式,以及為什么在Eclipse下運行時沒有要求顯式的注冊。
  如果你創建了自己的資源實現,你需要為其創建工廠然后進行注冊,以相似的方式,在你自己的插件(plug-in)中。例如,設想你已經創建了自己的資源實現類,EPO2ResourceImpl,你想要使用它來持久化.epo2資源。為此,需要創建資源工廠:

public class EPO2ResourceFactoryImpl implements Resource.Factory
{
    public Resource createResource(URI uri)
    {
        return new EPO2ResourceImpl(uri);
    }
}

  然后,你可以向plugin.xml文件中添加以下擴展:


    

  事實上,這就是在為生成器中的包選擇“資源類型(Resource Type)”時發生的事情。從以XML Schema描述的模型開始尤為重要,因為默認XML資源將不能符合模式的序列化。如果注冊不能完成或者你試圖加載沒有合適文件擴展名(file extension)的資源,Resource.load()將會拋出ClassNotFoundException。對于獨立的應用程序,需要在代碼進行以下等價的注冊:

Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
    "epo2", new EPO2ResourceFactoryImpl());

  盡管等價,這兩個資源工廠注冊表(registration)還是有細微差別的。后者,顯式注冊,工廠的實例被創建并且被注冊表中的一個map直接注冊。然而,前者,基于擴展名(extension-based)的注冊表,實際注冊的是描述符(Descriptor)
  描述符,另一個嵌套在Resource.Factory中的接口,在創建資源工廠時提供了額外的間接層(indirection)級別(level)。在完成之前所述的4步枚舉型之后,如果注冊獲取了描述符而不是資源工廠,它將調用createFactory()并返回結果。這項功能使EMF能夠推遲加載特定的資源工廠直到這個類被真正需要時。這對基于擴展名的注冊表很重要,其發生在平臺啟動時。

ResourceSet

  ResourceSet是持久化API中最高級別的接口,作用相當于資源的容器,以便允許它們之間的引用。它提供了訪問這些資源的途徑,從模型或者一組相關聯的模型中,定義了對象的上下文(context)。此外,它維護這URI轉換器,資源工廠注冊(resource factory registry),以及它自己使用的和用于資源的包注冊(package registry)
  類似于ResourceResourceSet并不表示模型化,但是它實現Notifier接口:

public interface ResourceSet extends Notifier
{
    int RESOURCE_SET__RESOURCES = 0;
    EList getResources();
    ...
}

  由getResource()返回的資源的列表,構成了它僅有的虛擬特征,表現得像個遏制引用(containment reference)。換句話說,資源每次只能在一個資源集合中。
  ResourceSet為創建新資源提供了用戶級別(user-level)的接口。在URI那一節,我們使用最簡單的方法來實現這個目的,createResource(),它授權(delegate)給集合的資源工廠注冊返回的資源工廠。回顧這個注冊,是getResourceFactoryRegistry()返回的,當它不能定位適當的資源工廠時,就授權給全局資源工廠。createResource()方法在內存中創建資源,并且將其添加到資源集合中,毫不費力就能讀入寫出持久化表示。在它盲目地創建資源前,也不會檢查集合是否已經包含給出的URI的資源,這就有可能使集合處于無效狀態。
  一個更強大的方法,getResource(),首先規范化給出的URI,檢查資源集合中是否有資源擁有與其匹配的規范化URI,如果有,返回這個資源。如果這個資源沒有加載,它將會被要求加載(demand-loaded),如果此方法的第二個布爾參數為真的話。如果資源沒有找到并且第二個參數為真,資源將會被要求創建(demand-created)和要求加載。使用getURIConverter()返回的URI 轉換器來規范化URI,使用getLoadOptions()返回的map中指定的選項來完成要求的加載。
  注意的是,資源的持久化形式不會被要求創建。如果因為持久化形式無法找到而導致要求的加載失敗,getResource()會拋出異常
  所以,在持久化框架的概述中最后的例子可以被簡化。在設置資源集合和創建URI之后,兩行就足以創建資源,加載,并且訪問其中的對象:

...
Resource resource = resourceSet.getResource(uri, true);
PurchaseOrder po = (PurchaseOrder)resource.getContents().get(0);
System.out.println("loaded: " + po);

  ResourceSet中的另一種簡便方法,getEObject(),允許我們進一步簡化,替換獲取資源和使用單個聲明檢索其中對象的兩行:

...
PurchaseOrder po =
    (PurchaseOrder)resourceSet.getEObject(uri.appendFragment("/"),true);
...

  getEObject()方法簡單地調用getResource()來獲取資源,必要的話進行要求的創建和要求的加載,然后使用指定URI的分段(fragment)來定位和返回資源里面的對象。
  包注冊,提供了一種手段來定位描述任一特殊包的元數據。有個全局包注冊,EPackage.Registry.INSTANCE,在其中生成的包會被自動地注冊。在其他情況下,特定語境(context-specific)的包注冊會更合適些。
  事實上,正是資源集合提供了語境(context)ResourceSet定義了getPackageRegistry()方法,其返回局部的(local)注冊。這個局部注冊只在局部不能找到包時,授權給全局注冊。因此,加載到給定資源集合的資源已經檢索的包,可以在不污染全局注冊的情況下被注冊。甚至有可能,針對同一個命名空間URI,僅僅通過局部注冊一個不同的包,來重寫一個全局注冊表。
  資源集合的主要目的是支持不同資源中對象之間的引用。特別的事,它們對要求的加載(demand-loading)代理解析(proxy resolution)至關重要。例如,考慮資源如下序列化:



    
        
    

  可以看出資源中的Supplier包含一個PurchaseOrder引用了另一個資源中Supplier中序列化的PurchaseOrderhref屬性表示的是跨文檔(cross-document)的引用,屬性的值是標識其他資源中引用的URI*。
  當加載這個資源時,代理被創建作為previousOrder引用的目標,指定對象的URI(例如:platform:/resource/project/sample.epo2#//@orders.1)。如果想要訪問采購清單的上個清單,可以調用 getPreviousOrder()EcoreUtil.resolve()被調用以便解析代理(resolve proxy)

XML資源 EMF資源和資源工廠實現 性能考量 主動對象的定制存儲

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67579.html

相關文章

  • Eclipse Modeling Framework, 2nd Edition. (EMF)學習筆記

    摘要:定義模型元模型用于表示中模型的模型稱為。用于表示的類型,它可以是基本類型,例如或對象類型等。此外,因為是貨物的容器并會在其中將貨物作為孩子序列化,所以需要標識出。 EMF介紹 為了理解EMF究竟是什么,你只需要知道一件事:模型(model)是什么?模型的目的是什么? EMF不要求全新的方法論亦或是任何復雜的建模工具。只需要從Eclipse的Java開發工具著手開始。 EMF將建模概念...

    yagami 評論0 收藏0
  • Eclipse Modeling Framework, 2nd Edition. (EMF)學習筆記

    摘要:定義模型元模型用于表示中模型的模型稱為。用于表示的類型,它可以是基本類型,例如或對象類型等。此外,因為是貨物的容器并會在其中將貨物作為孩子序列化,所以需要標識出。 EMF介紹 為了理解EMF究竟是什么,你只需要知道一件事:模型(model)是什么?模型的目的是什么? EMF不要求全新的方法論亦或是任何復雜的建模工具。只需要從Eclipse的Java開發工具著手開始。 EMF將建模概念...

    yacheng 評論0 收藏0
  • EMF學習筆記)——使用EMF編程——久化

    摘要:生成的包首次被訪問時,在全局包注冊表中自動地注冊。然而,類似于資源工廠注冊表,這種顯式注冊的過程僅當獨立運行時被要求,在下運行時通過擴展指針來自動地完成。通過使用合適的資源工廠,就可以確定被產生的和被使用的持久化形式。 持久化(Persistence)   EMF擁有一個強大的模型持久化框架。通過一個高度可定制資源實現(resource implementation)來支持XML序列化...

    helloworldcoding 評論0 收藏0
  • EMF學習筆記(二)——使用EMF編程——開發元數據

    摘要:使用元數據包中包含了中每一個被建模類對應的接口。任何對象的元數據是使用的實現來表示的。加載模型的序列化形式是個在運行期間獲取元數據的有效方法。反射提供一個反射式,可以檢查對象的元數據以及一般地訪問和操縱數據。 使用元數據   Java包org.eclipse.emf.ecore中包含了Ecore中每一個被建模類對應的接口。任何EMF對象的元數據是使用Ecore的實現(implement...

    Jiavan 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<