Live a simple life

          沉默(zhu_xing@live.cn)
          隨筆 - 48, 文章 - 0, 評(píng)論 - 132, 引用 - 0
          數(shù)據(jù)加載中……

          【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(七):WTP數(shù)據(jù)模型總結(jié)和模型管理

                  前面已經(jīng)詳細(xì)介紹過WTP語法Document(IStructuredDocument)、WTP語義Document(IDOMDocument或ICSSDocument)和WTP Model(IStructuredModel),在本節(jié)中將從總體上再看一下對(duì)我們后續(xù)基于WTP進(jìn)行代碼定制很重要的點(diǎn),同時(shí)將補(bǔ)充最核心的一個(gè)點(diǎn):WTP中的模型管理機(jī)制。
                  PS:如果前面的幾節(jié)是探微的過程,那邊本節(jié)將完成知著的過程,“探微知著”^_^

                  語法Document、語義DocumentWTP Model
                  
                                                  (說明:上圖中的實(shí)線可以理解為引用關(guān)系。)

                      
                         【從引用關(guān)系層面看】
                          1、從上圖一可以看的出來,IStructuredDocument并不引用IStrcuturedModel或者IDOMDocument(或ICSSDocument),也就是說IStructuredDocument本身并不關(guān)心IStrcuturedModel或者IDOMDocument(或ICSSDocument)的存在
                          2、結(jié)合上圖一和上圖二,可以看的出來IStructuredModel將IStructuredDocument和IDOMDocument(或ICSSDocument)作為其兩個(gè)組成部分。換個(gè)角度說,如果已知IStructuredModel存在的情況下,IStructuredModel可以作為三者的門面,對(duì)IStructuredModel進(jìn)行管理也就間接對(duì)IStructuredDocument和IDOMDocument(或ICSSDocument)進(jìn)行管理
                          3、我們解釋一下上圖一中的那條藍(lán)色虛線,我們已經(jīng)說過IStructuredDocument本身并不關(guān)心IStrcuturedModel或者IDOMDocument(或ICSSDocument)的存在,所以要想以IStructuredDocument獲取對(duì)應(yīng)的IStructuredModel,需要一個(gè)第三方的角色,來維護(hù)從IStructuredDocument到IStructuredModel的映射關(guān)系,這個(gè)角色就是后面要說的WTP提供的IModelManager。如果IStructuredDocument通過IModelManager獲取到了對(duì)應(yīng)的IStructuredModel,那么再通過IStructuredModel可以自然獲取到對(duì)應(yīng)的語義Document(IDOMDocument或者ICSSDocument)。這樣三者就完全聯(lián)系起來了^_^

                          我們看一下,以上的引用關(guān)系對(duì)應(yīng)的API接口是什么(需要熟練掌握):
                          1、WTP Model --》 語法Document
                                 IStructuredModel.getStructuredDocument()

                          2、WTP Model --》 語義Document
                                 IDOMModel.getDocument    返回的語義Document類型為IDOMDocument
                                 ICSSModel.getDocument      返回的語義Document類型為ICSSDocument

                          3、語義Document --》 WTP Model
                                 IDOMNode.getModel           (IDOMDocument本身就是IDOMNode^_^)
                                 ICSSDocument.getModel

                          4、語法Document --》 WTP Model
                                前提:對(duì)應(yīng)的IStructuredModel已經(jīng)被WTP提供的IModelManager托管了,否則是沒有意義的(前面說過,因?yàn)镮StructuredDocument并不關(guān)心IStructuredModel和語義Document是否存在)
                                 IModelManager.getModelForEdit(IStructuredDocument)
                                 IModelManager.getModelForRead(IStructuredDocument)
                                          
                          5、語法Document --》 語義Document
                                前提:對(duì)應(yīng)的IStructuredModel已經(jīng)被WTP提供的IModelManager托管了?。。?br />                       步驟:語法Document --》 WTP Model  --》 語義Document
                          
                          6、語義Document --》 語法Document
                                 方法一:IDOMNode.getStructuredDocument 
                                 方法二:語義Document --》 WTP Model  --》 語法Document

                          
                          PS:通過上面的5和6也可以體會(huì)到,WTP Model存在的情況下,完全可以在語法Document和語義Document之前起到一個(gè)橋梁的作用


                         【從依賴關(guān)系層面看】
                          1、通過上圖二IStructuredModel的構(gòu)造過程就可以看的出來,WTP Model和語義Document(IDOMDocument或者ICSSDocument)都是以IStructuredDocument為基礎(chǔ),也就是說依賴于它
                          2、語法Document(IStructuredDocument)不需要關(guān)心其他兩者是否存在
                          3、語義Document(IDOMDocument或者ICSSDocument)依賴于語法Document(IStructuredDocument)
                          4、一個(gè)完整的WTP Model必須有對(duì)應(yīng)的語法Document和語義Document,從這個(gè)意義上將,可以理解為WTP Model需要依賴語法Document和語義Document。

                          由上面四點(diǎn),我們可以簡要的畫一個(gè)三者之間的依賴關(guān)系圖:
                          
                                                    (依賴關(guān)系圖:上圖中的實(shí)線可以理解為依賴關(guān)系)            


                              【從動(dòng)態(tài)變化角度看(簡要了解一下就可以了^_^)】
                                上面我們講了這么多三者之間的關(guān)系,好像總感覺是從靜態(tài)的角度出發(fā)的,那么如果三者中的一者發(fā)生變化了,三者直接又會(huì)又什么樣的互動(dòng)呢?
                                  1、WTP Model作為變化源,變化情況如下:
                                         IStructuredModel引發(fā)的變化,通常情況下就是調(diào)用了IStructuredModel的reload和reinit的操作。這個(gè)操作會(huì)修改其持有的IStructuredDocument,引起IStructuredDocument改變事件。IStructuredModel本身又是一個(gè)IStructuredDocumentListener,所以會(huì)處理這種變化,在變化的處理過程中包含了修改其持有的語義Document。大致過程示意圖如下:
                                  

                                  2、IStructuredDocument作為變化源,變化情況如下(這將是我們最常見的情況):
                                                           
                                                                  
                                      3、IDOMDocument作為變化源,變化情況如下:
                      //獲取語義Document
                      IDOMDocument domDocument = ((IDOMModel)structuredModel).getDocument();
                      
                      
          //修改語義Document,例如刪除其第一個(gè)節(jié)點(diǎn)
                      Node node = domDocument.getChildNodes().item(0);
                      domDocument.removeChild(node);
                                    以上代碼會(huì)發(fā)生如下事情:首先DOM Document被修改,然后會(huì)回調(diào)DOMModelImpl中對(duì)應(yīng)的更新方法(例如DOMModelImpl.childReplaced),然后會(huì)調(diào)用一個(gè)XMLModelUpdater的角色,在這個(gè)XMLModelUpdater會(huì)去更新IStructuredDocument(replace text操作),這進(jìn)而會(huì)引發(fā)IStructuredDocument改變事件,會(huì)進(jìn)而進(jìn)入上面已經(jīng)闡述過的循環(huán)。大致示意圖如下:
                                      
                                  說明:語義Document(IDOMDoucment或者ICSSDocument)持有一個(gè)IStructuredModel的引用,所以才有了上圖中的回調(diào)??梢钥吹某鰜碚Z義Document(IDOMDoucment或者ICSSDocument)并沒有提供對(duì)應(yīng)的listener接口,采用的是直接回調(diào)的辦法。

                                  上面三個(gè)動(dòng)態(tài)變化需要經(jīng)常使用這幾個(gè)WTP數(shù)據(jù)模型才能有比較深的印象,考慮到確實(shí)有點(diǎn)繁瑣,所以就不做代碼分析了,這里留個(gè)大概印象就可以了。
                                  
                                  提醒:IStructuredModel對(duì)應(yīng)的三個(gè)子類(AbstractStructuredModel、DOMModelImpl和CSSModelImpl)分別都有IStructuredDocumentListener實(shí)現(xiàn),有時(shí)間可以看一下這些實(shí)現(xiàn)之間的差別,對(duì)加深WTP數(shù)據(jù)模型的認(rèn)識(shí)會(huì)有幫助。
                              

                     【IModelManager!!!】
                     ( IModelManager:org.eclipse.wst.sse.core.internal.provisional.IModelManager
                      
                        【IModelManager為什么存在?】
                       我們先來考慮幾個(gè)問題:
                       1、 無論是語法Document還是語義Document的實(shí)例化過程(可不是new一個(gè)實(shí)例那么簡單^_^)都十分繁瑣,這個(gè)實(shí)例化的活是留給客戶調(diào)用端還是提供一個(gè)負(fù)責(zé)實(shí)例化的中間角色(客戶端通過調(diào)用這個(gè)中間角色來完成實(shí)例化的工作)?
                          答案:肯定盡量選擇后者。將客戶端和對(duì)象的繁瑣實(shí)例化過程進(jìn)行解耦,是一個(gè)我們應(yīng)該盡量遵循的規(guī)則。這個(gè)封裝了實(shí)例化過程的中間角色就是IModelLoader:org.eclipse.wst.sse.core.internal.provisional.IModelLoader)和IDocumentLoader(org.eclipse.wst.sse.core.internal.document.IDocumentLoader),我可以寬泛地將這個(gè)中間角色理解為工廠,而且實(shí)例化過程可能有變化,所以這個(gè)工廠不能是一個(gè)簡單靜態(tài)工廠,而應(yīng)該是一個(gè)工廠方法應(yīng)用(為什么不是抽象工廠,因?yàn)椴皇莿?chuàng)建相關(guān)的系列實(shí)例,也談不上什么幾個(gè)產(chǎn)品系列^_^)。

                      2、一個(gè)WTP Model同時(shí)持有一個(gè)重量級(jí)的語法Document和語義Document,這個(gè)兩個(gè)Document無論是在時(shí)間占用(解析過程十分耗時(shí)),還是在內(nèi)存占用方法都比較客觀。那么,如果我們對(duì)WTP Model實(shí)例進(jìn)行緩存管理,在內(nèi)存占用可接受的情況下可以大大解決時(shí)間占用的性能瓶頸問題,不挺好嗎?
                          答案:是挺好的^_^。  IModelManager一部分任務(wù)就是干這個(gè)事情。注意這邊的緩存管理可不簡單就是將對(duì)象存儲(chǔ)下來這么簡單,也需要提供用于更新被緩存對(duì)象的方法。

                      3、如果提供能夠?qū)⑸厦鎯蓚€(gè)角色組合在一起,對(duì)一般用戶而且使用起來是不是會(huì)更方便一點(diǎn)?
                          答案:是的。但是有點(diǎn)不太優(yōu)雅,職責(zé)有點(diǎn)混淆,不過問題不是很丑陋^_^。

                      回答完以上三個(gè)問題之后,我們可以猜測出來IModelManager承擔(dān)的兩個(gè)個(gè)核心任務(wù):
                      1、創(chuàng)建型工廠(IDocumentLoader、IModelLoader)的門面,提供創(chuàng)建接口
                      2、緩存管理:包含緩存實(shí)例的存儲(chǔ)管理和更新維護(hù)等任務(wù)。
                      
                      【IModelManager創(chuàng)建職責(zé)】
                        
                         說明:
                          1、上圖中包含了創(chuàng)建IStructuredModel、IStructuredDocument的方法,并沒有提供創(chuàng)建語義Document(IDOMDocument或者ICSSDocument)的方法。為什么?我們前面說過IStructuredDocument可以并不關(guān)心IStructuredModel或者語義Document是否存在,所以可以允許獨(dú)立創(chuàng)建;而語法Document和語義Document是IStructuredModel的兩個(gè)必然組成部分,所以提供了IStructuredModel的創(chuàng)建方法,就間接提供了語義Document的創(chuàng)建服務(wù)。

                          2、以上創(chuàng)建方法返回的實(shí)例都是未經(jīng)托管的,每次都會(huì)創(chuàng)建一個(gè)新的實(shí)例。千萬不要誤認(rèn)為IModelManager提供的創(chuàng)建方法返回的實(shí)例都是緩存的?。?!^_^    前面說過,WTP提供的語法Document和語義Document在時(shí)間占用和內(nèi)存占用方面都是比較可觀的,小心?。。。。。。。。。。。。?!

                          3、注意createStructuredDocumentFor(IFile iFile)和createNewStructuredDocumentFor(IFile iFile)兩個(gè)方法的正確用法,前者基于iFile存在,后者基于iFile不存在。

                      【IModelManager管理職責(zé)】
                        
                        
                         
                        說明: 
                        1、getModelFor*不假定模型已經(jīng)被托管,沒有對(duì)應(yīng)的模型情況下會(huì)創(chuàng)建一個(gè)新的被托管的實(shí)例(但是不能以IDocument為參數(shù));getExistingModelFor*假設(shè)有對(duì)應(yīng)的被托管模型存在于IModelManager種,否則返回null,不創(chuàng)建新的被托管實(shí)例。
                         
                         2、getModelFor*和getExistingModelFor*都涉及到引用計(jì)數(shù)的概念,每次調(diào)用都會(huì)增加read或者editor計(jì)數(shù),使用完畢之后應(yīng)該調(diào)用IStructuredModel.releaseFromEdit或者IStructuredModel.releaseFromRead。

                         3、IModelManager并沒有提供IStructuredDocument的獲取接口,因?yàn)镮ModelManager管理的目標(biāo)只是IStructuredModel。IStructuredDocument雖然可以脫離IStructuredModel獨(dú)立存在,但是IModelManager不提供管理。

                          4、使用getModelFor*(IDocument)和getExistingModelFor*(IDocument)的前提必須是有對(duì)應(yīng)的IStructuredModel被托管了。示例代碼:           
          try {
                      IFile file 
          = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path("/project/WebContent/Test2.jsp"));
                      IStructuredDocument document 
          = StructuredModelManager.getModelManager().createStructuredDocumentFor(file);
                      Object model1 
          = StructuredModelManager.getModelManager().getModelForRead(document);
                      Object model2 
          = StructuredModelManager.getModelManager().getExistingModelForEdit(document);
                  } 
          catch (Exception e) {
                      e.printStackTrace();
                  }
                              如果上面代碼種的file代表的資源沒有對(duì)應(yīng)的IStructuredModel被托管,則model1和model2的獲取都會(huì)引發(fā)異常。如果調(diào)用getModelFor*(IFile)或 getExistingModelFor*(IFile)則不會(huì)出現(xiàn)問題。
                              
                              PS:IModelManager的其他操作就不一一列舉了,具體可以看一下對(duì)應(yīng)代碼。IModelManager的獲取方式上面代碼中已經(jīng)體現(xiàn):org.eclipse.wst.sse.core.StructuredModelManager中提供了getModelManager操作來獲取IModelManager實(shí)例。


                             【使用WTP IModelManager一定要注意的地方】
                              1、根據(jù)你的模型是否需要被緩存托管,判斷該調(diào)用什么方法。如果不需要被托管的模型卻被緩存托管了,則會(huì)大大增加內(nèi)存占用。

                              2、注意維護(hù)引用計(jì)數(shù)平衡


                     【語法Region VS 語義Region】
                        語法Document(IStructuredDocument)提供了語法Region(ITextRegion)的概念,語義Document(IDOMDocument或者ICSSDocument)對(duì)應(yīng)的是語義Region(IndexedRegion、IDOMNode、ICSSNode),那我們現(xiàn)在來看一下它們之間的區(qū)別和聯(lián)系。
                      
                      【區(qū)別】
                        
                         
                        顯而易見,語法Region(ITextRegion)是按照語法進(jìn)行劃分的,既然是structured region,那么劃分時(shí)候一個(gè)重要的判斷依據(jù)就是特定的文本是否是結(jié)構(gòu)化的。IStructuredDocumentRegion代表的就是一個(gè)結(jié)構(gòu)化的region,里面會(huì)含有一系列的葉子節(jié)點(diǎn)的text region。IStructuredDocumentRegion之間并不會(huì)呈現(xiàn)父子關(guān)系,例如父子標(biāo)簽之間是獨(dú)立的IStructuredDocumentRegion,因?yàn)檫@個(gè)父子是從語義層面才有意思
                      
                      
                      語義Region(IndexedRegion、IDOMNode、ICSSNode)則是按照語義進(jìn)行劃分的,體現(xiàn)的語義層面的包含關(guān)系。例如,子標(biāo)簽會(huì)作為一個(gè)child node(IDOMElement)存在于父標(biāo)簽中(同樣是一個(gè)IDOMElement);再例如一個(gè)IDOMAttr表示一個(gè)屬性,如果切換到語法region視角,則對(duì)應(yīng)于三個(gè)ITextRegion:AttributeNameRegion、AttributeEqualsRegion、AttributeValueRegion。

                      一句話,根據(jù)應(yīng)用場景的不同你可以選擇借助語法region進(jìn)行分析或者借助語義region進(jìn)行分析。例如:如果要判斷一個(gè)標(biāo)簽是否在其特定父標(biāo)簽中,則用語義region進(jìn)行分析會(huì)方便很多^_^。

                      【聯(lián)系】
                        那我們?nèi)绾螌⒄Z法Region和語義Region比較方便的聯(lián)系起來呢?
                        答案:offset(位置信息)?。。?br />
                        基于語法Document構(gòu)建語義Document,說白了就是把語法region列表重新組織為語義region列表,語法region本身就持有位置信息,語義region會(huì)持有對(duì)應(yīng)的語法region,所以語義region本身也可以提供位置信息了。前面曾經(jīng)說過,所有的語義region都是IndexedRegion接口的實(shí)現(xiàn),IndexedRegion定義的核心操作也就是獲取位置信息的。
                      根據(jù)offset信息可以定位到對(duì)應(yīng)的語法region或者語義region,涉及到的方法前面已經(jīng)在講述相關(guān)接口的時(shí)候講述過,這邊就不再重復(fù)了。(這些東西用用就熟悉了^_^)
                      IndexedRegion  IStructuredModel.getIndexedRegion(int offset)
                      IStructuredDocumentRegion   IStructuredDocument.getRegionAtCharacterOffset(int offset)

                      PS:如果你持有的是一個(gè)語義region,則可以直接根據(jù)語義region去獲取其引用的語法region。

                          

                【后記】
                      到目前,WTP數(shù)據(jù)模型相關(guān)的東西真的告一段落了,其實(shí)這并不是WTP數(shù)據(jù)模型的全部,后門我們?cè)诙x具體功能的時(shí)候會(huì)順便再講一下其他的數(shù)據(jù)模型,我們可以把那些模型稱之為元數(shù)據(jù)模型,很多其實(shí)就是再IStructuredModel基礎(chǔ)之上再提供額外的描述信息。


          本博客中的所有文章、隨筆除了標(biāo)題中含有引用或者轉(zhuǎn)載字樣的,其他均為原創(chuàng)。轉(zhuǎn)載請(qǐng)注明出處,謝謝!

          posted on 2008-09-18 17:57 zhuxing 閱讀(2194) 評(píng)論(2)  編輯  收藏 所屬分類: Eclipse Plug-in & OSGIWTP(Web Tools Platform)

          評(píng)論

          # re: 【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(七):WTP數(shù)據(jù)模型總結(jié)和模型管理  回復(fù)  更多評(píng)論   

          學(xué)習(xí)學(xué)習(xí)
          2008-09-19 17:22 | zhanggj

          # re: 【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(七):WTP數(shù)據(jù)模型總結(jié)和模型管理  回復(fù)  更多評(píng)論   

          V5
          2012-09-20 10:03 | imu2008
          主站蜘蛛池模板: 正阳县| 宜春市| 修水县| 新安县| 镇沅| 依安县| 新平| 额敏县| 都匀市| 永胜县| 扶绥县| 巫溪县| 亚东县| 贺州市| 方城县| 郁南县| 施秉县| 县级市| 崇左市| 兴城市| 措勤县| 永春县| 宽甸| 资阳市| 淮安市| 巴南区| 襄汾县| 浮梁县| 永善县| 黄骅市| 江永县| 毕节市| 安西县| 康平县| 观塘区| 若羌县| 玛沁县| 札达县| 南华县| 那坡县| 驻马店市|