專利名稱::偶爾連接的應(yīng)用服務(wù)器的制作方法
技術(shù)領(lǐng)域:
:本發(fā)明總的涉及移動(dòng)應(yīng)用架構(gòu),尤其涉及用于開發(fā)、部署和管理用于偶爾連接的移動(dòng)設(shè)備的應(yīng)用的移動(dòng)應(yīng)用架構(gòu)。
背景技術(shù):
:計(jì)算機(jī)和計(jì)算設(shè)備已經(jīng)越來越少、越來越快和越來越有效。結(jié)果,它們的功能進(jìn)化,并且它們能夠存儲(chǔ)和處理更多信息。然而,仍然有一個(gè)對(duì)設(shè)備可以本地存儲(chǔ)和處理什么的限制。最近,移動(dòng)連接的系統(tǒng)的發(fā)展已經(jīng)允許便攜設(shè)備的更多功能。這些設(shè)備包括計(jì)算機(jī)、PDA、蜂窩電話、筆記本計(jì)算機(jī)、黑莓型(blackberry-type)設(shè)備和其他移動(dòng)設(shè)備,只要在存在強(qiáng)的連接的地方它們就可以連接到因特網(wǎng)。盡管這些設(shè)備的應(yīng)用有幾種形式,但用戶傳統(tǒng)上由于應(yīng)用的部署和隨后的改變比較容易而偏好基于web的模型。此外,基于web的頁(yè)面對(duì)于用戶使用非常簡(jiǎn)單且直觀。移動(dòng)設(shè)備web瀏覽的最新發(fā)展出現(xiàn)幾個(gè)問題。難以在用戶所處的任何位置獲得連接。連接典型地是通過標(biāo)準(zhǔn)電話連接進(jìn)行的,這取決于蜂窩電話信號(hào)強(qiáng)度。目前在蜂窩電話網(wǎng)絡(luò)中存在許多死區(qū),這可以引起移動(dòng)設(shè)備和web服務(wù)器之間連接的停止時(shí)間。當(dāng)考慮通過典型的瀏覽器提供web頁(yè)面內(nèi)容所需的交互時(shí)更麻煩。當(dāng)用戶與web瀏覽器交互時(shí),瀏覽器將基于用戶輸入向服務(wù)器請(qǐng)求更多信息。這要求瀏覽器和web服務(wù)器之間的有效連接,以便檢索新信息來提供給用戶。因此,當(dāng)用戶在移動(dòng)設(shè)備上與web瀏覽器交互并且進(jìn)入信號(hào)強(qiáng)度弱的區(qū)域或死區(qū)時(shí),弱連接(或缺少連接)將可能導(dǎo)致移動(dòng)設(shè)備接收的內(nèi)容出錯(cuò)。因此,用戶常常不能以這種方式與web頁(yè)面交互。所需要的是一種移動(dòng)應(yīng)用體系框架,它能提供直觀的用戶接口和更可靠的用來向移動(dòng)設(shè)備用戶提供內(nèi)容的機(jī)制。該框架還應(yīng)當(dāng)提供來開發(fā)、部署和管理復(fù)雜的移動(dòng)解決方案,同時(shí)允許集成了現(xiàn)有企業(yè)組件的、簡(jiǎn)單的類似web的編程模型。
發(fā)明內(nèi)容在一個(gè)實(shí)施例中,偶爾連接的應(yīng)用服務(wù)器平臺(tái)提供一種使用與現(xiàn)有企業(yè)組件集成的、簡(jiǎn)單的類似Web的編程模型開發(fā)、部署和管理復(fù)雜移動(dòng)解決方案的框架。偶爾連接的應(yīng)用可以包括數(shù)據(jù)模型定義、用戶接口模板、包括定義動(dòng)作的腳本的客戶端控制器、以及在服務(wù)器側(cè)的用于描述如何在數(shù)據(jù)模型和企業(yè)之間仲裁的一組管道。在一個(gè)實(shí)施例中,偶爾連接的應(yīng)用服務(wù)器假設(shè)由偶爾連接的應(yīng)用使用的所有數(shù)據(jù)由外部系統(tǒng)永久地作為web服務(wù)存儲(chǔ)和管理。該數(shù)據(jù)模型可以是該數(shù)據(jù)的偶爾連接的應(yīng)用的預(yù)期用途的元數(shù)據(jù)描述,并且被優(yōu)化來允許在偶爾連接設(shè)備和外部系統(tǒng)之間有效遍歷和同步該數(shù)據(jù)。偶爾連接的數(shù)據(jù)模型可以描述永久應(yīng)用數(shù)據(jù)的結(jié)構(gòu)(和其他屬性)。偶爾連接的數(shù)據(jù)模型自身可以與瀏覽器同步,以便客戶端能夠智能地遍歷數(shù)據(jù)并與服務(wù)器同步數(shù)據(jù)。圖1A-B圖解根據(jù)本發(fā)明一個(gè)實(shí)施例的架構(gòu)概觀。圖2圖解根據(jù)本發(fā)明一個(gè)實(shí)施例的異步交互圖。圖3圖解根據(jù)本發(fā)明一個(gè)實(shí)施例的MAS應(yīng)用的編程模型。圖4圖解根據(jù)本發(fā)明一個(gè)實(shí)施例的實(shí)體關(guān)系圖。圖5圖解根據(jù)本發(fā)明一個(gè)實(shí)施例的UML實(shí)體關(guān)系圖。圖6圖解根據(jù)本發(fā)明一個(gè)實(shí)施例的節(jié)點(diǎn)實(shí)例圖。圖7圖解根據(jù)本發(fā)明一個(gè)實(shí)施例的選擇操作。圖8圖解根據(jù)本發(fā)明一個(gè)實(shí)施例的輸入輸出矩陣。圖9是根據(jù)本發(fā)明一個(gè)實(shí)施例的CRM模式類型圖。圖10圖解根據(jù)本發(fā)明一個(gè)實(shí)施例的部分CRM應(yīng)用的頁(yè)面流。圖11A-B圖解根據(jù)本發(fā)明一個(gè)實(shí)施例的同步方法。圖12A-D圖解根據(jù)本發(fā)明一個(gè)實(shí)施例的示例性keyref定義。具體實(shí)施例方式在一個(gè)實(shí)施例中,偶爾連接的應(yīng)用服務(wù)器平臺(tái)提供了用于開發(fā)、部署和管理復(fù)雜移動(dòng)解決方案的框架,具有集成現(xiàn)有企業(yè)組件的簡(jiǎn)單的類似web的編程模型。連接-連接的應(yīng)用可以包括數(shù)據(jù)模型定義;用戶接口模板;客戶端控制器,其包括定義行動(dòng)的腳本;和在服務(wù)器側(cè)上的一組管道(conduit),用于描述如何在數(shù)據(jù)模型和企業(yè)之間仲裁。在一個(gè)實(shí)施例中,偶爾連接的應(yīng)用服務(wù)器假設(shè)移動(dòng)應(yīng)用使用的所有數(shù)據(jù)由外部系統(tǒng)永久存儲(chǔ)和管理。數(shù)據(jù)模型可以是移動(dòng)應(yīng)用對(duì)該數(shù)據(jù)的預(yù)期使用的元數(shù)據(jù)描述,并且可以被優(yōu)化來允許在偶爾連接的設(shè)備和外部系統(tǒng)之間有效遍歷和同步該數(shù)據(jù)。偶爾連接的數(shù)據(jù)模型可以描述所有永久應(yīng)用數(shù)據(jù)的結(jié)構(gòu)(和其他特性)。模型自身可以與移動(dòng)瀏覽器同步以便客戶端能夠智能地遍歷數(shù)據(jù)并與服務(wù)器同步數(shù)據(jù)。偶爾連接的數(shù)據(jù)模型可以描述將在客戶端上被高速緩存和同步(或者可選地,在服務(wù)器上高速緩存)的數(shù)據(jù)。編程模型很多是使用元數(shù)據(jù)描述的,這為管理員和終端用戶提供了對(duì)所部署的應(yīng)用的高級(jí)控制。在一個(gè)實(shí)施例中,在BEASystems,SanJose,California的WebLogicWorkshop內(nèi)可以完全支持編程模型—使用Workshop的可視設(shè)計(jì)工具和雙程開發(fā)模型,并且允許開發(fā)者借用其他WebLogicPlatform組件,如LiquidData和Integration。建立移動(dòng)化解決方案可以像建立WorkshopWeb應(yīng)用一樣簡(jiǎn)單,而不需要專家移動(dòng)組。目標(biāo)是從開發(fā)、部署、維護(hù)到日常使用,以很棒的所有權(quán)的總成本得到很棒的移動(dòng)體驗(yàn)。圖1A-B示出一個(gè)實(shí)施例的總體系統(tǒng)架構(gòu)100,它包括移動(dòng)瀏覽器110、偶爾連接的應(yīng)用服務(wù)器120和外部Web服務(wù)140。偶爾連接的應(yīng)用服務(wù)器120(OCAS),例如移動(dòng)應(yīng)用服務(wù)器(MAS),可以仲裁(mediate)在移動(dòng)瀏覽器上運(yùn)行的客戶端應(yīng)用和通過Web服務(wù)訪問的外部系統(tǒng)之間的數(shù)據(jù)交換。該機(jī)制具有兩個(gè)階段首先,OCAS120可以協(xié)調(diào)外部數(shù)據(jù)和偶爾連接的數(shù)據(jù)模型之間的數(shù)據(jù)轉(zhuǎn)換;其次,OCAS120可以協(xié)調(diào)客戶端高速緩存和外部Web服務(wù)之間的同步。本發(fā)明的一個(gè)實(shí)施例是移動(dòng)客戶端111的偶爾連接的應(yīng)用服務(wù)器120。偶爾連接的應(yīng)用服務(wù)器120可以包括存儲(chǔ)器,用于存儲(chǔ)偶爾連接的數(shù)據(jù)模型127(如移動(dòng)數(shù)據(jù)移動(dòng));和高速緩存128,用于存儲(chǔ)偶爾連接的數(shù)據(jù)模型127所定義的數(shù)據(jù)節(jié)點(diǎn)。偶爾連接的應(yīng)用服務(wù)器120可以將偶爾連接的數(shù)據(jù)模型中的元數(shù)據(jù)所指示的數(shù)據(jù)節(jié)點(diǎn)高速緩存在高速緩存128中。偶爾連接的應(yīng)用服務(wù)器120可以是在一臺(tái)或多臺(tái)機(jī)器上運(yùn)行的軟件。偶爾連接的應(yīng)用服務(wù)器120可以在應(yīng)用服務(wù)器之上運(yùn)行,或者是應(yīng)用服務(wù)器的一部分。偶爾連接的客戶端111可以是個(gè)人數(shù)字助理(PDA)、電話、筆記本電腦或其他移動(dòng)計(jì)算設(shè)備??蛻舳诉€可以包括固定的計(jì)算機(jī),尤其是與服務(wù)器間歇聯(lián)系的計(jì)算機(jī)。偶爾連接的應(yīng)用服務(wù)器120可以在外部系統(tǒng)(如web服務(wù)140)和偶爾連接的數(shù)據(jù)模型127定義的數(shù)據(jù)節(jié)點(diǎn)之間轉(zhuǎn)換數(shù)據(jù)。本發(fā)明的一個(gè)實(shí)施例是包括偶爾連接的應(yīng)用服務(wù)器120的系統(tǒng)。偶爾連接的應(yīng)用服務(wù)器120可以被配置成向客戶端提供應(yīng)用。應(yīng)用可以允許客戶端讀取和更新應(yīng)用數(shù)據(jù),而不需要對(duì)偶爾連接的應(yīng)用服務(wù)器的當(dāng)前訪問。偶爾連接的應(yīng)用服務(wù)器120可以適用于從外部系統(tǒng)獲得應(yīng)用數(shù)據(jù)來發(fā)送給客戶端。偶爾連接的應(yīng)用服務(wù)器可以適用于將來自外部系統(tǒng)的數(shù)據(jù)轉(zhuǎn)換成數(shù)據(jù)節(jié)點(diǎn)。外部系統(tǒng)可以是服務(wù)總線、web服務(wù)或一些其他系統(tǒng)。偶爾連接的數(shù)據(jù)模型127可以指示移動(dòng)客戶端對(duì)外部數(shù)據(jù)的預(yù)期使用,并且在移動(dòng)客戶端111請(qǐng)求之前獲得外部數(shù)據(jù)。數(shù)據(jù)節(jié)點(diǎn)可以是獨(dú)立的數(shù)據(jù)塊,如XML數(shù)據(jù)。模型數(shù)據(jù)模型127可以包括對(duì)數(shù)據(jù)節(jié)點(diǎn)的XML定義,如XML模式(schema)或XMLDTD。本發(fā)明的一個(gè)實(shí)施例是包括偶爾連接的應(yīng)用服務(wù)器120的系統(tǒng)。偶爾連接的應(yīng)用服務(wù)器120的系統(tǒng)可以被配置成向客戶端提供應(yīng)用。應(yīng)用可以允許客戶端讀取并更新應(yīng)用,而不需要對(duì)偶爾連接的應(yīng)用服務(wù)器的當(dāng)前訪問。偶爾連接的應(yīng)用服務(wù)器120可以適用于從外部系統(tǒng)獲得應(yīng)用數(shù)據(jù)來發(fā)送給客戶端。偶爾連接的應(yīng)用服務(wù)器可以適用于將來自外部系統(tǒng)的數(shù)據(jù)轉(zhuǎn)換成數(shù)據(jù)節(jié)點(diǎn)。外部系統(tǒng)可以是服務(wù)總線、web服務(wù)或一些其他系統(tǒng)。移動(dòng)客戶端111可以傳送數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型115來在移動(dòng)客戶端111上產(chǎn)生顯示。自適應(yīng)用戶接口服務(wù)器126可以由高速緩存128中的數(shù)據(jù)節(jié)點(diǎn)和客戶端130的偶爾連接的數(shù)據(jù)模型127構(gòu)建HTML頁(yè)面。客戶端130可以包括具有對(duì)訪問服務(wù)器120的一致訪問的傳統(tǒng)web瀏覽器。自適應(yīng)UI服務(wù)器126可以提供在服務(wù)器上運(yùn)行客戶應(yīng)用的機(jī)制,允許從瘦(thin)客戶端(例如,普通Web瀏覽器、SMS電話等)的訪問。移動(dòng)客戶端111可以在不用與偶爾連接的應(yīng)用服務(wù)器120聯(lián)系的情況下使用數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型115運(yùn)行應(yīng)用。移動(dòng)瀏覽器110處的客戶端112可以使用高速緩存113中的數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型115來產(chǎn)生諸如HTML視圖119之類的顯示。在一個(gè)實(shí)施例中,可以使用模板來在移動(dòng)瀏覽器110上產(chǎn)生顯示。數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型可以在偶爾連接的應(yīng)用服務(wù)器120和移動(dòng)客戶端111之間同步。當(dāng)移動(dòng)客戶端111和偶爾連接的應(yīng)用服務(wù)器120之間的連接可用時(shí)該同步可以在后臺(tái)進(jìn)行。本發(fā)明的一個(gè)實(shí)施例是一偶爾連接的應(yīng)用服務(wù)器120,其包括同步單元131,例如同步引擎,用于同步數(shù)據(jù)節(jié)點(diǎn)(如高速緩存128中的數(shù)據(jù)節(jié)點(diǎn))與偶爾連接的數(shù)據(jù)模型定義的應(yīng)用的客戶端;和管道管理器124,用于在來自外部系統(tǒng)的數(shù)據(jù)和由偶爾連接的數(shù)據(jù)模型127定義的數(shù)據(jù)節(jié)點(diǎn)之間轉(zhuǎn)換。本發(fā)明的一個(gè)實(shí)施例是一方法,其包括在偶爾連接的應(yīng)用服務(wù)器120上存儲(chǔ)偶爾連接的數(shù)據(jù)模型127定義的節(jié)點(diǎn)以及節(jié)點(diǎn)之間的關(guān)系;以及在偶爾連接的應(yīng)用服務(wù)器120上高速緩存偶爾連接的數(shù)據(jù)模型127定義的數(shù)據(jù)節(jié)點(diǎn)。偶爾連接的應(yīng)用服務(wù)器120可以高速緩存偶爾連接的數(shù)據(jù)模型127中的元數(shù)據(jù)所指示的數(shù)據(jù)節(jié)點(diǎn)。本發(fā)明的一個(gè)實(shí)施例是一偶爾連接的應(yīng)用服務(wù)器120,包括用于存儲(chǔ)偶爾連接的數(shù)據(jù)模型127的存儲(chǔ)器和用于存儲(chǔ)偶爾連接的數(shù)據(jù)模型127定義的數(shù)據(jù)節(jié)點(diǎn)的高速緩存128。數(shù)據(jù)節(jié)點(diǎn)包括主關(guān)鍵字和同步狀態(tài)。主關(guān)鍵字定義數(shù)據(jù)節(jié)點(diǎn)。數(shù)據(jù)節(jié)點(diǎn)還可以包括至少一個(gè)輔關(guān)鍵字??梢允褂猛綘顟B(tài)來同步數(shù)據(jù)節(jié)點(diǎn)與移動(dòng)客戶端。偶爾連接的數(shù)據(jù)模型127可以包括數(shù)據(jù)節(jié)點(diǎn)的XML模式。本發(fā)明的一個(gè)實(shí)施例是一偶爾連接的應(yīng)用服務(wù)器120。偶爾連接的應(yīng)用服務(wù)器120可以包括存儲(chǔ)器,用于存儲(chǔ)偶爾連接的數(shù)據(jù)模型127,偶爾連接的數(shù)據(jù)模型127可以定義節(jié)點(diǎn)以及節(jié)點(diǎn)之間的關(guān)系;和管道管理器124,用于在來自外部系統(tǒng)的數(shù)據(jù)和偶爾連接的數(shù)據(jù)模型127定義的數(shù)據(jù)節(jié)點(diǎn)之間轉(zhuǎn)換。管道管理器124可以使用管道137,管道137定義在由偶爾連接的數(shù)據(jù)模型127定義的數(shù)據(jù)節(jié)點(diǎn)和對(duì)特定web服務(wù)140的請(qǐng)求和響應(yīng)數(shù)據(jù)之間的變換。該變換可以作為元數(shù)據(jù)包含。請(qǐng)求變換可以包括XQuery函數(shù),其用于創(chuàng)建輸出消息主體。響應(yīng)變換包括XQuery函數(shù),其用于處理輸入響應(yīng)并且創(chuàng)建由偶爾連接的數(shù)據(jù)模型127定義的數(shù)據(jù)節(jié)點(diǎn)。本發(fā)明的一個(gè)實(shí)施例是移動(dòng)客戶端111的偶爾連接的應(yīng)用服務(wù)器120,包括管道管理器124,用于喚起外部web服務(wù)140操作。管道管理器124可以使用管道137。管道可以定義在偶爾連接的數(shù)據(jù)模型定義的數(shù)據(jù)與對(duì)特定web服務(wù)140的請(qǐng)求和響應(yīng)之間的變換。本發(fā)明的一個(gè)實(shí)施例是一方法,其包括在偶爾連接的應(yīng)用服務(wù)器120上使用管道137在偶爾連接的數(shù)據(jù)模型127定義的數(shù)據(jù)節(jié)點(diǎn)與對(duì)特定web服務(wù)140的請(qǐng)求和響應(yīng)之間變換,數(shù)據(jù)節(jié)點(diǎn)是XML數(shù)據(jù);以及在偶爾連接的應(yīng)用服務(wù)器120上使用數(shù)據(jù)節(jié)點(diǎn)向移動(dòng)客戶端111提供數(shù)據(jù)供移動(dòng)瀏覽器顯示。數(shù)據(jù)節(jié)點(diǎn)可以被傳送到移動(dòng)客戶端111供顯示。本發(fā)明的一個(gè)實(shí)施例是包括可存儲(chǔ)在高速緩存113中的數(shù)據(jù)節(jié)點(diǎn)的移動(dòng)客戶端111。這些數(shù)據(jù)節(jié)點(diǎn)可以是XML格式的。移動(dòng)客戶端處的數(shù)據(jù)節(jié)點(diǎn)可以具有相關(guān)的同步狀態(tài)。同步狀態(tài)可以指示數(shù)據(jù)節(jié)點(diǎn)是否已經(jīng)與服務(wù)器120同步。當(dāng)?shù)椒?wù)器的訪問可用時(shí),數(shù)據(jù)節(jié)點(diǎn)可以在后臺(tái)同步,并且使用移動(dòng)客戶端11處的數(shù)據(jù)節(jié)點(diǎn)進(jìn)行移動(dòng)客戶端111處的顯示,而不用要求對(duì)服務(wù)器120的當(dāng)前訪問。同步狀態(tài)可以包括數(shù)據(jù)節(jié)點(diǎn)被本地創(chuàng)建或修改的指示;數(shù)據(jù)節(jié)點(diǎn)被本地創(chuàng)建或修改、且準(zhǔn)備好與服務(wù)器同步的指示;和數(shù)據(jù)節(jié)點(diǎn)與服務(wù)器同步被掛起的指示;數(shù)據(jù)節(jié)點(diǎn)與服務(wù)器同步的指示;以及該同步被服務(wù)器拒絕的指示;本地修改和服務(wù)器更新之間存在沖突的指示??梢允褂眠@些和其他同步狀態(tài)來更新客戶端111上的數(shù)據(jù)節(jié)點(diǎn)。移動(dòng)客戶端111可以從服務(wù)器120傳送數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型來在移動(dòng)客戶端上產(chǎn)生顯示。移動(dòng)客戶端111可以在不與服務(wù)器當(dāng)前聯(lián)系的情況下使用數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型115運(yùn)行應(yīng)用。服務(wù)器120和移動(dòng)客戶端111之間的數(shù)據(jù)節(jié)點(diǎn)的同步可以在后臺(tái)進(jìn)行。本發(fā)明的一個(gè)實(shí)施例是一偶爾連接的應(yīng)用服務(wù)器120,其包括定義節(jié)點(diǎn)類型和節(jié)點(diǎn)之間的關(guān)系的偶爾連接的數(shù)據(jù)模型115;和數(shù)據(jù)節(jié)點(diǎn)。數(shù)據(jù)節(jié)點(diǎn)可以是XML格式。偶爾連接的應(yīng)用服務(wù)器120可以與移動(dòng)客戶端111來回傳遞數(shù)據(jù)節(jié)點(diǎn)的同步狀態(tài)來同步數(shù)據(jù)節(jié)點(diǎn)。當(dāng)?shù)椒?wù)器的訪問可用時(shí),數(shù)據(jù)節(jié)點(diǎn)可以在后臺(tái)同步,并且使用移動(dòng)客戶端11處的數(shù)據(jù)節(jié)點(diǎn)進(jìn)行移動(dòng)客戶端111處的顯示,而不用要求對(duì)服務(wù)器120的當(dāng)前訪問。本發(fā)明的一個(gè)實(shí)施例是一種用于同步移動(dòng)設(shè)備上的移動(dòng)應(yīng)用的方法。該方法包括在移動(dòng)設(shè)備上顯示第一用戶接口,第一用戶接口來自存儲(chǔ)在移動(dòng)設(shè)備上的模板;在移動(dòng)設(shè)備上接收用戶的第一輸入;更新移動(dòng)設(shè)備中的同步參數(shù);在移動(dòng)設(shè)備上顯示第二用戶接口,第二用戶接口來自存儲(chǔ)在移動(dòng)設(shè)備上的第二模板并且是基于用戶輸入選擇的;以及從應(yīng)用服務(wù)器檢索數(shù)據(jù),數(shù)據(jù)包括一個(gè)或多個(gè)基于同步參數(shù)選擇的模板。本發(fā)明的一個(gè)實(shí)施例是移動(dòng)單元111,包括XML格式的數(shù)據(jù)節(jié)點(diǎn)的本地高速緩存113以及定義節(jié)點(diǎn)類型和節(jié)點(diǎn)之間關(guān)系的偶爾連接的數(shù)據(jù)模型115,其中移動(dòng)單元111使用數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型來產(chǎn)生在移動(dòng)單元上顯示的應(yīng)用??梢允褂媚0?35來在移動(dòng)節(jié)點(diǎn)單元上產(chǎn)生數(shù)據(jù)節(jié)點(diǎn)的接口。本發(fā)明的一個(gè)實(shí)施例是移動(dòng)單元110,其包括XML格式的數(shù)據(jù)節(jié)點(diǎn)的本地高速緩存128;以及定義節(jié)點(diǎn)類型和節(jié)點(diǎn)之間關(guān)系的偶爾連接的數(shù)據(jù)模型115;以及允許修改數(shù)據(jù)節(jié)點(diǎn)的動(dòng)作(action)。本發(fā)明的一個(gè)實(shí)施例是移動(dòng)單元110,包括存儲(chǔ)偶爾連接的數(shù)據(jù)模型115的存儲(chǔ)器和偶爾連接的數(shù)據(jù)模型115定義的數(shù)據(jù)節(jié)點(diǎn)的本地高速緩存113。數(shù)據(jù)節(jié)點(diǎn)包括主關(guān)鍵字和同步狀態(tài)。在一個(gè)實(shí)施例中,至少一個(gè)數(shù)據(jù)節(jié)點(diǎn)包括至少一個(gè)輔關(guān)鍵字??梢允褂猛綘顟B(tài)來同步模式數(shù)據(jù)與偶爾連接的應(yīng)用服務(wù)器。偶爾連接的數(shù)據(jù)模型115可以包括數(shù)據(jù)節(jié)點(diǎn)的至少一個(gè)XML模式。本發(fā)明的一個(gè)實(shí)施例是移動(dòng)客戶端的偶爾連接的應(yīng)用服務(wù)器120,包括用于在外部系統(tǒng)(如web服務(wù)140)和偶爾連接的數(shù)據(jù)模型127之間轉(zhuǎn)換的管道管理器;高速緩存128,可以用來存儲(chǔ)偶爾連接的數(shù)據(jù)模型127定義的數(shù)據(jù)節(jié)點(diǎn);和自適應(yīng)用戶接口服務(wù)器126。一些移動(dòng)客戶端111被傳送數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型來在移動(dòng)客戶端111上產(chǎn)生顯示,而其他客戶端從偶爾連接的應(yīng)用服務(wù)器120接收HTML頁(yè)面,偶爾連接的應(yīng)用服務(wù)器120是由自適應(yīng)用戶接口服務(wù)器126使用數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型構(gòu)造的。自適應(yīng)用戶接口服務(wù)器124服務(wù)的客戶端130可以具有傳統(tǒng)的瀏覽器。移動(dòng)客戶端111可以具有特殊的瀏覽器110,該瀏覽器使用數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型來產(chǎn)生顯示。本發(fā)明的一個(gè)實(shí)施例是一方法,其包括在服務(wù)器120上,存儲(chǔ)偶爾連接的數(shù)據(jù)模型127定義的數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型127;將數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型傳送給一些客戶端111,從而客戶端可以產(chǎn)生顯示;以及將在服務(wù)器上由數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型構(gòu)造的HTML頁(yè)面?zhèn)魉徒o其他客戶端130。本發(fā)明的一個(gè)實(shí)施例是一偶爾連接的數(shù)據(jù)模型,其包括描述節(jié)點(diǎn)結(jié)構(gòu)的節(jié)點(diǎn)類型,節(jié)點(diǎn)可以是邏輯上獨(dú)立的數(shù)據(jù)單元;和描述節(jié)點(diǎn)之間關(guān)系的keyref聲明。節(jié)點(diǎn)可以包括根節(jié)點(diǎn)。變量可以指向根節(jié)點(diǎn)。移動(dòng)瀏覽器110可以使用數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型115來在移動(dòng)單元111產(chǎn)生顯示。偶爾連接的數(shù)據(jù)模型可以包括節(jié)點(diǎn)圖。節(jié)點(diǎn)圖可以指示高速緩存哪個(gè)數(shù)據(jù)節(jié)點(diǎn)。節(jié)點(diǎn)類型可以包括XML定義,如XML模式(復(fù)型定義)。keyref聲明可以定義關(guān)鍵字和keyref。關(guān)鍵字可以是主關(guān)鍵字。Keyref可以是參照主關(guān)鍵字的外關(guān)鍵字定義。Keyref定義可以定義數(shù)據(jù)圖中節(jié)點(diǎn)之間的合法遍歷。本發(fā)明的一個(gè)實(shí)施例是一偶爾連接的數(shù)據(jù)模型,其包括節(jié)點(diǎn)類型,它是節(jié)點(diǎn)結(jié)構(gòu)的XML定義;和描述節(jié)點(diǎn)之間關(guān)系的元數(shù)據(jù),如keyref定義。節(jié)點(diǎn)可以是邏輯上獨(dú)立的數(shù)據(jù)單元。本發(fā)明的一個(gè)實(shí)施例是一種用于實(shí)現(xiàn)代理(proxy)的方法,其包括將web服務(wù)操作映射到編程模型(如偶爾連接的數(shù)據(jù)模型)內(nèi)的數(shù)據(jù),接收與數(shù)據(jù)有關(guān)的請(qǐng)求;以及啟動(dòng)對(duì)相應(yīng)web服務(wù)操作的調(diào)用。本發(fā)明的一個(gè)實(shí)施例是移動(dòng)單元111,其包括應(yīng)用數(shù)據(jù)節(jié)點(diǎn)的本地高速緩存113,數(shù)據(jù)節(jié)點(diǎn)是XML格式的;定義節(jié)點(diǎn)類型和節(jié)點(diǎn)之間關(guān)系的偶爾連接的數(shù)據(jù)模型115;和模板135,用于產(chǎn)生數(shù)據(jù)節(jié)點(diǎn)的接口。模板135可以是XHTML模板。模板135可以使用Spath表示。模板135可以訪問偶爾連接的數(shù)據(jù)模型115中的當(dāng)前位置。當(dāng)前變量可以指示當(dāng)前位置。在一個(gè)實(shí)施例中,模板135不修改偶爾連接的數(shù)據(jù)模型。在一個(gè)實(shí)施例中,模板135可以調(diào)用動(dòng)作。動(dòng)作可以修改數(shù)據(jù)節(jié)點(diǎn)。動(dòng)作可以允許在不連接到服務(wù)器120的情況下修改數(shù)據(jù)節(jié)點(diǎn)。模板135可用于多個(gè)應(yīng)用,每個(gè)應(yīng)用具有其自己的偶爾連接的數(shù)據(jù)模型和數(shù)據(jù)節(jié)點(diǎn)。模板135可以由瀏覽器110使之有效。圖11A-B示出本發(fā)明一個(gè)實(shí)施例的同步方法。在圖11A的例子中,客戶端1102包括客戶端版本的“數(shù)據(jù)節(jié)點(diǎn)A”1104??蛻舳税姹镜摹皵?shù)據(jù)節(jié)點(diǎn)A”1104具有同步狀態(tài)“準(zhǔn)備好同步”??蛻舳税姹镜摹皵?shù)據(jù)節(jié)點(diǎn)A”1104可以包括在客戶端1102上構(gòu)造或修改的數(shù)據(jù)。在圖11A的例子中,客戶端1102和服務(wù)器1108之間沒有有效連接??蛻舳松系膽?yīng)用可以使用客戶端版本的“數(shù)據(jù)節(jié)點(diǎn)A”1104而不必等待同步。“數(shù)據(jù)節(jié)點(diǎn)A”的改變可以包含在當(dāng)連接可用時(shí)發(fā)送的消息隊(duì)列1106中的消息中。服務(wù)器1108具有還沒送到客戶端1102的服務(wù)器版本的“數(shù)據(jù)節(jié)點(diǎn)B”1110。服務(wù)器版本的“數(shù)據(jù)節(jié)點(diǎn)B”1110可以由從“web服務(wù)B”1116得到的數(shù)據(jù)構(gòu)造。管道管理器可以使用“管道B”1114來將來自“web服務(wù)B”1116的響應(yīng)數(shù)據(jù)轉(zhuǎn)換成服務(wù)器版本的“數(shù)據(jù)節(jié)點(diǎn)B”1110。“數(shù)據(jù)節(jié)點(diǎn)B”可以包含在當(dāng)連接可用時(shí)發(fā)送的消息隊(duì)列1118中的消息中。圖11B示出當(dāng)連接變得可用時(shí)的情況??梢詫⒖蛻舳税姹镜摹皵?shù)據(jù)節(jié)點(diǎn)A”1104發(fā)送到服務(wù)器1108,并且客戶端版本的“數(shù)據(jù)節(jié)點(diǎn)A”1104可以使其同步狀態(tài)設(shè)為“等待同步”。服務(wù)器1108可以高速緩存服務(wù)器版本的“數(shù)據(jù)節(jié)點(diǎn)A”1111。管道管理器1112可以使用“管道A”1115來構(gòu)造要送到“web服務(wù)A”1117的請(qǐng)求數(shù)據(jù)??蛻舳?102可以存儲(chǔ)從服務(wù)器1108獲得的客戶端版本的“數(shù)據(jù)節(jié)點(diǎn)B”1105。使用在后臺(tái)與服務(wù)器同步的數(shù)據(jù)節(jié)點(diǎn),這允許具有到服務(wù)器的間歇連接的客戶端用本地版本的數(shù)據(jù)節(jié)點(diǎn)運(yùn)行應(yīng)用,并且在連接可用時(shí)更新。下面的描述給出了一個(gè)實(shí)施例的一個(gè)非限制性實(shí)現(xiàn)。下面的討論給出一個(gè)實(shí)施例,但本領(lǐng)域技術(shù)人員應(yīng)當(dāng)理解,可以進(jìn)行上述構(gòu)思的其他實(shí)現(xiàn)。下面給出的任何可能的限制性語(yǔ)言應(yīng)當(dāng)在特定非限制性實(shí)現(xiàn)的上下文中解釋,而不意圖限制總的構(gòu)思。本發(fā)明的一個(gè)實(shí)施例是提供偶爾連接的訪問機(jī)制的系統(tǒng),包括瀏覽器110。瀏覽器可以配置成在移動(dòng)設(shè)備111上實(shí)現(xiàn),并且向用戶提供用戶接口。用戶接口可以來自模板135。還包括應(yīng)用服務(wù)器120,應(yīng)用服務(wù)器120被配置成提供永久性數(shù)據(jù)存儲(chǔ)器并且與瀏覽器傳輸信息。在一個(gè)實(shí)施例中,偶爾連接的應(yīng)用服務(wù)器120(MAS)在應(yīng)用服務(wù)器(如BEASystems的WebLogic服務(wù)器)上運(yùn)行或者是其一部分。偶爾連接的應(yīng)用服務(wù)器120包含用于存儲(chǔ)應(yīng)用元數(shù)據(jù)的永久數(shù)據(jù)存儲(chǔ)器和用于優(yōu)化客戶端請(qǐng)求的數(shù)據(jù)高速緩存128。偶爾連接的應(yīng)用服務(wù)器120可由移動(dòng)瀏覽器通過一套基于Web的同步服務(wù)(可以擴(kuò)展SyncML標(biāo)準(zhǔn))訪問。這允許不同類型的客戶端利用MAS數(shù)據(jù)模型和同步能力。偶爾連接的應(yīng)用服務(wù)器120不需要保存客戶端的全部狀態(tài)。相反,偶爾連接的應(yīng)用服務(wù)器120可以基于偶爾連接的數(shù)據(jù)模型127中的元數(shù)據(jù)智能地高速緩存數(shù)據(jù)。此外,偶爾連接的應(yīng)用服務(wù)器120可以包含稱為自適應(yīng)UI服務(wù)器126的動(dòng)態(tài)內(nèi)容自適應(yīng)機(jī)制,它能夠?qū)⒁苿?dòng)應(yīng)用功能提供給瘦客戶端(例如,HTML網(wǎng)站、WAP、SMS)。在一個(gè)實(shí)施例中,偶爾連接的數(shù)據(jù)模型可以是移動(dòng)應(yīng)用對(duì)該數(shù)據(jù)的預(yù)期使用的元數(shù)據(jù)描述,并且可以被優(yōu)化來允許在偶爾連接的設(shè)備和外部系統(tǒng)之間有效遍歷和同步該數(shù)據(jù)。偶爾連接的數(shù)據(jù)模型可以是描述與外部服務(wù)相關(guān)的數(shù)據(jù)的節(jié)點(diǎn)(或?qū)嶓w),以及它們之間的遍歷(或關(guān)系)。例如,假設(shè)Web服務(wù)提供對(duì)客戶關(guān)系管理(CRM)應(yīng)用的訪問,那么數(shù)據(jù)模型可能具有帳戶、聯(lián)系人和訂購(gòu)單等節(jié)點(diǎn),以及讓應(yīng)用從給定節(jié)點(diǎn)(例如,帳戶)“導(dǎo)航”到所有有關(guān)節(jié)點(diǎn)(例如,聯(lián)系人和訂購(gòu)單)的遍歷。偶爾連接的數(shù)據(jù)模型可以作為虛擬的XML文檔面向開發(fā)者,具有指向數(shù)據(jù)模型中的根節(jié)點(diǎn)的顯式(manifest)變量$root??梢栽谔摂MXML文檔中通過keyref聲明來定義與節(jié)點(diǎn)有關(guān)的導(dǎo)航。這允許使用在XML的ECMAScript中使用的、在該文檔中稱為Spath的XPath符號(hào)的子集的簡(jiǎn)單遍歷句法。此外,移動(dòng)瀏覽器總是可以具有數(shù)據(jù)模型內(nèi)的當(dāng)前位置作為內(nèi)容(例如一個(gè)特定客戶或一組訂單)。模板和腳本可以通過另一顯式變量$current訪問該當(dāng)前位置。在一個(gè)實(shí)施例中,移動(dòng)瀏覽器110是(或者包括)Web瀏覽器的擴(kuò)展,該擴(kuò)展允許偶爾連接的便攜計(jì)算機(jī)和其他設(shè)備運(yùn)行應(yīng)用而不管它們恰巧是連接的還是脫機(jī)的。瀏覽器可以包括與當(dāng)前Web瀏覽器相同的HTML呈現(xiàn)器,還包括用戶接口面板和頁(yè)面流(pageflow)機(jī)制、具有智能同步能力的數(shù)據(jù)高速緩存和提供對(duì)數(shù)據(jù)高速緩存訪問的擴(kuò)展腳本語(yǔ)言。移動(dòng)瀏覽器的用戶接口可以由頁(yè)面模板組成。模板可以是XHTML頁(yè)面,具有到使用SPath表示的高速緩存數(shù)據(jù)的內(nèi)嵌綁定(binding)。在一個(gè)實(shí)施例中,模板不依賴服務(wù)器側(cè),從而不管瀏覽器的網(wǎng)絡(luò)連接狀態(tài)(即,在線或脫機(jī))如何都可以呈現(xiàn)它們。模板可以生成用戶接口事件,后者可以被控制器捕獲;控制器可以調(diào)用動(dòng)作腳本,動(dòng)作腳本能夠修改客戶端高速緩存中的數(shù)據(jù)并確定頁(yè)面流??蛻舳送絾卧梢宰詣?dòng)同步與偶爾連接的應(yīng)用服務(wù)器120的數(shù)據(jù)訪問和改變。可以通過指向引用實(shí)現(xiàn)客戶端用戶接口的XML應(yīng)用封裝和該應(yīng)用的偶爾連接的數(shù)據(jù)模型的URL,來向移動(dòng)瀏覽器110提供應(yīng)用。應(yīng)用然后可以同步到同步客戶端112。此外,一旦部署了應(yīng)用,可以自動(dòng)和無縫地更新應(yīng)用。在一個(gè)實(shí)施例中,自適應(yīng)UI服務(wù)器124可以是為每個(gè)現(xiàn)時(shí)用戶運(yùn)行客戶端應(yīng)用(模板、頁(yè)面流、動(dòng)作等)的代理。它可以生成送到瀏覽器130的HTML頁(yè)面(或SMS等),并且HTML頁(yè)面可以包含用于生成HTTP請(qǐng)求的適合的超鏈接,HTTP請(qǐng)求被自適應(yīng)服務(wù)器轉(zhuǎn)換成相應(yīng)的動(dòng)作調(diào)用。自適應(yīng)服務(wù)器126可以使用與移動(dòng)瀏覽器110相同的同步機(jī)制??蛻舳藨?yīng)用可以通過同步與服務(wù)器通信。同步進(jìn)程可以觸發(fā)管道請(qǐng)求來取出新的或更近的數(shù)據(jù),或者請(qǐng)求將被投遞回外部Web服務(wù)140的客戶端改變。管道137可以包含描述如何封裝Web服務(wù)請(qǐng)求和如何將它們的響應(yīng)轉(zhuǎn)換成數(shù)據(jù)模型內(nèi)容的元數(shù)據(jù)。例如,假設(shè)客戶端應(yīng)用修改高速緩存在客戶端上的特定帳戶節(jié)點(diǎn)(記錄)的額定碼(ratingcode);同步機(jī)制可以生成發(fā)送到服務(wù)器的更新命令。如果客戶端應(yīng)用然后檢索與帳戶相關(guān)的聯(lián)系人,然后添加新的聯(lián)系人,則同步機(jī)制可以生成取出和添加相應(yīng)數(shù)據(jù)節(jié)點(diǎn)的命令。管道可以描述如何調(diào)用所需的各種Web服務(wù)操作來實(shí)現(xiàn)這些操作中的每一個(gè)。系統(tǒng)可以使用標(biāo)準(zhǔn)Web服務(wù)來與外部數(shù)據(jù)源和業(yè)務(wù)進(jìn)程交換信息。管道機(jī)制可以允許偶爾連接的應(yīng)用服務(wù)器120調(diào)用這些操作來更新移動(dòng)數(shù)據(jù)高速緩存128。操作可以用作特定數(shù)據(jù)類型的獲取器和設(shè)置器;用作適配器的管道可以管理一套操作。管道管理器可以協(xié)調(diào)OCAS的數(shù)據(jù)高速緩存的同步請(qǐng)求和管道操作。管道可以是用于將Web服務(wù)與三種類型的關(guān)于數(shù)據(jù)模型的請(qǐng)求動(dòng)作相關(guān)系的元數(shù)據(jù)■導(dǎo)航到有關(guān)數(shù)據(jù),例如,得到與帳戶相關(guān)的聯(lián)系人;■CRUD操作;即,創(chuàng)建、讀取、更新和刪除數(shù)據(jù)的請(qǐng)求,例如,創(chuàng)建與帳戶有關(guān)的聯(lián)系人、更新聯(lián)系人細(xì)節(jié)、或者甚至請(qǐng)求刪除聯(lián)系人;■自定義操作,是需要在企業(yè)中發(fā)生的與一些數(shù)據(jù)有關(guān)、但對(duì)數(shù)據(jù)模型是不透明的動(dòng)作,例如,請(qǐng)求關(guān)閉任務(wù)。管道元數(shù)據(jù)可以向/從與相應(yīng)Web服務(wù)操作相關(guān)的SOAP消息映射OCAS數(shù)據(jù)模型和同步命令。可以使用XMLQuery或XScript定義管道元數(shù)據(jù)。當(dāng)前Web瀏覽器架構(gòu)對(duì)于移動(dòng)性的一個(gè)主要缺點(diǎn)是同步(阻塞式)請(qǐng)求-響應(yīng)消息收發(fā)協(xié)議(即,HTTP)。在OCAS中,消息收發(fā)可以是異步的。即,用戶接口活動(dòng)(例如,瀏覽頁(yè)面和修改數(shù)據(jù))可以相對(duì)網(wǎng)絡(luò)的連通性異步地運(yùn)行,并且同步請(qǐng)求可以相對(duì)瀏覽器異步地運(yùn)行。圖2示出移動(dòng)瀏覽器210、OCAS220和外部Web服務(wù)230之間的示例性異步交互。該系統(tǒng)實(shí)現(xiàn)瀏覽器和OCAS之間可靠、有序的消息隊(duì)列,并且可以在OCAS和Web服務(wù)之間使用持久的JMS隊(duì)列(用于異步操作調(diào)用)。如果瀏覽器在線,則可以將同步消息排隊(duì),稍后送到OCAS。否則,同步單元可以跟蹤這些事件并且只要一建立連接就生成同步消息。在服務(wù)器上,如果OCAS高速緩存了與客戶端的同步請(qǐng)求有關(guān)的數(shù)據(jù),則它可以立即響應(yīng)。如果高速緩存沒有保存適當(dāng)?shù)臄?shù)據(jù)(或者數(shù)據(jù)是失效的),則同步單元可以調(diào)用管道管理器。同步單元然后可以將更新的數(shù)據(jù)傳遞到瀏覽器。由于對(duì)于一個(gè)特定同步請(qǐng)求可能存在多個(gè)調(diào)用的管道,因此OCAS可以將多個(gè)同步消息傳遞到瀏覽器。當(dāng)瀏覽器接收到同步消息時(shí),可以更新本地高速緩存并且將事件送到控制器。如果當(dāng)前正顯示的數(shù)據(jù)被修改了(即,數(shù)據(jù)綁定到當(dāng)前模板),則控制器可以使當(dāng)前頁(yè)面刷新。即,可以重新計(jì)算頁(yè)面數(shù)據(jù)綁定并且在瀏覽器中遞增地重新顯示頁(yè)面,而不閃爍或失去當(dāng)前用戶輸入、插入記號(hào)(caret)或焦點(diǎn)。OCAS應(yīng)用可以包括客戶端和服務(wù)器組件。圖3示出示例性O(shè)CAS應(yīng)用的編程模型300。編程模型300包括移動(dòng)客戶端310、OCAS320和外部系統(tǒng)330。在一個(gè)實(shí)施例中,所有到外部系統(tǒng)(即,企業(yè))的通信可以通過Web服務(wù)(即,SOAP消息)實(shí)現(xiàn)。服務(wù)器編程模型可以包括每個(gè)應(yīng)用的數(shù)據(jù)模型定義323和描述Web服務(wù)操作的一組管道定義324。數(shù)據(jù)模型包括描述數(shù)據(jù)類型和關(guān)系的一組XML模式定義。管道定義包含Xscript和XMLQuery(XQuery)函數(shù),該函數(shù)將輸入和輸出的SOAP消息映射到數(shù)據(jù)模型。客戶端編程模式可以包括數(shù)據(jù)模型311(服務(wù)器上定義的模型的副本)、一組XHTML模板312和控制器定義313,控制器定義313包括XPF頁(yè)面流定義和Xscript動(dòng)作和函數(shù)。整個(gè)應(yīng)用的內(nèi)容可以通過單個(gè)XML文件描述,框架自動(dòng)使用該文件來向客戶端提供應(yīng)用組件。在一個(gè)實(shí)施例中,每個(gè)OCAS應(yīng)用可以具有其自己的偶爾連接的數(shù)據(jù)模型。偶爾連接的數(shù)據(jù)模型可以描述通過Web服務(wù)由后端應(yīng)用顯露的應(yīng)用數(shù)據(jù)的邏輯結(jié)構(gòu)(和其他屬性)。偶爾連接的數(shù)據(jù)模型可以包括節(jié)點(diǎn)類型,用于描述數(shù)據(jù)模型中的節(jié)點(diǎn)(或?qū)嶓w);和keyref,用于定義節(jié)點(diǎn)類型之間的關(guān)系。偶爾連接的數(shù)據(jù)模型可以用作其他OCAS組件處理數(shù)據(jù)或相互交換數(shù)據(jù)使用的通用語(yǔ)(linguafranca)。應(yīng)用的數(shù)據(jù)模型的實(shí)際設(shè)計(jì)(由應(yīng)用設(shè)計(jì)者完成)可以考慮數(shù)據(jù)的預(yù)期使用,以便優(yōu)化客戶端應(yīng)用對(duì)數(shù)據(jù)的訪問以及服務(wù)器與偶爾連接的設(shè)備之間的數(shù)據(jù)同步。也可以指定額外的元數(shù)據(jù)來讓應(yīng)用更容易地顯示數(shù)據(jù)驅(qū)動(dòng)(即,自動(dòng))的用戶接口。在一個(gè)實(shí)施例中,偶爾連接的數(shù)據(jù)模型僅描述數(shù)據(jù);OCAS假設(shè)所有操作數(shù)據(jù)由外部系統(tǒng)存儲(chǔ)和管理(所有),即,OCAS中沒有永久駐留的操作數(shù)據(jù)。偶爾連接的數(shù)據(jù)模型可以用來描述可在客戶端和服務(wù)器這兩者上高速緩存的數(shù)據(jù),并且本質(zhì)上可以是通過Web服務(wù)取出的企業(yè)中的數(shù)據(jù)之上的虛擬高速緩存視圖。在一個(gè)實(shí)施例中,在偶爾連接的數(shù)據(jù)模型中,存在稱為mas:root(在編程模型中用$root引用)的魔術(shù)(magic)起始節(jié)點(diǎn),一切從該節(jié)點(diǎn)流出??梢酝ㄟ^遍歷從任何節(jié)點(diǎn)訪問有關(guān)的節(jié)點(diǎn)。節(jié)點(diǎn)可以遵從XML模式定義(/schema/*/xsd)。遍歷也可以使用keyref聲明由模式定義來定義。自動(dòng)同步機(jī)制可以協(xié)調(diào)客戶端和服務(wù)器數(shù)據(jù)之間的改變??梢酝ㄟ^稱為管道的機(jī)制檢索并與外部系統(tǒng)交換數(shù)據(jù)。管道可以由一組管道文件(/conduit/*/jsx)配置,這組文件定義管道操作—用于調(diào)用和處理來自外部Web服務(wù)操作的結(jié)果的XScript和Xquery函數(shù)。管道操作可以包括與給定keyref相關(guān)的一對(duì)XMLQuery函數(shù);一個(gè)函數(shù)可以將出去的請(qǐng)求格式化成適當(dāng)?shù)腤eb服務(wù)操作,另一個(gè)可以處理進(jìn)來的響應(yīng)。管道操作還可以定于相關(guān)XScript函數(shù)中的過程邏輯。偶爾連接的數(shù)據(jù)模型可以表示為包括節(jié)點(diǎn)和遍歷的數(shù)據(jù)圖—與關(guān)系數(shù)據(jù)庫(kù)中的實(shí)體(即,表格行)和關(guān)系(即,主/外關(guān)鍵字字段)。節(jié)點(diǎn)是邏輯上獨(dú)立的數(shù)據(jù)單元(或?qū)嶓w—例如,客戶、訂購(gòu)單或聯(lián)系人記錄)并且可以表示為由XML模式定義的XML數(shù)據(jù)對(duì)象。在高速緩存內(nèi),每個(gè)節(jié)點(diǎn)可以包括主關(guān)鍵字、同步狀態(tài)(例如,包括序列號(hào))以及引用其他節(jié)點(diǎn)的外關(guān)鍵字。節(jié)點(diǎn)類型可以描述關(guān)于節(jié)點(diǎn)的特定類型的信息;這可以包括描述數(shù)據(jù)節(jié)點(diǎn)的結(jié)構(gòu)的XML模式定義。遍歷可以是兩個(gè)節(jié)點(diǎn)之間的方向廣西。遍歷可以主要是用于從一個(gè)節(jié)點(diǎn)導(dǎo)航到一組有關(guān)節(jié)點(diǎn)的機(jī)制。例如,帳戶可以與一組聯(lián)系人和一組任務(wù)相關(guān)聯(lián),每個(gè)任務(wù)也可以與聯(lián)系人相關(guān)聯(lián)。節(jié)點(diǎn)之間的關(guān)系可以由keyref聲明定義。它可以定義源和目標(biāo)節(jié)點(diǎn)類型,并且可以包括元數(shù)據(jù)來確定節(jié)點(diǎn)集的基數(shù)(cardinality)(例如,正好為1、0或更多,1或更多等)。管道管理者的元數(shù)據(jù)可以與keyref相關(guān)聯(lián)并且確定是否可以創(chuàng)建、更新、鏈接或移除節(jié)點(diǎn)。例如,管道的元數(shù)據(jù)確定是否有用于插入關(guān)于帳戶的通知或更新帳戶的已知Web服務(wù)操作。由keyref定義的特定節(jié)點(diǎn)集合可以稱為節(jié)點(diǎn)集。數(shù)據(jù)節(jié)點(diǎn)數(shù)據(jù)節(jié)點(diǎn)可以包括結(jié)構(gòu)化的數(shù)據(jù)(即,XML文檔),但可以對(duì)于遍歷是基本的(atomic);即,在一個(gè)實(shí)施例中,遍歷表示兩個(gè)節(jié)點(diǎn)之間的特定關(guān)系,但不引用特定節(jié)點(diǎn)內(nèi)的數(shù)據(jù);節(jié)點(diǎn)內(nèi)的數(shù)據(jù)也不能引用另一節(jié)點(diǎn)。常常單個(gè)企業(yè)文檔可能由多個(gè)節(jié)點(diǎn)類型構(gòu)成。例如,訂購(gòu)單可以包括行式項(xiàng)目(lineitem)(每個(gè)具有產(chǎn)品引用)和客戶引用。在這種情況下,訂購(gòu)單、行式項(xiàng)目、產(chǎn)品和客戶都可以表示為不同的節(jié)點(diǎn)類型。在這些“復(fù)合”節(jié)點(diǎn)的情況下,數(shù)據(jù)模型內(nèi)的keyref可以定義基數(shù),例如,行式項(xiàng)目只與一個(gè)產(chǎn)品相關(guān)聯(lián)。相反,根據(jù)應(yīng)用的需要,可以定義單個(gè)訂購(gòu)單節(jié)點(diǎn)類型來在單個(gè)模式中包含所有上述信息。判決取決于應(yīng)用設(shè)計(jì)者—根據(jù)基于不同遍歷、集合和面板要求單獨(dú)地鏈接不同節(jié)點(diǎn)的需要。例如,如果行式項(xiàng)目從未鏈接或顯示在訂購(gòu)單外面,則定義復(fù)合的訂購(gòu)單-行式項(xiàng)目節(jié)點(diǎn)類型可能是有意義的。關(guān)系模型偶爾連接的數(shù)據(jù)模型可以包括模式和keyref聲明,與關(guān)系實(shí)體和關(guān)系(主/外關(guān)鍵字)構(gòu)造類似。主關(guān)鍵字和外關(guān)鍵字示例的CRM系統(tǒng)(為了說明的目的在整個(gè)本文檔中參考它)是使用關(guān)系數(shù)據(jù)庫(kù)實(shí)現(xiàn)的。圖4所示的實(shí)體關(guān)系圖(ERD)400表示帳戶、聯(lián)系人、事件和用戶實(shí)體。帳戶、聯(lián)系人和用戶實(shí)體由下面的SQL定義。CREATETABLEaccount(pkeyINTNOTNULLPRIMARYKEY,parentPkeyINTFOREIGNKEYREFERENCESaccount(pkey),ownerPkeyINTFOREIGNKEYREFERENCESuser(pkey),nameVARCHAR,typeCHAR)CREATETABLEcontact{pkeyINTNOTNULLPRIMARYKEY,accountPkeyINTNOTNULLFOREIGNKEYREFERENCESaccount(pkey),ownerPkeyINTFOREIGNKEYREFERENCESuser(pkey),firstVARCHAR,lastVARCHAR,emailVARCHAR)CREATETABLEuser(pkeyINTNOTNULLPRIMARYKEY,loginVARCHAR)帳戶和聯(lián)系人實(shí)體都包含對(duì)用戶(所有者)的外關(guān)鍵字引用;每個(gè)聯(lián)系人實(shí)體定義對(duì)帳戶的文件引用。此外,每個(gè)帳戶具有引用父帳戶(即,具有子帳戶的帳戶)的可選外關(guān)鍵字。采樣查詢(SampleQuery)給定帳戶的主關(guān)鍵字pa,下面的SQL選擇所有聯(lián)系人SELECT*FROMcontactWHEREaccountPkey=pa給定聯(lián)系人的主關(guān)鍵字pc,下面的SQL選擇帳戶SELECTaccount.*FROMaccount,contactWHEREaccount.pkey=contact.accountPkeyANDcontact.pkey=pc然而,給定全部聯(lián)系人記錄c,則該簡(jiǎn)單SELECT查詢選擇相應(yīng)帳戶SELECT*FROMaccountWHEREaccount.pkey=c.accountPkey聯(lián)合表(JoinTable)假設(shè)事件可以屬于多個(gè)帳戶和聯(lián)系人(例如,有兩個(gè)客戶(account)出席的銷售會(huì)議)。將使用聯(lián)合表來建模,例如,CREATETABLEevent(pkeyINTNOTNULLPRIMARYKEY,titleVARCHAR,detailsVARCHAR)CREATETABLEevent_account{eventPkeyINTFOREIGNKEYREFERENCESEVENT(pkey),accountPkeyINTFOREIGNKEYREFERENCESACCOUNT(pkey)這里,由事件帳戶聯(lián)合表來建模多對(duì)多關(guān)系。給定帳戶的主關(guān)鍵字pa,下面的SQL(聯(lián)合)選擇所有有關(guān)事件SELECTevent.*FROMevent,event_accountWHEREevent_account.accountPkey=paANDevent.pkey=event_account.eventPkey類似地,給定事件的主關(guān)鍵字pe,下面的SQL選擇所有有關(guān)帳戶SELECTaccount.*FROMaccount,event_accountWHEREevent_account.eventPkey=peANDaccount.pkey=event_account.accountPkeyXML模式XML模式可以定義應(yīng)用所使用的數(shù)據(jù)模型中的節(jié)點(diǎn)類型。模式子目錄可以包括多個(gè).xsd文件,所有文件都在啟動(dòng)時(shí)由框架加載。模式類型定義可以包括兩部分復(fù)合類型(complexType)定義,描述類型的結(jié)構(gòu);和元數(shù)據(jù)定義(使用mas名字空間(namespace)),例如,定義如何構(gòu)建特定類型的標(biāo)簽。例如,下面模式定義了聯(lián)系人類型。<?xmlversion="1.0"?><xsd:schematargetNamespace="http://example.com/"elementFormDefault="qualified"attributeFormDefault="unqualified"xmlns:xsd="http://www.w3.org/2001/xMLSchema"xmlns:mas="run:bea.com"xmlns="http://example.com/">…<xsd:elementname="contact"type="contactType"><xsd:annotation><xsd:appinfo><mas:nodeAnnotation><mas:label$node.first+""+$node.last</mas:label></mas:nodeAnnotation></xsd:appinfo></xsd:annotation></xsd:element><xsd:complexTypename="contactType"><xsd:sequence><xsd:elementname="salutation"type="contactSalutationEnum"/><xsd:elementname="first"type="xsd:string"/><xsd:elementname="last"type="xsd:string"/><xsd:elementname="email"type="xsd:string"/></xsd:sequence></xsd:complexType><xsd:simpleTypename="contactSalutationEnum"><xsd:restrictionbase="xsd:string"><xsd:enumerationvalue="Mr"/><xsd:enumerationvalue="Mrs"/><xsd:enumerationvalue="Ms"/><xsd:enumerationvalue="Dr"/></xsd:restriction></xsd:simpleType>…下面的XML表示聯(lián)系人元素。<contact><salutation>Mr</salutation><first>Roger</first><last>Reed</last><email>roger@acme.com</email></contact>Keyref基礎(chǔ)偶爾連接的數(shù)據(jù)模型可以包括對(duì)所有應(yīng)用類型的標(biāo)準(zhǔn)XML模式定義。模式可以定義包含被其他XML引用的XML元素和屬性的節(jié)點(diǎn)??梢允褂胟eyref聲明來對(duì)這些引用進(jìn)行定義。Keyref定義可以包括兩部分關(guān)鍵字和keyref。關(guān)鍵字定義可以定義文檔中包含主關(guān)鍵字的地方。例如,下面的關(guān)鍵字表明,在每個(gè)<account>元素中作為稱為id的屬性出現(xiàn)的accountKey。<xsd:keyname="accountKey"><xsd:selectorxpath="account"/><xsd:fieldxpath="@id"/></xsd:key>在一個(gè)實(shí)施例中,關(guān)鍵字可以唯一地表示單個(gè)節(jié)點(diǎn)。關(guān)鍵字不能用于標(biāo)識(shí)節(jié)點(diǎn)內(nèi)重復(fù)的元素(例如,如果在訂購(gòu)單的模式內(nèi)定義行式項(xiàng)目,則不能使用關(guān)鍵字定義來定義各個(gè)行式項(xiàng)目)。Keyref定義可以定義文檔中包含外關(guān)鍵字的地方;參考(refer)屬性指的是相關(guān)聯(lián)的關(guān)鍵字定義。例如,下面的keyref表明,每個(gè)聯(lián)系人中包含帳戶屬性,該屬性是引用(上述)accountKey定義的外關(guān)鍵字。<xsd:keyrefname="contactAccountRef"refer="accountKey"><xsd:selectorxpath="contact"/><xsd:fieldxpath="@accountId"/></xsd:keyref>可以有許多引用相同(主)關(guān)鍵字定義的keyref(外關(guān)鍵字)定義。類型和實(shí)例圖使用UML來說明節(jié)點(diǎn)類型和keyref圖。圖5示出示例CRM應(yīng)用的UML實(shí)體關(guān)系圖(ERD)500。在該圖中,每個(gè)實(shí)體表示應(yīng)用節(jié)點(diǎn)類型(即,模式)。注意,根(root)實(shí)體是系統(tǒng)節(jié)點(diǎn)類型?;【€表示關(guān)系(即,keyref定義),其中黑色菱形表示源節(jié)點(diǎn)類型的外關(guān)鍵字的目標(biāo)節(jié)點(diǎn)類型。星型注釋表示多對(duì)一關(guān)系。每條線標(biāo)有相應(yīng)keyref的別名。圖6示出用于CRM情況的節(jié)點(diǎn)實(shí)例圖。名字空間下面給出示例性的名字空間實(shí)施例。服務(wù)器編程模型可以使用名字空間來區(qū)別框架和應(yīng)用XML元素。名字空間定義可以作為屬性包含在XML源文件的頂級(jí)元素中。以mas名字空間為前綴的元素表示系統(tǒng)元素。xmlns:mas="urn:bea.mas"按照慣例,以app名字空間前綴為前綴的元素表示應(yīng)用。xmlns:app="http://example.com/"此外,按照慣例(在本文檔中),ws名字空間前綴用于指示由示例Web服務(wù)定義所定義的元素(即,WDSL文件);sfdc前綴用于指示SalesForce(銷售人員)Web服務(wù)。xmlns:ws="http://www.openuri.org/"xmlns:sfdc= "urn:partner.soap.sforce.com"模式數(shù)據(jù)類型可以支持下面的XML模式數(shù)據(jù)類型。模式注釋標(biāo)準(zhǔn)的XSD模式定義可以通過在<xsd:appinfo>元素內(nèi)聲明mas元素來擴(kuò)展。<xsd:elementname="typeName"type="type"><xsd:annotation><xsd:appinfo>...</xsd:appinfo><xsd:documentation>schemadocumentation</xsd:documentation></xsd:annotation></xsd:element>支持下面的模式注釋標(biāo)簽mas:label元素聲明節(jié)點(diǎn)的缺省標(biāo)簽;它聲明XPath表達(dá)式,用于構(gòu)造串。表達(dá)式可以可選地引用$node變量,它是指XML節(jié)點(diǎn)對(duì)象的頂級(jí)元素。句法<mas:label>spath-expression</mas:label>例子下面的標(biāo)簽定義由聯(lián)系人的名和姓構(gòu)造串。<xsd:elementname="contact"type="contactType"><xsd:annotation><xsd:appinfo><mas:label>$node.first+""$node.last</mas:label></xsd:appinfo></xsd:annotation></xsd:element>這與下面的表達(dá)式等效。<mas:label>first+""+last</mas:label>標(biāo)簽定義還可以包含XScript函數(shù)和運(yùn)算符。($node.first)+($node.first.length()>0?"":"")+$node.last應(yīng)用數(shù)據(jù)模型定義的剖析下面的XML模式描述了定義帳戶和聯(lián)系人節(jié)點(diǎn)類型的簡(jiǎn)單應(yīng)用數(shù)據(jù)模型<xsd:schema...><xsd:complexTypename="accountType"><xsd:all><xsd:elementname="name"type="xsd:string"/><xsd:elementname="type"type="xsd:string"/></xsd:all><xsd:attributename="id"type="xsd:string"use="required"mas:type="pkey"/><xsd:attributename="ownerId"type="xsd:string"use="required"/><xsd:attributename="parentId"type="xsd:string"/></xsd:complexType><xsd:complexTypename="contactType"><xsd:all><xsd:elementname="first"type="xsd:string"/><xsd:elementname="last"type="xsd:string"/><xsd:elementname="email"type="xsd:string"/></xsd:all><xsd:attributename="id"type="xsd:string"use="required"mas:type="pkey"/><xsd:attributename="ownerId"type="xsd:string"use="required"/><xsd:attributename="accountId"type="xsd:string"use="required"/></xsd:complexType><xsd:elementname="graph"><xsd:complexType><xsd:elementname="root"type="mas:rootType"/><xsd:sequence><xsd:elementname="account"type="accountType"maxOccurs="unbounded"/><xsd:elementname="contact"type="contactType"maxOccurs="unbounded"/></xsd:sequence></xsd:complexType><xsd:keyname="accountKey"><xsd:selectorxpath="account"/><xsd:fieldxpath="@id"/></xsd:key><xsd:keyrefname="contactAccountRef"refer="accountKey"mas:alias="account"mas:inverseAlias="contacts"><xsd:selectorxpath="contact"/><xsd:fieldxpath="@accountId"/></xsd:keyref></xsd:element></xsd:schema>模式文件可以包括三部分節(jié)點(diǎn)類型(復(fù)合類型定義)、定義高速緩存“文檔”的結(jié)構(gòu)的圖定義、和與相對(duì)于圖(即,文檔)結(jié)構(gòu)的關(guān)鍵字/keyref定義。模式定義與前面一樣,數(shù)據(jù)模型包括XML模式定義。下面的模式定義account和contact節(jié)點(diǎn)類型。<xsd:schema...><xsd:complexTypename="accountType"><xsd:all><xsd:elementname="name"type="xsd:string"/></xsd:all><xsd:attributename="id"type="xsd:string"use="required"mas:type="pkey"/><xsd:attributename="ownerId"type="xsd:string"use="required"/><xsd:attributename="parentId"type="xsd:string"/></xsd:complexType><xsd:complexTypename="contactType"><xsd:all><xsd:elementname="first"type="xsd:string"/><xsd:elementname="last"type="xsd:string"/><xsd:elementname="email"type="xsd:string"/></xsd:all><xsd:attributename="id"type="xsd:string"use="required"mas:type="pkey"/><xsd:attributename="ownerId"type="xsd:string"use="required"/><xsd:attributename="accountId"type="xsd:string"use="required"/></xsd:complexType>所有類型可以定義主關(guān)鍵字字段(或?qū)傩?,聲明為關(guān)鍵字。在例子中,所有類型可以定義外部標(biāo)識(shí)符id,表示外部記錄的主關(guān)鍵字;contact類型也定義表示外關(guān)鍵字的屬性@accountId。上述模式定義將允許下面的實(shí)例數(shù)據(jù)<accountid="1.1"><name>Acme</name></account><contactid="1.2"accountId="1.1"><first>Bob</first><last>Harris</last><email>bob@acme.com</email></contact><contactid="1.3"accountId="1.1"><first>Maggie</first><last>Cheung</last><email>maggie@acme.com</email></contact>要注意,所示標(biāo)識(shí)符值是說明性的;此外,這些例子沒有顯示mas屬性,后者由框架管理,并且對(duì)于編程模型是不可見的。數(shù)據(jù)圖定義偶爾連接的數(shù)據(jù)模型可以作為虛擬XML文檔或數(shù)據(jù)圖面向開發(fā)者。應(yīng)用通過指定模式和keyref聲明來定義數(shù)據(jù)圖的結(jié)構(gòu)。然而,關(guān)鍵字keyref聲明自身可以包括相對(duì)于應(yīng)用模式的<graph>元素定義的固定文檔結(jié)構(gòu)的XPath。圖類型可以定義“扁平”的節(jié)點(diǎn)聲明序列。<xsd:complexTypename="rootType"/><xsd:elementname="root"type="rootType"/><xsd:complexTypename="graphType"><xsd:sequence><xsd:elementref="root"/></xsd:sequence></xsd:complexType><xsd:complexTypename="graphType"><xsd:complexContent><xsd:extensionbase="mas:graphType"><xsd:sequenceminOccurs="0"maxOccurs="unbounded"><xsd:choice><xsd:elementname="nodeName"type="nodeType"/></xsd:choice></xsd:sequence></xsd:extension></xsd:complexContent></xsd:complexType><xsd:elementname="graph"type="graphType"><key-definitions><keyref-definitions></xsd:element>例子<xsd:elementname="graph"><xsd:complexType><xsd:elementname="root"type="rootType"/><xsd:sequence><xsd:elementname="account"type="accountType"maxOccurs="unbounded"/><xsd:elementname="contact"type="contactType"maxOccurs="unbounded"/></xsd:sequence></xsd:complexType>這定義了根元素的類型,并且構(gòu)成應(yīng)用的所有模式類型的集合。要注意,圖結(jié)構(gòu)很大程度上可以是實(shí)現(xiàn)細(xì)節(jié)—開發(fā)者使用關(guān)鍵字/keyref定義遍歷數(shù)據(jù)圖。一種建議的圖實(shí)現(xiàn)是扁平的—即,所有節(jié)點(diǎn)類型是<graph>元素的第一級(jí)孩子。上述例子將允許下面的實(shí)例數(shù)據(jù)<graph><accountid="1.1"><name>Acme</name></account><contactid="1.2"accountId="1.1"><first>Bob</first><last>Harris</last><email>bob@acme.com</email></contact><contactid="1.3"accountId="1.1"><first>Maggie</first><last>Cheung</last><email>maggie@acme.com</email></contact><graph>關(guān)鍵字和KeyRef定義模式定義文件還可以包含關(guān)鍵字和keyref定義,它們可以聲明數(shù)據(jù)類型之間的主關(guān)鍵字和外關(guān)鍵字關(guān)系。關(guān)鍵字定義可以定義主關(guān)鍵字。關(guān)鍵字可以包括多個(gè)字段聲明(即,對(duì)于復(fù)合關(guān)鍵字)。keyref定義定義引用關(guān)鍵字定義的外關(guān)鍵字。例如,下面的關(guān)鍵字和keyref定義定義了從聯(lián)系人節(jié)點(diǎn)到其相關(guān)帳戶節(jié)點(diǎn)的多對(duì)一(查找)關(guān)系,和從根到帳戶的一對(duì)多關(guān)系。<xsd:keyname="accountKey"><xsd:selectorxpath="account"/><xsd:fieldxpath="@id"/></xsd:key><xsd:keyrefname="contactAccountRef"refer="accountKey"mas:alias="account”>mas:inverseAlias="contacts"><xsd:selectorxpath="contact"/><xsd:fieldxpath="@accountId"/></xsd:keyref></xsd:graph></xsd:schema>關(guān)鍵字和keyref定義應(yīng)當(dāng)具有唯一的名字。下面分別是關(guān)鍵字和keyref的命名傳統(tǒng)<xsd:keyname="<schema>Key"...<xsd:keyrefname="<sourceSchema><element|attribute>Ref"...例如,fooBarRef表示由名為bar的元素或?qū)傩远x的foo模式的keyref。即,(通常)keyref的選擇器XPath是“foo/bar”或“foo/@bar”。通常,keyref名是由連接keyref的選擇器和字段、并且剝?nèi)ト魏蝝as元素而構(gòu)建的“camelBack”(駝峰式)破損的名字。例如,<xsd:keyrefname="contactAccountRef"refer="accountKey"><xsd:selectorxpath="contact"/><xsd:fieldxpath="@accountId"/></xsd:keyref><xsd:keyrefname="messageFromRef"refer="contactEmailKey"><xsd:selectorxpath="message"/><xsd:fieldxpath="from"/></xsd:keyref><xsd:keyrefname="messageToRef"refer="contactEmailKey"><xsd:selectorxpath="message/to"/><xsd:fieldxpath="."/></xsd:keyref>要注意,類型可以通常從名字的后一部分推斷,這是由于這是元素或?qū)傩悦?,后面的XML指南將說明所包含的數(shù)據(jù)的用途??蚣芸梢源_??╧eyref名不與頂級(jí)元素屬性名沖突。別名keyref聲明可以定義數(shù)據(jù)圖內(nèi)的節(jié)點(diǎn)之間的合法遍歷。@@運(yùn)算符可以用于遍歷該圖,并且缺省地使用keyref名。然而,可以定義別名來使代碼更易讀。masalias屬性定義串,它可選地具有兩部分mas:alias="[XPath:]name"其中name表示別名,而可選的XPath前綴表示在@@運(yùn)算符和別名之前必須經(jīng)過的SPath(相對(duì)于圖)。即,varrefNode=srcNode.SPath.@@name如果不存在冒號(hào)分隔符,則別名XPath前綴與keyref的選擇器XPath相同。如果沒有定義別名,則必須使用keyref名(相對(duì)于keyref選擇器XPath)。關(guān)鍵字定義也可以聲明mas:alias屬性,它指示包含相關(guān)節(jié)點(diǎn)類型的節(jié)點(diǎn)集可從根節(jié)點(diǎn)遍歷。關(guān)鍵字定義的別名是簡(jiǎn)單的串,并且這也被@@運(yùn)算符使用mas:alias="name"例子下面的XML表示帳戶節(jié)點(diǎn)的實(shí)例<accountid="1.1"type="Web"ownerId="bob"><name>Acme</name><events><eventRef>1.2</eventRef><eventRef>1.3</eventRef></events><purchaseOrders><purchaseOrder><lineItem><prodId>ABC-1234</prodId></lineItem><lineItem><prodId>XYZ-4321</prodId></lineItem></purchaseOrder></purchaseOrders></account>帳戶節(jié)點(diǎn)的關(guān)鍵字定義如下<xsd:keyname="accountKey"mas:alias="accounts"><xsd:selectorxpath="acccunt"/><xsd:fieldxpath="@id"/></xsd:key>這允許下面的導(dǎo)航句法varaccounts=$root.@@accounts.*;“product”別名定義如下<xsd:keyrefname="accountProductsRef"refer="productKey"mas:alias="product"><xsd:selectorxpath="account/purchaseOrders/purchaseOrder/lineItem"/><xsd:fieldxpath="prodId"/></xsd:keyref>下面的表達(dá)式遍歷到第一訂購(gòu)單的第一行式項(xiàng)目所引用的產(chǎn)品。varproduct=account.purchaseOrders.*.lineItems.*.@@product;“owner”別名定義如下<xsd:keyrefname="accountOwnerRef"refer="UserKey"mas:alias="owner"><xsd:selectorxpath="account"/><xsd:fieldxpath="@ownerId"/></xsd:keyref>下面的表達(dá)式遍歷到“owner”別名所描述的keyref引用的用戶節(jié)點(diǎn)。varuser=account.@@owner;“event”別名定義如下<xsd:keyrefname="accountEventsRef"refer="eventKey"mas:alias="events"><xsd:seectorxpath="account/events/eventRef"/><xsd:fieldxpath="."/></xsd:keyref>下面的表達(dá)式遍歷到“event”別名所描述的keyref引用的事件節(jié)點(diǎn)。varevents=account.@@events.*;要注意,“product”別名也可以定義如下<xsd:keyrefname="accountproductsRef"refer="productKey"mas:alias="account:products"><xsd:selectorxpath="account/purchaseOrders/purchaseOrder/lineItem"/><xsd:fieldxpath="prodId"/></xsd:keyref>下面的表達(dá)式遍歷到所有行式項(xiàng)目(對(duì)所有訂購(gòu)單)的所有產(chǎn)品。varproducts=account.@@products.*;逆向關(guān)系keyref聲明可以可選地定義逆向keyref,后者允許在逆方向上導(dǎo)航。典型地,多對(duì)一keyref聲明逆keyref,允許逆向一對(duì)多遍歷。<xsd:keyrefname="name"refer="keyName"mas:alias="alias"mas:inverseAlias="inverseAlias">逆向?qū)傩远x如下例如,下面的keyref定義表示聯(lián)系人→帳戶和帳戶→聯(lián)系人關(guān)系<xsd:keyrefname="contactAccountRef"refer="accountKey"mas:alias="account"mas:inverseAlias="contacts"><xsd:selectorxpath="contact"/><xsd:fieldxpath="@accountId"/></xsd:keyref>每個(gè)聯(lián)系人節(jié)點(diǎn)包含引用account節(jié)點(diǎn)的@accountId屬性(外關(guān)鍵字)。即,varaccount=contact.@@accountId;逆向關(guān)系說明可以使用外關(guān)鍵字從帳戶節(jié)點(diǎn)遍歷到聯(lián)系人節(jié)點(diǎn)。即,varcontacts=account.@@contacts.*;在一個(gè)實(shí)施例中,逆向別名必須只包含屬性名(比較上述keyref別名),并且總是相對(duì)于頂級(jí)節(jié)點(diǎn)。要注意,多個(gè)keyref定義必須聲明“指回”同一節(jié)點(diǎn)類型的逆向關(guān)系。在這些情況下,逆向別名對(duì)于目標(biāo)節(jié)點(diǎn)類型當(dāng)然必須是唯一的。例如,bug節(jié)點(diǎn)可能具有owner和assignedTo的keyref,分別定義了bugs和assignedBugs的逆向別名。逆向關(guān)系也允許框架確保在雙向上的導(dǎo)航與高速緩存一致。根keyref可以定義不依賴外關(guān)鍵字值的節(jié)點(diǎn)之間的關(guān)系。例如,一組節(jié)點(diǎn)可以由使用當(dāng)前用戶的信息或其他外部信息(例如,日時(shí)、實(shí)時(shí)數(shù)據(jù)、外部系統(tǒng)狀態(tài))的查詢來定義。在這些情況下,節(jié)點(diǎn)集可能附屬到數(shù)據(jù)模型內(nèi)的任意節(jié)點(diǎn)類型。然而典型地,這些節(jié)點(diǎn)集附屬到根節(jié)點(diǎn)。在CRM例子中,特定用戶可訪問的一組帳戶可以由系統(tǒng)變量$user/username定義的用戶登錄名定義。應(yīng)用可能希望定義從根節(jié)點(diǎn)到該節(jié)點(diǎn)集的遍歷;即varaccounts=$root.@@accounts.*;我們?yōu)槊總€(gè)引用根節(jié)點(diǎn)的帳戶節(jié)點(diǎn)定義可選的人工外關(guān)鍵字。這是通過下面的keyref定義實(shí)現(xiàn)的<xsd:keyrefname="accountRootRef"refer="mas:rootKey"mas:inverseAlias="accounts"><xsd:selectorxpath="account"/><xsd:fieldxpath="@rootId"/></xsd:keyref>要注意,帳戶模式還必須為有效的keyref定義可選的@mas:rootId屬性<xsd:complexTypename="accountType"><xsd:all><xsd:elementname="name"type="xsd:string"/><xsd:elementname="type"type="xsd:string"/></xsd:all><xsd:attributename="id"type="xsd:string"use="required"mas:type="pkey"/><xsd:attributename="ownerId"type="xsd:string"/><xsd:attributename="parentId"type="xsd:string"/><xsd:attributename="rootId"type="mas:rootId"use="optional"/></xsd:complexType>@mas:rootId屬性引用框架定義的系統(tǒng)定義;通過下面的指令系統(tǒng)的模式定義輸入到應(yīng)用的模式中<xsd:importnamespace="urn:bea.mas"schemaLocation="mas.xsd"/>@@運(yùn)算符導(dǎo)航是從一個(gè)頁(yè)面移動(dòng)到頁(yè)面流內(nèi)的下一個(gè)頁(yè)面的動(dòng)作。這可能會(huì)或者不會(huì)改變$context系統(tǒng)變量。遍歷是在數(shù)據(jù)圖(高速緩存)內(nèi)移動(dòng)的動(dòng)作。SPath表達(dá)式使用@@運(yùn)算符“遍歷”圖,例如foo.@@bar其中foo表示節(jié)點(diǎn)(或者節(jié)點(diǎn)的子元素),而bar是由keyref定義(名字或別名)或者關(guān)鍵字別名定義為外關(guān)鍵字的子元素名。例如,假設(shè)我們有下面的數(shù)據(jù)<accountid="1.1"type="Web"><name>Acme</name><contacts><contactRef>1.2</contactRef><contactRef>1.3</contactRef></contacts><purchaseOrders><purchaseOrder><lineItem@prodId="ABC-1234"/><lineItem@prodId="XYZ-3000"/><lineItem@prodId="EOW-2004"/></purchaseOrder><purchaseOrder><lineItem@prodId="XYZ-3000"/></purchaseOrder></purchaseOrders></account><contactid="1.2"accountId="1.1"><email>bob@acme.com</email></contact<productid="ABC-1234"><price>1000.00</price>.</product>和下面的keyref定義<xsd:keyrefname="accountContactsRef"refer="contactPrimaryKey"mas:alias=".:contacts"><xsd:selectorxpath="account/contacts/contactRef"/><xsd:fieldxpath="."/></xsd:keyref><xsd:keyrefname="accountProductsRef"refer="productKey"mas:alias="purchaseOrders/purchaseOrder/lineItem:product"><xsd:selectorxpath="account/purchaseOrders/purchaseOrder/lineItem"/><xsd:fieldxpath="@prodId"/></xsd:keyref>不使用別名,下面的表達(dá)式是合法的varcontacts=account.contacts.*.@@contactRef;varprice=account.purchaseOrders.*.lineItems.*.@@(@prodId).price;使用別名允許下面的表達(dá)式varcontacts=account.@@contacts.*;varemail=account.@@contacts.email;varprice=account.purchaseOrders.*.lineItems.*.@@product.price;關(guān)鍵字和序列號(hào)所有可以表示為數(shù)據(jù)模型中的節(jié)點(diǎn)的外部記錄必須定義唯一的主關(guān)鍵字(pkey);主關(guān)鍵字必須顯示為Web服務(wù)SOAP接口的一部分。在一個(gè)實(shí)施例中,由于在某些情況下框架可能將一個(gè)用戶獲得的數(shù)據(jù)放在共享高速緩存中,因此主關(guān)鍵字可以在所有用戶的操作調(diào)用中一致。外部系統(tǒng)的Web服務(wù)操作可以可選地返回與特定節(jié)點(diǎn)相關(guān)聯(lián)的序列號(hào)(seq),它允許系統(tǒng)檢測(cè)更新的記錄。典型地,序列號(hào)對(duì)應(yīng)于數(shù)據(jù)庫(kù)時(shí)間戳。如果Web服務(wù)不提供序列號(hào),則框架基于記錄的XML值計(jì)算MD5散列。模式定義可以定義用于定義外部應(yīng)用的標(biāo)識(shí)符和(可選的)序列號(hào)(或時(shí)間戳)的元素。相應(yīng)模式元素定義mas:type屬性,它表示系統(tǒng)特性“pkey”或“seq”。例如,下面的模式定義應(yīng)用聯(lián)系人類型<xsd:complexTypename="contactType"><xsd:all><xsd:elementname="first"type="xsd:string"/><xsd:elementname="last"type="xsd:string"/><xsd:elementname="email"type="xsd:string"/></xsd:all><xsd:attributename="id"type="xsd:string"use="required"mas:type="pkey"/><xsd:attributename="timestamp"type="xsd:string"mas:type="seq"/><xsd:attributename="ownerId"type="xsd:string"use="required"/><xsd:attributename="accountId"type="xsd:string"use="required"/></xsd:complexType>該模式定義屬性@id和@timestamp,它們分別表示主關(guān)鍵字和序列號(hào)。例如,下面的XML表示管道返回的聯(lián)系人節(jié)點(diǎn)的實(shí)例<app:contactid="83FEB4C38AB36520"timestamp="12388832"accountId="B3F234AD3342ABA6"><app:first>Bob</app:first><app:last>Harris</app:last><app:email>bob@harris.com</app:email></app:contact>模式還可以包括適當(dāng)?shù)年P(guān)鍵字定義,例如<xsd:keyname="contactPrimaryKey"><xsd:selectorxpath="contact"/><xsd:fieldxpath="id"/></xsd:key><xsd:keyname="contactEmailKey"><xsd:selectorxpath="contact"/><xsd:fieldxpath="email"/></xsd:key>要注意,需要mas:type=“pkey”模式元素聲明來標(biāo)識(shí)節(jié)點(diǎn)的主關(guān)鍵字。由于關(guān)鍵字值可能較長(zhǎng),缺省情況下這些值不發(fā)送給客戶端,對(duì)客戶端編程模型是不可訪問的。可以指定mas:visible屬性來禁止該缺省行為。下面列出模式修飾(decoration)在關(guān)鍵字(不是keyref)字段沒有標(biāo)為可見的情況下,任何在客戶端上訪問該字段的嘗試都將無效(如同訪問不存在的字段)。即使在可見的情況下,關(guān)鍵字字段也是只讀的。varx=contact.id;//returnsnullvary=cont主關(guān)鍵字和序列號(hào)值由外部系統(tǒng)設(shè)置。對(duì)于定義為關(guān)鍵字的任何字段,修改該字段值的嘗試將產(chǎn)生運(yùn)行時(shí)錯(cuò)誤。當(dāng)創(chuàng)建新節(jié)點(diǎn)時(shí),不應(yīng)當(dāng)包含這些字段,例如,varcontact=<contact><first>Maggie</first><last>Cheung</last><email>maggie@acme.com</email></contact>通過引用賦值外關(guān)鍵字外關(guān)鍵字值可以通過賦值來設(shè)置。如果賦值表達(dá)式的RHS求節(jié)點(diǎn)的值,則其被自動(dòng)強(qiáng)迫為節(jié)點(diǎn)的主關(guān)鍵字。在下面的例子中,聯(lián)系人節(jié)點(diǎn)的帳戶外關(guān)鍵字(由帳戶keyref定義定義為帳戶屬性)被設(shè)置成引用提供的帳戶節(jié)點(diǎn)。functionsetAccount(contact,account)contact.@@accountId=account;}通過值賦值外關(guān)鍵字如果keyref定義應(yīng)用的模式聲明mas:visible主關(guān)鍵字,則可以通過公開值(即,不是節(jié)點(diǎn)引用)來設(shè)置相應(yīng)外關(guān)鍵字值。例如,下面的帳戶模式定義可視的pkey屬性<xsd:complexTypename="accountType"><xsd:complexConteut><xsd:all><xsd:elementname="name"type="xsd:string"/></xsd:all><xsd:attributename="id"type="xsd:string"use="required"mas:type="pkey"mas:visible="true"/><xsd:attributename="ownerId"type="xsd:string"use="required"/><xsd:attributename="parentId"type="xsd:string"/></xsd:complexContent></xsd:complexType>因此,應(yīng)用可以直接訪問該值。varaccount=account.@@id;也可以通過值設(shè)置引用帳戶節(jié)點(diǎn)的任何外關(guān)鍵字,例如functionsetAccount(contact)contact.@@account="A-1234";)注意,外關(guān)鍵字值可能對(duì)于當(dāng)前高速緩存在客戶端上的節(jié)點(diǎn)是不變的。此外,如果設(shè)置了壞值,則相關(guān)管道操作將失敗。關(guān)系多對(duì)一(查找)多對(duì)一關(guān)系可以使用關(guān)鍵字和keyref定義實(shí)現(xiàn),其中主和外關(guān)鍵字平行關(guān)系。<xsd:keyname="accountKey"><xsd:selectorxpath="account"/><xsd:fieldxpath="@id"/></xsd:key><xsd:keyrefname="contactAccountRef"refer="accountKey"><xsd:selectorxpath="contact"/><xsd:fieldxpath="@accountId"/></xsd:keyref>上述該關(guān)鍵字定義說明在每個(gè)<account>節(jié)點(diǎn)中出現(xiàn)accountKey(主關(guān)鍵字)(作為稱為id的屬性)。keyref定義說明contactAccountRef(外關(guān)鍵字)是指<contact>節(jié)點(diǎn)的account屬性。例如,給定下面的實(shí)例數(shù)據(jù)<accountid="1.1"><name>Acme</name></account><contactid="1.2"accountId="1.1"><first>Bob</first><last>Harris</last><email>bob@acme.com</email></contact>下面定義了帳戶的主關(guān)鍵字(即,accountKey)<accountid="1.1">下面定義從聯(lián)系人到相同帳戶的外關(guān)鍵字(即,contactAccountRef)<contactid="1.2"accountId="1.1">有時(shí)我們會(huì)想要使用節(jié)點(diǎn)內(nèi)包含的數(shù)據(jù)作為外關(guān)鍵字值。例如,將CRM例子擴(kuò)展來包括與聯(lián)系人相關(guān)聯(lián)的電子郵件消息。下面的模式描述消息節(jié)點(diǎn);它包括由from和to元素表示的兩個(gè)“天然”的外關(guān)鍵字(注意,每個(gè)消息可能具有多個(gè)to元素)。<xsd:complexTypename="messageType"><xsd:sequence><xsd:elementname="from"type="xsd:string"minOccurs="1"maxOccurs="1"/><xsd:elementname="to"type="xsd:string"maxOccurs="unbounded"/><xsd:elementname="subject"type="xsd:string"/><xsd:elementname="body"type="xsd:string"/></xsd:sequence></xsd:complexType>我們已經(jīng)定義了聯(lián)系人元素包含email元素。<xsd:complexTypename="contactType"><xsd:all><xsd:elementname="first"type="xsd:string"/><xsd:elementname="last"type="xsd:string"/><xsd:elementname="email"type="xsd:string"/></xsd:all><xsd:attributename="id"type="xsd:string"use="required"mas:type="pkey"/><xsd:attributename="ownerId"type="xsd:string"use="required"/><xsd:attributename="accountId"type="xsd:string"use="required"/></xsd:complexType>聯(lián)系人類型已經(jīng)定義了主關(guān)鍵字<xsd:keyname="contactPrimaryKey"><xsd:selectorxpath="contact"/><xsd:fieldxpath="@id"/></xsd:key>下面的關(guān)鍵字定義定義聯(lián)系人節(jié)點(diǎn)內(nèi)的email元素也可以用作關(guān)鍵字。<xsd:keyname="contactEmailKey"><xsd:selectorxpath="contact"/><xsd:fieldxpath="email"/></xsd:key>下面的keyref定義定義了消息節(jié)點(diǎn)內(nèi)的外關(guān)鍵字元素。<xsd:keyrefname="messageFromRef"refer="contactEmailKey"><xsd:selectorxpath="message"/><xsd:fieldxpath="from"/></xsd:keyref><xsd:keyrefname="messageToRef"refer="contactEmailKey"><xsd:selectorxpath="message/to"/><xsd:fieldxpath="."/></xsd:keyref>要注意,messageFromRefkeyref也可以寫成如下(盡管框架總是使用上述形式;注意,messageToRef必須寫成上述形式,因?yàn)榭赡苡卸鄠€(gè)<to>元素)<xsd:keyrefname="messageFromRef"refer="contactEmailKey"><xsd:selectorxpath="message/from"/><xsd:fieldxpath="."/></xsd:keyref>一對(duì)多(集合)一對(duì)多關(guān)系既可以實(shí)現(xiàn)為反向keyref,也可以實(shí)現(xiàn)為數(shù)據(jù)節(jié)點(diǎn)內(nèi)包含的顯式外關(guān)鍵字值。反向keyref所有多對(duì)一遍歷可以聲明定義一對(duì)多遍歷的反向keyref。顯式keyref確定的節(jié)點(diǎn)類型的模式聲明可以定義包含重復(fù)序列的元素(每個(gè)元素可以包含外關(guān)鍵字值)的復(fù)合XML文檔。例子下面的模式定義描述訂購(gòu)單實(shí)體。<xsd:elementname="purchaseOrder"type="purchaseOrderType"><xsd:complexTypename="purchaseOrderType"><xsd:sequence><xsd:elementname="price"type="xsd:double"/>…<xsd:complexTypename="lineItems"><xsd:sequencemaxOccurs="unbounded"><xsd:complexTyperef="lineItem"><xsd:sequence><xsd:elementname="prodId"type="xsd:string"/>…</xsd:sequence></xsd:complexType></xsd:sequence></xsd:complexType></xsd:sequence><xsd:attributename="id"type="xsd:string"mas:type="pkey"/></xsd:complexType>下面的關(guān)鍵字聲明定義訂購(gòu)單節(jié)點(diǎn)類型的主關(guān)鍵字。<xsd:keyname="purchaseOrderKey"><xsd:selectorxpath="purchaseOrder"/><xsd:fieldxpath="id"/></xsd:kev>下面的keyref聲明標(biāo)識(shí)訂購(gòu)單內(nèi)的元素(外關(guān)鍵字應(yīng)用的產(chǎn)品)。<xsd:keyrefname="purchaseOrderProductRef"refer="productKey"mas:alias="purchaseOrder:products"><xsd:selectorxpath="purchaseOrder/lineItems/lineItem"/><xsd:fieldxpath="prodId"/></xsd:keyref>該關(guān)系可以用圖12A來說明。例如,下面的XScript表達(dá)式檢索訂購(gòu)單的第一行式項(xiàng)目引用的產(chǎn)品。varproduct=purchaseOrder.@@products.*;多對(duì)多多對(duì)多關(guān)系作為多對(duì)的一對(duì)多關(guān)系實(shí)現(xiàn)。圖12B中給出了一個(gè)例子。即,帳戶和事件聲明下面的模式<xsd:complexTypename="accountType"><xsd:all><xsd:elementname="name"type="xsd:string"/></xsd:all><xsd:attributename="id"type="xsd:string"use="required"mas:type="pkey"/><xsd:attributename="ownerId"type="xsd:string"use="required"/><xsd:attributename="parentId"type="xsd:string"/></xsd:complexType>o0<xsd:complexTypename="eventType"><xsd:all><xsd:elementname="first"type="xsd:string"/><xsd:elementname="last"type="xsd:string"/></xsd:all><xsd:attributename="id"type="xsd:string"use="required"mas:type="pkey"/></xsd:complexType>并且聲明下面的keyref定義<xsd:keyrefname="accountEventRef"refer="eventKey"><xsd:selectorxpath="account"/><xsd:fieldxpath="events"/></xsd:key><xsd:keyrefname="eventAccountRef"refer="accountKey"><xsd:selectorxpath="event"/><xsd:fieldxpath="accounts"/></xsd:keyref>在一個(gè)實(shí)施例中,多對(duì)多keyref不能聲明反向keyref,這是由于通常框架沒有足夠的信息來維持一致。一對(duì)一在一個(gè)實(shí)施例中,一對(duì)一關(guān)系作為成對(duì)的多對(duì)一關(guān)系實(shí)現(xiàn)。例子假設(shè)系統(tǒng)的每個(gè)用戶也具有如12C所示的聯(lián)系人記錄。即,聯(lián)系人和用戶定義下面的keyref<xsd:keyrefname="userContactRef"refer="contactKey"mas:alias="contact"mas:inverseAlias="user"><xsd:selectorxpath="user"/><xsd:fieldxpath="@contactId"/></xsd:key>一對(duì)一keyref應(yīng)當(dāng)總是聲明反向keyref。varcontact=user.@@contact;contact.@@user==user;系統(tǒng)數(shù)據(jù)類型節(jié)點(diǎn)模式定義下面的XML模式定義節(jié)點(diǎn)的結(jié)構(gòu)。<?xmlversion="1.0"?><xsd:schematargetNamespace="urn:bea.mas"elementFormDefault="qualified"attributeFormDefault="unqualified"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns="urn:bea.mas"><xsd:elementname="nodeType"><xsd:complexType><xsd:sequence><xsd:anyminOccurs="0"maxOccurs="1"/></xsd:sequence><xsd:attributename="state"type="mas:syncStateType"/></xsd:complexType></xsd:element>節(jié)點(diǎn)定義可以包括下面的屬性。根節(jié)點(diǎn)在一個(gè)實(shí)施例中,對(duì)于每個(gè)應(yīng)用存在特定的根節(jié)點(diǎn),其具有節(jié)點(diǎn)類型mas:root;該節(jié)點(diǎn)不包含應(yīng)用數(shù)據(jù)并且不能修改??蚣茏詣?dòng)創(chuàng)建通過$root變量引用的根節(jié)點(diǎn)的實(shí)例。keyref可以引用mas:root作為它們的源類型,例如<keyrefname="accounts"sourceType="mas:root"targetType="app:contact"/>在一個(gè)實(shí)施例中,節(jié)點(diǎn)可以通過客戶端編程或服務(wù)器管道來實(shí)例化。節(jié)點(diǎn)集模式定義除了根節(jié)點(diǎn)外,所有節(jié)點(diǎn)屬于對(duì)應(yīng)于keyref的節(jié)點(diǎn)集。節(jié)點(diǎn)集由下面的XML模式定義<?xmlversion="1.0"?><xsd:schematargetNamespace="run:bea.com"elementFormDefault="qualified"attributeFormDefault="unqualified"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns="run:bea.com"><xsd:elementname="nodeSet"><xsd:complexType><xsd:sequence><xsd:elementref="node"maxOccurs="unbounded"/></xsd:sequence><xsd:attributename="keyref"type="xsd:string"/></xsd:complexType></xsd:element><nodeset>元素包含無限制的<node>元素的序列。每個(gè)節(jié)點(diǎn)集對(duì)應(yīng)于用于確定所包含的節(jié)點(diǎn)元素的節(jié)點(diǎn)類型的keyref(由keyref屬性定義的)。同步狀態(tài)所有持久的應(yīng)用數(shù)據(jù)可以存儲(chǔ)在與服務(wù)器同步的節(jié)點(diǎn)中。每個(gè)數(shù)據(jù)節(jié)點(diǎn)可以具有狀態(tài)同步屬性mas:state,該屬性具有由syncStateType類型定義的值。<xsd:simpleTypename="syncStateType"><xsd:restrictionbase="xsd:string"><xsd:enumerationvalue="dsync"/><xsd:enumerationvalue="modified"/><xsd:enumerationvalue="pending"/><xsd:enumerationvalue="uptodate"/><xsd:enumerationvalue="rejected"/><xsd:enumerationvalue="conflict"/><xsd:enumerationvalue="deleted"/></xsd:restriction></xsd:simpleType>狀態(tài)變量可以在客戶端和服務(wù)器之間傳遞來協(xié)調(diào)同步??蛻舳藢⒐?jié)點(diǎn)狀態(tài)設(shè)置為下面的一個(gè)值要注意,在一個(gè)實(shí)施例中,狀態(tài)變量不區(qū)分創(chuàng)建和修改的節(jié)點(diǎn),因?yàn)樗鼈兛梢杂?的全局序列號(hào)來區(qū)分。同步進(jìn)程觸發(fā)相應(yīng)的管道操作;一旦完成,服務(wù)器為每個(gè)節(jié)點(diǎn)賦予下面的一個(gè)值例如,下面的表示出節(jié)點(diǎn)可能的生存周期。管道在一個(gè)實(shí)施例中,客戶端應(yīng)用不直接調(diào)用Web服務(wù)操作—而是管道機(jī)制將單獨(dú)的(受限的)Web服務(wù)操作的語(yǔ)義按照客戶端的虛擬XML文檔映射到編程模型(例如,CRUD語(yǔ)義(創(chuàng)建、讀取、更新、刪除)、導(dǎo)航、客戶操作等)。客戶端數(shù)據(jù)模型改變與服務(wù)器同步,服務(wù)器然后觸發(fā)管道管理器來調(diào)用外部Web服務(wù)操作。在一個(gè)實(shí)施例中,管道定義特定keyref的一組協(xié)調(diào)的Web服務(wù)操作。每個(gè)keyref可以與恰好一個(gè)管道相關(guān)聯(lián)。Web服務(wù)可以與現(xiàn)有系統(tǒng)相接,如數(shù)據(jù)庫(kù)、LDAP目錄、ERP應(yīng)用和網(wǎng)站。它們也可以是提煉了由過程邏輯(例如,WLIJPD)協(xié)調(diào)的、復(fù)雜的長(zhǎng)期運(yùn)行的異步進(jìn)程(工作流)的包裝(wrapper)。在一個(gè)實(shí)施例中,盡管系統(tǒng)使用的Web服務(wù)可以具有一定的要求(例如,每個(gè)記錄必須包括唯一的主關(guān)鍵字,并且最好是序列號(hào)或時(shí)間戳),但對(duì)它們沒有偶爾連接的數(shù)據(jù)模型特定的要求。因此,MAS可以是這些資源的許多消費(fèi)者之一。在一個(gè)實(shí)施例中,管道不假定Web服務(wù)是用頭腦中的數(shù)據(jù)模型編寫的;即,傳遞到請(qǐng)求中的類型對(duì)于數(shù)據(jù)模型中的節(jié)點(diǎn)類型不能是同構(gòu)的,并且響應(yīng)也可以不同。因此,Web服務(wù)請(qǐng)求和響應(yīng)所使用的模式不需要與數(shù)據(jù)模型中的任何節(jié)點(diǎn)模式相同。管道可以包含元數(shù)據(jù)來從數(shù)據(jù)模型映射到Web服務(wù)操作調(diào)用的請(qǐng)求文檔中,并且從Web服務(wù)響應(yīng)映射回?cái)?shù)據(jù)模型中。這些源數(shù)據(jù)稱為變換,并且可以用XMLQuery語(yǔ)言表示。實(shí)際上,變換模型通用到足夠Web服務(wù)可以返回映射到數(shù)據(jù)模型中的幾個(gè)不同有關(guān)節(jié)點(diǎn)、并且仍然成功映射回?cái)?shù)據(jù)模型的響應(yīng)文檔。對(duì)于MAS高速緩存至關(guān)重要的元數(shù)據(jù)(即,記錄類型的主關(guān)鍵字和序列號(hào)/時(shí)間戳)也可以使用變換來映射。管道文件概述conduits子目錄可以包括多個(gè).jsx文件—所有文件在啟動(dòng)時(shí)由框架加載,這些文件包含管道定義。管道文件可以包括實(shí)現(xiàn)管道操作的XScript和XQuery函數(shù),這些文件還可以包含在注解塊中定義的元數(shù)據(jù)。注釋模型允許開發(fā)者使用可視化工具和腳本編輯器來建立管道文件。每個(gè)管道文件可以包含頭注解,它可以聲明下面的標(biāo)志(tag)例如/***@mas:conversationalshared="false"*@common:xmlnsnamespace="http://schemas.xmlsoap.org/soap/envelope/"prefix="soap"*@common:xmlnsnamespace="urn:partner.soap.sforce.com"prefix="sfdc"*@common:xmlnsnamespace="http://example.com/"prefix="app"*/mas:conversationalmas:conversational標(biāo)志具有下面的屬性common:xmlnscommon:xmlns標(biāo)志具有下面的屬性Web服務(wù)控制管道文件還包括(可能多個(gè))表示W(wǎng)eb服務(wù)控制的對(duì)象聲明??刂贫x出現(xiàn)在相應(yīng)變量聲明緊前面的頭塊中。例子/***@common:control*@jc:locationhttp-url="http://enterprise.soap.sforce.com/"*/ws=newWebServiceControl();定義了下列標(biāo)志jc:locationjc:location標(biāo)志具有下列屬性WebServiceControl對(duì)象管理Web服務(wù)操作的調(diào)用。WebServiceControl對(duì)象實(shí)現(xiàn)下列方法消息對(duì)象消息對(duì)象被送進(jìn)Web服務(wù)控制的invoke()函數(shù)并由此返回。varresponse=control.invoke(message);消息對(duì)象具有下列特性例如,假設(shè)從Web服務(wù)返回下列SOAP消息<soapenv;Envelopexmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Header><SessionHeaderxmlns="urn:partner.soap.sforce,com"><sessionId>12345678</sessionId></SessionHeader></soapenv:Header><soapenv:Body><createResponsexmlns="urn:partner.soap.sforce.com"><result><errorsxsi:nil="true"></errors><id>87654321</id><success>true</success></result></createResponse></soapenv:Body></soapenv:Envelope>下面的函數(shù)在打印來自消息頭的會(huì)話元素和來自消息主體的結(jié)果元素之前首先檢查invoke()函數(shù)調(diào)用沒有產(chǎn)生錯(cuò)誤functionselect($msg){varresponse=ws.invoke($msg);if(lresponse.error){print("Session:"+response.header.SessoinHeader.sessionId);print("ID:"+response.body.createResponse.result.id);}returnresponse;}這將記錄下面的輸出Session12345678ID:87654321操作定義管道操作可以直接映射到Web服務(wù)操作上。在一個(gè)實(shí)施例中,每個(gè)管道操作聲明最多三個(gè)函數(shù)1.請(qǐng)求變換創(chuàng)建輸出的消息主體的XQuery函數(shù);2.響應(yīng)變換處理輸入的響應(yīng)體、創(chuàng)建管道管理器處理的MAS節(jié)點(diǎn)的XQuery函數(shù);3.自定義函數(shù)實(shí)現(xiàn)自定義的過程邏輯(例如,創(chuàng)建消息頭或調(diào)用自定義傳輸或任何其他控制)的XScript(或Java)函數(shù)。自定義函數(shù)還可以包括在函數(shù)原型緊前面的頭塊中的注釋。例如/***@mas:operationtype="operationType"keyref="keyrefName"inverse="true"*@mas:transformtype="request"function="foo_request"*/@mas:transformtype="response"function="foo_response"functionfoo($msg,$source){returnws.invoke($msg);}自定義函數(shù)可以聲明下面的標(biāo)志mas:operationmas:operation標(biāo)志具有下列屬性操作可以引用keyref或模式(節(jié)點(diǎn))定義。@mas:operationtype="operationType"keyref="keyrefName"@mas:operationtype="operationType"node="nodeType"inverse屬性指示在反向keyref上調(diào)用操作。@mas:operationtype="operationType"keyref="keyrefName"inverse="true"例如,給定下面的keyref和key定義<xsd:keyrefname="contactAccountRef"refer="accountKey"mas:alias="account"mas:inverseAlias="contacts"><xsd:selectorxpath="contact"/><xsd:fieldxpath="@account"/></xsd:keyref><xsd:keyname="accountKey"><xsd:selectorxpath="account"/><xsd:fieldxpath="@id"/></xsd:key><xsd:keyname="contactKey"><xsd:selectorxpath="contact"/><xsd:fieldxpath="@id"/></xsd:key>管道可以實(shí)現(xiàn)下面的選擇操作/**@mas:operationtype="select"keyref="app:contactAccountRef"*/functionselectAccount($msg,$source){returnws.invoke($msg);}/**@mas:operationtype="select"keyref="app:contactAccountRef"inverse="true"*/funcitonselectContacts($msg,$source){returnws.invoke($msg);}遍歷contact.@@account將調(diào)用selectAccount(),而account.@@contacts.*將調(diào)用selectContact()。mas:transformmas:transform標(biāo)志具有下列屬性如果聲明相應(yīng)的@mas:transform標(biāo)志,則框架可以自動(dòng)調(diào)用請(qǐng)求和響應(yīng)變換。請(qǐng)求變換可以返回XML對(duì)象,用于構(gòu)建$msg變量主體。響應(yīng)變換可以處理管道操作的響應(yīng)。要注意,在Java中,請(qǐng)求和響應(yīng)Query變換要么被包含在自定義操作的注解塊(自動(dòng)生成的)中,或者包含在由注釋應(yīng)用的單獨(dú)文件中。mas:namespacemas:namespace標(biāo)志聲明函數(shù)的缺省名字空間并且具有下列屬性mas:fieldmas:field標(biāo)志聲明調(diào)用函數(shù)所需的自定義源字段;它具有下面的屬性生成的函數(shù)自定義函數(shù)的主體由WLW生成。用于選擇操作的缺省主體如下/***@mas:operationtype="select"keyref="keyrefName"*/functionoperationTypeSourceType($msg,$source){returncontrol.invoke($msg);}$msg變量應(yīng)用XML消息對(duì)象。如果聲明了匹配請(qǐng)求變換(見下面),則由查詢返回的XML對(duì)象創(chuàng)建消息對(duì)象的主體。$source變量可以包括源上下文節(jié)點(diǎn)(例如,node.@@keyrefName.*)。對(duì)于插入、更新和刪除操作,缺省主體可以如下/***@mas:operationtype="insert|update|delete"keyref="keyrefName"*/functionoperationTypeSourceType($msg,$node){returnws.invoke($msg);}$node變量包括要插入/更新/刪除的節(jié)點(diǎn)。對(duì)于自定義操作,主體可以如下/***@mas:operationtype="custom"node="nodeName"name="operationName"*/functionoperationTypesourceType($msg,$source,$node){returnws.invoke($msg);}這里,$node變量包括通過客戶端調(diào)用自定義應(yīng)用創(chuàng)建的查詢對(duì)象。變換操作可以可選地使用mas:transform注釋定義請(qǐng)求和響應(yīng)變換函數(shù)。例如,下面的操作實(shí)現(xiàn)給定帳戶標(biāo)識(shí)符(即,由contactAccountRef定義的反向keyref)檢索聯(lián)系人的選擇操作/***selectcontactsforanaccount:$acount.@@contacts.**@mas:operationtype="select"keyref="app:contactAccountRef"inverse="true"*@mas:transformtype="request"function="selectContacts_request"*@mas:transformtype="response"function="selectContacts_response"*/functionselectContacts($msg,$source){returnws.invoke($msg);}可以在調(diào)用管道操作之前調(diào)用請(qǐng)求變換;它返回輸出消息的XML主體,其被插入到消息對(duì)象$msg中并傳遞到管道操作。/***@mas:namespacetarget="sfdc"*@language:bodytype="xquery"*/functionselectContacts_request($source){<query><queryString>SELECT*FROMContactWHEREAccountId="{string($source/@id)}"</queryString></query>}可以在管道操作返回之后調(diào)用響應(yīng)變換(除非操作返回<error>對(duì)象)。向其傳遞從服務(wù)控制的invoke()函數(shù)返回的XML消息主體。響應(yīng)變換向管道管理器返回應(yīng)用節(jié)點(diǎn)的列表。/***@mas:namespacetarget="app"*@language:bodytype="xquery"*/functionselectContacts_response($response){for$iin$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<contactid="{string(i/sfdc:Id)}"accountId="{string($i/sfdc:Accountid)}"><modified>{string($i/sfdc:SystemModstamp)}</modified><fist>{string($i/sfdc:FistName)}</first><last>{string($i/sfdc:LastName)}</last><email>{string(i/sfdc:Email)}</email></contact>}要注意,管道操作能夠在響應(yīng)變換處理主體之前操控服務(wù)響應(yīng)消息的頭和主體。管道操作管道操作可以將Web服務(wù)映射到暴露給應(yīng)用編程模型的框架操作上。每個(gè)操作可以定義一對(duì)查詢,用于映射從相關(guān)Web服務(wù)操作接收和向其發(fā)送的相應(yīng)輸入和輸出XML消息。這些變換(典型地)包括XQuery表達(dá)式,用于將數(shù)據(jù)從外部系統(tǒng)數(shù)據(jù)格式變換到模式所定義的MAS應(yīng)用程序數(shù)據(jù)格式。操作類型在客戶端編程模型中,可以在節(jié)點(diǎn)(包括$root)或keyref上調(diào)用操作。例如$root.create(xml);//createnodenode.@@keyref.create(xml);//createandlinknodenode.@@keyref.*;//implicitselectnode.@@keyref.select(spath);//deepselectnode.update();//updatenode$root.foo(xml);//customoperation取決于操作類型,需要不同的輸入?yún)?shù)傳遞到管道操作。除了更新和刪除以外,所有其他操作都被傳遞(部分)表示操作上下文(源)的節(jié)點(diǎn)(mas:field聲明確定將多少源節(jié)點(diǎn)傳送到服務(wù)器)。這是由管道函數(shù)使用$source變量引用的。在更新操作(即,插入、更新和自定義操作)的情況下,用于調(diào)用管道操作的數(shù)據(jù)節(jié)點(diǎn)在XQuery變換中使用$node變量引用。此外,所有操作具有對(duì)包含關(guān)于當(dāng)前用戶的信息的$user系統(tǒng)變量的隱式訪問。對(duì)管道操作定義下面的輸入?yún)?shù)下面的表示出對(duì)于特定管道操作可以定義的不同類型的操作。變換每個(gè)管道操作可以定義一對(duì)查詢(變換),其創(chuàng)建和處理與從相關(guān)Web服務(wù)操作接收和向其發(fā)送的輸入和輸出XML消息對(duì)應(yīng)的XML對(duì)象??梢允褂孟鄳?yīng)管道函數(shù)上的mas:transform注釋聲明變換函數(shù)。按照慣例,變換函數(shù)名可以使用與管道函數(shù)相同的、具有_request和_response后綴的名。然而,在某些情況下,響應(yīng)變換可以由多個(gè)管道操作重復(fù)使用。變換可以實(shí)現(xiàn)為XQuery(XMLQuery)函數(shù)。例子下面的操作實(shí)現(xiàn)在給定帳戶標(biāo)識(shí)符(即,由contactAccountRef定義的反向keyref情況下檢索聯(lián)系人的選擇操作/***selectcontactsforanaccount:$account.@@contacts.**@mas:operationtype="select"keyref="app:contactAccountRef"inve$*@mas:transformtype="request"function="selectContacts_request"*@mas:transformtype="response"function="selectContacts_response"*/functionselectContacts(msg,$source){returnws.invoke(msg);}/***@mas:namespacetarget="sfdc"*@language:bodytype="xquery"*/functionselectContacts_request(source){<query><queryString>SELECT*FROMContactWHEREAccountId="{string(source/@id)}"</queryString></query>}/***@mas:namespacetarget="app"*@language:bodytype="xquery"*/functionselectContacts_response($response){for$iin$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<contactid="{string($i/sfdc:Id)}"accountId="{string(i/sfdc:AccountId)}"><modified>{string($i/sfdc:SystemModstamp)}</modified><fist>{string($i/sfdc:FistName)}</first><last>{string($i/sfdc:LastName)}</last><email>{string(i/sfdc:Email)}</email></contact>}請(qǐng)求變換可以構(gòu)建調(diào)用queryWeb服務(wù)操作的SOAP消息的主體。響應(yīng)變換處理Web服務(wù)操作的響應(yīng)SOAP消息的主體并且構(gòu)建<contact>節(jié)點(diǎn)的集合。請(qǐng)求變換請(qǐng)求變換可以由框架和數(shù)據(jù)模型元素創(chuàng)建輸出的Web服務(wù)消息。取決于操作類型(見上面的操作表),變換可以參考下面的系統(tǒng)變量,它們提供操作的上下文。上述select管道操作方法調(diào)用queryWeb服務(wù)操作,后者預(yù)期具有遵從下面XML模式定義的主體的SOAP消息。...<elementname="query"><complexType><sequence><elementname="queryString"type="xsd:string"/></sequence></complexType></element>下面的變換引用$source系統(tǒng)變量來指定查詢所需的AccountId外關(guān)鍵字。/***@mas:namespacetarget="sfdc"*@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*/functionselectContacts_request($source){<query><queryString>SELECT*FROMContactWHEREAccountId="{string($source/@id)}"</queryString></query>}例如,這可能產(chǎn)生下面的輸出SOAP消息主體<queryxmlns="urn:enterprise.soap.sforce.com"><queryString>SELECT*FROMContactWHEREAccountId=1000</queryString></query>響應(yīng)變換響應(yīng)變換可以處理輸入的Web服務(wù)消息并創(chuàng)建由管道管理器處理的節(jié)點(diǎn)(或節(jié)點(diǎn)集)。所有響應(yīng)變換可以引用下面的系統(tǒng)變量。按照上面的例子,queryWeb服務(wù)操作返回對(duì)應(yīng)于下面XML模式的SOAP消息。...<elementname="queryResponse"><complexType><sequence><elementname="result"type="tns:QueryResult"/></sequence></complexType></element><complexTypename="QueryResult"><sequence><elementname="done"type="xsd:boolean"/><elementname="queryLocator"type="tns:QueryLocator"nillable="true"/><elementname="records"minoccurs="0"maxoccurs="unbounded"type="ens:sobject"/><elementname="size"type="xsd:int"/></sequence></complexType>...每個(gè)<QueryResult>元素包含<sObject>元素的序列,后者是<Contact>模式類型的基本類型<complexTypename="sObject"abstract="true"><sequence><elementname="Id"minOccurs="0"type="tns:ID"/>...</sequence></complexType><complexTypename="Contact"><complexContent><extensionbase="ens:sObject"><sequence><elementname="AccountId"minOccurs="0"type="tns:ID"/><elementname="Email"minOccurs="0"type="xsd:string"/><elementname="FirstName"minOccurs="0"type="xsd:string"/><elementname="LastName"minOccurs="0"type="xsd:string"/><elementname="SystemModstamp"minOccurs="0"type="xsd:dateTime"/>...</sequence></extension></complexContent></complexType><elementname="Contact"type="ens:Contact"/>例如,輸入的SOAP消息主體可能是下面的形式<sfdc:queryResponsexmlns:sfdc="urn:enterprise.soap.sforce.com"><sfdc:result><sfdc:recordsxsi:type="urn:Contact"><sfdc:Id>1234</sfdc:Id><sfdc:AccountId>1000</sfdc:AccountId><sfdc:Email>reoger@acme.com</sfdc:Email><sfdc:FirstName>Roger</sfdc:FirstName><sfdc:LastName>Reed</sfdc:LastName></sfdc:records><sfdc:recordsxsi:type="urn:Contact"><sfdc:Id>5678</sfdc:Id><sfdc:AccountId>1000</sfdc:AccountId><sfdc:Email>sarah@acme.com</sfdc:Email><sfdc:FirstName>Sarah</sfdc:FirstName><sfdc:LastName>Smith</sfdc:LastName></sfdc:records></sfdc:result></sfdc:queryResponse>$response系統(tǒng)變量指向(SOAP消息主體內(nèi)的)頂級(jí)<queryResponse>元素。因此,應(yīng)當(dāng)使用下面的XPath表達(dá)式來引用<Contact>元素的陣列。$response/sfdc:queryResponse/sfdc:result/sfdc:records下面的變換處理輸入的SOAP消息并創(chuàng)建<contact>元素的列表。/***@mas:namespacetarget="app"*@language:bodytype="xquery"*/functionselectContacts_response($response){for$iin$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<contactid="{string($i/sfdc:Id)}"accountId="{string($i/sfdc:AccountId)}"><modified>{string($i/sfdc:SystemModstamp)}</modified><fist>{string($i/sfdc:FistName)}</first><last>{string($i/sfdc:LastName)}</last><email>{string($i/sfdc:Email)}</email></contact>}所有請(qǐng)求變換生成節(jié)點(diǎn),后者可以被服務(wù)器高速緩存,并且與客戶端的數(shù)據(jù)模型同步。容許(Permission)管道定義的操作確定可以在客戶端上相應(yīng)節(jié)點(diǎn)集上調(diào)用的操作。例如,如果管道不定義插入操作,則客戶端不能嘗試對(duì)相應(yīng)節(jié)點(diǎn)集創(chuàng)建和插入節(jié)點(diǎn)—如果它嘗試這樣做的話(例如,在自定義操作中),這將觸發(fā)運(yùn)行時(shí)錯(cuò)誤。客戶端側(cè)的編程模型將實(shí)施這些約束。例如,假設(shè)account指向特定的帳戶節(jié)點(diǎn),并且該帳戶節(jié)點(diǎn)與orderskeyref相關(guān)聯(lián)。在這種情況下,除非存在定義的與orderskeyref相關(guān)聯(lián)的管道插入操作,否則下面的代碼將引起錯(cuò)誤。account.@quotes.create{<quoteRequest><prodId>A1</prodId><qty>10</qty></quoteRequest>);類似地,除非為聯(lián)系人節(jié)點(diǎn)類型定義了更新操作,否則下面的代碼也將引起錯(cuò)誤。contact.address.zip="11201";在一個(gè)實(shí)施例中,客戶端操作(例如,create()函數(shù))的實(shí)現(xiàn)與管道操作(例如,插入)匹配。例如,管道操作插入不僅插入節(jié)點(diǎn),還使用keyref關(guān)系將其遍歷到另一節(jié)點(diǎn);因此在客戶端上創(chuàng)建節(jié)點(diǎn)必須自動(dòng)與相應(yīng)節(jié)點(diǎn)集的遍歷操作成對(duì)。描述實(shí)現(xiàn)的管道操作的元數(shù)據(jù)對(duì)用戶編程模型是可訪問的(通過相關(guān)聯(lián)的keyref)。自動(dòng)用戶接口能夠使用該信息生成基本菜單(插入、更新等)。出錯(cuò)處理管道機(jī)制區(qū)分兩種類型的錯(cuò)誤系統(tǒng)錯(cuò)誤(例如,協(xié)議和傳輸錯(cuò)誤)和應(yīng)用錯(cuò)誤(例如,非法的數(shù)據(jù))。此外,應(yīng)用錯(cuò)誤可以以兩種方式出現(xiàn)作為SOAP故障(即,協(xié)議級(jí)錯(cuò)誤)以及作為SOAP(或純XML)響應(yīng)消息的部分。管道操作實(shí)現(xiàn)為SOAP調(diào)用。如果在處理消息時(shí)存在錯(cuò)誤,則出現(xiàn)SOAP故障。這可能是由于基層架構(gòu)故障(例如,傳輸故障)、協(xié)議失敗(例如,錯(cuò)誤形成的消息)、或者應(yīng)用狀態(tài)錯(cuò)誤(例如,更新失敗)。如果在創(chuàng)建或處理輸出或輸入的SOAP消息時(shí)存在錯(cuò)誤,則出現(xiàn)系統(tǒng)錯(cuò)誤(例如,XQuery變換錯(cuò)誤)。如果外部應(yīng)用拒絕基于被作為消息主體的部分傳遞的值的操作請(qǐng)求,則出現(xiàn)應(yīng)用請(qǐng)求(例如,更新失敗)。在Web服務(wù)控制上的invoke()函數(shù)的調(diào)用期間,SOAP棧出現(xiàn)SOAP故障。通常,管道操作返回的XML對(duì)象的主體由響應(yīng)變換處理。然而,如果操作返回系統(tǒng)<mas:error>對(duì)象,則該對(duì)象被直接傳遞到管道管理器。要注意,主管道函數(shù)或響應(yīng)變換可以返回<mas:error>對(duì)象。下面給定<mas:error>對(duì)象定義<xsd:complexTypename="errorType"><xsd:sequence><xsd:elementname="pkey"type="xsd:any"minOccurs="0"maxOccurs="1"/><xsd:elementname="system"type="mas:systemErrorType"maxOccurs="1"/><xsd:elementname="message"type="xsd:string"/><xsd:elementname="field"type="mas:errorFieldType"maxOccurs="unbounded"/></xsd:sequence></xsd:complexType><xsd:complexTypename="systemErrorType"><xsd:sequence><xsd:elementname="code"type="xsd:any"/><xsd:elementname="message"type="xsd:string"/></xsd:sequence></xsd:complexType><xsd:complexTypename="errorFieldType"><xsd:sequence><xsd:elementname="code"type="xsd:any"/><xsd:elementname="message"type="xsd:string"/></xsd:sequence><xsd:attributename="xpath"type="xsd:string"/></xsd:complexType>即,<mas:error>對(duì)象具有下面的形式<mas:error><mas:pkey>primary-key</mas:pkey><mas:system><mas:code>error-code</mas:code><mas:message>message-string</mas:message></mas:system><mas:message>message-string</mas:message><mas:fieldxpath="spath-expression"><mas:code>error-code</mas:code><mas:message>message-string</mas:message></mas:field>...</mas:error>每個(gè)錯(cuò)誤對(duì)象可以包括受錯(cuò)誤影響的節(jié)點(diǎn)的主關(guān)鍵字。對(duì)于選擇操作,這將是源節(jié)點(diǎn)的主關(guān)鍵字;對(duì)于更新和刪除操作,這將引用更新的節(jié)點(diǎn)。系統(tǒng)錯(cuò)誤可以由服務(wù)器記錄。所有其他錯(cuò)誤值可以返回到客戶端并且傳遞到相應(yīng)調(diào)回函數(shù)。將錯(cuò)誤對(duì)象返回到應(yīng)用的調(diào)回函數(shù);該對(duì)象具有對(duì)應(yīng)于上述模式的特性。例子如果invoke()函數(shù)調(diào)用返回錯(cuò)誤,則下面的操作返回系統(tǒng)錯(cuò)誤。/***@mas:operationtype="select"keyref="keyrefName"*/functionoperationTypeSourceType($msg,$source){varresponse=control.invoke($msg);if(response.error){return<mas:error><mas:system><mas:message>system-error</mas:message></mas:system></mas:error>;}returnresponse;}適當(dāng)?shù)牡胤?,管道操作可以?fù)責(zé)重試失敗的invoke()調(diào)用。在這種情況下,管道需要確保Web服務(wù)操作是冪等(idempotent)還是采用某種可靠的通信形式。下面操作在失敗時(shí)重試invoke()函數(shù)后返回系統(tǒng)錯(cuò)誤。/***@mas:operationtype="select"keyref="keyrefName"*/functionoperationTypeSourceType($msg,$source){for(i=0;i<3;i++){varresponse=control.invoke($msg);if(!response.error){returnresponse;//OK}}return<mas:error><mas:system><mas:message>Retryfailed</mas:message></mas:system></mas:error>;}如果invoke()函數(shù)返回錯(cuò)誤,下面的操作首先檢查系統(tǒng)錯(cuò)誤,否則它返回一般的應(yīng)用錯(cuò)誤。如果invoke()函數(shù)成功,但Web服務(wù)響應(yīng)包含應(yīng)用錯(cuò)誤,則它調(diào)用效用函數(shù)(utilityfunction)來分析錯(cuò)誤消息并且返回復(fù)合的<error>對(duì)象,可能包含多個(gè)<field>錯(cuò)誤。/***@mas:operationtype="create"keyref="keyrefName"*/functionoperationTypeSourceType($msg,$source){varresponse=control.invoke($msg);if(response.error){if(response.error.code==101){return<mas:error><mas:system><mas:code>{response.error.code}</mas:code><mas:message>system-error</mas:message></mas:system></mas:error>;}else{return<mas:error><mas:message>general-error</mas:message></mas:error>;}}//checkforapplicationerrorsif(response.body.createResponse.result.errors){returnprocess_error(response.body.createResponse.result.errors);}returnresponse;//OK}//utilityfunctiontoprocessfielderrorsfunctionprocess_error(errors){varfields;for(i=0;i<errors.lengthi++){varpath=match_path(errors[i].fields);fields+=<mas:fieldxpath="{path}"><code>{$i/statusCode}</code><mas:message>{$i/message}</mas:message></mas:field>}return<mas:error>{fields}</mas:error>;}CRUD操作CRUD(創(chuàng)建讀取更新刪除)操作代表四種基本的關(guān)系數(shù)據(jù)操作。這些操作可以直接映射到MAS數(shù)據(jù)模型和客戶端編程模型上。要注意,Web服務(wù)的聯(lián)系人模式具有與上面定義的應(yīng)用的聯(lián)系人模式不同的形式。下面的選擇操作的例子說明了如何實(shí)現(xiàn)該映射。選擇select操作可以允許框架對(duì)特定源節(jié)點(diǎn)檢索keyref定義的節(jié)點(diǎn)。典型地,所有管道都定義了選擇操作,由于這是客戶端應(yīng)用用來檢索節(jié)點(diǎn)的基本機(jī)制??梢哉{(diào)用隨后的選擇操作(對(duì)不同的keyref)來構(gòu)建數(shù)據(jù)圖。例如,從帳戶節(jié)點(diǎn)導(dǎo)航到訂購(gòu)單keyref將調(diào)用AccountManagerWeb服務(wù)的getPurchaseOrders操作;然后,從訂購(gòu)單節(jié)點(diǎn)導(dǎo)航到行式項(xiàng)目keyref將調(diào)用OrderManagerWeb服務(wù)的getLineItems操作。選擇操作具有下面的形式/***@mas:operationtype="select"keyref="keyrefName"[inverse="true"]*@mas:transformtype="request"function="functionName_request"*@mas:transform.type="response"function="functionName_response"*/functionfunctionName($msg,$source){returnws.invoke($msg);}選擇操作用來檢索對(duì)應(yīng)于為特定源節(jié)點(diǎn)類型定義的keyrefName的節(jié)點(diǎn),例如,對(duì)特定聯(lián)系人節(jié)點(diǎn)選擇外關(guān)鍵字所引用的帳戶。反向?qū)傩远x操作實(shí)現(xiàn)反向關(guān)系,例如,選擇通過外關(guān)鍵字引用特定帳戶的所有聯(lián)系人。keyref定義可以具有下面的形式<xsd:keyrefname="keyrefName"refer="targetType"mas:alias="relationName"mas:inverseAlias="inverseRelationName"><xsd:selectorxpath="sourceType"/><xsd:fieldxpath="foreignKey"/></xsd:keyref>在關(guān)系項(xiàng)中,選擇操作對(duì)應(yīng)于下面的SQL表達(dá)式SELECT*FROMkeyref.targetTypeWHEREprimary_key=$source/foreign_key實(shí)現(xiàn)反向keyref的操作對(duì)應(yīng)于下面的SQL表達(dá)式SELECT*FROMkeyref.sourceTypeWHEREforeign_key=$source/primary_key選擇操作的請(qǐng)求變換可以為Web服務(wù)操作創(chuàng)建消息主體;它可以引用下面的系統(tǒng)變量,這些系統(tǒng)變量提供操作的上下文選擇操作的響應(yīng)變換可以將響應(yīng)消息主體映射到節(jié)點(diǎn)列表上。節(jié)點(diǎn)元素對(duì)應(yīng)于keyref定義的相應(yīng)節(jié)點(diǎn)類型的應(yīng)用定義模式。選擇操作的響應(yīng)變換可以引用下面的系統(tǒng)變量通過外關(guān)鍵字選擇(多對(duì)一)關(guān)系外關(guān)鍵字實(shí)現(xiàn)多對(duì)一(或查找)關(guān)系。例如,給定下面的模式和keyref定義,很自然想到聯(lián)系人節(jié)點(diǎn)的accountId屬性作為到聯(lián)系人所屬的帳戶節(jié)點(diǎn)的指針。<xsd:complexTypename="contactType"><xsd:all><xsd:elementname="first"type="xsd:string"/><xsd:elementname="last"type="xsd:string"/><xsd:elementname="email"type="xsd:string"/></xsd:all><xsd:attributename="id"type="xsd:string"use="required"mas:type="pkey"/><xsd:attributename="ownerId"type="xsd:string"use="required"/><xsd:attributename="accountId"type="xsd:string"use="required"/></xsd:complexType><xsd:keyrefname="contactAccountRef"refer="accountKey"mas:alias="account"><xsd:selectorxpath="contact"/><xsd:fieldxpath="@acccuntId"/></xsd:keyref>這將允許下面的客戶端遍歷(注意,@@運(yùn)算符引用keyref定義的別名)varaccount=contact.@@account;下面的管道操作實(shí)現(xiàn)該keyref關(guān)系/***@mas:operationtype="select"keyref="contactAccountRef"*@mas:transformtype="request"function="selectAccountByContact_request"*@mas:transformtype="response"function="selectAccountByContact_response"*/functionselectAccountByContact($msg,$source){returnws.invoke($msg);}/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*@mas:fieldxpath="@accountId"*/functionselectAccountByContact_request($source){<query><queryString>SELECT*FROMAccountWHEREId={string($source/@accountId)}</queryString></query>}/***@language:bodytype="xquery"*@mas:namespacetarget="app"*/functionselectAccountByContact_response($response){let$i:=$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<accountid="{string($i/sfdc:Id)}"><modified>{string($i/sfdc:SystemModstamp)}</modified><name>{string($i/sfdc:Name)}</name><type>{string($i/sfdc:Type)}</type></account>}管道操作函數(shù)可以由平臺(tái)自動(dòng)生成;它可以引用accountOwnerRefkeyref定義并且具有對(duì)請(qǐng)求和響應(yīng)變換函數(shù)的聲明(由工具生成)。/***@mas:operationtype="select"keyref="contactAccountRef"*@mas:transformtype="request"function="selectAccountByContact_request"*@mas:transformtype="response"function="selectAccountByContact_response"*/functionselectAccountByContact($msg,$source){returnws.invoke($msg);}請(qǐng)求變換請(qǐng)求變換可以引用表示帳戶節(jié)點(diǎn)的$source變量。函數(shù)注釋可以聲明輸出消息文檔的語(yǔ)言(XQuery)和目標(biāo)名字空間(引用管道文件的頭注釋中聲明的名字空間前綴)。函數(shù)也可以聲明指示函數(shù)要求聯(lián)系人節(jié)點(diǎn)的@accountId屬性的字段注釋;該聲明可以確保外關(guān)鍵字值作為同步請(qǐng)求的部分從調(diào)用的客戶端送到服務(wù)器。/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*@mas:fieldxpath="@accountId"*/functionselectAccountByContact_request($source){<query><queryString>SELECT*FROMAccountWHEREId={string(@source/@accountId)}</queryString></query>}響應(yīng)變換響應(yīng)變換可以引用$response變量,該變量代表從Web服務(wù)返回的消息的XML主體。函數(shù)注釋也可以聲明返回到管道管理器的XML對(duì)象的語(yǔ)言(XQuery)和目標(biāo)名字空間。函數(shù)可以假設(shè)Web服務(wù)<query>請(qǐng)求返回單個(gè)記錄。函數(shù)可以將其變換成具有相應(yīng)主關(guān)鍵字(id)和遵從模式定義的數(shù)據(jù)字段(包括表示序列號(hào)的<modified>元素)的單個(gè)<account>節(jié)點(diǎn)。/***@language:bodytype="xquery"*@mas:namespacetarget="app"*/functionselectOwnerByAccount_response($response){let$i:=$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<accountid="{string($i/sfdc:Id)}"><modified>{string($i/sfdc:SystemModstamp)}</modified><name>{string($i/sfdc:Name)}</name><type>{string($i/sfdc:Type)}</type></account>}<account>節(jié)點(diǎn)被返回到管道管理器并且同步回調(diào)用的應(yīng)用。管道管理器也可以選舉來將節(jié)點(diǎn)放入服務(wù)器的高速緩存中。反向選擇(一對(duì)多)外關(guān)鍵字定義的多對(duì)一關(guān)系當(dāng)然可以認(rèn)為是一對(duì)多關(guān)系的反方向。給定與上面部分中相同的模式和keyref定義,很自然想到屬于單個(gè)帳戶節(jié)點(diǎn)的聯(lián)系人節(jié)點(diǎn)集<xsd:complexTypename="contactType"><xsd:all><xsd:elementname="first"type="xsd:string"/><xsd:elementname="last"type="xsd:string"/><xsd:elementname="email"type="xsd:string"/><xsd:elementname="modified"type="xsd:string"/></xsd:all><xsd:attributename="id"type="xsd:string"use="required"mas:type="pkey"/><xsd:attributename="ownerId"type="xsd:string"use="required"/><xsd:attributename="accountId"type="xsd:string"use="required"/></xsd:complexType><xsd:keyrefname="contactAccountRef"refer="accountKey"mas:alias="account"mas:inverseAlias="contacts"><xsd:selectorxpath="contact"/><xsd:fieldxpath="@accountId"/></xsd:keyref>然而,這時(shí),keyref定義的mas:inverseAlias屬性用于反向遍歷keyref:varcontacts=account.@@contacts.*;下面的管道操作實(shí)現(xiàn)該反向keyref關(guān)系/***@mas:operationtype="select"keyref="contactAccountRef"inverse="true"*@mas:transformtype="request"function="selectContactsByAccount_request"*@mas:transformtype="response"function="selectContactsByAccount_response"*/functionselectContactsByAccount($msg,$source){returnws.invoke($msg);}/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*@mas:fieldxpath="@id"*/functionselectContactsByAccount_request(source){<query><queryString>SELECT*FROMContactWHEREaccountId={string($source/@id)}</queryString></query>}/***@language:bodytype="xquery"*@mas:namespacetarget="app"*/functionselectContactsByAccount_response($response){for$i:=$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<contactid="{string($i/sfdc:Id)}"accountId="{string($i/sfdc:AccountId)}"><modified>{string($i/sfdc:SystemModstamp)}</modified><fist>{string($i/sfdc:FistName)}</first><last>{string($i/sfdc:LastName)}</last><email>{string($i/sfdc:Email)}</email></contact>}管道操作函數(shù)可以由平臺(tái)自動(dòng)生成;它引用accountOwnerRefkeyref定義并且具有對(duì)請(qǐng)求和響應(yīng)變換函數(shù)的聲明(由工具生成)。操作也可以聲明它表示反向keyref關(guān)系。/***@mas:operationtype="select"keyref="contactAccountRef"inverse="true"*@mas:transformtype="request"function="selectContactsByAccount_request"*@mas:transformtype="response"function="selectContactsByAccount_response"*/functionselectContactsByAccount($msg,$source){returnws.invoke($msg);}請(qǐng)求變換請(qǐng)求變換可以引用表示聯(lián)系人節(jié)點(diǎn)的$source變量。函數(shù)注釋聲明輸出消息文檔的語(yǔ)言(XQuery)和目標(biāo)名字空間(引用管道文件的頭注釋中聲明的名字空間前綴)。函數(shù)也可以聲明指示函數(shù)要求帳戶節(jié)點(diǎn)的@id屬性的字段注釋;該聲明可以確保外關(guān)鍵字值作為同步請(qǐng)求的部分從調(diào)用的客戶端送到服務(wù)器。/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*@mas:fieldxpath="@id"*/functionselectContactsByAccount_request($source){<query><queryString>SELECT*FROMContactWHEREaccountId={string($source/@id)}</queryString></query>}響應(yīng)變換響應(yīng)變換可以引用$response變量,該變量代表從Web服務(wù)返回的消息的XML主體。函數(shù)注釋也可以聲明返回到管道管理器的XML對(duì)象的語(yǔ)言(XQuery)和目標(biāo)名字空間。函數(shù)可以假設(shè)Web服務(wù)<query>請(qǐng)求返回多個(gè)記錄。函數(shù)迭代結(jié)果并且將其變換成<contact>節(jié)點(diǎn)集。每個(gè)節(jié)點(diǎn)可以包含相應(yīng)主關(guān)鍵字(id)和遵從模式定義的數(shù)據(jù)字段;這包括帳戶外關(guān)鍵字(accountId屬性)和序列號(hào)(<modified>元素)。/***@language:bodytype="xquery"*/@mas:namespacetarget="app"functionselectContactsByAccount_response($response){for$i:=$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<contactid="{string($i/sfdc:Id)}"accountId="{string($i/sfdc:AccountId)}"><modified>{string($i/sfdc:SystemModstamp)}</modified><fist>{string($i/sfdc:FistName)}</first><last>{string($i/sfdc:LastName)}</last><email>{string($i/sfdc:Email)}</email></contact>}<contact>節(jié)點(diǎn)可以被返回到管道管理器并且同步回調(diào)用的應(yīng)用。管道管理器也可以選舉來將節(jié)點(diǎn)放入服務(wù)器的高速緩存中。非關(guān)系(上下文無關(guān))選擇可以定義不依賴外關(guān)鍵字值的節(jié)點(diǎn)之間的關(guān)系。例如,節(jié)點(diǎn)集可以由使用當(dāng)前用戶的信息或其他外部信息(例如,日時(shí)、實(shí)時(shí)數(shù)據(jù)、外部系統(tǒng)狀態(tài))的查詢來定義。在這些情況下,節(jié)點(diǎn)集可能附屬到數(shù)據(jù)模型內(nèi)的任意節(jié)點(diǎn)類型。然而典型地,這些節(jié)點(diǎn)集附屬到根節(jié)點(diǎn)。管道選擇操作可以引用keyref定義;由于按照定義,上下文無關(guān)選擇不需要源節(jié)點(diǎn)的上下文,因此在一個(gè)實(shí)施例中,它們總是在反向keyref上實(shí)現(xiàn)。下面的例子示出在CRM演示中,管道選擇操作是如何檢索當(dāng)前用戶的帳戶集的。帳戶節(jié)點(diǎn)類型具有下面的關(guān)鍵字定義。<xsd:keyname="accountKey"mas:alias="accounts"><xsd:selectorxpath="account"/><xsd:fieldxpath="@id"/></xsd:key>mas:alias屬性指示帳戶的節(jié)點(diǎn)集可從根節(jié)點(diǎn)遍歷;即,varaccounts=$root.@@accounts.*;可以與(上述)反向keyref選擇操作相同的方式實(shí)現(xiàn)管道。/***@mas:operationtype="select"key="accountKey"inverse="true"*@mas:transformtype="request"function="selectAccounts_request"*@mas:transformtype="response"function="selectAccounte-response"*/functionselectAccounts($msg,$source){returnws.invoke($msg);}/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*/functionselectAccounts_request($source){<query><queryString>SELECT*.AccountFROMAccount,UserWHEREUser.Alias={string($user/username)}ANDUser.Id=Account.OwnerId</queryString></query>}/***@language:bodytype="xquery"*@mas:namespacetarget="app"*/functionselectAccounts_response($response){for$i:=$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<accountid="{string($i/sfdc:Id)}"><modified>{string{$i/sfdc:SystemModstamp)}</modified><name>{string($i/sfdc:Name)}</name><type>{string($i/sfdc:Type)}</type></account>}請(qǐng)求變換請(qǐng)求變換可以引用$user系統(tǒng)變量,該變量用于構(gòu)建送到Web服務(wù)的請(qǐng)求查詢。/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*/functionselectAccounts_request($source)(<query><queryString>SELECT*.AccountFROMAccount,UserWHEREUser.Alias={string($user/username))ANDUser.Id=Account.OwnerId</queryString></query>}在這種情況下,服務(wù)可以實(shí)現(xiàn)聯(lián)合查詢(joinquery),選擇當(dāng)前用戶所擁有的所有帳戶(即,具有與當(dāng)前用戶的ID匹配的OwnerId外關(guān)鍵字)。要注意,變換不引用$source變量。響應(yīng)變換響應(yīng)變換可以以與前面部分定義的響應(yīng)變換相同的方式處理Web服務(wù)操作返回的帳戶集。/***@language:bodytype="xquery"*@mas:namespacetarget="app"*/functionselectAccounts_response($response)(for$i:=$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<accountid="{string($i/sfdc:Id)}"><modified>{string($i/sfdc:SystemModstamp)}</modified><name>{string($i/sfdc:Name)}</name><type>{string($i/sfdc:Type)}</type></account>}要注意,@mas:rootId屬性可以由管道管理器在<account>節(jié)點(diǎn)集返回它時(shí)自動(dòng)計(jì)算。插入插入操作可以在客戶端應(yīng)用將新創(chuàng)建的節(jié)點(diǎn)同步到服務(wù)器時(shí)由管道管理器調(diào)用。在客戶端上,可以以兩種方式之一創(chuàng)建節(jié)點(diǎn);即,create()函數(shù)既可以在keyref上調(diào)用也可以在root節(jié)點(diǎn)上調(diào)用varnode=source.@@keyref.create(<xml>);//contextualcreatevarnode=$root.create{<xml>);//contextfreecreate在兩種情況下,只有節(jié)點(diǎn)的XML對(duì)象可以傳送到服務(wù)器(即,不是源節(jié)點(diǎn))。這是因?yàn)樵谏舷挛膭?chuàng)建操作的情況中,節(jié)點(diǎn)必須包含引用源節(jié)點(diǎn)的外關(guān)鍵字;該值是由框架介于keyref定義自動(dòng)設(shè)置的。插入操作具有下面的形式/***@mas:operationtype="insert"node="nodeName"*@mas:transformtype="request"function="functionName_request"*@mas:transformtype="response"function="functionName_response"*/functionfunctionName($msg,$source){returnws.invoke($msg);}插入操作可以用來創(chuàng)建與nodeName聲明所引用的模式相對(duì)應(yīng)的節(jié)點(diǎn)。插入操作的請(qǐng)求變換創(chuàng)建Web服務(wù)操作的消息主體;它可以引用下面的系統(tǒng)變量,這些系統(tǒng)變量提供操作的上下文插入操作的響應(yīng)變換可以將響應(yīng)消息主體映射到部分構(gòu)建的節(jié)點(diǎn)上,該節(jié)點(diǎn)包含Web服務(wù)創(chuàng)建的記錄的主關(guān)鍵字(和可選的序列號(hào))。插入操作的響應(yīng)變換可以引用下面的系統(tǒng)變量節(jié)點(diǎn)的主關(guān)鍵字(和可選的序列號(hào))可以被返回到管道管理器,后者將該信息向后同步客戶端。節(jié)點(diǎn)最初在客戶端上是用臨時(shí)主關(guān)鍵字創(chuàng)建的;必須用外部系統(tǒng)的主關(guān)鍵字來代替這個(gè)值。節(jié)點(diǎn)典型地包含引用其他節(jié)點(diǎn)的外關(guān)鍵字值。如果在客戶端上創(chuàng)建多個(gè)相互引用的節(jié)點(diǎn),則系統(tǒng)需要確保以正確的依賴順序調(diào)用插入管道操作,并且使用Web服務(wù)返回的主關(guān)鍵字值來替換掛起節(jié)點(diǎn)的臨時(shí)外關(guān)鍵字值。非關(guān)系插入在一個(gè)實(shí)施例中,非關(guān)系插入操作不具有引用數(shù)據(jù)模型內(nèi)的其他節(jié)點(diǎn)類型的外關(guān)鍵字。例如,用戶節(jié)點(diǎn)類型可以由下面的模式定義<xsd:complexTypename="userType"><xsd:all><xsd;elementname="email"type="xsd:strinq"/></xsd:all><xsd:attributename="id"type="xsd:strinq"/></xsd:complexType>假設(shè)管理應(yīng)用程序能夠創(chuàng)建系統(tǒng)的新用戶;完成這個(gè)的客戶端代碼可能如下$root.create(<user><email>bob@acme.com</email></user>);在一個(gè)實(shí)施例中,這將要求下面的插入管道操作/***@mas:operationtype="insert"node="app:user"*@mas:transformtype="request"function="insertUser_request"*@mas:transformtype="response"function="insertUser_response"functioninsertUser($msg,$node){returnws.invoke($msg);}/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*/functioninsertUser_request($node){<create><sObjectsxsi:type="User"><Email>{string($node/app:email)}</Email></sObjects></create>}/***@language:bodytype="xquery"*@mas:namespacetarget="app"*/functioninsertUser_response($response){<userid="{string($response/sfdc:createResponse/sfdc:result/sfdc:Id)}"/>}請(qǐng)求變換請(qǐng)求變換可以引用表示應(yīng)用所創(chuàng)建的用戶節(jié)點(diǎn)的$node變量。函數(shù)注釋可以聲明輸出消息文檔的語(yǔ)言(XQuery)和目標(biāo)名字空間(引用管道文件的頭注釋中聲明的名字空間前綴)。/***@language:bodytype="xquery"*@#mas:namespacetarget="sfdc"*/functioninsertUser_request($node){<create><sObjectsxsi:type="User"><Email>{string($node/app:email)}</Email></sObjects></create>}響應(yīng)變換響應(yīng)變換可以引用$response變量,該變量代表從Web服務(wù)返回的消息的XML主體。函數(shù)注釋也可以聲明返回到管道管理器的XML對(duì)象的語(yǔ)言(XQuery)和目標(biāo)名字空間。在成功時(shí),Web服務(wù)可以返回遵從下面模式定義的消息主體。<elementname="createResponse"><complexType><sequence><elementname="result"minOccurs="1"type="tns:SaveResult"/></sequence></complexType></element><complexTypename="SaveResult"><sequence><elementname="id"type="tns:ID"/><elementname="success"type="xsd:boolean"/><elementname="errors"minOccurs="0"maxOccurs="unbounded"type="tns:Error"/></sequence></complexType>變換可以創(chuàng)建部分構(gòu)建的<user>節(jié)點(diǎn),該節(jié)點(diǎn)包含由應(yīng)用的模式定義的主關(guān)鍵字屬性(id)。/***@language:bodytype="xquery"*@mas:namespacetarget="app"*/functioninsertUser_response($response){<userid="{string($response/sfdc:createResponse/sfdc:result/sfdc:id)}"/>}該主關(guān)鍵字值可以由管道管理器處理并且與客戶端應(yīng)用同步。關(guān)系插入關(guān)系插入可以涉及包含引用高速緩存內(nèi)其他節(jié)點(diǎn)的外關(guān)鍵字值的節(jié)點(diǎn)。例如,下面的聯(lián)系人模式定義了所有者節(jié)點(diǎn)(@ownerID)和帳戶節(jié)點(diǎn)(@accountId)的外關(guān)鍵字。<xsd:complexTypename="contactType"><xsd:all><xsd:elementname="first"type="xsd:string"/><xsd:elementname="last"type="xsd:string"/><xsd:elementname="email"type="xsd:string"/></xsd:all><xsd:attributename="id"type="xsd:string"use="required"mas:type="pkey"/><xsd:attributename="ownerId"type="xsd:string"use="required"/><xsd:attributename="accountId"type="xsd:string"use="required"/></xsd:complexType>最初,聯(lián)系人XML對(duì)象可以由XScript賦值來構(gòu)建。varcontact=<contact><first>Sarah</first><last>Smith</last><email>sarah@acme.com</email></contact>;可以以多種方式創(chuàng)建包含外關(guān)鍵字的節(jié)點(diǎn)。給定上述聯(lián)系人XML對(duì)象以及表示所有人和聯(lián)系人節(jié)點(diǎn)的變量,下面的函數(shù)通過調(diào)用根節(jié)點(diǎn)上的create()函數(shù)創(chuàng)建聯(lián)系人節(jié)點(diǎn)。要注意,必須在調(diào)用create()之前設(shè)置外關(guān)鍵字。functioncreateContactl(account,owner,contact){contact.@@account=account;contact.@@owner=owner;return$root.create(contact);}然而,下面的函數(shù)實(shí)現(xiàn)相同的目的functioncreateContact2(account,owner,contact){contact.@@owner=owner;returnaccount.@@contacts.create(contact)}functioncreateContact3(account,owner,contact){contact.@@account=account;returnowner.@@contact=contact;}注意在這兩種情況下,缺失的外關(guān)鍵字是在節(jié)點(diǎn)被同步到服務(wù)器之前由框架提供的。因此,不管應(yīng)用如何創(chuàng)建節(jié)點(diǎn),管道操作只需要綁定到節(jié)點(diǎn)類型。管道操作可以以與前面部分中定義的操作相同的方式實(shí)現(xiàn)/***@mas:operationtype="insert"node="app:contact"*@mas:transformtype="request"function="insertContact_request"*@mas:transformtype="response"function="insertContact_response"*/functioninsertContact($msg,$node){returnws.invoke($msg);}/***@mas:namespacetarget="sfdc"*@language:bodytype="xquery"*/functioninsertContact_request($node){<create><sobjectsxsi:type="Contact"><AccountId>{string($node/app:@accountId})</AccountId><OwnerId>{string($node/app:@ownerId})</OwnerId><FirstName>(string($node/app:first)}</FirstName><LastName>{string($node/app:last)}</LastName><Email>{string($node/app:email)}</Email></sObjects></create>}/***@mas:namespacetarget="app"*@language:bodytype="xquery"*/functioninsertContact_response($response){<contactid="{string($response/sfdc:createResponse/sfdc:result/sfdc:id)}"/>}響應(yīng)變換返回的該主關(guān)鍵字值可以由管道管理器處理并且與客戶端應(yīng)用同步。當(dāng)最初創(chuàng)建了節(jié)點(diǎn)時(shí)用該值替換應(yīng)用程序分配的臨時(shí)主關(guān)鍵字。然而,在一個(gè)實(shí)施例中,如果應(yīng)用創(chuàng)建了相互引用的多個(gè)節(jié)點(diǎn),則也必須使用服務(wù)器返回的主關(guān)鍵字值來更新引用新插入節(jié)點(diǎn)的節(jié)點(diǎn)的外關(guān)鍵字值。例如,下面的函數(shù)首先創(chuàng)建所有者節(jié)點(diǎn),然后創(chuàng)建引用它的聯(lián)系人節(jié)點(diǎn)。functioncreateContact4(account){varowner=$root.create(<user><email>sarah@acme.com</email></user>);varcontact=<contact><first>Sarah</first><last>Smith</last><email>sarah@acme.com</email></contact>;contact.@@owner=owner;returnaccount.create(contact);}用戶節(jié)點(diǎn)的管道插入操作在聯(lián)系人節(jié)點(diǎn)的管道插入操作之前調(diào)用,并且聯(lián)系人節(jié)點(diǎn)的ownerId屬性包含從第一管道操作返回的適當(dāng)外關(guān)鍵字值。序列號(hào)在某些情況下被調(diào)用來創(chuàng)建節(jié)點(diǎn)的Web服務(wù)方法可能不返回序列號(hào)。管道能夠在單個(gè)管道操作內(nèi)進(jìn)行多個(gè)Web服務(wù)調(diào)用來檢索該信息。例如,前面部分中定義的管道操作如下擴(kuò)展/***@mas:operationtype="insert"node="app:contact"*@mas:transformtype="request"function="insertContact_request"*@mas:transformtype="response"function="insertContact_response"*/functioninsertContact($msg,$source){varresponse=ws.invoke($msg);varid=response.sfdc:createResponse.sfdc:result.sfdc:id;//retrievesequencenumbervarmsg2=createMessage(requestTimestamp(id));varresponse2=ws.invoke(msg2);//returnbothresponsesresponse.body+=response2.body.sfdc:queryResponse;returnresponse;}/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*/functionrequestTimestamp($id){<query><queryString>SELECTId,SystemModstampFROMContactWHEREId="{$id}"</queryString></query>}/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*/functioninsertContact_request($node){<create><sObjectsxsi:type="Contact"><AccountId>{string($node/app:@accountId})</AccountId><OwnerId>{string($node/app:@ownerId})</OwnerId><FirstName>{string($node/app:first)}</FirstName><LastName>{string($node/app:last)}</LastName><Email>{string($node/app:email)}</Email></sObjects></create>}/***@language:bodytype="xquery"*@mas:namespacetarget="app"*/functioninsertContact_response($response){<contactid="{string($response/sfdc:createResponse/sfdc:result/sfdc:id)}"><modified>{string($response/sfdc:queryResponse/sfdc:records/sfdc:SystemModstamp)}</modified></contact>}請(qǐng)求變換請(qǐng)求變換可以創(chuàng)建與前面部分中定義的相同的Web服務(wù)消息/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*/functioninsertContact_request($node){<create><sObjectsxsi:type="Contact"><AccountId>{string($node/app:@accountId})</AccountId><OwnerId>{string($node/app:@ownerId})</OwnerId><FirstName>{string($node/app:first)}</FirstName><LastName>{string($node/app:last)}</LastName><Email>{string($node/app:email)}</Email></sObjects></create>}管道函數(shù)然而在這種情況下,可以修改管道的自動(dòng)生成的Xscript函數(shù)來調(diào)用兩個(gè)Web服務(wù)調(diào)用。首先,可以使用從請(qǐng)求變換返回的消息來插入節(jié)點(diǎn)以及檢索插入的節(jié)點(diǎn)的主關(guān)鍵字。/***@mas:operationtype="insert"node="app:contact"*@mas:transformtype="request"function="insertContact_request"*@mas:transformtype="response"function="insertContact_response"*/functioninsertContact($msg,$source){varresponse=ws.invoke($msg);vari2d=response.sfdc:createResponse.sfdc:result.sfdc:id;接著,通過將插入節(jié)點(diǎn)的主關(guān)鍵字id傳遞進(jìn)管道中定義的輔助XQuery函數(shù)requestTimestamp(),來創(chuàng)建新消息對(duì)象。//retrievesequencenumbervarmsg2=createMessage(requestTimestamp(id));varresponse2=ws.invoke(msg2);輔助函數(shù)聲明與變換相同的語(yǔ)言和名字空間注釋,然而它們不被管道操作的注釋引用。函數(shù)構(gòu)建適當(dāng)?shù)南碚{(diào)用管道操作,以返回新創(chuàng)建的節(jié)點(diǎn)的序列號(hào)/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*/functionrequestTimestamp($id){<query><queryString>SELECTId,SystemModstampFROMContactWHEREId="{$d}"</queryString></query>}最終,可以通過創(chuàng)建由兩個(gè)消息主體構(gòu)成的單個(gè)XML對(duì)象來合并兩個(gè)Web服務(wù)操作的結(jié)果。//returnbothresponsesresponse.body+=response2.body.sfdc:queryResponse;returnresponse;}響應(yīng)變換響應(yīng)變換可以處理管道函數(shù)創(chuàng)建的XML對(duì)象,并且返回包含主關(guān)鍵字和節(jié)點(diǎn)序列號(hào)的單個(gè)<contact>節(jié)點(diǎn)。/***@language:bodytype="xquery"*/@mas:namespacetarget="app"*/functioninsertContact_response($response){<contactid="{string($response/sfdc:createResponse/sfdcresult/sfdc:id)}"><modified>{string($response/sfdc:queryResponse/sfdcrecords/sfdc:SystemModstamp)}</modified></contact>}更新更新操作可以由管道管理器在客戶端應(yīng)用修改節(jié)點(diǎn)時(shí)調(diào)用。當(dāng)企業(yè)被請(qǐng)求更新數(shù)據(jù)時(shí),它可能會(huì)拒絕—因?yàn)橛芯芙^它的策略/進(jìn)程或者因?yàn)槠渌讼雀淖兞藬?shù)據(jù)。第一種問題是無法避免的,并且要求更新操作和所有其他的一樣,能夠處理失敗??蚣芸梢詫?shí)現(xiàn)第二種情況的最優(yōu)并發(fā)模型。當(dāng)更新請(qǐng)求被送到Web服務(wù)操作時(shí),它可以不僅包括改變后的值,還包括可用來在修改時(shí)確定記錄是否為最新的序列號(hào)。(如果選擇操作上的Web服務(wù)不返回它自己的序列號(hào),則管道管理器可以計(jì)算基于節(jié)點(diǎn)值的MD5散列。)在客戶端上,節(jié)點(diǎn)可以通過腳本表達(dá)式修改,然而,直到在特定節(jié)點(diǎn)上調(diào)用update()函數(shù)時(shí)更新才同步到服務(wù)器,例如,functionmodify(contact,address){contact.email=address;contact.update();}在一個(gè)實(shí)施例中,客戶端應(yīng)用或更新操作都不能修改關(guān)鍵字值(即,關(guān)鍵字定義描述的任何字段)。更新操作可以具有下面的形式/***@mas:operationtype="update"node="nodeName"*@mas:transformtype="request"function="functionName_request"*@mas:transformtype="response"function="functionName_response"*/functionfunctionName($msg,$source){returnws.invoke($msg);}操作注釋聲明對(duì)應(yīng)于應(yīng)用模式的節(jié)點(diǎn)類型。更新操作的請(qǐng)求變換可以創(chuàng)建Web服務(wù)操作的消息主體;它可以引用下面的系統(tǒng)變量,這些系統(tǒng)變量提供操作的上下文更新操作的響應(yīng)變換可以將響應(yīng)消息主體映射到部分構(gòu)建的節(jié)點(diǎn)上,該節(jié)點(diǎn)包含修改后記錄的序列號(hào)。更新操作的響應(yīng)變換可以引用下面的系統(tǒng)變量例子下面的函數(shù)實(shí)現(xiàn)聯(lián)系人節(jié)點(diǎn)的更新管道操作/***@mas:operationtype="update"node="app:contact"*@mas:transformtype="request"function="updateContact_request"*@mas:transformtype="response"function="updateContact_response"*/functionupdateContact($msg,$source){ws.invoke($msg);//retrievesequencenumbervarmsg2=createMessage(requestTimestamp($source/@id));varresPonse2=ws.invoke(msg2);returnresponse2;}/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*/functionupdateContact_request($node){<update><sObjectsxsi:type="Contact"><Id>{string($node/app:@id})</Id><LastModifiedDate>{string($node/app:modified})</LastModifiedDate><AccountId>{string($node/app:@accountId})</AccountId><OwnerId>{string($node/app:@ownerId})</OwnerId><FirstName>{string($node/app:first)}</FirstName><LastName>{string{$node/app:last)}</LastName><Email>{string($node/app:email)}</Email></sObjects></update>}/***@language:bodytype="xquery"*@mas:namespacetarget="app"*/functionupdateContact_response($response){let$i:=$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<contactid="{string($i/sfdc:Id}}"><modified>{string{$i/sfdc:SystemModstamp)}</modified></contact>}請(qǐng)求變換請(qǐng)求變換可以創(chuàng)建用來調(diào)用更新操作的Web服務(wù)消息/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*/functionupdateContact_request($node){<update><sObjectsxsi;type="Contact"><Id>{string($node/app:@id})</Id><LastModifiedDate>{string($node/app:modified})</LastModifiedDate><AccountId>{string($node/app:@accountId})</AccountId><OwnerId>{string($node/app:@ownerId})</OwnerId><FirstName>{striug($node/app:first)}</FirstName><LastName>{string($node/app:last)}</LastName><Email>{string($node/app:email)}</Email></sObjects></update>}請(qǐng)求變換可以在節(jié)點(diǎn)的主關(guān)鍵字和元素LastModifiedDate中傳遞,該元素表示當(dāng)從服務(wù)檢索到記錄時(shí)的時(shí)間戳。這允許Web服務(wù)操作實(shí)現(xiàn)最優(yōu)并發(fā);即,如果送到操作的時(shí)間戳值與當(dāng)前系統(tǒng)時(shí)間戳值不匹配,則操作失敗。管道函數(shù)與插入操作一樣,可以修改管道的自動(dòng)生成的XScript函數(shù)來調(diào)用兩個(gè)Web服務(wù)調(diào)用。首先,使用從請(qǐng)求變換返回的消息來更新節(jié)點(diǎn)。/***@mas:operationtype="update"node="app:contact"*@mas:transformtype="request"function="updateContact_request"*@mas:transformtype="response"function="updateContact_response"*/functionupdateContact($msg,$source){ws.invoke($msg);接著,可以通過將更新的節(jié)點(diǎn)的主關(guān)鍵字id傳遞進(jìn)管道中定義的輔助XQuery函數(shù)requestTimestamp()來創(chuàng)建新消息對(duì)象(這是與上面插入操作定義的相同函數(shù))。//retrievesequencenumbervarmsg2=createMessage(requestTimestamp(id));varresponse2=ws.invoke(msg2);最終,可以返回第二個(gè)Web服務(wù)操作的結(jié)果來由響應(yīng)變換處理。returnresponse2;}響應(yīng)變換響應(yīng)變換可以處理管道函數(shù)創(chuàng)建的XML對(duì)象,并且返回包含主關(guān)鍵字和節(jié)點(diǎn)序列號(hào)的單個(gè)<contact>節(jié)點(diǎn)。/***@language:bodytype="xquery"*@mas:namespacetarget="app"*/functionupdateContact_response($response){let$i:=$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<contactid="{string($i/sfdc:Id)}"><modified>{string($i/sfdc:SystemModstamp)}</modified></contact>}沖突管理當(dāng)客戶端試圖修改和同步已經(jīng)被更新(由另一客戶端或其他外部改變進(jìn)程)的“失效”節(jié)點(diǎn)時(shí),可能發(fā)生節(jié)點(diǎn)沖突。失效節(jié)點(diǎn)是具有與服務(wù)器保存的當(dāng)前序列號(hào)不同的序列號(hào)的節(jié)點(diǎn)。如果MAS高速緩存了比客戶端嘗試更新的節(jié)點(diǎn)版本更新的節(jié)點(diǎn),則它可以用更新的節(jié)點(diǎn)直接響應(yīng)(即,不調(diào)用管道操作),將mas:state屬性設(shè)置為“conflict”。如果管道操作由于節(jié)點(diǎn)失效而拒絕更新,則可以返回具有適當(dāng)?shù)膍as:state屬性的最新節(jié)點(diǎn);這可以調(diào)用另一個(gè)往返(round-trip)來選擇最新節(jié)點(diǎn)。例子下面的更新操作函數(shù)檢測(cè)Web服務(wù)返回的錯(cuò)誤值。請(qǐng)求變換與上面定義的相同。/***@mas:operationtype="update"node="app:contact"*@mas:transformtype="request"function="updateContact_request"*@mas:transformtype="response"function="updateContact_response"*/functionupdateContact($msg,$source){varresponse=ws.invoke($msg);//checkforerrorif(!response.body.sfdc:updateResponse.sfdc:result.sfdc:success){//retrieveserver′srecordmsg=createMessage(selectContact_request$source/@id));response=ws.invoke(msg);//setstateexpandovarnode=response.body.sfdc:queryResponse.sfdc:result.sfdc:records;node.@state="conflict";}else(//retrievesequencenumbermsg=createMessage(requestTimestamp($source/@id));response=ws.invoke(msg);}returnresponse;}/***@language:bodytype="xquery"*@mas:namespacetarget="app"*/functionupdateContact_response($response)(let$i:=$response/sfdc:queryResponse/sfdc:result/sfdc:recordsif($i.@!=null)then<contactid="{string(i/sfdc:Id)}"accountId="{string($i/sfdc:AccountId)}"mas:state="{$response.result.@state}"><modified>{string($i/sfdc:SystemModstamp)}</modified><fist>{string($i/sfdc:FistName)}</first><last>{string($i/sfdc:LastName)}</last><email>{string($i/sfdc:Email)}</email></contact>else<contactid="{string($i/sfdc:Id)}"><modified>{string($i/sfdc:SystemModstamp)}</modified></contact>}管道函數(shù)管道函數(shù)可以首先檢查Web服務(wù)返回的錯(cuò)誤值。functionupdateContact($msg,$source){varresponse=ws.invoke($msg);//checkforerrorif(!response.body.sfdc:updateResponse.sfdc:result.sfdc:success){如果返回錯(cuò)誤,則函數(shù)可以向Web服務(wù)發(fā)送對(duì)整個(gè)節(jié)點(diǎn)的請(qǐng)求查詢;這里,操作重新使用上下文無關(guān)選擇操作的請(qǐng)求變換//retrieveserver′srecordmsg=createMessage(selectContact_request($source/@id));response=ws.invoke(msg);操作然后創(chuàng)建擴(kuò)展state屬性,從而響應(yīng)變換可以檢測(cè)到已經(jīng)從服務(wù)器檢索到?jīng)_突記錄。//setstateexpandovarnode=response.body.sfdc:queryResponse.sfdc:result.sfdc:records;node.@state="conflict";如果原始的Web服務(wù)方法成功,則函數(shù)只請(qǐng)求更新的序列號(hào)(如上)。//retrievesequencenumbermsg=creatsMessage(requestTimestamp($source/$id));response=ws.invoke(msg);不管更新是否成功,任何響應(yīng)都由響應(yīng)變換處理。returnresponse;}響應(yīng)變換響應(yīng)變換可以首先檢查來看管道操作是否創(chuàng)建了state擴(kuò)展屬性。如果是的話,則變換可以構(gòu)建完整的節(jié)點(diǎn)元素;否則它可以只返回如上的主關(guān)鍵字和序列號(hào)。functionupdateContact_response($response){let$i:=$response/sfdc:queryResponse/sfdc:result/sfdc:recordsif($i.@state!=null)then<contactid="{string($i/sfdc:Id)}"accountId="{string($i/sfdc:AccountId)}"mas:state="{$i.@state}"><modified>{string($i/sfdc:SystemModstamp)}</modified><fist>{string($i/sfdc:FistName)}</first><last>{string($i/sfdc:LastName)}</last><email>{string($i/sfdc:Email)}</email></contact>else<contactid="{string($i/sfdc:Id)}"><modified>{string($i/sfdc:SystemModstamp)}</modified></contact>}鏈接和解除鏈接(修改外關(guān)鍵字)節(jié)點(diǎn)可以通過XScript表達(dá)式修改。這也適用于外關(guān)鍵字值。這部分中的例子使用聲明了下面關(guān)鍵字定義的帳戶和聯(lián)系人節(jié)點(diǎn)類型。<xsd:keyname="accountKey"><xsd:selectorxpath="account"/><xsd:fieldxpath="@id"/></xsd:key><xsd:keyname="contactPrimaryKey"><xsd:selectorxpath="contact"/><xsd:fieldxpath="@id"/></xsd:key><xsd:keyname="contactEmailKey"><xsd:selectorxpath="contact"/><xsd:fieldxpath="email"/></xsd:key>下面的函數(shù)由于嘗試修改節(jié)點(diǎn)的關(guān)鍵字值,因此將產(chǎn)生運(yùn)行時(shí)錯(cuò)誤。functionfoobar(contact){contact.first=$context.first;contact.last=$context.last;contact.email=$context.email;//runtimeerror}然而,下面的函數(shù)成功地改變了帳戶屬性,其改變了引用帳戶節(jié)點(diǎn)的外關(guān)鍵字值。functionfoo(contact,account){contact.first=$context.first;contact.last=$context.last;contact.@@accountId=account;//changesaccountforeignkeycontact.update();}這里,外關(guān)鍵字由下面的keyref聲明定義<xsd:keyrefname="contactAccountRef"refer="accountKey"mas:alias="account"><xsd:selectorxpath="contact"/><xsd:fieldxpath="@accountId"/></xsd:keyref>類似地,下面的函數(shù)使用+=運(yùn)算符(也叫做link()函數(shù))來向帳戶的聯(lián)系人集添加聯(lián)系人節(jié)點(diǎn)functionbar(account,contact){account.@@contacts+=contact;}這種一對(duì)多關(guān)系由下面的keyref聲明定義,其包括反向關(guān)系<xsd:keyrefname="contactAccountRef"refer="accountKey"mas:alias="account"mas:inverseAlias="contacts"><xsd:selectorxpath="contact"/><xsd:fieldxpath="@accountId"/></xsd:keyref>在實(shí)際中(即,外部數(shù)據(jù)庫(kù))該操作可以通過將聯(lián)系人實(shí)體的account外關(guān)鍵字設(shè)置為帳戶的主關(guān)鍵字來實(shí)現(xiàn)。設(shè)置源節(jié)點(diǎn)中的外關(guān)鍵字(例如,contact.@@accountId)將自然地允許從目標(biāo)節(jié)點(diǎn)遍歷回源節(jié)點(diǎn)(例如,account.@@contacts.*),反之亦然。給定上述定義,下面的函數(shù)是等效的。functionfool(contact,account){contact.first=$context.first;contact.last=$context.last;contact.@@accountId=account;update(contact);}functionfoo2(contact,account){contact.first=$context.first;contact.last=$context.last;account.@@contacts+=contact;update(contact);}在一個(gè)實(shí)施例中,模式的外關(guān)鍵字元素(或?qū)傩?聲明與外部系統(tǒng)的約束(或Web服務(wù)操作的語(yǔ)義所暗示的約束)匹配。特別地,NOTNULL外關(guān)鍵字值(例如,在數(shù)據(jù)庫(kù)表字段上聲明的)在屬性的情況下應(yīng)當(dāng)由xsd:use"required"鏡像,而在元素的情況下應(yīng)當(dāng)由minOccurs="1"maxOccurs="1"鏡像。例如,給定上述定義,下面的函數(shù)將產(chǎn)生運(yùn)行時(shí)錯(cuò)誤。functionfoo(contact){contact.first=$context.first;contact.last=$context.last;contact.@@accountId=null;update(contact);}自定義查詢可以通過實(shí)現(xiàn)與兩個(gè)節(jié)點(diǎn)之間定義的keyref關(guān)系有關(guān)的選擇管道操作來檢索數(shù)據(jù);即,一個(gè)節(jié)點(diǎn)內(nèi)包含的外關(guān)鍵字值標(biāo)識(shí)有關(guān)節(jié)點(diǎn)的主關(guān)鍵字。這些選擇操作的輸出可以是由框架合并到本地高速緩存中的節(jié)點(diǎn)。自定義查詢可以是對(duì)客戶端編程模型不透明的管道查詢(或其他過程邏輯);即,不排他地基于主和外關(guān)鍵字關(guān)系顯式地選擇(或修改)數(shù)據(jù)。例如,搜索操作可以返回匹配自然語(yǔ)言表達(dá)式的XML對(duì)象的集合。不同種類的操作表現(xiàn)為圖8的矩陣800。操作具有歸類為臨時(shí)數(shù)據(jù)或永久數(shù)據(jù)的輸入和輸出。在一個(gè)實(shí)施例中,臨時(shí)數(shù)據(jù)不是應(yīng)用的節(jié)點(diǎn)圖的部分;即,它未被模式、關(guān)鍵字或keyref聲明定義,并且沒有被框架自動(dòng)合并到本地高速緩存中。臨時(shí)數(shù)據(jù)盡管可以被系統(tǒng)$context或$session變量(具有由客戶端應(yīng)用框架確定的生命期)引用,但并不假定它是持久的。永久數(shù)據(jù)可以完全由模式定義的應(yīng)用數(shù)據(jù)節(jié)點(diǎn)構(gòu)成。在一個(gè)實(shí)施例中,存在兩個(gè)實(shí)現(xiàn)自定義查詢的機(jī)制1.自定義操作可以允許客戶端向特定管道操作傳遞不透明、臨時(shí)的XML對(duì)象(文檔)。該操作可以異步地返回臨時(shí)XML文檔給客戶端回叫(callback)例如,下面的自定義操作myQuery以XML對(duì)象<myRequest>作為輸入,并且myCallback()函數(shù)返回XML對(duì)象$root.myQuery(<myRequest>productmobileapplication</myRequest>,myCallback);functionmyCallback(myOutput){...}2.自定義對(duì)象可以包括作為圖的一部分的(模式定義的)非永久節(jié)點(diǎn)的創(chuàng)建??梢栽诳蛻舳恕氨闅v”相應(yīng)keyref時(shí)調(diào)用操作,在這種情況下,客戶端對(duì)象作為$source節(jié)點(diǎn)傳遞進(jìn)相應(yīng)選擇管道操作中。例如,下面的自定義對(duì)象<taskQuery>被送到為將task節(jié)點(diǎn)與taskQuery節(jié)點(diǎn)相關(guān)聯(lián)的keyref定義的選擇管道操作varquery=$root.@@taskQueries.create(<taskQuerypriority="1"/>);vartasks=query.@@tasks.*;自定義操作自定義操作可以是用于調(diào)用自定義管道操作(函數(shù))的機(jī)制。函數(shù)輸入和輸出都可以是XML文檔直接量(literal)(不是由模式定義)。在一個(gè)實(shí)施例中,框架不將結(jié)果直接合并到本地高速緩存中。例如,假設(shè)我們希望在電子郵件地址集合中檢索沒有退出接收郵件的聯(lián)系人(對(duì)特定帳戶)。下面的代碼客戶端代碼調(diào)用自定義操作getList,該操作被傳遞XML對(duì)象<query>。functionbar(){account.getList(<queryoptedOut="false"/>,callback);}functioncallback(result){for(i=0;i<result.length;i++){addAddress(result[i].email);}}一旦從MAS返回結(jié)果,回叫(callback)處理該結(jié)果。下面的XQuery函數(shù)實(shí)現(xiàn)自定義請(qǐng)求/***@mas:namespacetarget="sfdc"*@mas:fieldxpath="@id"*@language:bodytype="xquery"*/functionfoo_request($source,$query){<query><queryString>SELECTId,EmailFROMContactWHEREAccountId="{string($source/@id)}"ANDHasoptedOutOfEmail={boolean($query/@optedOut)}</queryString></query>}來自Web服務(wù)的響應(yīng)可以由下面函數(shù)處理。要注意,結(jié)果作為單個(gè)XML文檔返回到客戶端回叫—即,這不被解釋為合并到本地高速緩存中的節(jié)點(diǎn)。/***@mas:namespacetarget="app"*/@language:bodytype="xquery"functionfoo_response($response){for$iin$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<contactid="{string($i/sfdc:Id)}"><email>{string($i/sfdc:Email)}</email></contact>}自定義操作定義可以聲明該操作的客戶端函數(shù)名和上下文。/***customoperatoinoncontact:account.getList(<queryoptedOut="false"/>);*@mas:operationtype="custom"node="app:account"name="getList"*@mas:transformtype="request"function="foo_request"*@mas:transformtype="response"function="foo_response"*/functionfoo($msg,$source,$query){$msg.header+=createHeader();returnws.invoke($msg);}自定義對(duì)象自定義對(duì)象可以包括作為圖的一部分的(模式定義的)非永久節(jié)點(diǎn)的創(chuàng)建??梢栽诳蛻舳恕氨闅v”相應(yīng)keyref時(shí)調(diào)用操作,在這種情況下,自定義對(duì)象可以作為$source節(jié)點(diǎn)傳遞進(jìn)相應(yīng)選擇管道操作中。實(shí)質(zhì)上,自定義操作可以包括將返回綁定到自定義對(duì)象的節(jié)點(diǎn)的管道操作的輸入數(shù)據(jù)。這可以允許結(jié)果成為客戶端高速緩存的一部分—以便這些節(jié)點(diǎn)被隨后的客戶端面板和行動(dòng)引用,并且以便返回操作來保持這些結(jié)果最新。例如,下面的模式聲明可以定義自定義對(duì)象taskQuery,其用于基于priority屬性的值選擇task節(jié)點(diǎn)的子集。<xsd:complexTypename="taskQuery"><xsd:attributename="priority"type="xsd:string"/></xsd:complexType>下面的關(guān)鍵字定義確保每個(gè)taskQuery對(duì)象是唯一的<xsd:keyrefname="taskQueryKey"><xsd:selectorxpath="taskQuery"/><xsd:fieldxpath="@priority"/></xsd:keyref>下面的keyref定義用于將taskQuery節(jié)點(diǎn)綁定到根節(jié)點(diǎn);它聲明應(yīng)用根節(jié)點(diǎn)的虛外關(guān)鍵字屬性mas:root;inverseAlias屬性聲明從根節(jié)點(diǎn)到taskQuery節(jié)點(diǎn)集合的遍歷;即,$root.@@taskQueries.*。<xsd:keyrefname="taskQueryRootRef"refer="mas:rootKey"mas:inverseAlias="taskQueries"><xsd:selectorxpath="taskQuery"/><xsd:fieldxpath="@mas:rootId"/></xsd:keyref>下面的keyref定義管道查詢操作返回的taskQuery節(jié)點(diǎn)和task節(jié)點(diǎn)之間的關(guān)系。每個(gè)task節(jié)點(diǎn)聲明虛taskQuery外關(guān)鍵字屬性,用于標(biāo)識(shí)選擇它的相應(yīng)查詢;inverseAlias屬性聲明從taskQuery節(jié)點(diǎn)到task節(jié)點(diǎn)集合的遍歷,即,query.@@tasks.*。<xsd:keyrefname="taskTaskQueryRef"refer="TaskQueryKey"mas:inverseAlias="tasks"><xsd:selectorxpath="task"/><xsd:fieldxpath="@taskQuery"/></xsd:keyref>這些keyref定義定義了下面圖12D所示的根節(jié)點(diǎn)與taskQuery和task節(jié)點(diǎn)之間的關(guān)系。taskQuery節(jié)點(diǎn)可以由客戶端腳本使用標(biāo)準(zhǔn)create()函數(shù)創(chuàng)建。functioninit(){varf=$root.@@taskQueries.create(<taskQuerypriority="1"/>);}在一個(gè)實(shí)施例中,沒有為taskQueryRootRefkeyref定義的管道插入操作,因此該客戶端腳本不觸發(fā)任何服務(wù)器活動(dòng)。下面的模板遍歷反向的taskTaskQueryRefkeyref定義。<netui:repeaterid="$s"source="$root.@@taskQueries.where(priority==′1′).@@tasks.*"><p>$s}</p></netui:repeater>這導(dǎo)致在相關(guān)管道操作上的隱式選擇;repeater(重復(fù)器)的source屬性引用上面創(chuàng)建的taskNode,并且這用作遍歷的source上下文;即,節(jié)點(diǎn)<taskQuerypriority=’1’/>被作為$source變量傳遞到操作中。相應(yīng)管道選擇操作由下面函數(shù)定義/***@mas:operationtype="select"keyref="app:taskTaskQueryRef"inverse="true"*@mas:transformtype="request"function="selectTasks_request"*@mas:transformtype="response"function="selectTasks_response"*/functionselectTasks($msg,$source){returnws.invoke($msg);}/***@mas:namespacetarget="sfdc"*@mas:fieldxpath="@priority"*@language:bodytype="xquery"*/functionselectTasks_request($source){<query><queryString>SELECTId,Priority,SubjectFROMTaskWHEREPriority="{string($source/@priority})"</queryString></query>}/***@mas:namespacetarget="app"*@language:bodytype="xquery"*/functionselectTasks_response($response){for$iin$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<taskid="{string($i/sfdc:Id)}"priority="{string($i/sfdc:Priority)}"><subject>{string($i/sfdc:Subject)}</subject></task>}應(yīng)用也可以定義管道選擇操作來“產(chǎn)生”(seed)代表“預(yù)罐裝”(pre-canned)的查詢的自定義對(duì)象。例如,下面的操作實(shí)現(xiàn)選擇操作,選擇操作當(dāng)客戶端遍歷$root.@@taskQueries.*時(shí)返回taskQuery對(duì)象的(恒定)集合。/***@mas:operationtype="select"keyref="app:taskQueryRootRef"inverse="true"*/functionselectTasks($msg,$source){return<taskQuerypriority=′1′/><taskQuerypriority=′2′/>;}該查詢可能例如由下面的模板引用<td><netui:repeaterid="s1"source="$root.@@taskQueries.*"><ahref="s1.select(s1.iterator)">Priority{s1}</a></netui:repeater></td><td><netui:repeaterid="s2"source="s1.selected.@@tasks.*"><p>{s2}</p></netui:repeater></td>第一repeaters1顯示taskQuery對(duì)象的集合;第二repeaters2顯示從第一repeater選擇的taskQuery檢索的最終得到的task。當(dāng)然,也可以通過實(shí)現(xiàn)持續(xù)這些查詢對(duì)象的Web服務(wù)來定義插入、更新和刪除自定義對(duì)象的管道操作—實(shí)際上,將這些查詢對(duì)象作為數(shù)據(jù)模型內(nèi)的普通節(jié)點(diǎn)對(duì)待。當(dāng)修改自定義對(duì)象節(jié)點(diǎn)時(shí)—不管是通過客戶端應(yīng)用直接修改還是通過同步選擇操作間接修改,所有相應(yīng)有關(guān)節(jié)點(diǎn)可以自動(dòng)與自定義對(duì)象解除鏈接;即,通過外關(guān)鍵字值引用對(duì)象的節(jié)點(diǎn)將該外關(guān)鍵字設(shè)為空(null)。這確保通過自定義對(duì)象遍歷到的節(jié)點(diǎn)精確地反映自定義對(duì)象的狀態(tài)。高級(jí)選擇操作選擇操作可以允許框架檢索特定keyref的節(jié)點(diǎn)。由于這是客戶端應(yīng)用用來檢索節(jié)點(diǎn)的基本機(jī)制,因此管道可以定義選擇操作。正常的選擇操作可以在當(dāng)客戶端應(yīng)用導(dǎo)航數(shù)據(jù)模型時(shí)由應(yīng)用自動(dòng)觸發(fā)。例如,下面的客戶端SPath表達(dá)式導(dǎo)致調(diào)用accountskeyref的選擇操作。$account.@@contacts.*管道選擇操作可以被傳遞相應(yīng)帳戶對(duì)象的主關(guān)鍵字。這部分詳細(xì)說明其他形式的選擇操作。高速緩存和優(yōu)化客戶端和MAS都可以高速緩存管道管理器返回的數(shù)據(jù)。因此,不是每個(gè)數(shù)據(jù)圖遍歷都不需要生成選擇請(qǐng)求??蛻舳撕头?wù)器都可以在生成新選擇請(qǐng)求之前維持每個(gè)節(jié)點(diǎn)和節(jié)點(diǎn)集的元數(shù)據(jù),該元數(shù)據(jù)用于確定相應(yīng)數(shù)據(jù)的集合可以依靠多久來更新。通常,需要根據(jù)選擇操作傳輸?shù)臄?shù)據(jù)量是很大的。因此,給定適合的Web服務(wù)操作的可用性,可以由框架實(shí)現(xiàn)特定的優(yōu)化。以與select操作相同的方式調(diào)用select_pkey操作,然而,它僅返回主關(guān)鍵字集。例如,在上面聯(lián)系人keyref上的相應(yīng)選擇操作的select_pkey操作將實(shí)現(xiàn)下面的響應(yīng)變換。/***@language:bodytype="xquery"*@mas:namespacetarget="app"*/functionselectContactsByAccount_response($response){for$i:=$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<contactid="{string($i/sfdc:Id)}"><modified>{string($i/sfdc:SystemModstamp)}</modified></contact>}MAS于是能夠確定哪個(gè)節(jié)點(diǎn)元素(如果有的話)當(dāng)前在高速緩存中。對(duì)于未包含在高速緩存內(nèi)的任何節(jié)點(diǎn),框架然后可以調(diào)用select_set操作,象正常的選擇操作那樣返回請(qǐng)求的pkey值集合的完整節(jié)點(diǎn)。上面例子的select_set操作將實(shí)現(xiàn)下面的請(qǐng)求變換/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*/functionselectContacts_request($keyset){<query><queryString>SELECT*FROMContactWHEREIdIN({for$xin$keysetreturn{$x},}}</queryString></query>}響應(yīng)變換可以與正常的選擇操作相同。選擇復(fù)合模式選擇操作可以返回定義為包含重復(fù)元素的復(fù)合文檔的節(jié)點(diǎn)。對(duì)節(jié)點(diǎn)類型的模式定義的復(fù)雜度沒有限制。然而,可能有對(duì)節(jié)點(diǎn)記錄大小的實(shí)際限制。下一部分將詳細(xì)說明當(dāng)復(fù)合文檔可能被分成多個(gè)節(jié)點(diǎn)時(shí)的情況。例子下面的模式示出包含多個(gè)lineItem元素的purchaseOrder節(jié)點(diǎn)類型。<xsd:elementname="purchaseOrder"type="purchaseOrderType"><xsd:complexTypename="purchaseOrderType"><xsd:sequence><xsd:elementname="price"type="xsd:double"/>...<xsd:complexTypename="lineItems"><xsd:sequencemaxOccurs="unbounded"><xsd:complexTyperef="lineItem"><xsd:sequence><xsd:elementname="prodId"type="xsd:string"/>...</xsd:sequence></xsd:complexType></xsd:sequence></xsd:complexType></xsd:sequence></xsd:complexType>例如,下面的XML文檔示出訂購(gòu)單模式。<purchaseOrder><price>1000.00</price>...<lineItems><lineItem><prodId>Widget-X</prodId>...</lineItem><lineItem><prodId>Widget-Y</prodId>....</lineItem>...</lineItems></purchaseOrder>下面的管道函數(shù)包含生成訂購(gòu)單集合的嵌套循環(huán),每個(gè)具有嵌套的行式項(xiàng)目的集合。/***@mas:operationtype="select"keyref="purchaseOrderAccountRef"inverse="true"*@mas:transformtype="request"function="selectPurchaseOrders_request"*@mas:transformtype="response"function="selectPurchaseOrders_response"*/functionselectPurchaseOrders($msg,$source){varresponse=ws.invoke($msg);varpos=response.sfdc:queryResponse.sfdc:result.sfdc:records;//retrievelineitemsforeachpurchaseorderfor(i=0;i<pos.length-1;i++){varmsg2=createMessage(requestLineItems(pos[i].sfdc:Id));varresponse2=ws.invoke(msg2);pos[i]+=response2.body.sfdc:queryResponse.sfdc:result.sfdc:records;}returnresponse;}/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*@mas:fieldxpath="@id"*/functionselectPurchaseOrders_request($source){<query><queryString>SELECT*FROMPurchaseOrderWHEREPurchaseOrder.AccountId={string($source/@id)}</queryString></query>}/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*/functionselectLineItems($id){<query><queryString>SELECT*FROMLineItemWHERELineItem.PurchaseOrderId=$d</queryString></query>}/***@language:bodytype="xquery"*@mas:namespacetarget="app"*/functionselectPurchaseOrders_response($response){for$po:=$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<purchaseOrderid="{string($po/ws:Id)}"><price>{string($po/ws:Price)}</price>...<lineItems>{for$liin$po/ws:recordsreturn<lineItem><prodId>{string($li/ws:ProdId)}</prodId>...</lineItem>}</lineItems></purchaseOrder>}選擇節(jié)點(diǎn)樹選擇操作可以返回定義為包含重復(fù)元素的復(fù)合文檔的節(jié)點(diǎn)。對(duì)節(jié)點(diǎn)類型的模式定義的復(fù)雜度沒有限制。在某些情況下,希望將復(fù)合文檔的部分分成由keyref關(guān)系綁定的獨(dú)立的節(jié)點(diǎn)。這些節(jié)點(diǎn)形成樹,其向后同步客戶端并且合并到高速緩存的數(shù)據(jù)圖中。將復(fù)合文檔分成多個(gè)節(jié)點(diǎn)的好處是通過在單個(gè)操作中檢索多級(jí)keyref(即,選擇特定帳戶的所有聯(lián)系人以及所有相關(guān)任務(wù))來提高性能。例子在下面的模式定義中,purchaseOrderType和lineItemType都被聲明為具有下面模式定義的節(jié)點(diǎn)類型。<xsd:complexTypename="purchaseOrderType"><xsd:complexType><xsd:sequence><xsd:elementname="price"type="xsd:double"/>...<xsd:sequence></xsd:complexType><xsd:complexType><xsd:elementname="lineItemType"><xsd:complexType><xsd:sequence><xsd:elementname="prodId"type="xsd:string"/>...</xsd:sequence></xsd:complexType></xsd:element>模式還聲明下面的關(guān)鍵字和keyref定義<xsd:keyname="purchaseOrderKey"><xsd:selectorxpath="purchaseOrder"/><xsd:fieldxpath="@id"/></xsd:key><xsd:keyname="lineItemKey"><xsd:selectorxpath="lineItem"/><xsd:fieldxpath="@id"/></xsd:key><xsd:keyrefname="lineItemPurchaseOrderRef"refer="purchaseOrderKey"mas:inverseAlias="lineItems"><xsd:selectorxpath="lineItem"/><xsd:fieldxpath="@purchaseOrderId"/></xsd:keyref>圖12D表示相應(yīng)的keyref。一旦復(fù)合文檔被分成單獨(dú)的節(jié)點(diǎn),框架就可以確保管道支持組成節(jié)點(diǎn)(例如,行式項(xiàng)目)上的客戶端操作。例如,可以防止客戶端應(yīng)用創(chuàng)建新的行式項(xiàng)目對(duì)象,除非存在lineItemkeyref的相應(yīng)插入操作。下面的管道定義是上面例子的修改版本。這里,內(nèi)部循環(huán)創(chuàng)建nodeset元素內(nèi)的節(jié)點(diǎn)元素。要注意,每個(gè)內(nèi)部對(duì)象也必須都定義主關(guān)鍵字。/***@mas:operationtype="select"keyref="purchaseOrderAccountRef"inverse="true"*@mas:transformtype="request"function="selectPurchaseOrders_request"*@mas:transformtype="response"function="selectPurchaseOrders_response"*/functionselectPurchaseOrders($msg,$source){varresponse=ws.invoke($msg);varpos=response.sfdc:queryResponse.sfdc:result.sfdc:records;//retrievelineitemsforeachpurchaseorderfor(i=0;i<pos.length-1;i++){varmsg2=createMessage(requestLineItems(pos[i].sfdc:Id));varresponse2=ws.invoke(msg2);pos[i]+=response2.body.sfdc:queryResponse.sfdc:result.sfdc:records;}returnresponse;}/***@language:bodytype="xquery"*@mas:namespacetarget="sfdc"*@mas:fieldxpath="@id"*/functionselectPurchaseOrders_request($source){<query><queryString>SELECT*FROMPurchaseOrderWHEREPurchaseOrder.AccountId={string($source/@id)}</queryString></query>}/***@language:bodytype="xquery"*@mas:namespacetarget="app"*/functionselectPurchaseOrders_response($response){for$po:=$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<purchaseOrderid="{string($po/ws:Id)}"><price>{string$po/ws:Price)}</price>...<mas:nodesetkeyref="lineItemPurchaseOrderRef">{for$liin$po/ws:recordsreturn<lineItemid="{string($li/ws:Id)}"><prodId>{string($li/ws:ProdId)}</prodId>....</lineItem>}</mas:nodeset></purchaseOrder>}深選擇(deepselect)如上面所討論的,應(yīng)用可以使用SPath表達(dá)式遍歷數(shù)據(jù)圖,這些遍歷可以使框架同步背景中所要求的數(shù)據(jù)。在一個(gè)實(shí)施例中,由于同步機(jī)制是被異步調(diào)用的,因此可能經(jīng)常出現(xiàn)不能根據(jù)當(dāng)前高速緩存的數(shù)據(jù)圖充分估值SPath表達(dá)式的情況。例如,如果客戶端沒有預(yù)先同步和高速緩存keyrefaccounts和contacts,則下面的SPath表達(dá)式將返回空列表。$root.@@accounts.*.@@contacts.*.@@tasks.*;在一個(gè)實(shí)施例中,除非在前的節(jié)點(diǎn)當(dāng)前位于高速緩存中,否則不能啟動(dòng)后面的keyref遍歷。在一個(gè)實(shí)施例中,客戶端代碼將首先遍歷$root@@accounts.*,然后等待同步通知,然后選擇$root.@@accounts.*.@@contacts.*,等待另一同步通知,最后表達(dá)式將調(diào)用所有帳戶的所有聯(lián)系人的所有任務(wù)的同步。select()函數(shù)可以使客戶端能請(qǐng)求服務(wù)器來代表它估值SPath表達(dá)式,然后將得到的節(jié)點(diǎn)圖同步到客戶端。例如$root.select(@@accounts.*.@@contacts.*.@@tasks.*);這里,整個(gè)Spath表達(dá)式被傳遞給服務(wù)器,后者調(diào)用連續(xù)的keyref遍歷并且管理節(jié)點(diǎn)的同步。要注意,服務(wù)器可以在一個(gè)同步消息或在多個(gè)同步消息上返回整個(gè)圖。SPath表達(dá)式還可以包含使用where()函數(shù)的謂詞(predicate)。例如$root.select(@@accounts.*.@@contacts.*.@@tasks.*.where(.priority==1));可以在得到的節(jié)點(diǎn)被同步到客戶端之前在服務(wù)器上解析謂詞表達(dá)式。下面的表達(dá)式可以對(duì)所有具有type=“Direct”元素的所有帳戶檢索所有聯(lián)系人和通知。$root.select(@@accounts.where(.type="Direct").keyref("contacts","notes").*;會(huì)話管理會(huì)話狀態(tài)可以由管道的自定義過程代碼管理。管道可以定義變量來存儲(chǔ)會(huì)話標(biāo)識(shí)符。這可以由管道創(chuàng)建,或者由Web服務(wù)返回—就像在這種情況下這樣//sessionobjectreturnedfromWebservicevarsessionId=null;管道可以定義函數(shù)來創(chuàng)建和發(fā)送用來啟動(dòng)會(huì)話的消息;然后該函數(shù)可以處理響應(yīng)來提取服務(wù)返回的任何有關(guān)會(huì)話的信息。下面的函數(shù)向Web服務(wù)發(fā)送<login>消息并且從響應(yīng)主體中提取會(huì)話標(biāo)識(shí)符。它也可以設(shè)置服務(wù)返回的Web服務(wù)控制的URL。//createandsendloginmessageandprocessresultsfunctionlogin(){varbody=<login><username>{$user.username}</username><password>{$user.password}</password></login>;varresponse=ws.invoke(body);//setsessionidsessionId=string(response.body.sfdc:result.sfdc:sessionId);//setURLforsubsequentcalls(fromthisconduit)ws.endPoint=string(response.body.sfdc:result.sfdc:serverUrl);}$userXML變量包含關(guān)于當(dāng)前用戶的信息;它是所有函數(shù)可訪問的系統(tǒng)變量。每個(gè)對(duì)話式方法可以指定包含會(huì)話標(biāo)識(shí)符的頭,下面(普通)的管道函數(shù)首先檢查對(duì)話是否開始(如果還沒有的話,調(diào)用login),然后返回恰當(dāng)?shù)念^XML片斷。//createconversationalheaderfunctioncreateHeader(){if(sessionId==null){login();}return<SessionHeader><sessiondId>{sessionId}</sessiondId></SessionHeader>;}例如,下面的XScript函數(shù)實(shí)現(xiàn)Web服務(wù)所需要的自定義會(huì)話管理。/***@mas:operationtype="select"keyref="app:contactAcoountRef"inverse="true"*@mas:transformtype="request"function="selectContacts_request"*@mas:transformtype="response"function="selectContacts_response"*/functionselectContacts($msg,$source){$msg.header+=createHeader();returnws.invoke($msg);}函數(shù)被傳遞進(jìn)消息對(duì)象$msg中,該對(duì)象包含由請(qǐng)求變換創(chuàng)建的主體。接著,函數(shù)調(diào)用createHeader()函數(shù)來獲得包含必要頭信息的XML對(duì)象。如果會(huì)話當(dāng)前還沒有開始,則該函數(shù)觸發(fā)(上述)login()函數(shù)。然后將頭對(duì)象添加到消息中。invoke()函數(shù)然后發(fā)送消息(包含頭)給Web服務(wù);它使用指定控制所提供的傳輸。用戶信息$user變量包含關(guān)干正調(diào)用管道操作所代表的用戶的數(shù)據(jù)??蛻舳司幊棠P陀脩艨梢酝ㄟ^在MAS上引用應(yīng)用的URL來訪問應(yīng)用。用戶第一次從客戶機(jī)進(jìn)行該操作,應(yīng)用的所有組件都可以從服務(wù)器自動(dòng)“下載”。如果應(yīng)用開發(fā)者只指定了應(yīng)用的一個(gè)數(shù)據(jù)模型,則可以下載該數(shù)據(jù)模型的元數(shù)據(jù)。元數(shù)據(jù)可以包含足夠的信息來讓移動(dòng)瀏覽器提供應(yīng)用的最小用戶接口。使用元數(shù)據(jù),移動(dòng)瀏覽器可以最初顯示根節(jié)點(diǎn)及其keyref。用戶可以通過點(diǎn)擊這些keyref來導(dǎo)航應(yīng)用數(shù)據(jù)。當(dāng)用戶選擇keyref時(shí),數(shù)據(jù)同步引擎異步地取出該keyref的節(jié)點(diǎn)并自動(dòng)顯示數(shù)據(jù)(當(dāng)可用時(shí))。例如,用戶可以遍歷Account鏈接來使得取出Account節(jié)點(diǎn);然后遍歷Account的Contactskeyref來瀏覽該Account的Contacts。該模型能起到作用,但不是特別令人滿意—UI生硬,并且由于沒有預(yù)取出數(shù)據(jù)而經(jīng)歷“不平穩(wěn)”(jerkey)。這部分描述應(yīng)用程序員如何才能自定義用戶接口。程序員有兩種基本物件用來自定義客戶端應(yīng)用。第一種是“模板”,它可以用來提供數(shù)據(jù)集的自定義用戶接口。程序員可以使用“模板”附加自定義的方法來呈現(xiàn)(render)節(jié)點(diǎn)和節(jié)點(diǎn)集,“模板”可以是具有嵌入的SPath表達(dá)式的XHTML模板,用來從數(shù)據(jù)模型和嵌入元素訪問數(shù)據(jù)以在節(jié)點(diǎn)集上重復(fù)。偶爾連接的數(shù)據(jù)模型自身作為源自魔術(shù)變量$root的大的虛擬XML文檔提供。在一個(gè)實(shí)施例中,數(shù)據(jù)模型中存在“當(dāng)前”位置(例如,Account或Account的Contacts),并且模板可以通過另一魔術(shù)變量$current可得到它。URL可以表示分支到另一模板和該模板內(nèi)的新“當(dāng)前”數(shù)據(jù)(例如,到Account、到其Contacts)。盡管模板可以以XHTML表示,它們可以包含對(duì)XHTML模型自身的重要擴(kuò)展,這“部分”將在下面說明。它允許比HTML通常所提供的(但當(dāng)客戶端也是控制器時(shí)也是可以的)更豐富的交互UI。第二種物件讓程序員脫機(jī)地完成頁(yè)面中的按鈕和URL。每個(gè)URL可以引用以(也放在客戶目錄中的)頁(yè)面流文件(controller.xpf)中的XML的ECMAScript(又稱為JavaScript)編寫的“action”(動(dòng)作)。該文件包含一組腳本“動(dòng)作”。動(dòng)作具有對(duì)數(shù)據(jù)模型的完全訪問權(quán),從而它們可以計(jì)算值、修改客戶端上的數(shù)據(jù),從而觸發(fā)延遲的同步,顯式地觸發(fā)同步和深選擇,調(diào)用自定義操作,或者引起導(dǎo)航來將當(dāng)前值(currency)設(shè)置為數(shù)據(jù)模型的另一部分??刂破髦械拿總€(gè)“動(dòng)作”可以返回?cái)?shù)據(jù)模型內(nèi)的新當(dāng)前值(或者如果動(dòng)作實(shí)際上不改變數(shù)據(jù)模型內(nèi)的“當(dāng)前值”,則返回CONTINUE)和通常該當(dāng)前值的上下文中使用的特定模板。例如,頁(yè)面中列出Contacts來查看有關(guān)Contacts的動(dòng)作可以僅僅是一個(gè)liner,用來將當(dāng)前值設(shè)為有關(guān)Contacts并且使用Contact列表模板來顯示它們,大致像下面這樣functionshowContactsForAccount($account){$context.account=$account;return[$account.@@contacts.*,"ContactsTemplate.tmpl"];}模型視圖控制器MAS客戶端應(yīng)用可以由頁(yè)面流文件(controller.xpf)和一組頁(yè)面模板(.tmpl)構(gòu)成,頁(yè)面流文件可以包含XScript動(dòng)作和函數(shù)??蛻舳丝梢跃S持應(yīng)用數(shù)據(jù)的本地高速緩存。該數(shù)據(jù)是由偶爾連接的數(shù)據(jù)模型描述并且使用SPath引用和操控的。面板是包含嵌入的SPath表達(dá)式的XHTML頁(yè)面。這些表達(dá)式可以引用高速緩存中的任何數(shù)據(jù)和系統(tǒng)變量及函數(shù)。由于模板只能引用本地?cái)?shù)據(jù),因此它們可以獨(dú)立于機(jī)器的網(wǎng)絡(luò)連接狀態(tài)提供(即,允許用戶脫機(jī)運(yùn)行應(yīng)用)。系統(tǒng)變量$current可以為數(shù)據(jù)加入光標(biāo);$current引用單個(gè)節(jié)點(diǎn)或節(jié)點(diǎn)列表。$current的值可以由調(diào)用系統(tǒng)函數(shù)的動(dòng)作和錨(anchor)改變。系統(tǒng)變量$context可以提供動(dòng)作和模板交換臨時(shí)變量的機(jī)制。例如,模板可以將輸入字段綁定到context變量或高速緩存內(nèi)的節(jié)點(diǎn)元素。模板也可以包括重復(fù)器,后者在數(shù)據(jù)或數(shù)據(jù)模式的指定部分上迭代。重復(fù)器允許模板自動(dòng)建立復(fù)雜的列表和表格,并且允許用戶選擇各個(gè)記錄并且對(duì)它們調(diào)用動(dòng)作。頁(yè)面流機(jī)制響應(yīng)于用戶接口和外部事件調(diào)用動(dòng)作。用戶接口事件可以由模板內(nèi)的<a>錨觸發(fā);外部事件可以由到數(shù)據(jù)的外部同步更新觸發(fā)。當(dāng)應(yīng)用首次開始時(shí),它可以調(diào)用頁(yè)面流內(nèi)的begin()動(dòng)作,確定要顯示的第一模板。動(dòng)作可以是由模板和外部事件調(diào)用的XScript函數(shù)。動(dòng)作可以修改數(shù)據(jù),以及模板可訪問的$current和$context變量。系統(tǒng)變量$page引用當(dāng)前可見的頁(yè)面文檔;這允許動(dòng)作訪問頁(yè)面控制特性。當(dāng)$page或$current系統(tǒng)變量被動(dòng)作改變時(shí)可以發(fā)生導(dǎo)航??蛻舳薱ab保存<$pagex$currentx$context>變量的歷史棧。這允許用戶在歷史中來回導(dǎo)航,并且允許模板保存它們的上下文(以及,例如,輸入元素的邊界值)。XScriptSPath表達(dá)式客戶端編程模型可以使用XML的ECMAScript(E4X,XScript),后者本質(zhì)上是自然支持XML的JavaScript;SPath是類似XPath的語(yǔ)言,它允許應(yīng)用查詢XML數(shù)據(jù)圖。它使用“點(diǎn)”運(yùn)算符來“遍歷”圖內(nèi)的元素。元素可以常規(guī)XML元素或數(shù)據(jù)節(jié)點(diǎn)。XML操作系統(tǒng)變量可以用‘$’符號(hào)作前綴,并且是無法歸類的(untyped)。其他變量的使用由XScript規(guī)范定義。下面的聲明創(chuàng)建變量foo和bar。foo=100;varbar="Alchemy";Var關(guān)鍵字將變量放在當(dāng)前函數(shù)的局部范圍之內(nèi),未聲明Var的變量被放在全局范圍中。下面的聲明將foo的值設(shè)為新創(chuàng)建的XML對(duì)象varfoo=<foo>Alchemy</foo>;也可以如下創(chuàng)建和引用復(fù)合的XML對(duì)象varfoo=<foo><bar>Alchemy</bar></foo>;varbar=foo.barbar=="Alchemy"XML對(duì)象也可以聲明屬性,后者使用‘@’運(yùn)算符引用,例如varfoo=<fooid="100"><bar>Alchemy</bar></foo>;varid=foo.@id;可以隱式地添加屬性(即,擴(kuò)展)foo.@ping="200";下面的例子改變<bar>元素的文本值varfoo=<foo><bar>Alchemy</bar></foo>;foo.bar="MAS";foo==<foo><bar>MAS</bar></foo>下面的例子取代整個(gè)<bar>元素varfoo=<foo><bar>Alchemy</bar></foo>;for.bar=<foobar>Mobilized</foobar>foo==<foo><foobar>Mobilized</foobar></foo>+=運(yùn)算符用于向已有父元素添加或插入新的XML元素,例如varfoo=<foo><bar>Alchemy</bar></foo>;for.bar+=<bar>Mobilized</bar>foo==<foo><bar>Alchemy</bar><foobar>Mobilized</foobar></foo>相反,使用delete(刪除)運(yùn)算符來移除元素。varfoo=<foo><bar>Alchemy</bar></foo>;deletefoo.barfoo==<foo></foo>數(shù)據(jù)圖操作偶爾連接的數(shù)據(jù)模型可以作為具有顯式變量$root的虛擬XML文檔面向開發(fā)者,變量$root指向數(shù)據(jù)模型中的根節(jié)點(diǎn)。可以通過keyref定義并且使用@@運(yùn)算符在虛擬XML文檔中建模到相關(guān)節(jié)點(diǎn)的導(dǎo)航。節(jié)點(diǎn)操控在本文檔中,術(shù)語(yǔ)節(jié)點(diǎn)用于指示數(shù)據(jù)模型節(jié)點(diǎn)。例如,下面的例子創(chuàng)建XML元素。varaccount=<account><name>Acme</name><type>Direct</type></account>在一個(gè)實(shí)施例中,當(dāng)將XML元素插入(當(dāng)前使用create()函數(shù))數(shù)據(jù)高速緩存中時(shí),將其當(dāng)作節(jié)點(diǎn)??梢酝ㄟ^在keyref上調(diào)用create()函數(shù)創(chuàng)建新節(jié)點(diǎn)。例如,下面的例子創(chuàng)建了新account節(jié)點(diǎn)。$root.@@accounts.create(<account><name>BrooklynIndustries</name></account>);可以使用常規(guī)SPath表達(dá)式引用和修改節(jié)點(diǎn)元素內(nèi)包含的數(shù)據(jù)。下面的例子改變$contact節(jié)點(diǎn)內(nèi)的元素的字面值。account.name="AcmeLtd";也可以通過賦值在節(jié)點(diǎn)內(nèi)創(chuàng)建新XML元素,例如account.address=<address><street>335Madison</street><zip>11211</zip></address>數(shù)據(jù)操作節(jié)點(diǎn)類型之間的關(guān)系可以由偶爾連接的數(shù)據(jù)模型中的keyref定義來定義。例如,下面的聲明指定accoutskeyref源自根節(jié)點(diǎn),并且包含由模式定義的account類型的節(jié)點(diǎn)。<keyrefname="accounts"sourceType="mas:root"targetType="app:account">在客戶端編程模型中,可以使用@@運(yùn)算符遍歷keyref。例如$root.@@accountskeyref()函數(shù)也可以用于引用指定的keyref。下面的例子與下面例子等效$root.keyref("accounts")keyref可以認(rèn)為是對(duì)指定的父節(jié)點(diǎn)引用keyref。下面的例子引用$root節(jié)點(diǎn)的accountskeyref的所有account節(jié)點(diǎn)。$root.@@accounts.*$root.keyref("accounts").*該表達(dá)式返回節(jié)點(diǎn)集,其中每個(gè)節(jié)點(diǎn)將是account類型,例如<account><name>Acme</name></account><account><name>Bancroft</name></account>[]運(yùn)算符可以用于訪問節(jié)點(diǎn)集內(nèi)的特定節(jié)點(diǎn)。下面的表達(dá)式返回accounts節(jié)點(diǎn)集中的第一個(gè)節(jié)點(diǎn)。$root.@@accounts.*length()函數(shù)可以用來返回節(jié)點(diǎn)集中的節(jié)點(diǎn)數(shù)。$root.@@accounts.*.length()要注意,這與下面返回值1(一)的表達(dá)式非常不同。$root.@@accounts.length()即,$root.@@accounts返回單個(gè)元素<accounts>??梢允褂貌捎肧Path表達(dá)式作為參數(shù)的where()函數(shù)過濾數(shù)據(jù)圖。例如,下面的語(yǔ)句將accountskeyref中的所有contact節(jié)點(diǎn)與指定的姓匹配并且返回節(jié)點(diǎn)列表。$root.@@accounts.*.where(.name=="Acme");要注意,這與下面的表達(dá)式等效。$root.@@accounts.*.(thisXML.name=="Acme");where子句可以求出節(jié)點(diǎn)列表,并且后面可以跟有SPath表達(dá)式。例如,下面的表達(dá)式返回名為“Acme”的所有帳戶的聯(lián)系人的節(jié)點(diǎn)列表。$root.@@accounts.*.where(.name=="Acme").@@contacts.*;標(biāo)簽每個(gè)節(jié)點(diǎn)類型聲明可以定義標(biāo)簽,標(biāo)簽是引用節(jié)點(diǎn)的SPath表達(dá)式。lable()函數(shù)返回計(jì)算出的串。<p>{$context.account.label()}</pKeyref也可以定義由label()函數(shù)返回的標(biāo)簽。<p>{$root.@@accounts.label()}</p>節(jié)點(diǎn)的標(biāo)簽是由label()函數(shù)獲得的。例如當(dāng)節(jié)點(diǎn)或keyref被其自身引用時(shí),強(qiáng)制自動(dòng)調(diào)用label()函數(shù)。下面的例子與上面例子等效。<p>{$context.account}</p><p>{$root.@@accounts}</p>名字空間在客戶端編程模型中,可以在應(yīng)用自己的缺省名字空間中實(shí)現(xiàn)所有的操作。缺省名字空間是使用setDefaultNamespace函數(shù)設(shè)置的。functionbegin(){$pageFlow.setDefaultNamespace("http://example.com/");...}這將缺省應(yīng)用名字空間自動(dòng)加到所有XML操作中。例如,下面的表達(dá)式varaccount=<account><name>Acme</name></account>;生成下面的XML<accountxmlns="http://example.com/"><name>Acme</name></account>系統(tǒng)變量和函數(shù)引用這一節(jié)說明可以擴(kuò)展ECMAScript以用于XML標(biāo)準(zhǔn)的系統(tǒng)變量和函數(shù)。系統(tǒng)變量所有的系統(tǒng)變量可以用‘$’符號(hào)作前綴;用戶變量按照慣例也可以使用‘$’符號(hào)??蚣芏x下面的系統(tǒng)變量,它們可以從模板和動(dòng)作引用客戶端數(shù)據(jù)模型可以表示應(yīng)用的持久數(shù)據(jù)。然而,應(yīng)用可能需要臨時(shí)存儲(chǔ)在頁(yè)面變換過程中維持的信息,而不是同步到MAS;這可能例如用于實(shí)現(xiàn)“剪貼板”、“向?qū)А焙推渌囗?yè)面進(jìn)程。開發(fā)者能夠創(chuàng)建$context和$session內(nèi)的新變量。$context$context變量表示調(diào)用動(dòng)作可能希望傳遞到模板的額外數(shù)據(jù)。這與JPF中的前向豆(forwardbean)或者HTTPGET屬性類似。上下文變量可以作為歷史的一部分預(yù)留。$session$session變量表示應(yīng)用的“會(huì)話”狀態(tài);與$context對(duì)象不同,它不作為歷史的一部分存儲(chǔ)。它典型地用于存儲(chǔ)與整個(gè)應(yīng)用(即,不是特定頁(yè)面)有關(guān)的信息。這些變量在應(yīng)用的生存期內(nèi)存活,并且當(dāng)應(yīng)用(和瀏覽器)關(guān)閉和啟動(dòng)時(shí)不變和消失(dehydrate)。例如,下面的函數(shù)可以用于設(shè)置用戶定義的count狀態(tài)變量。functiononExternalSync(){$ession.count=$root.@@message.*.length();}每個(gè)頁(yè)面于是可以包括下面的XHTML片斷,每當(dāng)約束狀態(tài)變量改變時(shí)其將自動(dòng)被更新。<p>Youhave{$session.count}messages.</p><p>Click<ahref="$pageFlow.navigate($root.@@messages.*,′showMessages.tmpl′)">here</a>toseethem</p>$current$current變量表示節(jié)點(diǎn)(或節(jié)點(diǎn)列表),并且典型地由模板將其與相對(duì)SPath表達(dá)式一起用來將UI元素綁定到數(shù)據(jù)。$user$user變量包含關(guān)于正調(diào)用管道操作所代表的用戶的數(shù)據(jù)。該對(duì)象包括下面字段。$history$history變量可以由控制器修改。$history變量可以實(shí)現(xiàn)下面的函數(shù)。$pageflow$pageFlow對(duì)象支持下面的函數(shù)。$globalApp$globalApp變量實(shí)現(xiàn)下面的函數(shù)。數(shù)據(jù)模型函數(shù)在節(jié)點(diǎn)上定義下面的函數(shù)在keyref上定義下面的函數(shù)元數(shù)據(jù)函數(shù)客戶端編程模型可以允許開發(fā)者訪問描述應(yīng)用的部分元數(shù)據(jù)。meta()數(shù)據(jù)模型元數(shù)據(jù)可以通過在節(jié)點(diǎn)或keyref上調(diào)用meta()函數(shù)來訪問,例如$root.meta();$root.keyref("accounts").meta();在meta對(duì)象上定義下面的函數(shù)schema()在schema對(duì)象上定義下面的函數(shù)例如,下面的模板例子使用嵌套重復(fù)器構(gòu)造標(biāo)識(shí)keyref層次的表。<netuirepeaterid="s1"source=$root.keyref(′*′)"iterator=$i"><ul><netui:repeaterid="s2"source="$1.selected.meta().schema().keyref(′*′)"iterator="$j"><li>{j}</li></netui:repeater></ul></netui:repeater>對(duì)于CRM用途的情況將產(chǎn)生下面的輸出。accounts·owner·subAccounts·quoteRequests·contacts·notes·events·tasks偶爾連接的數(shù)據(jù)模型上面部分中描述的數(shù)據(jù)模型可以作為虛擬的XML文檔面向開發(fā)者,具有指向根節(jié)點(diǎn)的顯式變量$root。在一個(gè)實(shí)施例中,移動(dòng)瀏覽器總是具有數(shù)據(jù)模型內(nèi)的當(dāng)前位置(作為上下文)(例如,特定帳戶或帳戶集)。模板和腳本可以通過另一顯式變量$current訪問該當(dāng)前位置。圖中示出CRM應(yīng)用的示意圖900;應(yīng)用定義了六種節(jié)點(diǎn)類型Account,Contact,Note,Event,Task和QuoteRequest。框架生成描述整個(gè)應(yīng)用數(shù)據(jù)模型的XML模式。這可以使用應(yīng)用模式和keyref定義來生成。例如,CRM應(yīng)用具有下面的模式<?xmlversion="1.0"?><xsd:schematargetNamespace="http://example.com/"elementFormDefault="qualified"attributeFormDefault="unqualified"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:mas="run:bea.com"xmlns="http://example.com/"><xsd:elementname="graph"><xsd:complexType><xsd:sequence><xsd:elementref="root"minOccurs="1"maxOccurs="1"><xsd:elementref="account"maxOccurs="unbounded"><xsd:elementref="contact"maxOccurs="unbounded"><xsd:elementref="note"maxOccurs="unbounded"><xsd:elementref="event"maxOccurs="unbounded"><xsd:elementref="task"maxOccurs="unbounded"><xsd:elementref="quoteRequast"maxOccurs="unbounded"></xsd:sequence></xsd:complexType></xsd:element>...</xsd:schema><graph>元素可以表示應(yīng)用數(shù)據(jù)模型的頂級(jí)元素;這可以包含恰好一個(gè)<root>節(jié)點(diǎn)聲明,加上每個(gè)應(yīng)用模式的每個(gè)節(jié)點(diǎn)的無限實(shí)例(account,contact,note,event,task和quoteRequest)。<root>元素可以被$root系統(tǒng)變量引用。由于根節(jié)點(diǎn)是特殊的系統(tǒng)類型,因此根節(jié)點(diǎn)內(nèi)不包含用戶數(shù)據(jù)對(duì)象。$root.@@accounts.*;偶爾連接的數(shù)據(jù)模型可以定義應(yīng)用節(jié)點(diǎn)類型,這些可以從應(yīng)用模式和keyref定義構(gòu)建。例如,下面的例子詳述account節(jié)點(diǎn)類型;它包含模式元素(name和type)和keyref定義(owner,subAccounts,contacts,notes,events,tasks和quotes)。<xsd:elementname="account"><xsd:complexType><xsd:sequence><xsd:elementname="name"type="xsd:string"/><xsd:elementname="type"type="accountType"/></xsd:sequence><xsd:attributename="ownerId"/><xsd:attributename="parentAccountId"/></xsd:complexType></xsd:element>帳戶節(jié)點(diǎn)定義定義了在服務(wù)器上定義的相應(yīng)模式所描述的元素(和可能的屬性)。如上所述,keyref定義確定從帳戶節(jié)點(diǎn)的可能的遍歷。例如varuser=account.@@owner;varcontacts=$root.@@accounts.*.@@contacts.*;類似地,下面的例子定義contact節(jié)點(diǎn)類型。<xsd:elementname="contact"><xsd:complexType><xsd:sequence><xsd:elementname="salutation"type="contactSalutationEnum"/><xsd:elementname="first"type="xsd:string"/><xsd:elementname="last"type="addressType"/><xsd:elementname="email"type="xsd:string"/></xsd:sequence><xsd:attributename="accountId"/><xsd:attributename="ownerId"/></xsd:complexType></xsd:element>下面的XML示出用戶如何訪問該數(shù)據(jù)的客戶端模型(盡管決不會(huì)有實(shí)際的XML文件看起來像這樣)。<graph><rootaccounts="a1a2"/><accountid="a1"owner="bob"contacts="c1c2"notes="n1"events="e1"tasks="t1"><name>Acme</name><type>Direct</type></account><accountid="a2"owner="bob"contacts="c3"><name>Bancroft</name><type>Web</type></account><contactid="c1"owner="bob"events="e2"tasks="t2"><salutation>Mr</salutation><first>Roger</first><last>Reed</last><email>roger@acme.com</email></contact><contactid="c2"owner="bob"notes="n2"><salutation>Ms</salutation><first>Sarah</first><last>Smith</last><email>sarah@acme.com</email></contact><contactid="c2"owner="bob"notes="n2"><salutation>Ms</salutation><first>Sarah</first><last>Smith</last><email>sarah@acme.com</email></contact><noteid="n1"><title>ROIinformation</title><body>AttacheddocumentdetailsROIforproduct</body></note><noteid="n2"><title>Customerrequirements</title><body>Attacheddocumentpresentscustomer′scurrentandanticipatedneeds</body></note><eventid="e1"assigned="fred"><title>Salesmeeting</title></event><eventid="e2"assigned="fred"><title>Productdemonstration</title></event><taskid="t1"assigned="fred"><title>PrepareRFPforsalescall</title><status>Notstarted</status></task><taskid="t2"assigned="fred"><title>Sendwhitepapertocustomer</title><status>completed</status></task></graph>概述在一個(gè)實(shí)施例中,客戶端有兩種方式修改數(shù)據(jù)圖。第一,可以將模板中的輸入元素直接綁定到數(shù)據(jù)節(jié)點(diǎn);該機(jī)制允許用戶修改屬于已有節(jié)點(diǎn)的XML元素而不需要代碼。第二,(并且是典型地)模板調(diào)用修改數(shù)據(jù)的動(dòng)作。在一個(gè)實(shí)施例中,這些對(duì)數(shù)據(jù)的改變并不同步地送到服務(wù)器。相反,后臺(tái)進(jìn)程同步與服務(wù)器的更新。實(shí)際上,由于整個(gè)頁(yè)面流機(jī)制可以獨(dú)立于網(wǎng)絡(luò)(服務(wù)器)連接運(yùn)行,因此將典型地存在多個(gè)對(duì)數(shù)據(jù)的脫機(jī)改變,其將在一旦建立連接時(shí)與服務(wù)器同步和協(xié)調(diào)。編程模型也可以實(shí)現(xiàn)用于拖延更新或插入的記錄的同步。例如,可以創(chuàng)建表示訂購(gòu)單的節(jié)點(diǎn),但用戶可能不想將其同步,直到所有行式項(xiàng)目被添加并點(diǎn)擊“提交”按鈕為止。服務(wù)器可能由于與其他用戶的樂觀的并發(fā)沖突,或者由于外部應(yīng)用錯(cuò)誤而拒絕同步請(qǐng)求。每個(gè)節(jié)點(diǎn)具有由框架管理的同步狀態(tài)。這可以允許應(yīng)用顯示標(biāo)記,該標(biāo)記指示哪個(gè)記錄是掛起同步、最新或被服務(wù)器拒絕。模式確認(rèn)當(dāng)create()和update()函數(shù)被調(diào)用時(shí),框架進(jìn)行下面操作A)按照應(yīng)用模式確認(rèn)對(duì)象,并且確認(rèn)所有要求的外關(guān)鍵字;B)確保高速緩存與可以在反方向上遍歷的關(guān)系(即,反向關(guān)系)一致。如果任一條件不滿足,則產(chǎn)生運(yùn)行時(shí)錯(cuò)誤。此外,當(dāng)調(diào)用link()或unlink()函數(shù)(+=/-=運(yùn)算符)時(shí)實(shí)施關(guān)鍵字/keyref一致。創(chuàng)建節(jié)點(diǎn)下面的動(dòng)作可以使用create()函數(shù)創(chuàng)建節(jié)點(diǎn)。varpo=<purchaseOrder><date>03/12/05</date></purchaseOrder>;po.lineItems+=<lineItem><prodId>ABC</prodId><qty>100</qty></lineItem>po.lineItems+=<lineItem><prodId>XYZ</prodId><qty>200</qty></lineItem>節(jié)點(diǎn)po可以通過XML賦值表達(dá)式(第一行)構(gòu)建。第二和第三表達(dá)式修改XML節(jié)點(diǎn)。然而,節(jié)點(diǎn)直到create()函數(shù)被調(diào)用之前不需要被確認(rèn)。更新節(jié)點(diǎn)類似地,應(yīng)用可以通過直接訪問節(jié)點(diǎn)的數(shù)據(jù)來修改已有節(jié)點(diǎn)。例如,下面的節(jié)點(diǎn)檢索特定訂購(gòu)單,然后改變狀態(tài)并添加新的行式項(xiàng)目po=$account.@@purchaseOrders.where(.date=="03/12/05").*;po.status="getQuote";po.lineItems+=<lineItem><prodId>DEF</prodId><qty>300</qty></lineItem>$po.update();再次調(diào)用update()函數(shù)來確認(rèn)節(jié)點(diǎn)。創(chuàng)建節(jié)點(diǎn)可以使用create()函數(shù)來在客戶端上創(chuàng)建新節(jié)點(diǎn)。varnode=sourceNode.@@keyref.create(<node>[,callback,id);可以在支持插入管道操作的keyref上調(diào)用該函數(shù)。該函數(shù)返回節(jié)點(diǎn)對(duì)象。例子例如,下面的XScript構(gòu)建指定$account對(duì)象的contactskeyref內(nèi)的新contact節(jié)點(diǎn)。varcontact=<contact><salutation>Mr</salutation><first>Sydney</first><last>James</last><email>sydney@james.com</email></contact>;node=account.@@contacts.create(contact);典型地用三個(gè)階段創(chuàng)建節(jié)點(diǎn)首先動(dòng)作創(chuàng)建context變量,然后使得顯示模板。functioninit(){$context.contact=<contact><salutation/><first/><last/><email/></contact>;return["editContact.tmpl"];}接著,模板將輸入控制綁定到各個(gè)context元素。<inputtype="text"netui:bind="$context.email"/>接著,模板調(diào)用第二動(dòng)作;框架在調(diào)用動(dòng)作之前自動(dòng)將HTML輸入值變換回context變量。動(dòng)作然后創(chuàng)建新節(jié)點(diǎn)。functioncreate(){$context.contact=$account.@@contacts.create($context.contact);return["showContact.tmpl"];}在上面的例子中,動(dòng)作用create()函數(shù)構(gòu)建的節(jié)點(diǎn)取代當(dāng)前context變量($context.contact);這允許下一模板(showContact.tmpl)引用創(chuàng)建的節(jié)點(diǎn)。要注意,在調(diào)用create()函數(shù)之前,$context.contact只包含合式的XML元素;然后,它指向確認(rèn)的節(jié)點(diǎn)(例如,支持各個(gè)節(jié)點(diǎn)函數(shù)的節(jié)點(diǎn))。在一個(gè)實(shí)施例中,定義insert管道操作的keyref允許創(chuàng)建節(jié)點(diǎn),并且嘗試在無效節(jié)點(diǎn)集上創(chuàng)建節(jié)點(diǎn)將引起運(yùn)行時(shí)錯(cuò)誤?;亟衏reate()函數(shù)也可以指定回叫函數(shù),在同步機(jī)制接收到來自服務(wù)器的關(guān)于節(jié)點(diǎn)已被創(chuàng)建的應(yīng)答(即,相關(guān)管道操作成功返回新主關(guān)鍵字)時(shí)調(diào)用回叫函數(shù)。例如functionfoo(account,quote){node=account.@@requests.create(quote,bar);}functionbar(request){$context.lastRequest=request;}回叫函數(shù)可以被傳遞作為參數(shù)的所創(chuàng)建節(jié)點(diǎn)。更新節(jié)點(diǎn)update()函數(shù)可以用于同步在客戶端上修改的節(jié)點(diǎn)。node.update([callback,id]);在支持更新管道操作的keyref上調(diào)用函數(shù)??梢允褂贸R?guī)XScript表達(dá)式修改節(jié)點(diǎn)。對(duì)于創(chuàng)建的節(jié)點(diǎn),同步作為后臺(tái)進(jìn)程運(yùn)行。然而,除非調(diào)用update()函數(shù),否則修改的節(jié)點(diǎn)不會(huì)被標(biāo)記同步。update()函數(shù)可以將相關(guān)節(jié)點(diǎn)的syncState屬性設(shè)置為MODIFIED(修改后的)。該機(jī)制可以允許在節(jié)點(diǎn)被同步之前對(duì)單個(gè)節(jié)點(diǎn)進(jìn)行多次編輯。例子在下面的代碼中,頭兩個(gè)表達(dá)式可以將$contact節(jié)點(diǎn)的syncState設(shè)置為DSYNC;而后一個(gè)表達(dá)式可以將syncState設(shè)置為MODIFIED。contact.first="Bob";contact.address=<address><zip>10017</zip></address>;$contact.update();回叫update()函數(shù)也可以指定回叫函數(shù),在同步機(jī)制接收到來自服務(wù)器的關(guān)于節(jié)點(diǎn)已被更新的應(yīng)答(即,相關(guān)管道操作成功)時(shí)調(diào)用回叫函數(shù)。例如functionfoo(account,quote){quote.update(bar);}functionbar(request){$context.lastRequest=request;}回叫函數(shù)可以被傳遞作為參數(shù)的所創(chuàng)建節(jié)點(diǎn)。沖突管理在一個(gè)實(shí)施例中,當(dāng)客戶端試圖修改和同步已經(jīng)被更新(由另一客戶端或其他外部改變進(jìn)程)的“失效”節(jié)點(diǎn)時(shí),發(fā)生節(jié)點(diǎn)沖突。失效節(jié)點(diǎn)是具有與服務(wù)器保存的當(dāng)前序列號(hào)不同的序列號(hào)的節(jié)點(diǎn)。如果服務(wù)器由于節(jié)點(diǎn)失效而拒絕更新,則它返回最新節(jié)點(diǎn),同步狀態(tài)屬性設(shè)置為“conflict”。更新操作可以設(shè)置回叫,當(dāng)從服務(wù)器返回節(jié)點(diǎn)時(shí)(不管是否有沖突)調(diào)用回叫。如果沒有設(shè)置回叫,則客戶端框架自動(dòng)用服務(wù)器返回的最新節(jié)點(diǎn)替代客戶端的失效節(jié)點(diǎn)。呼叫函數(shù)應(yīng)當(dāng)首先使用syncState()系統(tǒng)函數(shù)測(cè)試沖突狀態(tài)。它必須設(shè)置應(yīng)用的全局變量(即,$session),例如,functionupdateCallback(node){if(node.syncState()==CONFLICT){$session.message="<ahref=′showConflict()′>editconflicts</a>";$session.conflict=node;}}為了通知用戶發(fā)生了沖突,每個(gè)模板可以包括狀態(tài)區(qū)域,該區(qū)域引用該全局變量,例如,<netui:html>$session.message}</netui:html>這里,全局變量包含HTML錨,其允許用戶導(dǎo)航到用來顯示沖突編輯器頁(yè)面的動(dòng)作functionshowConflict(){$context.node=$session.conflict;$return["showConflict.tmpl"];下面showConflict模板并排顯示失效節(jié)點(diǎn)和最新節(jié)點(diǎn)的值。Spath表達(dá)式調(diào)用對(duì)數(shù)據(jù)節(jié)點(diǎn)定義的conflict()函數(shù);這返回最新節(jié)點(diǎn)。注意,盡管沖突節(jié)點(diǎn)可能包含外關(guān)鍵字值,但@@運(yùn)算符不能從沖突節(jié)點(diǎn)遍歷。<p>Contactrecordconflictedwithserver.</p><formnetui:action=$pageFlow.updateConflict()"><table><tbody><tr><td>First</td><td>{$context.node.conflict().first}</td><td><inputtype="text"netui:bind="$context.node.first"/></td></tr><tr><td>Last</td><td>{$context.node.conflict().last}</td>td><inputtype="text"netui:bind="ontext.node.last"/></td></tr><tr><td>Email</td><td>{$context.node.conflict().email}</td><td><inputtype="text"netui:bind="$context.node.email"/></td></tr><trcolspan="3"><td><inputtype="submit"value="Create"/></td></tr></tbody></table></form><ahref="copyValues($context.node)">Copyserver′srecord.</a>如果按下提交按鈕,則窗體調(diào)用下面的updateConflict()動(dòng)作functionupdateConflict(){$context.node.update();$tatus.message=null;$status.conflict=null;return["BACK"];}這調(diào)用當(dāng)前節(jié)點(diǎn)上的update()函數(shù),其觸發(fā)同步機(jī)制來再次嘗試。這里,控制器立即返回到在用戶點(diǎn)擊狀態(tài)區(qū)域之前顯示的前一頁(yè)面。上面模板還定義在點(diǎn)擊時(shí)調(diào)用下面copyValues()動(dòng)作的錨functioncopyValues(node){node.copy(node.conflict());return["CONTINUE"];}該動(dòng)作將最新節(jié)點(diǎn)值復(fù)制到失效節(jié)點(diǎn)中,并且返回到showConflict頁(yè)面。鏈接和解除鏈接節(jié)點(diǎn)在一個(gè)實(shí)施例中,使用link()函數(shù)來將節(jié)點(diǎn)(或節(jié)點(diǎn)列表)添加到表示一對(duì)多關(guān)系的keyref。node.@@keyref.link(nodeList);要注意,nodeList參數(shù)必須引用已經(jīng)創(chuàng)建的節(jié)點(diǎn)。使用unlink()函數(shù)來從表示一對(duì)多關(guān)系的keyref中移除節(jié)點(diǎn)(或節(jié)點(diǎn)列表)。node.@@keyref.unlink(nodeList);例子,下面的函數(shù)從current(contact)節(jié)點(diǎn)的相關(guān)keyref中移除所有“Web”帳戶。然后它鏈接傳遞進(jìn)函數(shù)的單個(gè)newAccount節(jié)點(diǎn)。functionfoo(newAccount){contact=$current.@@accounts.*.whete(.type=="Web");current.@@accounts.unlink($contact);contact.@@account.link(newAccount);}錯(cuò)誤處理當(dāng)管道操作失敗時(shí),服務(wù)器可以生成錯(cuò)誤對(duì)象并將其返回到客戶端。該錯(cuò)誤對(duì)象被返回到應(yīng)用的回叫函數(shù);該對(duì)象具有對(duì)應(yīng)于上述模式的特性。錯(cuò)誤對(duì)象被返回到應(yīng)用的回叫函數(shù);該對(duì)象具有對(duì)應(yīng)于上述模式的特性。functionupdateNode(node){node.update(updateCallback,<token/>)}functionupdateCallback(id,error){varmsg=error.message;varnode=error.node();varfields=error.field.*;}該錯(cuò)誤對(duì)象還可以實(shí)現(xiàn)field()函數(shù),該函數(shù)用于訪問各個(gè)錯(cuò)誤字段,例如,varmsg=error.field(spath).message;自定義對(duì)象模板和動(dòng)作都不能直接存取外部資源(例如,Web服務(wù))。相反,外部進(jìn)程被模型化為由MAS框架同步的數(shù)據(jù)對(duì)象。多數(shù)管道操作可以映射到節(jié)點(diǎn)實(shí)體上的CRUD操作(即,選擇、創(chuàng)建、更新等),這些操作直接對(duì)應(yīng)于客戶端編程模型函數(shù)(導(dǎo)航、創(chuàng)建、更新等)。然而,典型地,不可能將所有Web服務(wù)操作映射到框架的標(biāo)準(zhǔn)操作上。例如,Web服務(wù)操作可能需要從多個(gè)節(jié)點(diǎn)元素構(gòu)成或者包含用戶輸入的臨時(shí)值的參數(shù)集。在這些情況下,應(yīng)用定義包含Web服務(wù)操作的輸入和輸出參數(shù)的自定義節(jié)點(diǎn)類型。這種機(jī)制稱為自定義草走。create()函數(shù)可以用來與創(chuàng)建普通節(jié)點(diǎn)相同的方式創(chuàng)建新的自定義對(duì)象。varresultNodes=customNode.@@keyref-B.*;自定義操作典型地不實(shí)現(xiàn)相應(yīng)keyref的插入管道操作。相反,自定義對(duì)象被用作觸發(fā)選擇管道操作的隨后遍歷的上下文。例如,varresultNodes=customNode.@@keyref-B.*;下面的圖示出keyref聲明例子下面的例子假設(shè)具有下面原型的Web服務(wù)操作xsd:doublesubmitQuote(xsd:stringprodId,xsd:integerqty);操作采用prodId和qty輸入?yún)?shù),并且返回price值。這需要包含prodId和qty參數(shù)以及price響應(yīng)字段的節(jié)點(diǎn)類型的自定義XML模式定義。與普通節(jié)點(diǎn)一樣創(chuàng)建自定義節(jié)點(diǎn)。例如,下面的XML表示合式的quoteRequest元素。<quoteRequest><prodId/><qty>0</qty></quoteRequest>典型地,調(diào)用動(dòng)作通過賦值包含缺省值的合式XML對(duì)象來創(chuàng)建context變量。下面的例子創(chuàng)建quoteRequest元素并且使控制器導(dǎo)航到inputRequest模板。functioninitiateRequest(){$context.request=<quoteRequest><prodId/><qty>0</qty></quoteRequest>;return["inputRequest.tmpl"];}模板將<input>元素綁定到各個(gè)字段值。<table><tbody><tr><td>ProductID</td><td><inputnetui:bind="$context.quoteRequest.prodId"/></td></tr><tr><td>Quantity</td><td><inputnetui:bind="$context.quoteRequest.qty"/></td></tr><tr><tdcolspan="2"><inputtype="submit"value="Submit"onClick="submitQuoteRequest()"/></td></tr></tbody></table>模板具有提交按鈕,其調(diào)用submitRequest動(dòng)作來從合式的quoteRequest元素創(chuàng)建節(jié)點(diǎn)。functionsubmitQuoteRequest(){$current.@@quotes.create($context.request);return["showRequests.tmpl";}create()函數(shù)立即返回標(biāo)記為新創(chuàng)建的節(jié)點(diǎn)以便同步。與創(chuàng)建普通節(jié)點(diǎn)一樣,同步作為后臺(tái)進(jìn)程進(jìn)行。因此,動(dòng)作使導(dǎo)航器顯示當(dāng)前quoterequest集。showRequests模板引用模板的輸入和輸出值。要注意,新創(chuàng)建的請(qǐng)求的response.price元素將最初返回空值。<netui:repeaterid="$quotes"source="$current.@@quotes.*"iterator="$i"><tr><td>{$i.prodId}</td><td>{$i.qty}</td><td>{$i.response.price}</td></tr></netui:repeater>有時(shí)同步機(jī)制可以將創(chuàng)建的節(jié)點(diǎn)發(fā)送給服務(wù)器,后者將調(diào)用相關(guān)自定義操作。如果成功,則創(chuàng)建<response>元素并且將節(jié)點(diǎn)同步回服務(wù)器。<quoteRequest><prodId>Widget-Z</prodId><qty>1000</qty><response><price>2000.00</price></response></quoteRequest>如果showRequests模板仍然可見,則客戶端框架使得再次提出模板,這將更新相應(yīng)表行。選擇節(jié)點(diǎn)可以在任何keyref上調(diào)用select()函數(shù)并且不立即返回值。該函數(shù)不能在模板內(nèi)調(diào)用。node.@@keyref.select(spath,[callback,id]);也可以在根節(jié)點(diǎn)上調(diào)用select()函數(shù)$root.select(spath,[callback,id]);該機(jī)制允許客戶端請(qǐng)求由SPath表達(dá)式描述的虛擬XML文檔的部分的同步。例如,下面表達(dá)式請(qǐng)求當(dāng)前高速緩存內(nèi)的所有帳戶的所有聯(lián)系人。$root.@@accounts.*.select(@@contacts.*);下面表達(dá)式請(qǐng)求從根節(jié)點(diǎn)可訪問的所有帳戶的所有聯(lián)系人。$root.select(@@accounts.*.@@contacts.*);在一個(gè)實(shí)施例中,SPath表達(dá)式不引用局部函數(shù),并且,表達(dá)式不引用無法被解析成非純量值的局部變量。表達(dá)式被傳遞給服務(wù)器,后者將表達(dá)式轉(zhuǎn)換成相應(yīng)XPath表達(dá)式。用謂詞選擇某些keyref可能較大而難以完全同步到客戶端。在這些情況下,客戶端能夠使用where()函數(shù)過濾keyref。例如,下面的選擇表達(dá)式使得只同步匹配where()謂詞的帳戶節(jié)點(diǎn)。$root.select(@@acounts.*.where(.type=="Web"));下面表達(dá)式選擇匹配上述帳戶的所有聯(lián)系人。$root.select(@@acounts.*.where(.type=="Web")).contacts.*;下面表達(dá)式選擇(所有帳戶的)具有匹配的電子郵件地址的所有聯(lián)系人。$root.select(@@accounts.*.@@contact.*.where(.email=="bob@acme.com"));謂詞選擇機(jī)制也可以用于允許用戶預(yù)選擇將要同步的節(jié)點(diǎn)。例如,我們可以將選中的Boolean屬性添加到帳戶節(jié)點(diǎn)類型并且將其綁定到模板內(nèi)的復(fù)選框元素。<netui:repeaterid="s1"source="$root.@@accounts.*"iterator="i"><tr><td><inputtype="checkbox"netui:bind="i.@@checked"></a></td><td>{i}</td></tr></netui:repeater>下面表達(dá)式(包含在模板調(diào)用的動(dòng)作內(nèi))將使得同步機(jī)制對(duì)所有選中的帳戶檢索所有聯(lián)系人。$root.select(@@acounts.*.where(.@@checked==true).@@contacts.*);回叫回叫機(jī)制允許調(diào)用者指定在SPath的整個(gè)同步完成時(shí)要調(diào)用的函數(shù)。例如$root.select(@@accounts.*.@@contacts.*,$id,callbackFn);這個(gè)例子向服務(wù)器發(fā)送同步腳本來檢索所有帳戶的所有聯(lián)系人,并且將函數(shù)callbackFn登記為客戶端框架在同步完成時(shí)調(diào)用的回叫。$id變量被送到函數(shù)中以便表示特定的選擇調(diào)用。例子例如,本機(jī)制的一個(gè)應(yīng)用可以是讓特定應(yīng)用的所有模板包含每個(gè)頁(yè)面的底部處的“狀態(tài)條”元素,其綁定到臨時(shí)數(shù)據(jù)值(例如,$session.message)。<p>Status:<span>{$session.message}</span></p>可以從用回叫啟動(dòng)選擇的一個(gè)模板調(diào)用動(dòng)作。q1="Q1";functionbeginSearch(email){$root.select(@@accounts.*.@@contact.*.where(.email==email),q1,onUpdate);}在這種情況下,beginSearch()函數(shù)采用表示聯(lián)系人電子郵件地址的參數(shù),并且選擇(所有帳戶的)具有匹配電子郵件地址元素的所有聯(lián)系人。用戶定義的回叫函數(shù)onUpdate()在同步請(qǐng)求完成時(shí)被調(diào)用。functiononUpdate(id){if(id==q1){$session.message=+"Receivedresults.";}...}該函數(shù)將id輸入變量與傳遞進(jìn)上述select()函數(shù)的請(qǐng)求常數(shù)匹配;然后它改變$ession.message變量,使得任何綁定到該變量的模板被刷新。同步通常,同步可以在后臺(tái)運(yùn)行。在一個(gè)實(shí)施例中,用戶對(duì)同步有影響的唯一控制是當(dāng)選擇操作完成時(shí)登記回叫。然而,當(dāng)創(chuàng)建或修改節(jié)點(diǎn)時(shí),有時(shí)需要確保將一組操作作為邏輯上完整的單元來執(zhí)行。要注意,這比起要求完全交互語(yǔ)義來是較低的限制。例如,下面的函數(shù)改變聯(lián)系人的名和姓,以及引用該帳戶節(jié)點(diǎn)的外關(guān)鍵字。functionfoo(contact,account){contact.first=$context.first;contact.last=$context.last;contact.@@accountId=account;}在一個(gè)實(shí)施例中,當(dāng)創(chuàng)建或修改節(jié)點(diǎn)時(shí),它們自己的同步狀態(tài)設(shè)為DSYNC(延遲同步)。然而,直到控制器調(diào)用的原始動(dòng)作沒有錯(cuò)誤地返回,才安排它們同步。這時(shí)所有標(biāo)為DSYNC的節(jié)點(diǎn)被改為MODIFIED。動(dòng)作可以調(diào)用后繼動(dòng)作,在這種情況下,最外面的動(dòng)作形成該隱式轉(zhuǎn)換的范圍。客戶端框架實(shí)現(xiàn)(每個(gè)應(yīng)用)單線程的動(dòng)作模型。這包括由輸入的同步消息調(diào)用的動(dòng)作和由框架進(jìn)行的同步消息的處理。因此,可以在動(dòng)作內(nèi)操作到“亂碼”(clobber)數(shù)據(jù)的輸入同步更新。在一些情況下,高速緩存將被調(diào)用一系列模板的頁(yè)面流(例如,“向?qū)А?更新。在這些情況下,為了將同步延遲直到整個(gè)頁(yè)面流成功完成為止,應(yīng)用必須創(chuàng)建或?qū)?fù)制相關(guān)數(shù)據(jù)到上下文變量中。然后最終頁(yè)面流動(dòng)作更新高速緩存。用戶延遲的同步有時(shí),用戶將希望延遲明顯的同步,直到準(zhǔn)備好提交記錄為止(例如,通過按下提交按鈕)。例如,下面的模板顯示(帳戶的)訂購(gòu)單列表以及每個(gè)項(xiàng)目的復(fù)選框。復(fù)選框被綁定到用于確定項(xiàng)目狀態(tài)的屬性。<netui:repeaterid="s1"source="$account.@@purchaseOrders.*"iterator="i"><tr><td><inputtype="checkbox"netui:bind="i.@@complete"></a></td><td>{i}</td></tr></netui:repeater><inputtype="submit"onClick="$pageFlow.submit()"/>提交按鈕調(diào)用submit()動(dòng)作,后者對(duì)所有被設(shè)置為完成的訂購(gòu)單調(diào)用update()。funcitonsubmit(){for(i=0;i<$accounts.@@purchaseOrders.*.length();i++)varpo=$account.@@purchaseOrders.*[i];if(po.syncState()=="DSYNC"&&po.@@complete==true){$po.update();}}}這個(gè)例子需要外部系統(tǒng)解釋complete屬性的含義;即,延遲處理記錄(同時(shí)管理持久性),直到用戶設(shè)置了適當(dāng)?shù)闹禐橹埂D0迥0蹇梢允菢?gòu)成應(yīng)用的用戶接口的合式(并且有效)的XHTML頁(yè)面。模板典型地引用高速緩存中的數(shù)據(jù),它們也可以導(dǎo)致調(diào)用動(dòng)作。在一個(gè)實(shí)施例中,模板不包含可直接修改數(shù)據(jù)圖的腳本表達(dá)式。模板可以引用用作光標(biāo)的$current系統(tǒng)變量;$current引用單個(gè)節(jié)點(diǎn)或節(jié)點(diǎn)列表。在一個(gè)實(shí)施例中,$current的值只能由調(diào)用系統(tǒng)函數(shù)的動(dòng)作和錨改變,這稱為導(dǎo)航。模板還包含重復(fù)器,其在指定部分?jǐn)?shù)據(jù)或數(shù)據(jù)模型上迭代。重復(fù)器允許模板自動(dòng)建立復(fù)雜的列表和表格,并且允許用戶能夠選擇各個(gè)記錄并對(duì)它們調(diào)用動(dòng)作或?qū)Ш健O到y(tǒng)變量$context可以提供一種動(dòng)作和模板交換臨時(shí)變量的機(jī)制。例如,模板可以將輸入字段綁定到上下文變量或數(shù)據(jù)節(jié)點(diǎn)元素。當(dāng)模板調(diào)用動(dòng)作時(shí),頁(yè)面的輸入值被自動(dòng)同步回到綁定的變量。模板可以通過定義HTML<a>錨來生成事件,當(dāng)用戶電極它們時(shí)觸發(fā)。在一個(gè)實(shí)施例中,錨具有三種不同的用途1)導(dǎo)航錨可以指定SPath表達(dá)式(例如,$current.@@orders.*),這導(dǎo)致控制器改變$current變量指向不同的節(jié)點(diǎn)或節(jié)點(diǎn)集,這稱為導(dǎo)航。系統(tǒng)可以提供可將特定模板與一定節(jié)點(diǎn)類型和keyref相關(guān)聯(lián)的元數(shù)據(jù),允許瀏覽器自動(dòng)選擇適當(dāng)?shù)哪0濉?)調(diào)用系統(tǒng)函數(shù)框架可以實(shí)現(xiàn)各種修改應(yīng)用的行為的系統(tǒng)函數(shù)。例如,navigate()函數(shù)導(dǎo)航到特定模板并且設(shè)置$current變量;select()函數(shù)(在重復(fù)器內(nèi)調(diào)用)用于從列表或表格中選擇特定節(jié)點(diǎn)。3)調(diào)用動(dòng)作4)動(dòng)作可以處理綁定到在前模板的上下文變量并且執(zhí)行計(jì)算或修改數(shù)據(jù)。然后動(dòng)作可以直接返回到當(dāng)前頁(yè)面,在這種情況下,更新任何數(shù)據(jù)綁定式控制并且刷新顯示。動(dòng)作也可以使控制器改變$current和$page變量,導(dǎo)致發(fā)生導(dǎo)航。同步可以在后臺(tái)進(jìn)行??蛻舳藙?chuàng)建和修改的節(jié)點(diǎn)經(jīng)過各種同步狀態(tài),這些狀態(tài)對(duì)于模板也是可以通過系統(tǒng)函數(shù)訪問的,并且可以顯示給用戶。此外來自服務(wù)器的同步更新使綁定到相關(guān)節(jié)點(diǎn)的模板立即更新。表達(dá)式估值在一個(gè)實(shí)施例中,模板可以通過引用花括號(hào)內(nèi)的SPath表達(dá)式將來自高速緩存的數(shù)據(jù)直接并入頁(yè)面。估值的表達(dá)式的結(jié)果作為常規(guī)XHTML對(duì)待。例如,下面的表達(dá)式顯示當(dāng)前節(jié)點(diǎn)的標(biāo)簽。<p>{$current.label()}</p>在一個(gè)實(shí)施例中,在每次刷新頁(yè)面時(shí)估值花括號(hào)內(nèi)包含的表達(dá)式。當(dāng)從動(dòng)作控制傳回控制時(shí)刷新頁(yè)面。因此,花括號(hào)內(nèi)包含的表達(dá)式可以用于定義XHTML標(biāo)志的動(dòng)態(tài)值。例如,下面的表達(dá)式估值變量$context.address的內(nèi)容并且將結(jié)果放入錨標(biāo)志的href屬性中<ahref="{$context.address}">Click</a>動(dòng)作可以改變?cè)撋舷挛淖兞康闹?context.address="mailto:alchemy@bea.com";這將導(dǎo)致當(dāng)控制傳回到頁(yè)面時(shí)生成下面的XHTML表達(dá)式<ahref="mailto:alchemy@bea.com">Click</a>系統(tǒng)變量這部分詳細(xì)說明在一個(gè)實(shí)施例中歷史棧上維持的三個(gè)系統(tǒng)變量($current,$context,和$page)。$current$current變量引用節(jié)點(diǎn)列表(一個(gè)或多個(gè)節(jié)點(diǎn))。這可以是對(duì)節(jié)點(diǎn)或節(jié)點(diǎn)集的顯式引用,或者是產(chǎn)生節(jié)點(diǎn)列表的估值SPath表達(dá)式。設(shè)計(jì)模板來處理單個(gè)節(jié)點(diǎn)或節(jié)點(diǎn)列表。$current保證指向單個(gè)節(jié)點(diǎn)。此外,$current.length()表達(dá)式可以用來檢測(cè)節(jié)點(diǎn)列表中的節(jié)點(diǎn)數(shù)。例如,CRM應(yīng)用可以實(shí)現(xiàn)accountDetail.tmpl頁(yè)面,期望$current指向單個(gè)帳戶節(jié)點(diǎn)。<html><head><metacurrent="node"/><title>AccountDetail</title></head><body><p>Account:{$current}</p><ahref="$pageFlow.navigate($current.@@contacts.*,′contacts.tmpl′)">Contacts</a>...</body></html>相反,contacts.tmpl頁(yè)面期望$current包含所有帳戶的整個(gè)聯(lián)系人集合。<html><head><metacurrent="nodelist"/><title>Contacts</title></head><body><table><tbody><tr><netui:repeaterid="$contacts"source="$current"iterator="$i"focused="true"><td>first</td><td>{$i.first}</td><td>last</td><td.last}</td><td>email</td><td>.email}</td><td><ahref="$.previous()">Previous</a></td><td><ahref="$s.next()">Next</a></td></netui:repeater></tr></tbody></table></body></html>這里,重復(fù)器允許用戶在聯(lián)系人節(jié)點(diǎn)的集合中循環(huán)。$context上下文變量為模板和動(dòng)作提供“便箋”來協(xié)調(diào)多頁(yè)面進(jìn)程;它們?cè)诟拍钌吓c會(huì)話變量相似。上下文變量是通過在動(dòng)作內(nèi)執(zhí)行的賦值操作創(chuàng)建的。$context.foo=100;$context.foo.bar=<bar>FooBar</bar>模板使用表達(dá)式語(yǔ)言句法引用上下文變量。<p>{$context.foo}</p><p>{$context.foo.bar}</p>動(dòng)作可以在$context對(duì)象上調(diào)用reset()函數(shù)來移除所有當(dāng)前上下文變量。$context.reset();$page$page變量包含當(dāng)前提供的模板。動(dòng)作使用它來訪問當(dāng)前提供的頁(yè)面內(nèi)的HTML控制的狀態(tài)。XHTML標(biāo)志擴(kuò)展這部分詳細(xì)說明客戶端框架支持的XHTML的擴(kuò)展。在一個(gè)實(shí)施例中,模板必須包含合式和有效的XHTML。這部分中描述的XHTML擴(kuò)展定義在netui名字空間中;所有例子需要下面的名字空間聲明。<htmlxmlns="http://www.w3.org/1999/xhtml"xmlns:netui="http://www.bea.com/netui">錨標(biāo)志<a>(錨)標(biāo)志創(chuàng)建超鏈接,用戶可以點(diǎn)擊該超鏈接來使事件觸發(fā)。錨用于導(dǎo)航、調(diào)用系統(tǒng)函數(shù)(包括選擇項(xiàng)目)以及調(diào)用動(dòng)作。錨可以指定SPath表達(dá)式(例如,$current.@@orders.*),其導(dǎo)致控制器改變$current變量的值來指向不同節(jié)點(diǎn)或節(jié)點(diǎn)集,這稱為導(dǎo)航。錨可以調(diào)用各種系統(tǒng)函數(shù)之一。例如,navigate()函數(shù)導(dǎo)航到特定模板并且設(shè)置$current變量,在重復(fù)器內(nèi)調(diào)用的select()函數(shù)用于從列表或表格中選擇特定節(jié)點(diǎn)。錨可以調(diào)用動(dòng)作,該動(dòng)作可以處理綁定到模板的上下文變量來執(zhí)行計(jì)算或修改數(shù)據(jù)。然后動(dòng)作可以直接返回到當(dāng)前頁(yè)面,在這種情況下,更新任何數(shù)據(jù)綁定式控制并且無縫地刷新顯示。動(dòng)作也可以使控制器改變$current和$page變量,導(dǎo)致發(fā)生導(dǎo)航。<ahref="ur1"/>錨可以使用下面的屬性。url屬性可以具有下面的格式錨典型地用于導(dǎo)航到不同的頁(yè)面或者選擇數(shù)據(jù)。導(dǎo)航可以通過各種方式實(shí)現(xiàn)導(dǎo)航;下面的例子都使瀏覽器導(dǎo)航到根節(jié)點(diǎn)。<ahref="$root">Example1</a><ahref="$pageFlow.navigate($root,′bar.tmpl′)">Example2</a><ahref="$pageFlow.foo($root,′bar.tmpl′)">Example3</a>functionfoo($s,$p){return[$s,$p];}<ahref="$globalApp.history.home()">Example4</a>例1聲明SPath表達(dá)式,該表達(dá)式由控制器直接估值并且用于設(shè)置$current的值。例2調(diào)用系統(tǒng)navigate()函數(shù),該函數(shù)將$current設(shè)為估值的SPath表達(dá)式,并且使用可選的第二參數(shù)來設(shè)置模板。例3調(diào)用(控制器文件中定義的)用戶動(dòng)作,該動(dòng)作使用送入的參數(shù)來創(chuàng)建前向?qū)ο?數(shù)組);這與例2效果相同。例4調(diào)用home()系統(tǒng)函數(shù),該函數(shù)是在$history對(duì)象上調(diào)用的。選擇下面的例子顯示列出訂單集和通過點(diǎn)擊來“選擇”它們中的一個(gè)作為“所選”訂單。<netui:repeaterid="foo"source="$current.@@orders.*"iterator="$hisorder"><ahref="$foo.select($thisorder)">$thisorder.label()}</a></netui:repeater>下面例子一次顯示一個(gè)訂單,并且讓用戶在它們之間前后移動(dòng)。<netui:repeaterid="foo"source="$courrent.@@orders.*"iterator="$thisorder"focused="true"><tr><td>OrderID:</td><td>{$thisorder.id}</td><td>OrderDate:</td><td>{$thisorder.date}</td><td>OrderAmount:</td><td>{$thisorder.amount}</td></tr><tr><td><ahref="$foo.previous()">Previous</a></td><td><ahref="$foo.next()">Next</a></td></tr></netui:repeater>窗體在一個(gè)實(shí)施例中,為了顯示數(shù)據(jù),所有需要的是包含在花括號(hào)中的SPath。例如,如果$current指向聯(lián)系人,則下面將顯示聯(lián)系人的名字和地址<tr><td>First:</td><td>{$current.name.first}</td><td>Last:</td><td>{$current.name.last}</td></tr>但這是只讀模型。在一個(gè)實(shí)施例中,為了寫變量,除了將用戶輸入映射到數(shù)據(jù)模型的netui:bind屬性,還支持HTML窗體元素。支持下面的HTML窗體元素來綁定讀/寫變量。這些標(biāo)志的每一個(gè)都支持netui:bind屬性,該屬性使用SPath表達(dá)式引用讀/寫變量。<inputtype="intputType"netui:bind="SPath"/>SPath表達(dá)式典型地應(yīng)用$context變量。例如<inputtype="text"netui:bind="$context·address.name"/>該變量用于在提供頁(yè)面時(shí)設(shè)置輸入字段的值。當(dāng)調(diào)用提交動(dòng)作(包括通過下面的<inputtype=″submit">標(biāo)志)時(shí)或者當(dāng)導(dǎo)航發(fā)生(見上面的錨)時(shí),綁定值被寫回到該變量。輸入標(biāo)志<input>標(biāo)志是通用的輸入標(biāo)志,用于基于其type屬性值實(shí)現(xiàn)各種簡(jiǎn)單控制。<inputtype="inputType"netui:bind="spath-expr"/>框架將netui:bind屬性添加到XHTML中支持的標(biāo)準(zhǔn)屬性。支持下面類型的<input>標(biāo)志。下面的例子示出各種形式的<input>標(biāo)志。<inputtype="text"netui:bind="$context.contact.email"/><inputtype="radio"netui:bind="$context.contact.selected"value="yes"/><inputtype="radio"netui:bind="$context.contact.selected"value="no"/><inputtype="checkbox"value="chinese"netui:bind="$context.contact.langsSpoken"/><inputtype="password"netui:bind="$context.login.password"/><inputtype="hidden"netui:bind="$context.contact.MailingCountry"value="uSA"/><inputtype="button"value="pressthisbutton"/>radioradio標(biāo)志可以被分組從而可以只選擇一個(gè)值;同一邏輯組中的每個(gè)radio標(biāo)志必須綁定到相同的SPath表達(dá)式。<p>Selected:<inputtype="radio"netui:bind="$context.contact.selected"value="yes">Yes</input><inputtype="radio"netui:bind="$context.contact.selected"value="no">No</input></p>當(dāng)前選擇的控制將value屬性所指定的值綁定到SPath表達(dá)式。如果沒有指定value屬性,則設(shè)置布爾值true。提交提交類型定義onClick屬性,其與錨的方式相同(見上面)。<inputtype="submit"onClick="$pageFlow.submitContact()"/>當(dāng)點(diǎn)擊時(shí),這導(dǎo)致用當(dāng)前輸入標(biāo)志值寫(頁(yè)面上的)所有綁定變量。TextArea標(biāo)志<textarea>標(biāo)志允許用戶輸入和編輯多行文本,可以包括顯示滾動(dòng)條。<textareanetui:bind="spath-expr"/>框架將netui:bind屬性添加到XHTML中支持的標(biāo)準(zhǔn)屬性。例如,下面的XHTML元素創(chuàng)建<textarea>元素,其綁定到$context變量所引用的note節(jié)點(diǎn)的comments子元素。<textareanetui:bind="$current.note.comments"/>select標(biāo)志<select>標(biāo)志允許用戶從下降(dropdown)控制中選擇多個(gè)應(yīng)用定義的值之一。<select.netui:bind="spath-expr"/>框架將netui:bind屬性添加到XHTML中支持的標(biāo)準(zhǔn)屬性。contactType模式定義包含salutation元素,它定義有contactSalutationEnum類型。<xsd:complexTypename="contactType"><xsd:sequence><xsd:elementname="salutation"type="contactSalutationEnum"/><xsd:elementname="first"type="xsd:string"/><xsd:elementname="last"type="xsd:string"/><xsd:elementname="email"type="xsd:string"/></xsd:sequence></xsd:complexType><xsd:simpleTypename="contactSalutationEnum"><xsd:restrictionbase="xsd:string"><xsd:enumerationvalue="Mr"/><xsd:enumerationvalue="Mrs"/><xsd:enumerationvalue="Ms"/><xsd:enumerationvalue="Dr"/></xsd:restriction></xsd:simpleType>下面的XHTML用于創(chuàng)建<select>元素。<selectnetui:bind="$context.contact.salutation">可以顯式地聲明選項(xiàng)值<selectnetui:bind="$context.contact.salutation"><optionvalue="Mr">Mr</option><optionvalue="Ms">Ms</option><optionvalue="Mrs">Mrs</option><optionvalue="Dr">Dr</option></select>或者,可以使用重復(fù)器創(chuàng)建選項(xiàng)值<selectnetui:bind="$context.contact.salutation"iterator="i"><netui:repeatersource="$globalApp.schema(′contactSalutationEnum′)"><optionvalue="{$i.@value}">{$i.@value}</option></netui:repeater></select>要注意,選擇匹配netui:bind表達(dá)式的值作為缺省值。如果綁定值為null,則選擇第一選項(xiàng)。例子下面的例子將email上下文變量綁定到文本輸入字段??梢允褂么绑w的action屬性或者嵌套的錨標(biāo)志調(diào)用相應(yīng)操作。<formnetui:action="$pageFlow.inputEmailAddress()"><inputtype="text"netui:bind="$context.email"/><inputtype="submit"value="Submit"/></form>典型地,上下文變量首先在前面導(dǎo)致顯示模板的動(dòng)作中被實(shí)例化。下面的錨調(diào)用addContact()動(dòng)作<ahref="$pageFlow.addContact()"/>CreateNewContact</a>然后動(dòng)作創(chuàng)建三個(gè)上下文變量,然后命令控制器顯示addContact模板。動(dòng)作首先重置所有的已有上下文變量,然后使用賦值運(yùn)算符創(chuàng)建新變量。functionaddContact(){$context.reset();$context.account=$current;$context.salutation="";$context.first="";$context.last="";$context.email="";return["addContact.tmpl"];}addContact模板顯示具有綁定輸入字段的窗體。<formnetui:action="$pageFlow.createContact()"><table><tbody><tr><td>Title</td><td><selectnetui:bind="$context.salutation"><optionvalue="Mr">Mr</option><opticnvalue="Ms">Ms</option><optionvalue="Mrs">Mrs</option><optionvalue="Dr">Dr</option></select></td></tr><tr><td>First</td><td><inputtype="text"netui:bind="$context.first"/></td></tr><tr><td>Last</td><td><inputtype="text"netui:bind="$context.last"/></td></tr><tr><td>Email</td><td><inputtype="text"netui:bind="$context.email"/></td></tr><trcolspan="2"><td><inputtype="submit"value="Create"/></td></tr></tbody></table></form>當(dāng)包含綁定變量的模板調(diào)用動(dòng)作時(shí),可以使用當(dāng)前XHTML窗體值設(shè)置變量。在這種情況下,提交的<input>元素調(diào)用下面的窗體的createContact動(dòng)作。functioncreateContact(){$context.account.@@contacts.create(<contact><salutation>{$context.salutation}</salutation><first>{$context.first}</first><last>{$context.last}</last><email>{$context.email}</email></contact>);return["showContacts.tmpl"];}有條件的標(biāo)志可以使用<netui:if>標(biāo)志來基于計(jì)算出的條件有條件地包括XHTML段。<netui:ifcond="spath-expr">...</netui:if>cond屬性定義當(dāng)呈現(xiàn)頁(yè)面時(shí)估值的SPath表達(dá)式。如果該表達(dá)式估值為true,則<netui:if>元素內(nèi)包含的XHTML段被插入XHTML頁(yè)面。表達(dá)式使用標(biāo)準(zhǔn)XScript強(qiáng)制來估值布爾結(jié)果。下面的表達(dá)式全部估值為true{true}{100}{"somestring"}{<xml>}{root}下面的例子包括用來實(shí)現(xiàn)條件模板的<if>標(biāo)志。這里,僅當(dāng)變量為非null(即,空或零長(zhǎng)度、文本)時(shí),才顯示$current.email表列;所有其他值強(qiáng)制為true。<table><tbody><tr><td>{$current.salutation}</td><td>{$current.first}</td><td>{$current.last}</td><netui:ifcond="$current.email"><td>$current.email}</td></netui:if></tr></tbody></table>要注意,條件模板可以表示為模板設(shè)計(jì)器中的性質(zhì)頁(yè)。Repeater標(biāo)志模板合并來自數(shù)據(jù)圖和系統(tǒng)變量的規(guī)則XHTML元素和數(shù)據(jù)。它們頁(yè)可以包含當(dāng)呈現(xiàn)時(shí)生成XHTML的元素(與JSP中的Taglibs相似)。repeater是HTML生成器標(biāo)志,其在元素列表上重復(fù)(例如,帳戶的節(jié)點(diǎn)列表)。<netui:repeater>是用于重復(fù)元素的相同HTML的標(biāo)志;對(duì)在估值的SPath表達(dá)式中的每個(gè)元素重復(fù)<netui:repeater>元素的所有子元素。句法<netui:repeaterid="tag-id"source="spath-expr"[iterator="variable-name"][selected="spath-expr"[orderBy="orderBy-expr"]/>每個(gè)<netui:repeater>元素具有source屬性,描述它應(yīng)當(dāng)在其上迭代的節(jié)點(diǎn)集合。從概念上說,對(duì)于source屬性描述的每個(gè)節(jié)點(diǎn),模板內(nèi)的所有XHTML被重復(fù)。重復(fù)的XHTML段可以訪問iterator屬性引用的迭代的節(jié)點(diǎn)實(shí)例。repeater定義下面的屬性??梢栽趓epeater對(duì)象上調(diào)用下面的函數(shù)。重復(fù)部分下面的模板段定義顯示由accountskeyref定義的節(jié)點(diǎn)列表的repeater。<ul><netui:repeaterid="$repeaterl"source="$current.@@accounts.*"iterator="$i"><li>{$.label()}</li></netui:repeater></ul>這產(chǎn)生了下面的輸出對(duì)source屬性定義的節(jié)點(diǎn)列表中的每個(gè)節(jié)點(diǎn)(即,每個(gè)account節(jié)點(diǎn))重復(fù)<netui:repeater>元素內(nèi)包含的所有XHTML元素。導(dǎo)航和選擇重復(fù)的部分可能包含調(diào)用動(dòng)作或系統(tǒng)函數(shù)的錨。例如,下面的repeater顯示account的列表,顯示具有每個(gè)account標(biāo)簽的錨(超鏈接)。<ul><netui:repeaterid="$repeater1"source="$current.@@accounts.*"iterator="$i"><li><ahref="$pageFlow.navigate($i,′showDetail.tmpl′)">{$i.label()}</a></li></netui:repeater></ul>點(diǎn)擊所述錨中的一個(gè)導(dǎo)致調(diào)用系統(tǒng)導(dǎo)航函數(shù),導(dǎo)致控制器導(dǎo)航到showDetail.tmpl模板,$current設(shè)為指到相應(yīng)重復(fù)的元素的$i值所引用的節(jié)點(diǎn)。repeater實(shí)現(xiàn)內(nèi)置函數(shù)select(),該函數(shù)允許用戶從列表中選擇特定元素。例如,下面的模板段將上述節(jié)點(diǎn)列表表示為HTML錨的列表。<ul><netui:repeaterid="$repeater1"source="$current.@@accounts.*"iterator="$i"><li><ahref="$repeater1.select($i)">{$i.label()}</a></li></netui:repeater></ul>點(diǎn)擊特定錨導(dǎo)致repeater的selected屬性被設(shè)為$i變量的當(dāng)前值。面板的其他部分可以引用repeater的當(dāng)前所選值。<ul><netui:repeaterid="$repeater1"source="$current.@@accounts.*"iterator="$i"><li><ahref="$repeater1.select($i)"style={$repeater1.selected.contains($i)?"background-color:yellow":""}>{$i.label()}</a></li></netui:repeater></ul>這產(chǎn)生下面的輸出要注意,上面的<a>錨聲明style屬性,其包含SPath表達(dá)式,如果選擇相關(guān)項(xiàng),則改變?cè)氐谋尘邦伾elected屬性可以由其他repeater(稱為鏈?zhǔn)?和隨后調(diào)用的動(dòng)作訪問。重復(fù)的HTML部分也可以引用selected屬性來可視地指示當(dāng)前所選項(xiàng)。鏈?zhǔn)絩epeaterrepeater可以鏈接在一起,從而對(duì)父repeater中的元素的選擇影響子repeater中的顯示。例如,下面的repeater顯示與前面repeater中所選節(jié)點(diǎn)(Contact)相關(guān)聯(lián)的消息列表。<ul><netui:repeaterid="$repeater1"source="$current.@@accounts.*"iterator=$i"><li><ahref="$repeater1.select($i)">{$i.label()}</a></li></netui:repeater></ul><br/><ul><netui:repeaterid="$repeater2"source=$repeater1.selected.@@contacts.*"iterator="$j"><li>$j.label()</li></netui:repeater></ul>下面的模板示出嵌套的repeater,創(chuàng)建多列的顯示(在下面示出)。<table><tbody><tr><td>App</td><td>Repeater1</td><td>Repeater2</td><td>Contacts</td></tr><tr><td>{$current}</td><td><ul><netui:repeaterid="$x"source="$current.@@keyref(′*′)"iterator="$i"><li><ahref=$x.select($i)">{$i}</a></li></netui:repeater></ul></td><td><ul><netui:repeaterid="$y"source="$x.selected.*"iterator="$j"><li><ahref="$y.select($)">{$j}</a></li></netui:repeater></ul></td><td><ul><netui:repeatersource="$y.selected.@@contacts.*"iterator="$k"><li>{$k}</li></netui:repeater></ul></td></tr></tbody></table>第一repeater生成keyref錨的列表;第二repeater將其source變量綁定到前一repeater的所選節(jié)點(diǎn),并且產(chǎn)生節(jié)點(diǎn)錨的列表。最后的repeater產(chǎn)生contact節(jié)點(diǎn)的列表。要注意,該repeater的source屬性專門遍歷到contactskeyref—跳過了自動(dòng)keyref列。當(dāng)調(diào)用repeater的select()函數(shù)時(shí),它自動(dòng)地觸發(fā)模板重新顯示—修改相關(guān)repeater的source,并且將相關(guān)repeater的所選變量設(shè)為null。模板必須避免repeater之間的循環(huán)依存關(guān)系。由于模板的當(dāng)前光標(biāo)沒有改變,因此不認(rèn)為選擇機(jī)制是導(dǎo)航。上面的例子導(dǎo)致下面的顯示上述模板表示UI的導(dǎo)航部分—允許最終用戶遍歷一系列keyref。我們還可以修改UI來表示節(jié)點(diǎn)的表。例如<td><table><tbody><netui:repeatersource="$y.@@contacts.*"iterator="$k"><tr><td>{$k.email}</td><td>$k.label()}</td></tr></netui:repeater></tbody></table></td>這產(chǎn)生下面的輸出聚焦的repeaterrepeater也可以被定義為“聚焦”,意味著repeater在一個(gè)時(shí)刻僅顯示一個(gè)元素并且保持光標(biāo),而不是在source屬性定義的整個(gè)元素集合上迭代。可以在聚焦的repeater對(duì)象上調(diào)用下面的額外函數(shù)。在下面的例子中,focus屬性聲明要顯示的節(jié)點(diǎn)集中的單個(gè)節(jié)點(diǎn)。下面的動(dòng)作調(diào)用包含聚焦的repeater的模板并且將$current設(shè)為與指定帳戶的contactkeyref有關(guān)的節(jié)點(diǎn)列表functionselectContacts($account){$context.cursor=$account.*;return[$account.*,"focusedContacts.tmpl"];}錨調(diào)用repeater上的函數(shù),該函數(shù)移動(dòng)repeater的光標(biāo)。<netui:repeaterid="$s"source="$current"iterator="$i"><netui:ifcond="$a.position($context.cursor)==$i.count()"><td>first</td><td>($i.first}</td><td>last</td><td>$i.last}</td><td>email</td><td>($i.email}</td></netui:if></netui:repeater><netui:ifcond="$s.position($context.cursor)>0"><ahref="$context.cursor=$current[$s.position($context.cursor)-1]">previous</a></netui:if><netui:ifcond="$s.position($context.cursor)<($s.length()-1)"><ahref="$context.cursor=$current[$s.position($context.cursor)+1]">next</a></netui:if>這產(chǎn)生下面的輸出默認(rèn)地,聚焦的repeater設(shè)置光標(biāo)指向$current節(jié)點(diǎn)列表中的第一節(jié)點(diǎn)。如果定義了selected屬性,則使用它來將光標(biāo)涉到適當(dāng)?shù)墓?jié)點(diǎn)(通常由通過前一動(dòng)作設(shè)置的上下文變量定義)。<netui:repeaterid="$s"source="$current"iterator="$i"selected="$context.selected"><td>first</td><td>{$i.first}</td><td>last</td><td>{$i.last}</td><td>email</td><td>{$i.email}</td></netui:repeater>排序的repeaterrepeater可以通過聲明orderBy屬性來指定枚舉元素的順序。orderBy屬性是包含類似XQuery的表達(dá)式的串<netui:repeaterid="id"source="source"iterator="var"orderBy="OrderByClause">其中OrderByClause遵從下面的BNF語(yǔ)法(SPath表達(dá)式表示特定repeater項(xiàng)的字段值)OrderByClause::=OrderSpec(","OrderSpec)*OrderSpec::=SPathOrderModifierOrderModifier::=("ascending"|"descending")?(("empty""greatest")|("empty""least"))?("collation"StringLiteral)?要注意,表達(dá)式假設(shè)穩(wěn)定順序(即,應(yīng)當(dāng)在多個(gè)調(diào)用上預(yù)留相等值的順序)。例如,下面的repeater通過contact的姓(即,$i.last)的降序值列出contact。<netui:repeaterid="$s"source="$current.@@contacts.*"iterator="$i"orderBy="$i.lastdescending"><td>last</td><td>{$i.last}</td><td>first</td><td>{$i.first}</td><td>email</td><td>{$i.email}</td></netui:repeater>下面的repeater按照姓以升序(即,缺省)排序,然后按照名以降序排序。<netui:repeaterid="$s"source="$current.@@contacts.*"iterator="$i"orderBy="$i.lastemptyleast,$i.firstdescending">要注意,在上面的例子中,空的姓值被認(rèn)為是最低的。元數(shù)據(jù)Repeaterrepeater也可以用于在數(shù)據(jù)模型定義的元數(shù)據(jù)上重復(fù)。例如,node.keyref(′*′)函數(shù)返回keyref元素的列表,該元素描述從相應(yīng)節(jié)點(diǎn)類型可能的導(dǎo)航。這可以用作repeater用來顯示keyref列表的source。<ul><netui:repeaterid="$repeater1"source="$current.@@keyref(′*′)"iterator="$i"><li>{$i.label()}</li></netui:repeater></ul>如果$current指向account節(jié)點(diǎn),上面的例子將返回下面的輸出·subAccounts·contacts·notes·events·qutotesnode.schema()函數(shù)返回表示相應(yīng)節(jié)點(diǎn)類型的XML模式定義的XML文檔。這可以用作repeater用來構(gòu)建輸入窗體的source。<netui:repeaterid="repeater1"source="$current.meta().schema()"showNull="true"iterator="$i"><tr><td>{$current.meta().schema().getFieldLabel($i)}</td><td>{$i)</td></tr></netui:repeater>上面的例子產(chǎn)生下面的輸出圖像標(biāo)志標(biāo)準(zhǔn)XHTML<img>標(biāo)志用于顯示圖像。<img[src="filename"][netuicontent="spath-expr"[netuitype="content-type"]/>圖像標(biāo)志定義下面的屬性。除了標(biāo)準(zhǔn)XHTML屬性外,框架支持netui:content和netui:type屬性來聲明SPath表達(dá)式,引用包含圖像的二進(jìn)制源的元素。這要求節(jié)點(diǎn)類型之一在其XML模式定義內(nèi)定義適合的元素。例如,擴(kuò)展下面的contact模式來并入<image>數(shù)據(jù)元素。<xsd:complexTypename="contactType"><xsd:sequence><xsd:elmntname="salutation"type="contactSalutationEnum"/><xsd:elementname="first"type="xsd:string"/><xsd:elementname="last"type="xsd:string"/><xsd:elementname="email"type="xsd:string"/><xsd:elementname="image"type="xsd:base64Binary"/></xsd:sequence></xsd:complexType>這將被認(rèn)為使用下面的XHTML<imgnetui:content="$current.contact.image"netui:type="bmp"/>include標(biāo)志標(biāo)準(zhǔn)<netui:include>標(biāo)志用于插入引用的<netui:includetemplate="templateFile"[$current="spath-expr"/>include標(biāo)志定義template屬性,該屬性為要插入到當(dāng)前頁(yè)面的模板名命名??蛇x的current屬性用于在插入的模板的范圍內(nèi)設(shè)置$current變量。例如,下面的XHTML段擴(kuò)展鏈?zhǔn)絩epeater示例,并且并入新的顯示(對(duì)特定Acccount,$y)的Contacts列表的repeater($z)。<netui:include>標(biāo)志包括detail.tmpl模板,并且將其$current變量定義為repeater的所選節(jié)點(diǎn)(即,contact節(jié)點(diǎn))。<td><ul><netui:repeaterid="$z"source="$y.@@contacts.*"iterator="$k"><li><ahref="select($k)">{$k}</a></li></netui:repeater></ul></td><td><netui:includecurrent="$z.selected"template="detail.tmpl"/></td>detail.tmpl模板定義如下。<td><table><tbody><tr><td>Detail</td></tr><tr><td>{$current.label()}</td></tr><tr><td>{$current.email}</td></tr></tbody></table></td>這產(chǎn)生下面的輸出。HTML標(biāo)志<netui:html>標(biāo)志用于將原始XHTML插入到當(dāng)前頁(yè)面。<netui:html>{spath-expr}</netui:html>通常,估值SPath表達(dá)式并且結(jié)果值被轉(zhuǎn)換為串,而不是處理為HTML。然而,在開和閉<netui:html>標(biāo)志之間包含的所有估值SPath表達(dá)式作為要由瀏覽器處理的HTML插入到頁(yè)面中。例如,給定下面的動(dòng)作代碼$current.productDesc="<p>A<b>great</b>newproduct.</p>";下面的模板HTML將返回下面的輸出<netui:html>{$current.productDesc}</netui:html>Agreatnewproduct.可以在<netui:html>元素內(nèi)組合HTML和表達(dá)式。例如,下面的模板HTML將返回下面的輸出<netui:html><ul><li>$current.productDesc}</li><li>{$current.productDetail}</li><ul></netui:html>·Agreatnewproduct.·FromthepeoplewhobroughtyouWebLogic.控制器控制可以負(fù)責(zé)響應(yīng)于外部同步消息處理用戶接口和數(shù)據(jù)庫(kù)引起的事件??刂破骺梢允沟脠?zhí)行動(dòng)作腳本并且瀏覽器實(shí)例化和顯示模板??刂破鞯娜笔⌒袨榭梢酝ㄟ^實(shí)現(xiàn)controller.xpf來擴(kuò)展,后者是用XML的ECMAScript書寫,并且本質(zhì)上是JPF的EMACScript版本??刂破魑募梢园瑒?dòng)作和規(guī)則ECMAScript函數(shù)和全局變量定義。頁(yè)面流controller.xpf文件可以定義應(yīng)用的頁(yè)面流。應(yīng)用的客戶端部分包括控制器定義、動(dòng)作和面板集??刂破魑募梢园╔Script函數(shù)和動(dòng)作定義。動(dòng)作由面板(和其他動(dòng)作)調(diào)用,并且可以訪問相同的$root、$current和$context變量;它們不能直接修改$current變量—相反,它們返回前向陣列(forwardarray),其被控制器轉(zhuǎn)換用來確定$current和$page的值。動(dòng)作能夠修改和添加新$context變量,該變量用于向/從頁(yè)面?zhèn)鬟f狀態(tài)。該上下文狀態(tài)也存儲(chǔ)在歷史棧上。每個(gè)應(yīng)用定義控制器文件,后者至少應(yīng)當(dāng)包括開始函數(shù)(或動(dòng)作)的定義;當(dāng)運(yùn)行應(yīng)用時(shí)調(diào)用它。至少,開始函數(shù)應(yīng)當(dāng)返回包含要顯示的第一模板的文件名的前向陣列。functionbegin(){return["home.tmpl"];}前向陣列前向陣列是XScript對(duì)象(即,串、變量、SPath表達(dá)式)的陣列,被控制器轉(zhuǎn)換用來確定要顯示的下一模板(即,$page變量),以及設(shè)置$current系統(tǒng)變量的值。定義了下面的前向?qū)ο蟮念愋颓跋蜿嚵锌梢园ㄈ我忭樞虻那跋驅(qū)ο?。它不能包括多個(gè)SPath表達(dá)式、多個(gè)模板文件名或者模板文件名和導(dǎo)航串常數(shù)(例如,“CONTINUE”)。下面的都是合法的前向陣列。return["BACK"]return["home.tmpl"];return["home.tmpl",$root.@@accounts.*];return[nextAction];return[];要注意,什么也不返回或者返回空的前向陣列的動(dòng)作不修改$page和$current變量;這與返回[“CONTINUE”]是等效的。在下面的例子中,動(dòng)作使用上下文變量來執(zhí)行計(jì)算并且在成功的情況下導(dǎo)航到showOrder模板。出錯(cuò)的情況下,動(dòng)作設(shè)置錯(cuò)誤上下文變量并且指示控制器來保持在當(dāng)前模板。functioncalulateTotal(){if($context.order.qty<=0){$context.error="Error:Quantitynotset.";return["CONTINUE"];}$context.order.total=$context.order.price*$context.order.qty;return["showOrder.tmpl"];}動(dòng)作動(dòng)作可以提供用于應(yīng)用修改數(shù)據(jù)、修改當(dāng)前模板或影響導(dǎo)航的機(jī)制。例如,動(dòng)作可以創(chuàng)建或更新數(shù)據(jù)節(jié)點(diǎn),計(jì)算特定節(jié)點(diǎn)集上的總數(shù)或?qū)g覽器重定向到數(shù)據(jù)模型的另一部分。由于在一個(gè)實(shí)施例中,模板只能訪問存儲(chǔ)在本地?cái)?shù)據(jù)高速緩存(或$context)中的數(shù)據(jù),因此動(dòng)作提供一種(通過因特網(wǎng))與外部系統(tǒng)交互的機(jī)制。動(dòng)作由模板錨調(diào)用。動(dòng)作調(diào)用使用與常規(guī)ECMAScript函數(shù)相同的句法,除了它們作為$pageFlow(控制器)對(duì)象上的方法被調(diào)用外。$pageFlow.actionName([param1[,param2[,...]]])例子下面的錨聲明調(diào)用foo()動(dòng)作,傳遞進(jìn)串參數(shù)。<ahref="$pageFlow.foo(′world′)">Foo</a>下面示出動(dòng)作定義(在controller.xpf中定義)。functionfoo($p){$context.bar=<hello>{$p}</hello>;return["CONTINUE"];}在這種情況下,動(dòng)作設(shè)置$context變量(包含輸入?yún)?shù)的XML對(duì)象)并且返回控制到當(dāng)前模板。下面的例子返回前向?qū)ο?,改?current變量來指向accountskeyref所包含的節(jié)點(diǎn)集處。functionexamplel($p){...return[$root.@@accounts.*];}下面的例子改變$current來指向根節(jié)點(diǎn)處,并且還改變當(dāng)前模板。functionexample2($p){...return[$root,"bar.tmpl"];}定時(shí)器定時(shí)器實(shí)現(xiàn)簡(jiǎn)單的事件機(jī)制。addTimer()函數(shù)用于登記回叫函數(shù),后者是在經(jīng)過指定延遲后(或者以一定間隔)調(diào)用的。vartimerId=$pageFlow.addTimer(callback,delay[,period]);在$pagefolow對(duì)象上調(diào)用該函數(shù),并且返回唯一標(biāo)識(shí)定時(shí)器實(shí)例的標(biāo)識(shí)符。cancelTimer()函數(shù)用于取消定時(shí)器。$pageFlow.addTimer(timerId);在$pagefolow對(duì)象上調(diào)用該函數(shù),并且返回唯一標(biāo)識(shí)定時(shí)器實(shí)例的標(biāo)識(shí)符。例子在下面的例子中,函數(shù)foo()設(shè)置定時(shí)器,這立即調(diào)度bar()函數(shù),然后以1秒間隔重復(fù)。functionfoo(){vartimerId=$pageFlow.addTimer(bar,0,1000);}functionbar(timerId,count){$root.select(@@accounts.*.@@contacts.*.@@tasks.*.where(.priority==1));if(count==10){$pageFlow.cancelTimer(timerId);}}這里,回叫函數(shù)bar()調(diào)用深選擇操作,輪詢服務(wù)器以便更新SPath表達(dá)式所定義的數(shù)據(jù)集。在第10次調(diào)用時(shí)通過調(diào)用cancelTimer()系統(tǒng)函數(shù)取消定時(shí)器。瀏覽器實(shí)現(xiàn)單線程的執(zhí)行模型;因此,至少直到調(diào)用函數(shù)返回時(shí)才執(zhí)行回叫函數(shù)。歷史每次發(fā)生導(dǎo)航時(shí),<$currentx$contextx$page>元組(tuple)被放到歷史棧上,可通過$history系統(tǒng)變量訪問。調(diào)用back()系統(tǒng)動(dòng)作使得這些值被退回到前一歷史狀態(tài)。類似地,forward()將這些值移動(dòng)到下一歷史狀態(tài)。如果用戶向后移動(dòng)然后引起發(fā)生另一導(dǎo)航(即,不是向前移動(dòng)),則整個(gè)前向的歷史被截?cái)?。在歷史棧中向后和向前移動(dòng)保留所有repeater的當(dāng)前所選值;由于$context變量是歷史幀的部分,因此也保留了窗體變量。對(duì)$history對(duì)象定義的函數(shù)如上定義。頁(yè)面流例子圖10示出CRM應(yīng)用1000的一部分的簡(jiǎn)單頁(yè)面流;圖a)表示數(shù)據(jù)模型(模式和keyref)的部分;圖b)表示頁(yè)面流,它包括四個(gè)模板,每個(gè)具有指示$current節(jié)點(diǎn)類型的虛線。該情況實(shí)現(xiàn)自定義操作來啟動(dòng)對(duì)特定帳戶的報(bào)價(jià)請(qǐng)求。這個(gè)例子輸出創(chuàng)建用作選擇操作的上下文的自定義對(duì)象(報(bào)價(jià)請(qǐng)求)的處理。Home模板包含允許用戶導(dǎo)航到調(diào)用AccountDetail模板的特定帳戶的repeater(見下面)。AccountDetail模板示出前面報(bào)價(jià)列表,并且允許用戶調(diào)用createQuoteRequest動(dòng)作(A)。<ahref="$pageFlow.createQuoteRequest()">CreateQuoteRequest</a>這引起下面的動(dòng)作被調(diào)用。functioncreateQuoteRequest(){$context.quoteRequest.prodId="";$context.quoteRequest.qty=0;return["createQuoteRequest.html"];}該動(dòng)作在當(dāng)前上下文內(nèi)創(chuàng)建<quoteRequest>XML對(duì)象,并且設(shè)置prodId和qty子元素的值。要注意,這創(chuàng)建合式的<quoteRequest>元素并且與下面表達(dá)式等效$context.quoteRequest=<quoteRequest><prodId/></qty>0<qty></quoteRequest>;動(dòng)作然后返回“templeate”前向路徑,調(diào)用createQuoteRequest模板而不改變$current變量。下面示出createQuoteRequest模板。要注意,$current仍然指向account節(jié)點(diǎn)。<p>QuoteRequestfor(current.label()}</p><table><tbody><tr><td>ProductID</td><td><inputnetui:bind="$context.quoteRequest.prodId"/></td></tr><tr><td>Quantity</td><td><inputnetui:bind="$context.quoteRequest.qty"/></td></tr><tr><tdcolspan="2"><inputtype="submit"value="Submit"onClick="submitQuoteRequest()"/></td></tr></tbody></table>該模板允許用戶編輯前面動(dòng)作創(chuàng)建的<quoteRequest>元素。窗體提交動(dòng)作將當(dāng)前的窗體值復(fù)制到綁定$context變量,然后調(diào)用下面的submitQuoteRequest動(dòng)作(B)。functionsubmitQuoteRequest(){if($context.quoteRequest.prodId?。剑ⅲ?context.quoteRsquest.qty<=0}{return["CONTINUE"];}else{$current.@@quoteRequests.create($context.quoteRequest);return["BACK"];}}動(dòng)作執(zhí)行對(duì)<quoteRequest>元素值的驗(yàn)證,并且如果有錯(cuò)誤則返回模板(CONTINUE)。否則,它將<quoteRequest>元素添加到當(dāng)前account的quoteRequestskeyref。要注意,$context.quoteRequest變量是包含由窗體綁定的值的合式的<quoteRequest>元素,例如<quoteRequest><prodId>widget-Z</prodId><qty>1000</qty></quoteRequest>一旦成功,動(dòng)作導(dǎo)航“BACK”到前一AccountDetail模板(BACK)。下面的AccountDetail模板顯示同步的priceQuote的列表。<p>Account:{$current}</p><td>ProductID</td><td>Quantity</td><td>price</td><netui:repeatersource="$current.@@quoteRequests.*"iterator="i"><td>{$i.prodId}</td><td>{si.qty}</td><td>{si.@@quote.price}</td></netui:repeater><ahref="$pageFlow.createQuoteRequest()}">CreateQuoteRequest</a>該模板將產(chǎn)生下面的顯示要注意,上面的submitQuoteRequest動(dòng)作立即返回,從而新的quoteRequest節(jié)點(diǎn)將直到服務(wù)器用同步的quote節(jié)點(diǎn)響應(yīng)時(shí)才顯示價(jià)格字段。構(gòu)建原型為了構(gòu)建并運(yùn)行圓形,需要安裝下面的應(yīng)用ApacheAnt,SunjavaJDK,Perforce客戶端,BEAWorkshop8.1。還應(yīng)當(dāng)設(shè)置下面的環(huán)境變量。該指南假設(shè)Perforce客戶端已經(jīng)被安裝,并且具有//alchemy/mas到C:\alchemy\mas的映射。使用下面的命令同步最近的源代碼并且重建框架。C:\alchemy\mas>p4syncC:\alchemy\mas>antrebuild運(yùn)行應(yīng)用可以通過瀏覽器的antbuild文件(\alchemy\mas\src\browser\build.xml)調(diào)用原型瀏覽器。定義下面的運(yùn)行時(shí)變量例如,下面的命令調(diào)用瀏覽器,運(yùn)行具有指定窗口大小的導(dǎo)航器應(yīng)用。ant-f..\..\src\browser\bulid.xml-Dmas.appname=crm-Dclient.geometry=400x200run創(chuàng)建批處理文件(例如,run.bat)來調(diào)用該命令是很方便的。還可以通過設(shè)置下面的環(huán)境變量來配置瀏覽器特性變量可以包括下面的設(shè)置例如,下面的命令在客戶端模式中運(yùn)行瀏覽器并且打開數(shù)據(jù)持久性。setMAS_PROPS=-Dmas.singleproc=false-Dpersistent=true要注意,通過在Windowshosts文件(C:\WINDOWS\SYSTEM32\DRIVERS\ETC\hosts)中聲明物理IP地址,可以將服務(wù)定義(管道元文件)中定義的Web服務(wù)URL映射到物理服務(wù)器上,例如,下面的hosts文件聲明將上面的Web服務(wù)映射到alchemy測(cè)試服務(wù)器。172.17.33.34example.com調(diào)試所有出錯(cuò)和跟蹤信息被寫入到\alchemy\mas\alchemy.log文件中。應(yīng)用封裝下面的表表示對(duì)單獨(dú)的MAS應(yīng)用的文件和目錄結(jié)構(gòu)。apps/應(yīng)用根目錄appName/應(yīng)用子目錄run.bat客戶端啟動(dòng)腳本schemas/*.xsd應(yīng)用節(jié)點(diǎn)類型metadata/*.xml管道元和keyrefclient/客戶端應(yīng)用文件control.xpf頁(yè)面流文件*.tmpl模板文件.mas/高速緩存文件(客戶端/服務(wù)器)workshop/演示的WS項(xiàng)目原型加載shemas和meta目錄中的所有文件。應(yīng)用根目錄(/apps)對(duì)應(yīng)于mas.approot和mas.client.approot運(yùn)行時(shí)特性(上述)。部署和管理應(yīng)用可以從(Workshop內(nèi)運(yùn)行的)MAS將應(yīng)用部署到客戶端。l.Workshop必須在運(yùn)行應(yīng)用管理服務(wù)器(見下面)。2.應(yīng)用組件(上述控制器模板、元文件和模式文件)必須首先被zip壓縮成單個(gè)文件(app.zip);為了進(jìn)行壓縮,創(chuàng)建新的zip文件,然后將整個(gè)app文件夾(例如,\mas\apps\crm)拖入WinZip中(確定沒有選中“savefullpathinfo”)。3.查看應(yīng)用管理頁(yè)面http://www.localhost.com7001/mas。注意,這可能要花一段時(shí)間。a.點(diǎn)擊“Browse...”并選擇zip文件;b.點(diǎn)擊“Deploy”將應(yīng)用上載到服務(wù)器(在上面mas.approot特性定義的位置)。4.管理頁(yè)面顯示每個(gè)應(yīng)用的部署URL。5.為了在客戶端上“install”應(yīng)用,在單進(jìn)程模式中運(yùn)行移動(dòng)瀏覽器(不指定mas.app特性);這將調(diào)用app選擇器對(duì)話框。setMAS_PROPS=-Dmas.singleproc=falseant-f..\..\src\browser\bulid.xmlrun6.輸入應(yīng)用URL到適當(dāng)?shù)木庉嬁蛑胁⑶尹c(diǎn)擊OK。運(yùn)行應(yīng)用管理服務(wù)器1.設(shè)置下面的全局環(huán)境變量setJAVA_OPTIONS=-Dmas.approot=c:\alchemy\uas\apps2.將\alchemy\mas\src\masiws.work加載到workshop中。3.在project窗格中雙擊controller.jpf文件。4.如果提醒庫(kù)升級(jí),回答yes然后點(diǎn)擊Install。忽略紅色的“couldnotbereplaced”警告是安全的。5.啟動(dòng)服務(wù)器(Tools→WebLogicServer→StartWebLogicServer)。6.在服務(wù)器被啟動(dòng)后,運(yùn)行下面的命令(忽略WebLogic的部署錯(cuò)誤是安全的)。C:\alchemy\mas>antdeploy7.從Workshop在選擇controller.jpf的情況下點(diǎn)擊運(yùn)行按鈕(綠三角)。最后(在標(biāo)準(zhǔn)慢服務(wù)器引導(dǎo)程序填充之后)你將看到枚舉安裝的應(yīng)用及其URL以及用于上載新應(yīng)用的Deploy按鈕的網(wǎng)頁(yè)。8.為客戶端應(yīng)用部署創(chuàng)建c:\temp\apps。9.設(shè)置下面的環(huán)境變量setMAS_PROPS=-Dmas.client.approot=c:\temp\apps-Dmas.singleproc=false10.運(yùn)行下面的命令C:\alchemy\mas\src\browser>antrun11.將(上面)網(wǎng)頁(yè)中列出的任何URL粘貼到對(duì)話框中并點(diǎn)擊Install。最后,該應(yīng)用將在最頂?shù)慕M合框中列出,你可以登錄。MAS模式定義應(yīng)用模式定義應(yīng)當(dāng)使用下面模式指令將公共的MAS模式文件導(dǎo)入<xsd:importnamespace="urn:bea.mas"schemaLocation="mas.xsd"/>MAS模式文件包含對(duì)所有框架XML類型的定義。<?xmlversion="1.0"encoding="UTF-8"?><xsd:schematargetNamespace="urn:bea.mas"xmlns="urn:bea.mas"xmlns:xsd="http://www.w3.org/2001/XMLSchema"elementFormDefault="qualified"attributeFormDefault="unqualified"><xsd:simpleTypename="idType"><xsd:restrictionbase="xsd:anySimpleType"/></xsd:simpleType><xsd:complexTypename="nodeSetType"><xsd:sequence><xsd:anyminOccurs="1"maxOccurs="1"/></xsd:sequence><xsd:attributename="keyref"type="xsd:string"use="required"/></xsd:complexType><xsd:complexTypename="rootType"/><xsd:elementname="root"type="rootType"/><xsd:complexTypename="graphType"><xsd:sequence><xsd:elementref="root"/></xsd:sequence></xsd:complexType><xsd:complexTypename="errorType"><xsd:sequenceminOccurs="0"maxOccurs="unbounded"><xsd:choice><xsd:elementname="pkey"type="idType"/><xsd:elementname="system"type="systemErrorType"/><xsd:elementname="message"type="xsd:string"/><xsd:elementname="field"type="fieldErrorType"/></xsd:choice></xsd:sequence></xsd:complexType><xsd:complexTypename="systemErrorType"><xsd:sequence><xsd:elementname="code"type="xsd:anySimpleType"/><xsd:elementname="message"type="xsd:string"/></xsd:sequence></xsd:complexType><xsd:complexTypename="fieldErrorType"><xsd:sequence><xsd:elementname="code"type="xsd:anySimpleType"/><xsd:elementname="message"type="xsd:string"/></xsd:sequence><xsd:attributename="xpath"type="xsd:string"/></xsd:complexType></xsd:schema>自動(dòng)用戶接口框架集成了自動(dòng)瀏覽器(稱為導(dǎo)航器),它可以用于遍歷節(jié)點(diǎn)圖。下面的輸出是使用下面的命令行句法由CRM例子產(chǎn)生的。ant-f..\..\src\browser\bulid.xml-Dmas.app=crm-Dmas.client.app=navigator導(dǎo)航器首先示出所有與root節(jié)點(diǎn)相關(guān)聯(lián)的keyref(即,accounts)。當(dāng)選擇keyref的情況下,顯示對(duì)應(yīng)節(jié)點(diǎn);在這種情況下,選擇accountskeyref并且顯示對(duì)應(yīng)的account節(jié)點(diǎn)。接著,選擇account節(jié)點(diǎn),并且顯示與account節(jié)點(diǎn)類型(即,sourceType="account")相關(guān)聯(lián)的keyref?,F(xiàn)在,當(dāng)選擇contactskeyref時(shí),顯示對(duì)應(yīng)的contact節(jié)點(diǎn)列表。該導(dǎo)航器使用與上面所述相同的模板repeater和導(dǎo)航機(jī)制。因此,可以用自定義模板、動(dòng)作和頁(yè)面流逐漸擴(kuò)展缺省導(dǎo)航器。自動(dòng)UI包括兩個(gè)模板第一個(gè)是“navigator”模板,其顯示當(dāng)前“聚焦的”節(jié)點(diǎn)($current)和用戶可以導(dǎo)航到的keyref的列表;第二個(gè)模板是特定節(jié)點(diǎn)的“具體”形式圖。在導(dǎo)航器模板中,一旦選擇了keyref,就將相關(guān)節(jié)點(diǎn)集的節(jié)點(diǎn)列表作為列表顯示。<table><tbody></tr><td><b>{$current}</b></td></tr><tr><netui:repeaterid="$x"source="$current.keyref(′*′).*"iterator="$i"><td><imgsrc="bullet.TIF"></td><td><ahref="select($i)">{$i}</a></td></netui:repeater></tr><tr><netui:repeaterid="$y"source=$x.selected.*"iterator="$j"><td><ahref="$pageFlow.navigate{$j,′navigator.tmpl′)">NAV</a></td><td><ahref="$pageFlow.navigate($j,′detail.tmpl′)">{$j}</a></td></netui:repeater></tr></tbody></table>在節(jié)點(diǎn)列表中每節(jié)點(diǎn)顯示兩個(gè)錨(超鏈接)第一個(gè)錨“NAV”允許用戶導(dǎo)航到相關(guān)聯(lián)的節(jié)點(diǎn),在所選節(jié)點(diǎn)$j作為$current的情況下重新顯示當(dāng)前導(dǎo)航器模板;第二個(gè)錨(顯示強(qiáng)制的節(jié)點(diǎn)$j的標(biāo)簽)導(dǎo)航到下面的具體模板。<table><tbody><trcolspan="2"><td><b>{$current.label()}</b></td></tr><netui:repeaterid="$il"source="$current.*"iterator="$i"><tr><td>$current.name()}</td><td>{$i}</td></tr></netui:repeater></tbody></table>具體模板顯示當(dāng)前節(jié)點(diǎn)標(biāo)簽并且包括repeater,其在節(jié)點(diǎn)的XML文檔中迭代,并且顯示元素標(biāo)志名和對(duì)應(yīng)值。導(dǎo)航CRM例子的自動(dòng)瀏覽器的輸出如下所示。第一頁(yè)面流顯示聚焦在根節(jié)點(diǎn)上的導(dǎo)航器模板;用戶選擇accountskeyref,然后向下到“Acme”帳戶。這導(dǎo)航到同一導(dǎo)航器模板,設(shè)置$current指向“Acme”帳戶節(jié)點(diǎn)。用戶然后選擇contactskeyref并且點(diǎn)擊“SarahSmith”的聯(lián)系人記錄;這時(shí),導(dǎo)航器顯示具體模板,$current設(shè)為表示聯(lián)系人的節(jié)點(diǎn)。瀏覽器的后退按鈕允許用戶從具體模板導(dǎo)航回導(dǎo)航器模板。CRM使用情況數(shù)據(jù)模型定義這部分詳細(xì)說明示例CRM應(yīng)用的應(yīng)用組件。數(shù)據(jù)模型如上所述,圖5示出CRM應(yīng)用的實(shí)體關(guān)系圖(ERD)。根和用戶節(jié)點(diǎn)是系統(tǒng)節(jié)點(diǎn)類型。根節(jié)點(diǎn)表示虛擬XML文檔(表示單個(gè)用戶能訪問的數(shù)據(jù))的根。用戶節(jié)點(diǎn)表示系統(tǒng)的單個(gè)用戶,并且由系統(tǒng)自動(dòng)生成。根節(jié)點(diǎn)包括account節(jié)點(diǎn)并且定義accountskeyref。每個(gè)account節(jié)點(diǎn)可以包括contact、event、note和task節(jié)點(diǎn),并且定義相應(yīng)keyref。類似地,每個(gè)contact節(jié)點(diǎn)可以包括event、note和task節(jié)點(diǎn)。account節(jié)點(diǎn)還可以包括sub-account并且定義subAccountskeyref。account和contact節(jié)點(diǎn)都包括引用系統(tǒng)用戶的ownerkeyref。類似地,task和event節(jié)點(diǎn)定義分配的(用戶)keyref。所有這些keyref具有基數(shù)1。模式和keyref定義下面的部分詳細(xì)說明五個(gè)應(yīng)用模式,這些都定義在/schemas/crm.xsd文件中。<?xmlversion="1.0"?><xsd:schematargetNamespace="http://example.com/"elementFormDefault="qualified"attributeFormDefault="unqualified"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:mas="urn:bea.com"xmlns="http://example.com/">Account類型account節(jié)點(diǎn)類型由下面的模式定義。<xsd:complexTypename="accountType"><xsd:all><xsd:elementname="name"type="xsd:string"/><xsd:elementname="type"type="accountTypeEnum"/></xsd:all><xsd:attributename="id"type="xsd:string"mas:type="pkey"/><xsd:attributename="timestamp"type="xsd:string"mas:type="seq"/><xsd:attributename="ownerId"type="xsd:string"/><xsd:attributename="parentAccountId"type="xsd:string"/></xsd:complexType><xsd:simpleTypename="accountTypeEnum"><xsd:restrictionbase="xsd:string"><xsd:enumerationvalue="Direct"/><xsd:enumerationvalue="Web"/><xsd:enumerationvalue="Channel"/><xsd:enumerationvalue="Partner"/></xsd:restriction></xsd:simpleType>要注意,account類型定義簡(jiǎn)單的標(biāo)簽聲明,它包括name元素。此外,type字段具有由accountType簡(jiǎn)單類型定義所定義的約束值的集合。下面的部分示出顯示第一聲明的keyref的/conduit/crm.jsx文件的上部。要注意,該應(yīng)用是在app名字空間中聲明的。<?xmlversion="1.0"?><graphMetaxmlns="run:bea.com"xmlns:mas="run:bea.com"xmlns:app="http://example.com/"><keyrefname="account"sourceType="mas:root"targetType="app:account">...</keyref></graphMeta>accountskeyref將用戶的root節(jié)點(diǎn)與account節(jié)點(diǎn)集合相關(guān)聯(lián)。在CRM應(yīng)用中,這是綁定到root節(jié)點(diǎn)的唯一keyref。<keyrefname="accounts"sourceType="mas:root"targetType="app:account"/>下面的keyref定義與account節(jié)點(diǎn)類型(即,所有app:account被聲明為sourceType屬性)有關(guān)。帳戶包括子帳戶(subAccounts)和聯(lián)系人、通知、事件、任務(wù)和報(bào)價(jià)請(qǐng)求的節(jié)點(diǎn)集合。<keyrefname="subAccounts"sourceType="app:account"targetType="app:account"/><keyrefname="contacts"sourceType="app:account"targetType="app:contact"/><keyrefname="notes"sourceType="app:account"targetType="app:note"/><keyrefname="events"sourceType="app:account"targetType="app:event"/><keyrefname="tasks"sourceType="app:account"targetType="app:task"/><keyrefname="quotes"sourceType="app:account"targetType="app:quoteRequest"/>account節(jié)點(diǎn)類型還包括對(duì)單個(gè)user節(jié)點(diǎn)的引用(查找),它表示該節(jié)點(diǎn)的當(dāng)前所有者。這是通過下面指定基數(shù)約束(正好為1)的聲明表達(dá)的。<keyrefname="owner"sourceType="app:account"targetType="mas:user"minOccurs="1"maxOccurs="1"/>Contact類型contact節(jié)點(diǎn)類型由下面的模式定義。<xsd:elementname="contact"type="contactType"><xsd:annotation><xsd:appinfo><mas:nodeAnnotation><mas:label>$node.first+""+$node.last</mas:label></mas:nodeAnnotation></xsd:appinfo></xsd:annotation></xsd:element><xsd:complexTypename="contactType"><xsd:sequence><xsd:elementname="salutation"type="contactSalutationEnum"/><xsd:elementname="first"type="xsd:string"/><xsd:elementname="last"type="xsd:string"/><xsd:elementname="email"type="xsd:string"/></xsd:sequence></xsd:complexType><xsd:simpleTypename="contactSalutationEnum"><xsd:restrictionbase="xsd:string"><xsd:enumerationvalue="Mr"/><xsd:enumerationvalue="Mrs"/><xsd:enumerationvalue="Ms"/><xsd:enumerationvalue="Dr"/></xsd:restriction></xsd:simpleType>要注意,account節(jié)點(diǎn)類型定義標(biāo)簽聲明,它包括first和last名字元素。此外,salutation字段具有由contactSalutationEnum簡(jiǎn)單類型定義所定義的約束值集合。下面的keyref定義與contact節(jié)點(diǎn)類型(即,所有app:contact被聲明為sourceType屬性)有關(guān)。帳戶包括通知、事件和任務(wù)的節(jié)點(diǎn)集合。<keyrefname="notes"sourceType="app:contact"targetType="app:note"/><keyrefname="events"sourceType="app:contact"targetType="app:event"/><keyrefname="tasks"sourceType="app:contact"targetType="app:task"/>contact節(jié)點(diǎn)類型還包括對(duì)單個(gè)user節(jié)點(diǎn)的引用(查找),它表示該節(jié)點(diǎn)的當(dāng)前所有者。這是通過下面指定基數(shù)約束(正好為1)的聲明表達(dá)的。<keyrefname="owner"sourceType="app:contact"targetType="mas:user"minOccurs="1"maxOccurs="1"/>Note類型note節(jié)點(diǎn)類型由下面的模式定義。<xsd:elementname="note"type="noteType"><xsd:annotation><xsd:appinfo><mas:nodeAnnotation><mas:label>$node.title</mas:label></mas:nodeAnnotation></xsd:appinfo></xsd:annotation></xsd:element><xsd:complexTypename="noteType"><xsd:sequence><xsd:elementname="title"type="xsd:string"/><xsd:elementname="body"type="xsd:string"/></xsd:sequence></xsd:complexType>note不包括keyref定義。Event類型event節(jié)點(diǎn)類型由下面的模式定義。<xsd:elementname="event"type="eventType"><xsd:annotation><xsd:appinfo><mas:nodeAnnotation><mas:label>$node.title</mas:label></mas:nodeAnnotation></xsd:appinfo></xsd:annotation></xsd:element><xsd:complexTypename="eventType"><xsd:sequence><xsd:elementname="title"type="xsd:string"/></xsd:sequence></xsd:complexType>event節(jié)點(diǎn)類型還包括對(duì)單個(gè)user節(jié)點(diǎn)的引用(查找),它表示事件的當(dāng)前assigned用戶。這是通過下面指定基數(shù)約束(正好為1)的聲明表達(dá)的。<keyrefname="assigned"sourceType="app:event"targetType="mas:user"minOccurs="1"maxOccurs="1"/>Task類型task節(jié)點(diǎn)類型由下面的模式定義。<xsd:elementname="task"type="taskType"><xsd:annotation><xsd:appinfo><mas:nodeAnnotation><mas:label>$node.title</mas:label></mas:nodeAnnotation></xsd:appinfo></xsd:annotation></xsd:element><xsd:complexTypename="taskType"><xsd:sequence><xsd:elementname="title"type="xsd:string"/><xsd:elementname="status"type="taskStatusEnum"/></xsd:sequence></xsd:complexType><xsd:simpleTypename="taskStatusEnum"><xsd:restrictionbase="xsd:string"><xsd:enumerationvalue="Notstarted"/><xsd:enumerationvalue="Inprogress"/><xsd:enumerationvalue="Completed"/><xsd:enumerationvalue="Deferred"/></xsd:restriction></xsd:simpleType>task節(jié)點(diǎn)類型還包括對(duì)單個(gè)user節(jié)點(diǎn)的引用(查找),它表示事件的當(dāng)前assigned用戶。這是通過下面指定基數(shù)約束(正好為1)的聲明表達(dá)的。<keyrefname="assigned"sourceType="app:task"targetType="mas:user"minOccurs="1"maxOccurs="1"/>QuoteRequest類型quoteRequest節(jié)點(diǎn)類型由下面的模式定義。<?xmlversion="1.0"?><xsd:schematargetNamespace="http://example.com/"elementFormDefault="qualified"attributeFormDefault="unqualified"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:mas="run:bea.com"xmlns="http://example.com/"><xsd:elementname="quoteRequest"type="quoteRequestType"/><xsd:complexTypename="quoteRequestType"><xsd:sequence><xsd:elementname="prodId"type="xsd:string"/><xsd:elementname="qty"type="xsd:integer"/><xsd:elementname="response"minOccurs="0"type="quoteRequestResponseType"/></xsd:sequence></xsd:complexType><xsd:complexTypename="quoteRequestResponseType"><xsd:sequence><xsd:elementname="price"type="xsd:double"/></xsd:sequence></xsd:complexType></xsd:schema>示例應(yīng)用模式下面的部分示出客戶端變成模型訪問的虛擬數(shù)據(jù)圖的應(yīng)用數(shù)據(jù)??蚣苌上旅鎸?duì)應(yīng)用數(shù)據(jù)的XML模式定義。<?xmlversion="1.0"?><xsd:schematargetNamespace="http://example.com/"elementFormDefault="qualified"attributeFormDefault="unqualified"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:mas="run:bea.com"xmlns="http://example.com/"><xsd:elementname="graph"><xsd:complexType><xsd:sequence><xsd:elementref="root"minOccurs="1"maxOccurs="1"><xsd:elementref="account"maxOccurs="unbounded"><xsd:elementref="contact"maxOccurs="unbounded"><xsd:elementref="note"maxOccurs="unbounded"><xsd:elementref="event"maxOccurs="unbounded"><xsd:elementref="task"maxOccurs="unbounded"></xsd:sequence></xsd:complexType></xsd:element></xsd:schema>graph元素表示應(yīng)用數(shù)據(jù)模型的頂級(jí)元素;這包括正好一個(gè)root節(jié)點(diǎn)聲明加上對(duì)每個(gè)應(yīng)用模式的每個(gè)節(jié)點(diǎn)的無限聲明(account、contact、note、event和task)。下面的類型定義是由應(yīng)用模式和keyref定義生成的。<xsd:elementname="account"><xsd:complexType><xsd:sequence><xsd:elementname="name"type="xsd:string"/><xsd:elementname="type"type="accountType"/></xsd:sequence></xsd:complexType></xsd:element><xsd:elementname="contact"><xsd:complexType><xsd:sequence><xsd:elementname="salutation"type="contactSalutationEnum"/><xsd:elementname="first"type="xsd:string"/><xsd:elementname="last"type="addressType"/><xsd:elementname="email"tyPe="xsd:string"/></xsd:sequence></xsd:complexType></xsd:element>...<xsd:elementname="note"><xsd:complexType><xsd:sequence><xsd:elementname="title"type="xsd:string"/><xsd:elementname="body"type="xsd:string"/></xsd:sequence></xsd:complexType></xsd:element><xsd:elementname="event"><xsd:complexType><xsd:sequence><xsd:elementname="title"type="xsd:string"/></xsd:sequence></xsd:complexType></xsd:element><xsd:elementname="task"><xsd:complexType><xsd:sequence><xsd:elementname="title"type="xsd:string"/><xsd:elementname="status"type="taskStatusEnum"/></xsd:sequence></xsd:complexType></xsd:element>...示例應(yīng)用數(shù)據(jù)系統(tǒng)具有三個(gè)用戶“alex”、“bob”和“carol”(這些是虛擬圖中未示出的系統(tǒng)對(duì)象)。<graph><rootaccounts="a1a2"/><accountid="a1"owner="bob"contacts="c1c2"notes="n1"events="e1"tasks="t1"><name>Acme</name><type>Direct</type></account><accountid="a2"owner="bob"contacts="c3"><name>Bancroft</name><type>Web</type></account><contactid="c1"owner="bob"events="e2"tasks="t2"><salutation>Mr</salutation><first>Roger</first><last>Reed</last><email>roger@acme.com</email></contact><contactid="c2"owner="bob"notes="n2"><salutation>Ms</salutation><first>Sarah</first><last>Smith</last><email>sarah@acme.com</email></contact><contactid="c2"owner="bob"notes="n2"><salutation>Ms</salutation><first>Sarah</first><last>Smith</last><email>sarah@acme.com</email></contact><noteid="n1"><title>ROIinformation</title><body>AttacheddocumentdetailsROIforproduct</body></note><noteid="n2"><title>Customerrequirements</title><body>Attacheddocumentpresentscustomer′scurrentandanticipatedneeds</body></note><eventid="e1"assigned="fred"><title>Salesmeeting</title></event><eventid="e2"assigned="fred"><title>Productdemonstration</title></event><taskid="t1"assigned="fred"><title>PrepareRFPforsalescall</title><status>Notstarted</status></task><taskid="t2"assigned="fred"><title>Sendwhitepapertocustomer</title><status>Completed</status></task></graph>示例SPath表達(dá)式下面的部分示出一些SPath表達(dá)式和基于上面示例數(shù)據(jù)的期望值。下面的表達(dá)式返回accountskeyref的節(jié)點(diǎn)集(節(jié)點(diǎn)列表)。$root.@@accounts.*<accountid="a1"owner="bob"contacts="c1c2"notes="n1"events="e1"tasks="t1"><name>Acme</name><type>Direct</type></account><accountid="a2"owner="bob"contacts="c3"><name>Bancroft</name><type>Web</type></account>下面的表達(dá)式返回所有account節(jié)點(diǎn)的name元素集合。$root.@@accounts.*.nameAcmeBancroft下面表達(dá)式返回所有名為Acme的所有account的所有contact。$root.@@accounts.*.where(name=="Acme").@@contacts.*<contactid="c1"owner="bob"events="e2"tasks="t2"><salutation>Mr</salutation><first>Roger</first><last>Reed</last><email>roger@acme.com</email></contact><contactid="c2"owner="bob"notes="n2"><salutation>Ms</salutation><first>Sarah</first><last>Smith</last><email>sarah@acme.com</email></contact>下面表達(dá)式返回具有指定電子郵件地址的所有contact(對(duì)所有account)。var$contactX=$root.@@accounts.*.@@contactswhere(email=="sarah@acme.com")<contactid="c2"owner="bob"events="e2"tasks="t2"><salutation>Ms</salutation><first>Sarah</first><last>Smith</last><email>sarah@acme.com</email></contact>下面表達(dá)式設(shè)置$contactX節(jié)點(diǎn)內(nèi)的<salutation>元素的值。$contactX.salutation="Mrs"<contactid="c2"owner="bob"events="e2"tasks="t2"><salutation>Mrs</salutation><first>Sarah</first><last>Smith</last><email>sarah@acme.com</email></contact>下面的表達(dá)式創(chuàng)建指定帳戶的新聯(lián)系人。要注意,它使用系統(tǒng)變量來設(shè)置owner屬性。$accountX.@@contacts.create(<contactownerId="$globalApp.user"><salutation>Dr</salutation><first>David</first><last>Daniels</last><email>david@acme.com</email></contact>);下面表達(dá)式創(chuàng)建對(duì)指定的contact創(chuàng)建新task;然后它修改assignedkeyref。var$newTask=<task><title>PerpareRFP</title><status>Notstarted</status></task>$contactx.@@tasks.create($ewTask);$ewTask.@@assigned=$root.@@users.*.where(.username=="fred");CRM情況數(shù)據(jù)模型定義這部分示出示例CRMWeb服務(wù)的(由Workshop生成的)WSDL的部分。<?xmlversion="l.0"encoding="utf-8"?><definitionsxmlns="http://schemas.xmlsoap.org/wsdl/"xmlns:conv="http://www.openuri.org/2002/04/soap/conversation/"xmlns:cw="http://www.openuri.org/2002/04/wsdl/conversation/"xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"xmlns:jms="http://www.openuri.org/2002/04/wsdl/jms/"xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"xmlns:s="http://www.w3.org/2001/XMLSchema"xmlns:s0="http://www.openuri.org/"xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"targetNamespace="http://www.openuri.org/">...類型定義WSDL包括兩種類型定義消息參數(shù)的輸入和輸出類型定義;和(對(duì)單獨(dú)的復(fù)合類型)字段類型定義。<types>部分包括對(duì)操作輸入和輸出類型以及對(duì)作為操作參數(shù)傳遞的復(fù)合元素的模式定義。下面的類型定義與getAccountsByUserWeb服務(wù)操作的輸入(getAccountsByUser)和輸出(getAccountsByUserResponse)消息類型有關(guān)。<types><s:schemaxmlns:s="http://www.w3.org/2001/XMLSchema"mlns:ope="http://www.openuri.org/"elementFormDefault="qualified"trgetNamespace="http://www.openuri.org/"><s:elementname="getAccountsByUser"><s:complexType><s:sequence><s:elementname="userId"type="s:string"minoccurs="0"/></s:sequence></s:complexType></s:element><s:elementname="getAccountsByUserResponse"><s:complexType><s:sequence><s:elementname="getAccountsByUserResult"type="ope:ArrayOfAccount"minOccurs="0"/></s:sequence></s:complexType></s:element>下面的類型定義定義在上面輸入/輸出操作定義中引用的參數(shù)的復(fù)合類型。<s:complexTypename="ArrayOfAccount"><s:sequence><s:elementname="Account"type="ope:Account"nillable="true"minOccurs="0"maxOccurs="unbounded"/></s:sequence></s:complexType><s:elementname="Account"nillable="true"type="ope:Account"/><s:complexTypename="Account"><s:sequence><s:elementname="id"type="s:string"/><s:elementname="timestamp"type="s:string"/><s:elementname="name"type="s:string"minOccurs="0"/><s:elementname="type"type="s:string"minOccurs="0"/><s:elementname="ownerId"type="s:string"minOccurs="0"/></s:sequence></s:complexType></s:schema>下面的類型定義全部與getContactsByAccount和addContactToAccountWeb服務(wù)操作有關(guān)。<s:elementname="getContactsByAccount"><s:complexType><s:sequence><s:elementname="accountId"type="s:string"minOccurs="0"/></s:sequence></s:complexType></s:element><s:elementname="getContactsByAccountResponse"><s:complexType><s:sequence><s:elementname="getContactsByAccountResult"type="ope:ArrayOfContact"minOccurs="0"/></s:sequence></s:complexType></s:element><s:elementname="addContactToAccount"><s:complexType><s:sequence><s:elementname="accountId"type="s:string"minOccurs="0"/><s:elementname="contact"type="ope:Contact"minOccurs="0"/></s:sequence></s:complexType></s:element><s:elementname="addContactToAccountResponse"><s:complexType><s:sequence><s:elementname="addContactToAccountResult"type="s:string"minOccurs="0"/></s:sequence></s:complexType></s:element><s:complexTypename="ArrayOfContact"><s:sequence><s:elementname="Contact"type="ope:Contact"nillable="true"minOccurs="0"maxOccurs="unbounded"/></s:sequence></s:complexType><s:elementname="Contact"nillable="true"type="ope:Contact"/><s:complexTypename="Contact"><s:sequence><s:elementname="id"type="s:string"/><s:elementname="timestamp"type="s:string"/><s:elementname="first"type="s:string"minOccurs="0"/><s:elementname="last"type="s:string"minOccurs="0"/><s:elementname="email"type="s:string"minOccurs="0"/></s:sequence></s:complexType></s:schema></types>消息定義每個(gè)Web服務(wù)操作定義一對(duì)消息,這對(duì)消息定義輸入和輸出類型。<messagename="getAccountsByUserSoapIn"><partname="parameters"element="s0:getAccountsByUser"/></message><messagename="getAccountsByUserSoapOut"><partname="parameters"element="s0:getAccountsByUserResponse"/></message>PortType、綁定和服務(wù)定義管道在結(jié)構(gòu)上與portType定義相似;portType操作被映射到管道操作上;input和output元素對(duì)應(yīng)于transformOut和transformInXquery聲明。<portTypename="CRMSoap"><operationname="getAccountsByUser"><inputmessage="s0:getAccountsByUserSoapIn"/><outputmessage="s0:getAccountsByUserSoapOut"/></operation>...</portType><bindingname="CRMSoap"type="s0:CRMSoap"><soap:bindingtransport="http://schemas.xmlsoap.org/soap/http"style="document"/><operationname="getAccountsByUser"><soap:operationsoapAction="http://www.openuri.org/getAccountsByUser"style="document"/><input><soap:bodyuse="literal"/></input><output><soap:bodyuse="literal"/></output></operation>...</binding><servicename="CRM"><portname="CRMSoap"binding="s0:CRMSoap"><soap:addresslocation="http://BISHAMON7001/CRMWeb/CRM.jws"/></port></service>SalesForce管道定義下面的管道文件實(shí)現(xiàn)與SalesForce.comWeb服務(wù)相連的管道的部分。/***@mas:statefulshared="false"*@common:xmlnsnamespace="http://schemas.xmlsoap.org/soap/envelope/prefix="soap"*@common:xmlnsnamespace="urn:partner.soap.sforce.com"prefix="sfdc′*@common:xmlnsnamespace="http://example.com/"prefix="app"*//***@common:control*@jc:locationhttp-url="http://enterprise.soap.sforce.com/"*/ws=newWebServiceControl();//sessionobjectreturnedfromwebservicevarsessionId=null;//createandsendloginmessageandprocessresultsfunctionlogin(){varbody=<login><username>{$user.username}</username><password>{$user.password}</password></login>;varresponse=ws.invoke(body);//setsessionidsessionId=string(response.body.sfdc:result.sfdc:sessionId);//setURLforsubsequentcalls(fromthisconduit)ws.endPoint=string(response.body.sfdc:result.sfdc:serverUrl);}//createconversationalheaderfunctioncreateHeader(){if(sessionId==null){login();}return<SessionHeader><sessiondId>{sessionId}</sessiondId></SessionHeader>;}/***selectcontactsforanaccount;$account.@@contacts.**@mas:operationtype="select"keyref="app:contactAccountRef"inverse="tru*@mas:transformtype="request"function="selectContacts_request"*@mas:transformtype="response"function="selectContacts_response"*/functionselectContacts($msg,$source){$msg.header+=createHeader();returnws.invoke($msg);}/***@mas:namespacetarget="sfdc"*@mas:fieldxpath="@id"*@language:bodytype="xquery"*/functionselectContacts_request($source){<query><queryString>SELECT*FROMContactWHEREAccountId="{string($source/@id)}"</queryString></query>}/***@mas:namespacetarget="app"*@language:bodytype="xquery"*/functionselectContacts_response($response){for$iin$response/sfdc:queryResponse/sfdc:result/sfdc:recordsreturn<contactid="{string($i/sfdc:Id)}"accountId="{string($i/sfdc:AccountId)}"><modified>{string($i/sfdc:SystemModstamp)}</modified><fist>{string($i/sfdc:FistName)}</first><last>{string($i/sfdc:LastName)}</last><email>{string($i/sfdc:Email)}</email></contact>}/***insertcontact:$root.create(<contact>...</contact>);*@mas:operationtype="insert"node="app:contact"*@mas:transformtype="request"function="insertContact_request"*@mas:transformtype="response"function="insertContact_response"*/functioninsertContact($msg,$node){$msg.header+=createHeader();varresponse=ws.invoke($msg);varid=response.sfdc:createResponse.sfdc:result.sfdc:Id;//retrievesequencenumbervar$msg2=createMessage(<query><queryString>SELECTSystemModstampFROMContactWHEREId="{id}"</queryString></query>);$msg2.header+=createHeader();varresponse2=ws.invoke($msg2);//returnbothresponsesresponse.body+=response2.body.sfdc:queryResponse;returnresponse;}/***@mas:namespacetarget="sfdc"*@language:bodytype="xquery"*/functioninsertContact_request($node){<create><sObjectsxsi:type="Contact"><AccountId>{string($node/app:@accountId})</AccountId><FirstName>{string($node/app:first})</FistName><LastName>{string($node/app:last})</LastName><Email>{string($node/app:email})</Email></sObjects></create>}/***@mas:namespacetarget="app"*@language:bodytype="xquery"*/functioninsertContact_response($response){<contactid="{string($response/sfdc:createResponse/sfdc:result/sfdc:Id)}"><modified>{string($response/sfdc:queryResponse/sfdc:records/sfdc:SystemModstamp)}</modified></contact>}在一個(gè)實(shí)施例中,偶爾鏈接的應(yīng)用服務(wù)器可以與服務(wù)總線(servicebus)交互。在一個(gè)實(shí)施例中,服務(wù)總線像web服務(wù)器一樣工作。服務(wù)總線可以是從多個(gè)位置獲得信息的代理。服務(wù)器總線可以●在封裝協(xié)議、傳輸協(xié)議、安全方案、負(fù)載內(nèi)容、單向和請(qǐng)求/響應(yīng)范例、同步和異步通信以及點(diǎn)到點(diǎn)和pub/sub的領(lǐng)域,消除(bridge)發(fā)送者發(fā)送和接收者期望的消息之間的差距?!裨谕瓿上穸嗄康牡匕l(fā)布、基于內(nèi)容的路由、鑒別和授權(quán)以及資格映射這樣的任務(wù)的中間提供額外的計(jì)算能力。●在度量收集和顯示、警報(bào)顯示、跟蹤事件收集和使用、消息存檔和SLA管理的中間提供監(jiān)視能力。服務(wù)總線可以是中間人。到服務(wù)總線的消息可以通過傳輸進(jìn)入,它被處理來確定要將其路由到哪兒并且被變換以便消息濃縮。然后它再次通過傳輸出去。響應(yīng)可以沿著相反路徑。當(dāng)消息經(jīng)過時(shí)可以向感興趣的接聽者發(fā)布消息的副本。中間人的消息處理可以通過控制臺(tái)指定的元數(shù)據(jù)驅(qū)動(dòng)。服務(wù)總線可以支持WebLogic管理的服務(wù)器的分簇(clustering)。配置和元數(shù)據(jù)被自動(dòng)傳播到管理的服務(wù)器供快速本地檢索??梢詮乃泄芾淼姆?wù)器自動(dòng)收集監(jiān)視的度量,以便集中并顯示在控制臺(tái)上。中間人調(diào)用的中間人(代理服務(wù))和外部服務(wù)都可以模型化為服務(wù)。服務(wù)可以具有●稱為端口(也稱為端點(diǎn))的具體接口集,每個(gè)具有傳輸?shù)刂泛拖嚓P(guān)配置。端口集組成服務(wù)的負(fù)載平衡和失敗轉(zhuǎn)移備選并且特征相同?!駟蝹€(gè)可選的抽象接口(類比物是java接口),它是操作可能破壞的接口中的消息部分的結(jié)構(gòu)的定義(類比物是與參數(shù)的java接口的方法),●單個(gè)綁定,定義抽象接口中的消息部分到具體消息的封裝和該消息到傳輸?shù)慕壎ā!耜P(guān)于WS安全性(WSS)和WS可靠消息收發(fā)(WS-RM)的策略、授權(quán)策略和需要綁定層透明執(zhí)行的動(dòng)作(如登錄)。在基于HTTP(S)或JMS傳輸?shù)臉?biāo)準(zhǔn)SOAPweb服務(wù)的情況下,抽象接口、具體接口和綁定的WSDL表示是可能的。WSDL資源或現(xiàn)有的服務(wù)可以用于跳躍開始(jumpstart)新服務(wù)的接口的定義。服務(wù)總線可以支持JMS(對(duì)BEA和外部JMS提供商)、HTTP(S)、電子郵件、文件、WS-RM和FTP作為服務(wù)傳輸。服務(wù)總線可以支持HTTP和JMS異步傳輸?shù)恼?qǐng)求/響應(yīng)和單向范例。它可選地支持有序的消息傳送(如果底層的傳輸支持它)。服務(wù)總線可以支持XML、非XML(用MFL描述的結(jié)構(gòu))、二進(jìn)制、具有附件的MIME(電子郵件)以及SOAP1.1和1.2(具有或沒有RPC風(fēng)格和文檔風(fēng)格的附件)封裝。服務(wù)對(duì)同一綁定可以具有多個(gè)端口。這些端口可以用作負(fù)載平衡和失敗轉(zhuǎn)移備選。服務(wù)可以定義對(duì)其斷開使用的負(fù)載平衡策略。支持的策略是循環(huán)復(fù)用和隨機(jī)(加權(quán)或未加權(quán))。端口不僅用作負(fù)載平衡目的地,在失敗時(shí)還用作失敗轉(zhuǎn)移備用。對(duì)于HA負(fù)載平衡方案來說這兩個(gè)概念是連在一起的。服務(wù)還可以定義失敗時(shí)的重試策略和(對(duì)于請(qǐng)求/響應(yīng)的)超時(shí)策略。服務(wù)可以定義應(yīng)用到其接口中的消息的安全策略。這可以在服務(wù)級(jí)(應(yīng)用到所有消息)或?qū)Ψ?wù)操作的各個(gè)消息指定。服務(wù)可以被分類。可以定義類別方案。類別本質(zhì)上是關(guān)鍵字名,并且類別值是關(guān)鍵字名的值。服務(wù)可以具有多個(gè)類別名的多個(gè)值。類別對(duì)于發(fā)現(xiàn)目的非常有用。存在多個(gè)定義關(guān)鍵字名和允許的值分層的標(biāo)準(zhǔn)本體論(ontology)(或類別方案)。服務(wù)總線只允許使用分層中的葉值分類服務(wù)。服務(wù)集合可以由稱為服務(wù)提供商的組織或應(yīng)用來提供。定義服務(wù)的提供商是可選的,并且你可以具有單獨(dú)的服務(wù)。這些既可以是企業(yè)內(nèi)部的子組織,也可以是外部的合作組織,甚至單獨(dú)的應(yīng)用(句法取決于用戶)。此外,服務(wù)提供商可以被分類,如搜索服務(wù)。服務(wù)提供商與資格相關(guān)聯(lián),并且可以依賴于用戶,從而它可以屬于授權(quán)角色。服務(wù)提供商可以發(fā)送和接收消息。服務(wù)消費(fèi)者可以是組織或應(yīng)用,并且只能發(fā)送消息(或接收同步響應(yīng))。此外,服務(wù)提供商可以被分類,如搜索服務(wù)。服務(wù)消費(fèi)者與資格相關(guān)聯(lián),并且依賴于用戶,從而它可以屬于授權(quán)角色。代理服務(wù)的實(shí)現(xiàn)可以由流水線定義指定。它包括請(qǐng)求流水線定義和響應(yīng)流水線定義。流水線指定在調(diào)用外部(或其他代理)服務(wù)之前對(duì)于對(duì)代理服務(wù)的請(qǐng)求消息執(zhí)行什么動(dòng)作,并且在代理返回響應(yīng)之前對(duì)來自代理調(diào)用的服務(wù)的響應(yīng)執(zhí)行什么處理。每個(gè)流水線可以是階段的序列。送入流水線的消息可以伴有可由流水線階段訪問或修改的消息上下文變量的集合(包括具有消息內(nèi)容的變量)。流水線中的主要階段如下?!褡儞Q階段,允許是否嵌套結(jié)構(gòu)來選擇要執(zhí)行的影響上下文的變換。web服務(wù)呼出或DB查找可以是用來設(shè)置輸出上下文變量的Xquery或XSLT變換的替代?!衤酚呻A段(僅在請(qǐng)求流水線中允許),允許是否合并(和嵌套)結(jié)構(gòu)和范例結(jié)構(gòu)來定義消息要路由到的單個(gè)端點(diǎn)和操作??梢栽谙⒈话l(fā)布到每個(gè)端點(diǎn)之前定義影響上下文變量的變換集合。web服務(wù)呼出或DB查找可以是用來設(shè)置上下文變量的Xquery或XSLT變換的替代?!癜l(fā)布階段,允許是否合并(和嵌套)結(jié)構(gòu)和范例結(jié)構(gòu)來定義消息要發(fā)布到的端點(diǎn)和操作集合??梢栽谙⒈话l(fā)布到每個(gè)端點(diǎn)之前定義影響上下文變量的變換集合。web服務(wù)呼出或DB查找可以是用來設(shè)置上下文變量的Xquery或XSLT變換的替代。上下文的改變與每個(gè)發(fā)布的端點(diǎn)是孤立的,并且不影響流水線的隨后處理?!馱S-安全處理以及授權(quán)在綁定層中透明地執(zhí)行?!窀欕A段,允許用用戶定義的信息寫跟蹤記錄,從而可以使用跟蹤系統(tǒng)按照用戶定義的準(zhǔn)則來搜索。●歸檔階段,為了歷史和保持記錄的目的將消息寫到存檔?!袢罩倦A段,允許將所選的上下文記錄到系統(tǒng)日志以便進(jìn)行調(diào)試?!耱?yàn)證階段,按照MFL模式的XML驗(yàn)證文檔。●自定義階段,允許用戶使用階段SDK實(shí)現(xiàn)的階段定義它們自己的動(dòng)作。每個(gè)流水線可以包括階段的序列。然而,單個(gè)服務(wù)級(jí)請(qǐng)求流水線可以可選地分支出操作流水線(每個(gè)操作最多一個(gè),并且可選地為缺省操作流水線)。因此,沒有從消息內(nèi)容確定操作的標(biāo)準(zhǔn)方法,操作的確定是通過用戶所選的準(zhǔn)則進(jìn)行的。響應(yīng)處理以相關(guān)操作流水線開始,然后加入單個(gè)服務(wù)級(jí)響應(yīng)流水線。上下文可以在請(qǐng)求流水線和響應(yīng)流水線中共享,并且其值與各個(gè)請(qǐng)求/響應(yīng)消息相關(guān)聯(lián)。上下文可以是預(yù)定義的XML變量集合。可以動(dòng)態(tài)地向上下文添加或刪除新變量。預(yù)定義的上下文變量具有關(guān)于消息、傳輸頭、安全原理、當(dāng)前代理服務(wù)的元數(shù)據(jù)、主路由的元數(shù)據(jù)和代理服務(wù)調(diào)用的訂閱服務(wù)的信息。上下文可以由階段用Xquery/Xupdate表達(dá)式讀取和修改。上下文的核心是變量$header、$body和$attachments。這些分別是包含SOAP頭、SOAP主體內(nèi)容和MIME附件的包裝變量。上下文給出這樣的印象,即,所有消息都是soap消息,而非soap消息被映射到該范例中。在二進(jìn)制或MFL數(shù)據(jù)的情況下,表示$attachments或$body中的文檔的XML元素是指具有唯一標(biāo)識(shí)符的文檔。在SOAPRPC的情況下,主體內(nèi)容自身是包含分類的RPC參數(shù)的包裝元素。服務(wù)總線可以具有如果在設(shè)計(jì)時(shí)期望的話可以使用的內(nèi)置型系統(tǒng)。當(dāng)在設(shè)計(jì)時(shí)創(chuàng)建條件或變換的Xquery表達(dá)式時(shí),可以聲明變量為編輯器中的一個(gè)或多個(gè)類型以幫助容易地創(chuàng)建Xquery。類型在XML模式、MFL或WSDL資源中。該類型聲明處理知道要分類的變量的本質(zhì)(是類型的元素或類型自身的包裝)。它還提供幫助來容易地訪問$body中的SOAPRPC參數(shù)或文檔。每個(gè)階段可以具有在該階段中出現(xiàn)錯(cuò)誤時(shí)執(zhí)行的步驟序列。該步驟序列組成該階段的出錯(cuò)流水線。此外,可以為整個(gè)流水線或整個(gè)代理服務(wù)定義出錯(cuò)流水線。在出錯(cuò)時(shí)調(diào)用存在的最低范圍的出錯(cuò)流水線。該出錯(cuò)流水線允許消息發(fā)布到端點(diǎn),制訂返回到代理的調(diào)用者的出錯(cuò)響應(yīng)消息,記錄該消息,在修改上下文后繼續(xù),或者產(chǎn)生異常。產(chǎn)生異常將控制轉(zhuǎn)交給下一較高范圍的出錯(cuò)流水線。請(qǐng)求流水線的處理可以包括進(jìn)入傳輸處理、進(jìn)入綁定層、流水線執(zhí)行、輸出綁定層和輸出傳輸處理步驟。綁定層自動(dòng)進(jìn)行要執(zhí)行的一些處理,像將消息映射到/從上下文變量,封裝和解封裝消息以及進(jìn)行WSS安全和授權(quán)。主路由目的地和發(fā)布目的地都遵從該范例。在主路由端點(diǎn)被調(diào)用時(shí),響應(yīng)流水線處理遵從類似的模型。來自階段的web服務(wù)呼出通過傳輸層前面的綁定層。呼出響應(yīng)沿著反向路徑。用戶是安全負(fù)責(zé)人,可以是人、組織或應(yīng)用。用戶可以調(diào)用UI接口(控制臺(tái)用戶)或消息接口(模型化為服務(wù)消費(fèi)者或提供商的用戶)。服務(wù)總線資源可以是可再用的共同的實(shí)體定義或描述,并且典型地是該實(shí)體的元數(shù)據(jù)。資源可以由多個(gè)服務(wù)使用,并且是企業(yè)或部分中的標(biāo)準(zhǔn)化定義或描述。資源的例子有類別方案、MFL模式、XSD模式、Xquery圖、XSLT圖、WSDL接口和WS-策略文件。類別方案可以定義單個(gè)類別名和類別名值的分層集合??梢允褂玫怯浀姆桨阜诸惙?wù)提供商和消費(fèi)者。它們可以以一個(gè)類別方案的多個(gè)葉值或者來自多個(gè)類別方案的葉值分類。模式可以描述本原或結(jié)構(gòu)數(shù)據(jù)的類型。MFL模式描述非XML數(shù)據(jù)的類型。XML模式描述XML的類型。XML模式類型可以導(dǎo)入或包括其他模式文件。變換圖可以描述兩種類型之間的映射。XSLT圖描述使用XLST標(biāo)準(zhǔn)的XML數(shù)據(jù)的映射。Xquery圖描述使用Xquery標(biāo)準(zhǔn)的XML和非XML(MFL)數(shù)據(jù)的映射。WSDL接口可以是服務(wù)接口的模板并且描述包括該接口中的操作的服務(wù)的出現(xiàn)接口,以及操作簽名中的消息部分的類型。它還可選地描述消息部分到消息的綁定(封裝)和消息到傳輸?shù)慕壎?。它還可選地描述服務(wù)的具體接口。WS-策略可以描述安全和可靠消息傳輸策略。它描述應(yīng)當(dāng)使用什么算法簽名或加密消息中的什么。它可以描述對(duì)于接收到的消息應(yīng)當(dāng)使用什么鑒別機(jī)制。在一個(gè)實(shí)施例中,偶爾連接的應(yīng)用服務(wù)器平臺(tái)提供一個(gè)框架用來使用與現(xiàn)有企業(yè)組件集成的類似Web的編程模型開發(fā)、部署和管理復(fù)雜移動(dòng)解決方案。移動(dòng)應(yīng)用可以包括數(shù)據(jù)模型定義、用戶接口模板、包括定義動(dòng)作的腳本的客戶端控制器、以及在服務(wù)器側(cè)的用于描述如何在數(shù)據(jù)模型和企業(yè)之間仲裁的一組管道。偶爾連接的應(yīng)用服務(wù)器可以假設(shè)移動(dòng)應(yīng)用使用的所有數(shù)據(jù)由外部系統(tǒng)永久地存儲(chǔ)和管理。數(shù)據(jù)模型可以是移動(dòng)應(yīng)用對(duì)該數(shù)據(jù)的預(yù)期用途的元數(shù)據(jù)描述,并且被優(yōu)化來允許在偶爾連接設(shè)備和外部系統(tǒng)之間有效遍歷和同步該數(shù)據(jù)。偶爾鏈接的數(shù)據(jù)模型可以描述永久性應(yīng)用數(shù)據(jù)的結(jié)構(gòu)(和其他特性)。模型自身可以與移動(dòng)瀏覽器同步,從而客戶端能夠智能地遍歷數(shù)據(jù)并且與服務(wù)器同步數(shù)據(jù)。本發(fā)明的其他特征、方面和目的可以通過回顧附圖和權(quán)利要求書獲得。應(yīng)當(dāng)理解,可以開發(fā)本發(fā)明的其他實(shí)施例并使其落入本發(fā)明和權(quán)利要求書的宗旨和范圍內(nèi)。為了說明和描述的目的提供對(duì)本發(fā)明的前述優(yōu)選實(shí)施例的描述。它并不意圖窮舉或?qū)⒈景l(fā)明限制在所披露的具體形式。顯然,對(duì)本領(lǐng)域技術(shù)人員來說許多修改和變型將是明顯的。選擇和描述實(shí)施例以便最好地說明本發(fā)明原理及其實(shí)際應(yīng)用,從而允許本領(lǐng)域技術(shù)人員明白本發(fā)明各個(gè)實(shí)施例以及適合特定用途的各種修改。本發(fā)明的范圍意圖由權(quán)利要求書及其等效物限定。除了包括專門設(shè)計(jì)的集成電路或其他電子電路的實(shí)施例外,本發(fā)明還可以使用根據(jù)本發(fā)明公開的教學(xué)編程的常規(guī)通用或?qū)S脭?shù)字計(jì)算機(jī)或微處理器來方便地實(shí)現(xiàn),這對(duì)于計(jì)算機(jī)領(lǐng)域的技術(shù)人員是清楚的。熟練程序員基于本公開的教學(xué)可以容易地準(zhǔn)備適當(dāng)?shù)能浖幋a。本方面還可以通過專用集成電路的準(zhǔn)備或通過互連常規(guī)組件電路的適當(dāng)網(wǎng)絡(luò)來實(shí)現(xiàn),這對(duì)于本領(lǐng)域技術(shù)人員是容易理解的。本發(fā)明包括計(jì)算機(jī)程序產(chǎn)品,它是其上存儲(chǔ)有指令的存儲(chǔ)介質(zhì),指令可以用于編程計(jì)算機(jī)來執(zhí)行本發(fā)明的任何處理。存儲(chǔ)介質(zhì)可以包括但不限于,包括軟盤、光盤、DVD、CD-ROM、微型驅(qū)動(dòng)器和磁光盤在內(nèi)的任何類型的盤、ROM、RAM、EPROM、EEPROM、DRAM、VRAM、閃存器件、磁或光卡、毫微系統(tǒng)(包括分組存儲(chǔ)IC)或適于存儲(chǔ)指令和/或數(shù)據(jù)的任何類型的介質(zhì)或器件。存儲(chǔ)在任何一種計(jì)算機(jī)可讀介質(zhì)上,本發(fā)明包括用于控制通用/專用計(jì)算機(jī)或微處理器的硬件和用于允許計(jì)算機(jī)或微處理器與人類用戶或其他利用本發(fā)明結(jié)果的機(jī)構(gòu)交互的軟件。該軟件可以包括,但不限于,設(shè)備驅(qū)動(dòng)器、操作系統(tǒng)和用戶應(yīng)用。通用/專用計(jì)算機(jī)或微處理器的編程(軟件)中包括用于實(shí)現(xiàn)本發(fā)明的教學(xué)軟件模塊,包括但不限于用于偶爾連接的應(yīng)用服務(wù)器的系統(tǒng)和方法。權(quán)利要求1.一種偶爾連接的應(yīng)用服務(wù)器,包括同步單元,其被配置成將數(shù)據(jù)節(jié)點(diǎn)與應(yīng)用的客戶端同步,應(yīng)用包括偶爾連接的數(shù)據(jù)模型;和管道管理器,其被配置成在來自外部系統(tǒng)的數(shù)據(jù)和由偶爾連接的數(shù)據(jù)模型所定義的數(shù)據(jù)節(jié)點(diǎn)之間轉(zhuǎn)換。2.如權(quán)利要求1所述的偶爾連接的應(yīng)用服務(wù)器,其中,偶爾連接的應(yīng)用服務(wù)器被配置成按照偶爾連接的數(shù)據(jù)模型中的元數(shù)據(jù)所指示的那樣在高速緩存中高速緩存數(shù)據(jù)節(jié)點(diǎn)。3.如權(quán)利要求1所述的偶爾連接的應(yīng)用服務(wù)器,其中,偶爾連接的數(shù)據(jù)模型指示客戶端對(duì)外部數(shù)據(jù)的預(yù)期用途。4.如權(quán)利要求1所述的偶爾連接的應(yīng)用服務(wù)器,其中,管道管理器被配置成使用管道,管道定義在偶爾連接的數(shù)據(jù)模型所定義的數(shù)據(jù)與對(duì)特定網(wǎng)頁(yè)服務(wù)的請(qǐng)求和響應(yīng)之間的變換。5.如權(quán)利要求1所述的偶爾連接的應(yīng)用服務(wù)器,還包括自適應(yīng)用戶接口服務(wù)器,其中,至少一個(gè)客戶端從偶爾連接的應(yīng)用服務(wù)器接收HTML頁(yè)面,所述HTML頁(yè)面是由自適應(yīng)用戶接口服務(wù)器使用數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型構(gòu)造的。6.如權(quán)利要求1所述的偶爾連接的應(yīng)用服務(wù)器,其中,向至少一個(gè)客戶端傳送數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型來在客戶端產(chǎn)生顯示。7.如權(quán)利要求6所述的偶爾連接的應(yīng)用服務(wù)器,其中,所述至少一個(gè)客戶端能在不與偶爾連接的應(yīng)用服務(wù)器聯(lián)系的情況下使用數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型運(yùn)行應(yīng)用。8.一種方法,包括在服務(wù)器中,將數(shù)據(jù)節(jié)點(diǎn)與用于包括偶爾連接的數(shù)據(jù)模型的應(yīng)用的客戶端同步;和在服務(wù)器中,在來自外部系統(tǒng)的數(shù)據(jù)和由偶爾連接的數(shù)據(jù)模型所定義的數(shù)據(jù)節(jié)點(diǎn)之間轉(zhuǎn)換。9.如權(quán)利要求8所述的方法,其中,偶爾連接的應(yīng)用服務(wù)器按照偶爾連接的數(shù)據(jù)模型中的元數(shù)據(jù)所指示的那樣在高速緩存中高速緩存數(shù)據(jù)節(jié)點(diǎn)。10.如權(quán)利要求8所述的方法,其中,所述偶爾連接的數(shù)據(jù)模型指示客戶端對(duì)外部數(shù)據(jù)的預(yù)期用途。11.如權(quán)利要求8所述的方法,其中,所述轉(zhuǎn)換使用管道,管道定義在偶爾連接的數(shù)據(jù)模型所定義的數(shù)據(jù)與對(duì)特定網(wǎng)頁(yè)服務(wù)的請(qǐng)求和響應(yīng)之間的變換。12.如權(quán)利要求8所述的方法,其中,向客戶端傳送數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型來在客戶端產(chǎn)生顯示。13.一種偶爾連接的應(yīng)用服務(wù)器,包括存儲(chǔ)器,用于存儲(chǔ)偶爾連接的數(shù)據(jù)模型;和高速緩存,用于存儲(chǔ)偶爾連接的數(shù)據(jù)模型所定義的數(shù)據(jù)節(jié)點(diǎn),其中,偶爾連接的應(yīng)用服務(wù)器按照偶爾連接的數(shù)據(jù)模型中的元數(shù)據(jù)所指示的那樣在高速緩存中高速緩存數(shù)據(jù)節(jié)點(diǎn)。14.如權(quán)利要求13所述的偶爾連接的應(yīng)用服務(wù)器,其中,偶爾連接的應(yīng)用服務(wù)器被配置成在來自外部系統(tǒng)的數(shù)據(jù)和由偶爾連接的數(shù)據(jù)模型所定義的數(shù)據(jù)節(jié)點(diǎn)之間轉(zhuǎn)換。15.如權(quán)利要求13所述的偶爾連接的應(yīng)用服務(wù)器,其中,數(shù)據(jù)節(jié)點(diǎn)包括XML。16.如權(quán)利要求13所述的偶爾連接的應(yīng)用服務(wù)器,還包括管道管理器,其中,管道管理器被配置成使用管道,管道定義在偶爾連接的數(shù)據(jù)模型所定義的數(shù)據(jù)與對(duì)特定網(wǎng)頁(yè)服務(wù)的請(qǐng)求和響應(yīng)之間的變換。17.如權(quán)利要求13所述的偶爾連接的應(yīng)用服務(wù)器,還包括自適應(yīng)用戶接口服務(wù)器,其中,至少一個(gè)客戶端從偶爾連接的應(yīng)用服務(wù)器接收HTML頁(yè)面,所述HTML頁(yè)面是由自適應(yīng)用戶接口服務(wù)器使用數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型構(gòu)造的。18.如權(quán)利要求13所述的偶爾連接的應(yīng)用服務(wù)器,其中,向至少一個(gè)客戶端傳送數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型來在客戶端產(chǎn)生顯示。19.如權(quán)利要求18所述的偶爾連接的應(yīng)用服務(wù)器,其中,所述至少一個(gè)客戶端能在不與偶爾連接的應(yīng)用服務(wù)器聯(lián)系的情況下使用數(shù)據(jù)節(jié)點(diǎn)和偶爾連接的數(shù)據(jù)模型運(yùn)行應(yīng)用。20.如權(quán)利要求20所述的偶爾連接的應(yīng)用服務(wù)器,其中,偶爾連接的應(yīng)用服務(wù)器與客戶端之間的數(shù)據(jù)節(jié)點(diǎn)的同步能在后臺(tái)進(jìn)行。21.一種偶爾連接的應(yīng)用服務(wù)器,包括第一組件,其被配置成將數(shù)據(jù)節(jié)點(diǎn)與應(yīng)用的客戶端同步,應(yīng)用包括偶爾連接的數(shù)據(jù)模型;和第二組件,其被配置成在來自外部系統(tǒng)的數(shù)據(jù)和由偶爾連接的數(shù)據(jù)模型所定義的數(shù)據(jù)節(jié)點(diǎn)之間轉(zhuǎn)換。22.一種系統(tǒng),包括偶爾連接的應(yīng)用服務(wù)器,其被配置成向客戶端提供應(yīng)用,應(yīng)用在不需要對(duì)偶爾連接的應(yīng)用服務(wù)器的當(dāng)前訪問的情況下允許客戶端讀取和更新應(yīng)用數(shù)據(jù),偶爾連接的應(yīng)用服務(wù)器適用于從外部系統(tǒng)獲得應(yīng)用數(shù)據(jù)來發(fā)送到客戶端,其中,偶爾連接的應(yīng)用服務(wù)器適用于將來自外部系統(tǒng)的數(shù)據(jù)轉(zhuǎn)換成數(shù)據(jù)節(jié)點(diǎn)。23.如權(quán)利要求22所述的系統(tǒng),其中,外部系統(tǒng)是服務(wù)總線。24.如權(quán)利要求22所述的系統(tǒng),其中,外部系統(tǒng)是網(wǎng)頁(yè)服務(wù)。全文摘要提供使用與現(xiàn)有企業(yè)組件集成的、簡(jiǎn)單的類似Web的編程模型開發(fā)、部署和管理復(fù)雜移動(dòng)解決方案的框架。移動(dòng)應(yīng)用可以包括數(shù)據(jù)模型定義、用戶接口模板、包括定義動(dòng)作的腳本的客戶端控制器、以及在服務(wù)器側(cè)的用于描述如何在數(shù)據(jù)模型和企業(yè)之間仲裁的一組管道。在一個(gè)實(shí)施例中,偶爾連接的應(yīng)用服務(wù)器假設(shè)由移動(dòng)應(yīng)用使用的數(shù)據(jù)由外部系統(tǒng)永久地存儲(chǔ)和管理。偶爾連接的數(shù)據(jù)模型可以是移動(dòng)應(yīng)用對(duì)該數(shù)據(jù)的預(yù)期用途的元數(shù)據(jù)描述,并且被優(yōu)化來允許在偶爾連接設(shè)備和外部系統(tǒng)之間有效遍歷和同步該數(shù)據(jù)。文檔編號(hào)G06F17/30GK101421726SQ200580001602公開日2009年4月29日申請(qǐng)日期2005年5月20日優(yōu)先權(quán)日2004年5月20日發(fā)明者亞當(dāng)·博斯沃思,理查德·伯登,亞歷克斯·凱辛,亞歷克斯·洛伊德,法羅克·H·埃斯卡菲,肯·昂格,特里·盧卡斯,亞歷山大·博斯沃思申請(qǐng)人:Bea系統(tǒng)公司