CN101421726B - 偶尔连接的应用服务器 - Google Patents

偶尔连接的应用服务器 Download PDF

Info

Publication number
CN101421726B
CN101421726B CN2005800016028A CN200580001602A CN101421726B CN 101421726 B CN101421726 B CN 101421726B CN 2005800016028 A CN2005800016028 A CN 2005800016028A CN 200580001602 A CN200580001602 A CN 200580001602A CN 101421726 B CN101421726 B CN 101421726B
Authority
CN
China
Prior art keywords
xsd
node
data
application server
mas
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Active
Application number
CN2005800016028A
Other languages
English (en)
Other versions
CN101421726A (zh
Inventor
亚当·博斯沃思
理查德·伯登
亚历克斯·凯辛
亚历克斯·洛伊德
法罗克·H·埃斯卡菲
肯·昂格
特里·卢卡斯
亚历山大·博斯沃思
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Oracle International Corp
Original Assignee
Oracle International Corp
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Priority claimed from US11/122,294 external-priority patent/US7650432B2/en
Application filed by Oracle International Corp filed Critical Oracle International Corp
Publication of CN101421726A publication Critical patent/CN101421726A/zh
Application granted granted Critical
Publication of CN101421726B publication Critical patent/CN101421726B/zh
Active legal-status Critical Current
Anticipated expiration legal-status Critical

Links

Images

Classifications

    • HELECTRICITY
    • H04ELECTRIC COMMUNICATION TECHNIQUE
    • H04LTRANSMISSION OF DIGITAL INFORMATION, e.g. TELEGRAPHIC COMMUNICATION
    • H04L67/00Network arrangements or protocols for supporting network services or applications
    • H04L67/01Protocols
    • H04L67/10Protocols in which an application is distributed across nodes in the network
    • H04L67/1095Replication or mirroring of data, e.g. scheduling or transport for data synchronisation between network nodes
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F16/00Information retrieval; Database structures therefor; File system structures therefor
    • G06F16/20Information retrieval; Database structures therefor; File system structures therefor of structured data, e.g. relational data
    • G06F16/27Replication, distribution or synchronisation of data between databases or within a distributed database system; Distributed database system architectures therefor
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F16/00Information retrieval; Database structures therefor; File system structures therefor
    • G06F16/20Information retrieval; Database structures therefor; File system structures therefor of structured data, e.g. relational data
    • G06F16/27Replication, distribution or synchronisation of data between databases or within a distributed database system; Distributed database system architectures therefor
    • G06F16/273Asynchronous replication or reconciliation
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F16/00Information retrieval; Database structures therefor; File system structures therefor
    • G06F16/80Information retrieval; Database structures therefor; File system structures therefor of semi-structured data, e.g. markup language structured data such as SGML, XML or HTML
    • G06F16/83Querying
    • G06F16/835Query processing
    • G06F16/8358Query translation
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F8/00Arrangements for software engineering
    • G06F8/60Software deployment
    • HELECTRICITY
    • H04ELECTRIC COMMUNICATION TECHNIQUE
    • H04LTRANSMISSION OF DIGITAL INFORMATION, e.g. TELEGRAPHIC COMMUNICATION
    • H04L67/00Network arrangements or protocols for supporting network services or applications
    • H04L67/2866Architectures; Arrangements
    • H04L67/289Intermediate processing functionally located close to the data consumer application, e.g. in same machine, in same home or in same sub-network
    • HELECTRICITY
    • H04ELECTRIC COMMUNICATION TECHNIQUE
    • H04WWIRELESS COMMUNICATION NETWORKS
    • H04W8/00Network data management
    • H04W8/18Processing of user or subscriber data, e.g. subscribed services, user preferences or user profiles; Transfer of user or subscriber data
    • HELECTRICITY
    • H04ELECTRIC COMMUNICATION TECHNIQUE
    • H04LTRANSMISSION OF DIGITAL INFORMATION, e.g. TELEGRAPHIC COMMUNICATION
    • H04L67/00Network arrangements or protocols for supporting network services or applications
    • H04L67/01Protocols
    • H04L67/02Protocols based on web technology, e.g. hypertext transfer protocol [HTTP]
    • HELECTRICITY
    • H04ELECTRIC COMMUNICATION TECHNIQUE
    • H04WWIRELESS COMMUNICATION NETWORKS
    • H04W4/00Services specially adapted for wireless communication networks; Facilities therefor
    • HELECTRICITY
    • H04ELECTRIC COMMUNICATION TECHNIQUE
    • H04WWIRELESS COMMUNICATION NETWORKS
    • H04W88/00Devices specially adapted for wireless communication networks, e.g. terminals, base stations or access point devices
    • H04W88/02Terminal devices

Landscapes

  • Engineering & Computer Science (AREA)
  • Theoretical Computer Science (AREA)
  • Databases & Information Systems (AREA)
  • General Engineering & Computer Science (AREA)
  • Physics & Mathematics (AREA)
  • General Physics & Mathematics (AREA)
  • Data Mining & Analysis (AREA)
  • Computer Networks & Wireless Communication (AREA)
  • Signal Processing (AREA)
  • Software Systems (AREA)
  • Computing Systems (AREA)
  • Information Transfer Between Computers (AREA)
  • Information Retrieval, Db Structures And Fs Structures Therefor (AREA)

Abstract

提供使用与现有企业组件集成的、简单的类似Web的编程模型开发、部署和管理复杂移动解决方案的框架。移动应用可以包括数据模型定义、用户接口模板、包括定义动作的脚本的客户端控制器、以及在服务器侧的用于描述如何在数据模型和企业之间仲裁的一组管道。在一个实施例中,偶尔连接的应用服务器假设由移动应用使用的数据由外部系统永久地存储和管理。偶尔连接的数据模型可以是移动应用对该数据的预期用途的元数据描述,并且被优化来允许在偶尔连接设备和外部系统之间有效遍历和同步该数据。

Description

偶尔连接的应用服务器
版权声明
本申请文件的一部分公开包含受到版权保护的材料。版权所有者不反对当出现在专利商标局专利文件或记录中时对专利文件或专利公开中的任一个的传真再现,但在其他情况下将保留所有任何版权。
优先权要求
Bosworth等人在2004年5月20日提交的名为“MOBILE APPLICATIONSERVER”的美国临时专利No.60/573077[Attorney’s DocketNo.BEAS-01537US0];和
Bosworth等人在2005年4月20日提交的名为“OCCASIONALLY-CONNECTED APPLICATION SERVER”的美国专利No.11/122294[Attorney’s Docket No.BEAS-01537US1]。
技术领域
本发明总的涉及移动应用架构,尤其涉及用于开发、部署和管理用于偶尔连接的移动设备的应用的移动应用架构。
背景技术
计算机和计算设备已经越来越少、越来越快和越来越有效。结果,它们的功能进化,并且它们能够存储和处理更多信息。然而,仍然有一个对设备可以本地存储和处理什么的限制。
最近,移动连接的系统的发展已经允许便携设备的更多功能。这些设备包括计算机、PDA、蜂窝电话、笔记本计算机、黑莓型(blackberry-type)设备和其他移动设备,只要在存在强的连接的地方它们就可以连接到因特网。尽管这些设备的应用有几种形式,但用户传统上由于应用的部署和随后的改变比较容易而偏好基于web的模型。此外,基于web的页面对于用户使用非常简单且直观。
移动设备web浏览的最新发展出现几个问题。难以在用户所处的任何位置获得连接。连接典型地是通过标准电话连接进行的,这取决于蜂窝电话信号强度。目前在蜂窝电话网络中存在许多死区,这可以引起移动设备和web服务器之间连接的停止时间。
当考虑通过典型的浏览器提供web页面内容所需的交互时更麻烦。当用户与web浏览器交互时,浏览器将基于用户输入向服务器请求更多信息。这要求浏览器和web服务器之间的有效连接,以便检索新信息来提供给用户。因此,当用户在移动设备上与web浏览器交互并且进入信号强度弱的区域或死区时,弱连接(或缺少连接)将可能导致移动设备接收的内容出错。因此,用户常常不能以这种方式与web页面交互。
所需要的是一种移动应用体系框架,它能提供直观的用户接口和更可靠的用来向移动设备用户提供内容的机制。该框架还应当提供来开发、部署和管理复杂的移动解决方案,同时允许集成了现有企业组件的、简单的类似web的编程模型。
发明内容
在一个实施例中,偶尔连接的应用服务器平台提供一种使用与现有企业组件集成的、简单的类似Web的编程模型开发、部署和管理复杂移动解决方案的框架。
偶尔连接的应用可以包括数据模型定义、用户接口模板、包括定义动作的脚本的客户端控制器、以及在服务器侧的用于描述如何在数据模型和企业之间仲裁的一组管道。在一个实施例中,偶尔连接的应用服务器假设由偶尔连接的应用使用的所有数据由外部系统永久地作为web服务存储和管理。该数据模型可以是该数据的偶尔连接的应用的预期用途的元数据描述,并且被优化来允许在偶尔连接设备和外部系统之间有效遍历和同步该数据。
偶尔连接的数据模型可以描述永久应用数据的结构(和其他属性)。偶尔连接的数据模型自身可以与浏览器同步,以便客户端能够智能地遍历数据并与服务器同步数据。
附图说明
图1A-B图解根据本发明一个实施例的架构概观。
图2图解根据本发明一个实施例的异步交互图。
图3图解根据本发明一个实施例的MAS应用的编程模型。
图4图解根据本发明一个实施例的实体关系图。
图5图解根据本发明一个实施例的UML实体关系图。
图6图解根据本发明一个实施例的节点实例图。
图7图解根据本发明一个实施例的选择操作。
图8图解根据本发明一个实施例的输入输出矩阵。
图9是根据本发明一个实施例的CRM模式类型图。
图10图解根据本发明一个实施例的部分CRM应用的页面流。
图11A-B图解根据本发明一个实施例的同步方法。
图12A-D图解根据本发明一个实施例的示例性keyref定义。
具体实施方式
在一个实施例中,偶尔连接的应用服务器平台提供了用于开发、部署和管理复杂移动解决方案的框架,具有集成现有企业组件的简单的类似web的编程模型。
连接-连接的应用可以包括:数据模型定义;用户接口模板;客户端控制器,其包括定义行动的脚本;和在服务器侧上的一组管道(conduit),用于描述如何在数据模型和企业之间仲裁。在一个实施例中,偶尔连接的应用服务器假设移动应用使用的所有数据由外部系统永久存储和管理。数据模型可以是移动应用对该数据的预期使用的元数据描述,并且可以被优化来允许在偶尔连接的设备和外部系统之间有效遍历和同步该数据。
偶尔连接的数据模型可以描述所有永久应用数据的结构(和其他特性)。模型自身可以与移动浏览器同步以便客户端能够智能地遍历数据并与服务器同步数据。
偶尔连接的数据模型可以描述将在客户端上被高速缓存和同步(或者可选地,在服务器上高速缓存)的数据。编程模型很多是使用元数据描述的,这为管理员和终端用户提供了对所部署的应用的高级控制。
在一个实施例中,在BEA Systems,San Jose,California的WebLogicWorkshop内可以完全支持编程模型—使用Workshop的可视设计工具和双程开发模型,并且允许开发者借用其他WebLogic Platform组件,如LiquidData和Integration。
建立移动化解决方案可以像建立Workshop Web应用一样简单,而不需要专家移动组。目标是从开发、部署、维护到日常使用,以很棒的所有权的总成本得到很棒的移动体验。
图1A-B示出一个实施例的总体系统架构100,它包括移动浏览器110、偶尔连接的应用服务器120和外部Web服务140。
偶尔连接的应用服务器120(OCAS),例如移动应用服务器(MAS),可以仲裁(mediate)在移动浏览器上运行的客户端应用和通过Web服务访问的外部系统之间的数据交换。该机制具有两个阶段:首先,OCAS 120可以协调外部数据和偶尔连接的数据模型之间的数据转换;其次,OCAS 120可以协调客户端高速缓存和外部Web服务之间的同步。
本发明的一个实施例是移动客户端111的偶尔连接的应用服务器120。偶尔连接的应用服务器120可以包括存储器,用于存储偶尔连接的数据模型127(如移动数据移动);和高速缓存128,用于存储偶尔连接的数据模型127所定义的数据节点。偶尔连接的应用服务器120可以将偶尔连接的数据模型中的元数据所指示的数据节点高速缓存在高速缓存128中。
偶尔连接的应用服务器120可以是在一台或多台机器上运行的软件。偶尔连接的应用服务器120可以在应用服务器之上运行,或者是应用服务器的一部分。偶尔连接的客户端111可以是个人数字助理(PDA)、电话、笔记本电脑或其他移动计算设备。客户端还可以包括固定的计算机,尤其是与服务器间歇联系的计算机。
偶尔连接的应用服务器120可以在外部系统(如web服务140)和偶尔连接的数据模型127定义的数据节点之间转换数据。
本发明的一个实施例是包括偶尔连接的应用服务器120的系统。偶尔连接的应用服务器120可以被配置成向客户端提供应用。应用可以允许客户端读取和更新应用数据,而不需要对偶尔连接的应用服务器的当前访问。偶尔连接的应用服务器120可以适用于从外部系统获得应用数据来发送给客户端。偶尔连接的应用服务器可以适用于将来自外部系统的数据转换成数据节点。外部系统可以是服务总线、web服务或一些其他系统。
偶尔连接的数据模型127可以指示移动客户端对外部数据的预期使用,并且在移动客户端111请求之前获得外部数据。
数据节点可以是独立的数据块,如XML数据。模型数据模型127可以包括对数据节点的XML定义,如XML模式(schema)或XML DTD。
本发明的一个实施例是包括偶尔连接的应用服务器120的系统。偶尔连接的应用服务器120的系统可以被配置成向客户端提供应用。应用可以允许客户端读取并更新应用,而不需要对偶尔连接的应用服务器的当前访问。偶尔连接的应用服务器120可以适用于从外部系统获得应用数据来发送给客户端。偶尔连接的应用服务器可以适用于将来自外部系统的数据转换成数据节点。外部系统可以是服务总线、web服务或一些其他系统。
移动客户端111可以传送数据节点和偶尔连接的数据模型115来在移动客户端111上产生显示。自适应用户接口服务器126可以由高速缓存128中的数据节点和客户端130的偶尔连接的数据模型127构建HTML页面。客户端130可以包括具有对访问服务器120的一致访问的传统web浏览器。自适应UI服务器126可以提供在服务器上运行客户应用的机制,允许从瘦(thin)客户端(例如,普通Web浏览器、SMS电话等)的访问。
移动客户端111可以在不用与偶尔连接的应用服务器120联系的情况下使用数据节点和偶尔连接的数据模型115运行应用。移动浏览器110处的客户端112可以使用高速缓存113中的数据节点和偶尔连接的数据模型115来产生诸如HTML视图119之类的显示。在一个实施例中,可以使用模板来在移动浏览器110上产生显示。
数据节点和偶尔连接的数据模型可以在偶尔连接的应用服务器120和移动客户端111之间同步。当移动客户端111和偶尔连接的应用服务器120之间的连接可用时该同步可以在后台进行。
本发明的一个实施例是一偶尔连接的应用服务器120,其包括:同步单元131,例如同步引擎,用于同步数据节点(如高速缓存128中的数据节点)与偶尔连接的数据模型定义的应用的客户端;和管道管理器124,用于在来自外部系统的数据和由偶尔连接的数据模型127定义的数据节点之间转换。
本发明的一个实施例是一方法,其包括:在偶尔连接的应用服务器120上存储偶尔连接的数据模型127定义的节点以及节点之间的关系;以及在偶尔连接的应用服务器120上高速缓存偶尔连接的数据模型127定义的数据节点。偶尔连接的应用服务器120可以高速缓存偶尔连接的数据模型127中的元数据所指示的数据节点。
本发明的一个实施例是一偶尔连接的应用服务器120,包括用于存储偶尔连接的数据模型127的存储器和用于存储偶尔连接的数据模型127定义的数据节点的高速缓存128。数据节点包括主关键字和同步状态。主关键字定义数据节点。数据节点还可以包括至少一个辅关键字。可以使用同步状态来同步数据节点与移动客户端。偶尔连接的数据模型127可以包括数据节点的XML模式。
本发明的一个实施例是一偶尔连接的应用服务器120。偶尔连接的应用服务器120可以包括:存储器,用于存储偶尔连接的数据模型127,偶尔连接的数据模型127可以定义节点以及节点之间的关系;和管道管理器124,用于在来自外部系统的数据和偶尔连接的数据模型127定义的数据节点之间转换。
管道管理器124可以使用管道137,管道137定义在由偶尔连接的数据模型127定义的数据节点和对特定web服务140的请求和响应数据之间的变换。该变换可以作为元数据包含。
请求变换可以包括XQuery函数,其用于创建输出消息主体。响应变换包括XQuery函数,其用于处理输入响应并且创建由偶尔连接的数据模型127定义的数据节点。
本发明的一个实施例是移动客户端111的偶尔连接的应用服务器120,包括管道管理器124,用于唤起外部web服务140操作。管道管理器124可以使用管道137。管道可以定义在偶尔连接的数据模型定义的数据与对特定web服务140的请求和响应之间的变换。
本发明的一个实施例是一方法,其包括:在偶尔连接的应用服务器120上使用管道137在偶尔连接的数据模型127定义的数据节点与对特定web服务140的请求和响应之间变换,数据节点是XML数据;以及在偶尔连接的应用服务器120上使用数据节点向移动客户端111提供数据供移动浏览器显示。数据节点可以被传送到移动客户端111供显示。
本发明的一个实施例是包括可存储在高速缓存113中的数据节点的移动客户端111。这些数据节点可以是XML格式的。移动客户端处的数据节点可以具有相关的同步状态。同步状态可以指示数据节点是否已经与服务器120同步。当到服务器的访问可用时,数据节点可以在后台同步,并且使用移动客户端11处的数据节点进行移动客户端111处的显示,而不用要求对服务器120的当前访问。
同步状态可以包括:数据节点被本地创建或修改的指示;数据节点被本地创建或修改、且准备好与服务器同步的指示;和数据节点与服务器同步被挂起的指示;数据节点与服务器同步的指示;以及该同步被服务器拒绝的指示;本地修改和服务器更新之间存在冲突的指示。可以使用这些和其他同步状态来更新客户端111上的数据节点。
移动客户端111可以从服务器120传送数据节点和偶尔连接的数据模型来在移动客户端上产生显示。移动客户端111可以在不与服务器当前联系的情况下使用数据节点和偶尔连接的数据模型115运行应用。服务器120和移动客户端111之间的数据节点的同步可以在后台进行。
本发明的一个实施例是一偶尔连接的应用服务器120,其包括:定义节点类型和节点之间的关系的偶尔连接的数据模型115;和数据节点。数据节点可以是XML格式。偶尔连接的应用服务器120可以与移动客户端111来回传递数据节点的同步状态来同步数据节点。当到服务器的访问可用时,数据节点可以在后台同步,并且使用移动客户端11处的数据节点进行移动客户端111处的显示,而不用要求对服务器120的当前访问。
本发明的一个实施例是一种用于同步移动设备上的移动应用的方法。该方法包括:在移动设备上显示第一用户接口,第一用户接口来自存储在移动设备上的模板;在移动设备上接收用户的第一输入;更新移动设备中的同步参数;在移动设备上显示第二用户接口,第二用户接口来自存储在移动设备上的第二模板并且是基于用户输入选择的;以及从应用服务器检索数据,数据包括一个或多个基于同步参数选择的模板。
本发明的一个实施例是移动单元111,包括XML格式的数据节点的本地高速缓存113以及定义节点类型和节点之间关系的偶尔连接的数据模型115,其中移动单元111使用数据节点和偶尔连接的数据模型来产生在移动单元上显示的应用。
可以使用模板135来在移动节点单元上产生数据节点的接口。
本发明的一个实施例是移动单元110,其包括:XML格式的数据节点的本地高速缓存128;以及定义节点类型和节点之间关系的偶尔连接的数据模型115;以及允许修改数据节点的动作(action)。
本发明的一个实施例是移动单元110,包括存储偶尔连接的数据模型115的存储器和偶尔连接的数据模型115定义的数据节点的本地高速缓存113。数据节点包括主关键字和同步状态。
在一个实施例中,至少一个数据节点包括至少一个辅关键字。可以使用同步状态来同步模式数据与偶尔连接的应用服务器。偶尔连接的数据模型115可以包括数据节点的至少一个XML模式。
本发明的一个实施例是移动客户端的偶尔连接的应用服务器120,包括用于在外部系统(如web服务140)和偶尔连接的数据模型127之间转换的管道管理器;高速缓存128,可以用来存储偶尔连接的数据模型127定义的数据节点;和自适应用户接口服务器126。一些移动客户端111被传送数据节点和偶尔连接的数据模型来在移动客户端111上产生显示,而其他客户端从偶尔连接的应用服务器120接收HTML页面,偶尔连接的应用服务器120是由自适应用户接口服务器126使用数据节点和偶尔连接的数据模型构造的。
自适应用户接口服务器124服务的客户端130可以具有传统的浏览器。移动客户端111可以具有特殊的浏览器110,该浏览器使用数据节点和偶尔连接的数据模型来产生显示。
本发明的一个实施例是一方法,其包括:在服务器120上,存储偶尔连接的数据模型127定义的数据节点和偶尔连接的数据模型127;将数据节点和偶尔连接的数据模型传送给一些客户端111,从而客户端可以产生显示;以及将在服务器上由数据节点和偶尔连接的数据模型构造的HTML页面传送给其他客户端130。
本发明的一个实施例是一偶尔连接的数据模型,其包括:描述节点结构的节点类型,节点可以是逻辑上独立的数据单元;和描述节点之间关系的keyref声明。
节点可以包括根节点。变量可以指向根节点。移动浏览器110可以使用数据节点和偶尔连接的数据模型115来在移动单元111产生显示。偶尔连接的数据模型可以包括节点图。节点图可以指示高速缓存哪个数据节点。
节点类型可以包括XML定义,如XML模式(复型定义)。keyref声明可以定义关键字和keyref。关键字可以是主关键字。Keyref可以是参照主关键字的外关键字定义。Keyref定义可以定义数据图中节点之间的合法遍历。
本发明的一个实施例是一偶尔连接的数据模型,其包括:节点类型,它是节点结构的XML定义;和描述节点之间关系的元数据,如keyref定义。节点可以是逻辑上独立的数据单元。
本发明的一个实施例是一种用于实现代理(proxy)的方法,其包括:将web服务操作映射到编程模型(如偶尔连接的数据模型)内的数据,接收与数据有关的请求;以及启动对相应web服务操作的调用。
本发明的一个实施例是移动单元111,其包括:应用数据节点的本地高速缓存113,数据节点是XML格式的;定义节点类型和节点之间关系的偶尔连接的数据模型115;和模板135,用于产生数据节点的接口。
模板135可以是XHTML模板。模板135可以使用Spath表示。
模板135可以访问偶尔连接的数据模型115中的当前位置。当前变量可以指示当前位置。在一个实施例中,模板135不修改偶尔连接的数据模型。
在一个实施例中,模板135可以调用动作。动作可以修改数据节点。动作可以允许在不连接到服务器120的情况下修改数据节点。
模板135可用于多个应用,每个应用具有其自己的偶尔连接的数据模型和数据节点。模板135可以由浏览器110使之有效。
图11A-B示出本发明一个实施例的同步方法。在图11A的例子中,客户端1102包括客户端版本的“数据节点A”1104。客户端版本的“数据节点A”1104具有同步状态“准备好同步”。客户端版本的“数据节点A”1104可以包括在客户端1102上构造或修改的数据。在图11A的例子中,客户端1102和服务器1108之间没有有效连接。客户端上的应用可以使用客户端版本的“数据节点A”1104而不必等待同步。“数据节点A”的改变可以包含在当连接可用时发送的消息队列1106中的消息中。
服务器1108具有还没送到客户端1102的服务器版本的“数据节点B”1110。服务器版本的“数据节点B”1110可以由从“web服务B”1116得到的数据构造。管道管理器可以使用“管道B”1114来将来自“web服务B”1116的响应数据转换成服务器版本的“数据节点B”1110。“数据节点B”可以包含在当连接可用时发送的消息队列1118中的消息中。
图11B示出当连接变得可用时的情况。可以将客户端版本的“数据节点A”1104发送到服务器1108,并且客户端版本的“数据节点A”1104可以使其同步状态设为“等待同步”。服务器1108可以高速缓存服务器版本的“数据节点A”1111。管道管理器1112可以使用“管道A”1115来构造要送到“web服务A”1117的请求数据。客户端1102可以存储从服务器1108获得的客户端版本的“数据节点B”1105。
使用在后台与服务器同步的数据节点,这允许具有到服务器的间歇连接的客户端用本地版本的数据节点运行应用,并且在连接可用时更新。
下面的描述给出了一个实施例的一个非限制性实现。下面的讨论给出一个实施例,但本领域技术人员应当理解,可以进行上述构思的其他实现。下面给出的任何可能的限制性语言应当在特定非限制性实现的上下文中解释,而不意图限制总的构思。
本发明的一个实施例是提供偶尔连接的访问机制的系统,包括浏览器110。浏览器可以配置成在移动设备111上实现,并且向用户提供用户接口。用户接口可以来自模板135。还包括应用服务器120,应用服务器120被配置成提供永久性数据存储器并且与浏览器传输信息。
在一个实施例中,偶尔连接的应用服务器120(MAS)在应用服务器(如BEA Systems的WebLogic服务器)上运行或者是其一部分。偶尔连接的应用服务器120包含用于存储应用元数据的永久数据存储器和用于优化客户端请求的数据高速缓存128。
偶尔连接的应用服务器120可由移动浏览器通过一套基于Web的同步服务(可以扩展SyncML标准)访问。这允许不同类型的客户端利用MAS数据模型和同步能力。
偶尔连接的应用服务器120不需要保存客户端的全部状态。相反,偶尔连接的应用服务器120可以基于偶尔连接的数据模型127中的元数据智能地高速缓存数据。此外,偶尔连接的应用服务器120可以包含称为自适应UI服务器126的动态内容自适应机制,它能够将移动应用功能提供给瘦客户端(例如,HTML网站、WAP、SMS)。
在一个实施例中,偶尔连接的数据模型可以是移动应用对该数据的预期使用的元数据描述,并且可以被优化来允许在偶尔连接的设备和外部系统之间有效遍历和同步该数据。
偶尔连接的数据模型可以是描述与外部服务相关的数据的节点(或实体),以及它们之间的遍历(或关系)。例如,假设Web服务提供对客户关系管理(CRM)应用的访问,那么数据模型可能具有帐户、联系人和订购单等节点,以及让应用从给定节点(例如,帐户)“导航”到所有有关节点(例如,联系人和订购单)的遍历。
偶尔连接的数据模型可以作为虚拟的XML文档面向开发者,具有指向数据模型中的根节点的显式(manifest)变量$root。可以在虚拟XML文档中通过keyref声明来定义与节点有关的导航。这允许使用在XML的ECMAScript中使用的、在该文档中称为Spath的XPath符号的子集的简单遍历句法。此外,移动浏览器总是可以具有数据模型内的当前位置作为内容(例如一个特定客户或一组订单)。模板和脚本可以通过另一显式变量$current访问该当前位置。
在一个实施例中,移动浏览器110是(或者包括)Web浏览器的扩展,该扩展允许偶尔连接的便携计算机和其他设备运行应用而不管它们恰巧是连接的还是脱机的。浏览器可以包括与当前Web浏览器相同的HTML呈现器,还包括用户接口面板和页面流(page flow)机制、具有智能同步能力的数据高速缓存和提供对数据高速缓存访问的扩展脚本语言。
移动浏览器的用户接口可以由页面模板组成。模板可以是XHTML页面,具有到使用SPath表示的高速缓存数据的内嵌绑定(binding)。在一个实施例中,模板不依赖服务器侧,从而不管浏览器的网络连接状态(即,在线或脱机)如何都可以呈现它们。
模板可以生成用户接口事件,后者可以被控制器捕获;控制器可以调用动作脚本,动作脚本能够修改客户端高速缓存中的数据并确定页面流。客户端同步单元可以自动同步与偶尔连接的应用服务器120的数据访问和改变。
可以通过指向引用实现客户端用户接口的XML应用封装和该应用的偶尔连接的数据模型的URL,来向移动浏览器110提供应用。应用然后可以同步到同步客户端112。此外,一旦部署了应用,可以自动和无缝地更新应用。
在一个实施例中,自适应UI服务器124可以是为每个现时用户运行客户端应用(模板、页面流、动作等)的代理。它可以生成送到浏览器130的HTML页面(或SMS等),并且HTML页面可以包含用于生成HTTP请求的适合的超链接,HTTP请求被自适应服务器转换成相应的动作调用。自适应服务器126可以使用与移动浏览器110相同的同步机制。
客户端应用可以通过同步与服务器通信。同步进程可以触发管道请求来取出新的或更近的数据,或者请求将被投递回外部Web服务140的客户端改变。管道137可以包含描述如何封装Web服务请求和如何将它们的响应转换成数据模型内容的元数据。
例如,假设客户端应用修改高速缓存在客户端上的特定帐户节点(记录)的额定码(rating code);同步机制可以生成发送到服务器的更新命令。如果客户端应用然后检索与帐户相关的联系人,然后添加新的联系人,则同步机制可以生成取出和添加相应数据节点的命令。管道可以描述如何调用所需的各种Web服务操作来实现这些操作中的每一个。
系统可以使用标准Web服务来与外部数据源和业务进程交换信息。管道机制可以允许偶尔连接的应用服务器120调用这些操作来更新移动数据高速缓存128。操作可以用作特定数据类型的获取器和设置器;用作适配器的管道可以管理一套操作。管道管理器可以协调OCAS的数据高速缓存的同步请求和管道操作。
管道可以是用于将Web服务与三种类型的关于数据模型的请求动作相关系的元数据:
■导航到有关数据,例如,得到与帐户相关的联系人;
■CRUD操作;即,创建、读取、更新和删除数据的请求,例如,创建与帐户有关的联系人、更新联系人细节、或者甚至请求删除联系人;
■自定义操作,是需要在企业中发生的与一些数据有关、但对数据模型是不透明的动作,例如,请求关闭任务。
管道元数据可以向/从与相应Web服务操作相关的SOAP消息映射OCAS数据模型和同步命令。可以使用XML Query或XScript定义管道元数据。
当前Web浏览器架构对于移动性的一个主要缺点是同步(阻塞式)请求-响应消息收发协议(即,HTTP)。在OCAS中,消息收发可以是异步的。即,用户接口活动(例如,浏览页面和修改数据)可以相对网络的连通性异步地运行,并且同步请求可以相对浏览器异步地运行。
图2示出移动浏览器210、OCAS 220和外部Web服务230之间的示例性异步交互。该系统实现浏览器和OCAS之间可靠、有序的消息队列,并且可以在OCAS和Web服务之间使用持久的JMS队列(用于异步操作调用)。
如果浏览器在线,则可以将同步消息排队,稍后送到OCAS。否则,同步单元可以跟踪这些事件并且只要一建立连接就生成同步消息。
在服务器上,如果OCAS高速缓存了与客户端的同步请求有关的数据,则它可以立即响应。如果高速缓存没有保存适当的数据(或者数据是失效的),则同步单元可以调用管道管理器。同步单元然后可以将更新的数据传递到浏览器。由于对于一个特定同步请求可能存在多个调用的管道,因此OCAS可以将多个同步消息传递到浏览器。
当浏览器接收到同步消息时,可以更新本地高速缓存并且将事件送到控制器。如果当前正显示的数据被修改了(即,数据绑定到当前模板),则控制器可以使当前页面刷新。即,可以重新计算页面数据绑定并且在浏览器中递增地重新显示页面,而不闪烁或失去当前用户输入、插入记号(caret)或焦点。
OCAS应用可以包括客户端和服务器组件。图3示出示例性OCAS应用的编程模型300。编程模型300包括移动客户端310、OCAS 320和外部系统330。
在一个实施例中,所有到外部系统(即,企业)的通信可以通过Web服务(即,SOAP消息)实现。服务器编程模型可以包括每个应用的数据模型定义323和描述Web服务操作的一组管道定义324。数据模型包括描述数据类型和关系的一组XML模式定义。管道定义包含Xscript和XML Query(XQuery)函数,该函数将输入和输出的SOAP消息映射到数据模型。
客户端编程模式可以包括数据模型311(服务器上定义的模型的副本)、一组XHTML模板312和控制器定义313,控制器定义313包括XPF页面流定义和Xscript动作和函数。整个应用的内容可以通过单个XML文件描述,框架自动使用该文件来向客户端提供应用组件。
在一个实施例中,每个OCAS应用可以具有其自己的偶尔连接的数据模型。偶尔连接的数据模型可以描述通过Web服务由后端应用显露的应用数据的逻辑结构(和其他属性)。偶尔连接的数据模型可以包括:节点类型,用于描述数据模型中的节点(或实体);和keyref,用于定义节点类型之间的关系。偶尔连接的数据模型可以用作其他OCAS组件处理数据或相互交换数据使用的通用语(lingua franca)。
应用的数据模型的实际设计(由应用设计者完成)可以考虑数据的预期使用,以便优化客户端应用对数据的访问以及服务器与偶尔连接的设备之间的数据同步。
也可以指定额外的元数据来让应用更容易地显示数据驱动(即,自动)的用户接口。在一个实施例中,偶尔连接的数据模型仅描述数据;OCAS假设所有操作数据由外部系统存储和管理(所有),即,OCAS中没有永久驻留的操作数据。
偶尔连接的数据模型可以用来描述可在客户端和服务器这两者上高速缓存的数据,并且本质上可以是通过Web服务取出的企业中的数据之上的虚拟高速缓存视图。在一个实施例中,在偶尔连接的数据模型中,存在称为mas:root(在编程模型中用$root引用)的魔术(magic)起始节点,一切从该节点流出。
可以通过遍历从任何节点访问有关的节点。节点可以遵从XML模式定义(/schema/*/xsd)。遍历也可以使用keyref声明由模式定义来定义。
自动同步机制可以协调客户端和服务器数据之间的改变。可以通过称为管道的机制检索并与外部系统交换数据。管道可以由一组管道文件(/conduit/*/jsx)配置,这组文件定义管道操作—用于调用和处理来自外部Web服务操作的结果的XScript和Xquery函数。
管道操作可以包括与给定keyref相关的一对XML Query函数;一个函数可以将出去的请求格式化成适当的Web服务操作,另一个可以处理进来的响应。管道操作还可以定于相关XScript函数中的过程逻辑。
偶尔连接的数据模型可以表示为包括节点和遍历的数据图—与关系数据库中的实体(即,表格行)和关系(即,主/外关键字字段)。节点是逻辑上独立的数据单元(或实体—例如,客户、订购单或联系人记录)并且可以表示为由XML模式定义的XML数据对象。在高速缓存内,每个节点可以包括主关键字、同步状态(例如,包括序列号)以及引用其他节点的外关键字。节点类型可以描述关于节点的特定类型的信息;这可以包括描述数据节点的结构的XML模式定义。遍历可以是两个节点之间的方向广西。遍历可以主要是用于从一个节点导航到一组有关节点的机制。例如,帐户可以与一组联系人和一组任务相关联,每个任务也可以与联系人相关联。节点之间的关系可以由keyref声明定义。它可以定义源和目标节点类型,并且可以包括元数据来确定节点集的基数(cardinality)(例如,正好为1、0或更多,1或更多等)。管道管理者的元数据可以与keyref相关联并且确定是否可以创建、更新、链接或移除节点。例如,管道的元数据确定是否有用于插入关于帐户的通知或更新帐户的已知Web服务操作。由keyref定义的特定节点集合可以称为节点集。
数据节点
数据节点可以包括结构化的数据(即,XML文档),但可以对于遍历是基本的(atomic);即,在一个实施例中,遍历表示两个节点之间的特定关系,但不引用特定节点内的数据;节点内的数据也不能引用另一节点。
常常单个企业文档可能由多个节点类型构成。例如,订购单可以包括行式项目(line item)(每个具有产品引用)和客户引用。在这种情况下,订购单、行式项目、产品和客户都可以表示为不同的节点类型。
在这些“复合”节点的情况下,数据模型内的keyref可以定义基数,例如,行式项目只与一个产品相关联。相反,根据应用的需要,可以定义单个订购单节点类型来在单个模式中包含所有上述信息。判决取决于应用设计者—根据基于不同遍历、集合和面板要求单独地链接不同节点的需要。例如,如果行式项目从未链接或显示在订购单外面,则定义复合的订购单-行式项目节点类型可能是有意义的。
关系模型
偶尔连接的数据模型可以包括模式和keyref声明,与关系实体和关系(主/外关键字)构造类似。
主关键字和外关键字
示例的CRM系统(为了说明的目的在整个本文档中参考它)是使用关系数据库实现的。图4所示的实体关系图(ERD)400表示帐户、联系人、事件和用户实体。
帐户、联系人和用户实体由下面的SQL定义。
CREATE TABLE account(
   pkey           INT NOT NULL PRIMARY KEY,
   parentPkey     INT FOREIGN KEY REFERENCES account(pkey),
   ownerPkey      INT FOREIGN KEY REFERENCES user(pkey),
   name           VARCHAR,
   type           CHAR
)
CREATE TABLE contact(
   pkey           INT NOT NULL PRIMARY KEY,
   accountPkey    INT NOT NULL FOREIGN KEY REFERENCES account(pkey),
   ownerPkey      INT FOREIGN KEY REFERENCES user(pkey),
   first          VARCHAR,
   last           VARCHAR,
   email          VARCHAR
)
CREATE TABLE user(
   pkey           INT NOT NULL PRIMARY KEY,
   login          VARCHAR
)
帐户和联系人实体都包含对用户(所有者)的外关键字引用;每个联系人实体定义对帐户的文件引用。此外,每个帐户具有引用父帐户(即,具有子帐户的帐户)的可选外关键字。
采样查询(Sample Query)
给定帐户的主关键字pa,下面的SQL选择所有联系人:
SELECT*FROM contact WHERE accountPkey=pa
给定联系人的主关键字pc,下面的SQL选择帐户:
SELECT account.*FROM account,contact
WHERE account.pkey=contact.accountPkey
AND contact.pkey=pc
然而,给定全部联系人记录c,则该简单SELECT查询选择相应帐户:
SELECT*FROM account WHERE account.pkey=c.accountPkey
联合表(Join Table)
假设事件可以属于多个帐户和联系人(例如,有两个客户(account)出席的销售会议)。将使用联合表来建模,例如,
CREATE TABLE event(
   pkey           INT NOT NULL PRIMARY KEY,
   title          VARCHAR,
   details        VARCHAR
)
CREATE TABLE event_account(
   eventPkey      INT FOREIGN KEY REFERENCES EVENT(pkey),
   accountPkey    INT FOREIGN KEY REFERENCES ACCOUNT(pkey)
)
这里,由事件_帐户联合表来建模多对多关系。给定帐户的主关键字pa,下面的SQL(联合)选择所有有关事件:
SELECT event.*FROM event,event_account
WHERE event_account.accountPkey=pa
AND event.pkey=event_account.eventPkey
类似地,给定事件的主关键字pe,下面的SQL选择所有有关帐户:
SELECT account.*FROM account,event_account
WHERE event_account.eventPkey=pe
AND account.pkey=event_account.accountPkey
XML模式
XML模式可以定义应用所使用的数据模型中的节点类型。模式子目录可以包括多个.xsd文件,所有文件都在启动时由框架加载。
模式类型定义可以包括两部分:复合类型(complexType)定义,描述类型的结构;和元数据定义(使用mas名字空间(namespace)),例如,定义如何构建特定类型的标签。
例如,下面模式定义了联系人类型。
  <?xml version=″1.0″?>
  <xsd:schema targetNamespace=″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:element name=″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:complexType name=″contactType″>
   <xsd:sequence>
       <xsd:element name=″salutation″type=″contactSalutationEnum″/>
       <xsd:element name=″first″type=″xsd:string″/>
       <xsd:element name=″last″type=″xsd:string″/>
       <xsd:element name=″email″type=″xsd:string″/>
   </xsd:sequence>
</xsd:complexType>
<xsd:simpleType name=″contactSalutationEnum″>
   <xsd:restriction base=″xsd:string″>
       <xsd:enumeration value=″Mr″/>
       <xsd:enumeration value=″Mrs″/>
       <xsd:enumeration value=″Ms″/>
       <xsd:enumeration value=″Dr″/>
   </xsd:restriction>
</xsd:simpleType>
下面的XML表示联系人元素。
<contact>
   <salutation>Mr</salutation>
   <first>Roger</first>
   <last>Reed</last>
   <email>rogeracme.com</email>
</contact>
Keyref基础
偶尔连接的数据模型可以包括对所有应用类型的标准XML模式定义。模式可以定义包含被其他XML引用的XML元素和属性的节点。可以使用keyref声明来对这些引用进行定义。
Keyref定义可以包括两部分:关键字和keyref。
关键字定义可以定义文档中包含主关键字的地方。例如,下面的关键字表明,在每个<account>元素中作为称为id的属性出现的accountKey。
<xsd:key name=″accountKey″>
    <xsd:selector xpath=″account″/>
    <xsd:field xpath=″id″/>
</xsd:key>
在一个实施例中,关键字可以唯一地表示单个节点。关键字不能用于标识节点内重复的元素(例如,如果在订购单的模式内定义行式项目,则不能使用关键字定义来定义各个行式项目)。
Keyref定义可以定义文档中包含外关键字的地方;参考(refer)属性指的是相关联的关键字定义。例如,下面的keyref表明,每个联系人中包含帐户属性,该属性是引用(上述)accountKey定义的外关键字。
<xsd:keyref name=″contactAccountRef″refer=″accountKey″>
    <xsd:selector xpath=″contact″/>
    <xsd:field xpath=″accountId″/>
</xsd:keyref>
可以有许多引用相同(主)关键字定义的keyref(外关键字)定义。
类型和实例图
使用UML来说明节点类型和keyref图。
图5示出示例CRM应用的UML实体关系图(ERD)500。在该图中,每个实体表示应用节点类型(即,模式)。注意,根(root)实体是系统节点类型。
弧线表示关系(即,keyref定义),其中黑色菱形表示源节点类型的外关键字的目标节点类型。星型注释表示多对一关系。每条线标有相应keyref的别名。图6示出用于CRM情况的节点实例图。
名字空间
下面给出示例性的名字空间实施例。服务器编程模型可以使用名字空间来区别框架和应用XML元素。名字空间定义可以作为属性包含在XML源文件的顶级元素中。
以mas名字空间为前缀的元素表示系统元素。
xmlns:mas=″urn:bea.mas″
按照惯例,以app名字空间前缀为前缀的元素表示应用。
xmlns:app=″http://example.com/″
此外,按照惯例(在本文档中),ws名字空间前缀用于指示由示例Web服务定义所定义的元素(即,WDSL文件);sfdc前缀用于指示SalesForce(销售人员)Web服务。
xmlns:ws=″http://www.openuri.org/″
xmlns:sfdc=″urn:partner.soap.sforce.com″
模式数据类型
可以支持下面的XML模式数据类型。
  状态   含义
  xsd:base64Binary   基本的64编码字节阵列(即,字节的阵列)
  xsd:boolean   布尔值(即,“true”或“false”)
  xsd:date
  xsd:decimal
  xsd:double   IEEE 64位浮点数
  xsd:integer   任意长度的有符号整数
  xsd:string   任意长度的串
模式注释
标准的XSD模式定义可以通过在<xsd:appinfo>元素内声明mas元素来扩展。
<xsd:element name=″typeName″type=″type″>
   <xsd:annotation>
      <xsd:appinfo>
      </xsd:appinfo>
      <xsd:documentation>schema documentation</xsd:documentation>
   </xsd:annotation>
</xsd:element>
支持下面的模式注释:
  元素   含义
  mas:lable   声明标签Xpath表达式。
标签
mas:label元素声明节点的缺省标签;它声明XPath表达式,用于构造串。表达式可以可选地引用$node变量,它是指XML节点对象的顶级元素。
句法
<mas:label>spath-expression</mas:label>
例子
下面的标签定义由联系人的名和姓构造串。
<xsd:element name=″contact″type=″contactType″>
   <xsd:annotation>
      <xsd:appinfo>
         <mas:label>$node.first+″″+$node.last</mas:label>
      </xsd:appinfo>
   </xsd:annotation>
</xsd:element>
这与下面的表达式等效。
<mas:label>first+″″+last</mas:label>
标签定义还可以包含XScript函数和运算符。
($node.first)+($node.first.length()>0?″″:″)+$node.last
应用数据模型定义的剖析
下面的XML模式描述了定义帐户和联系人节点类型的简单应用数据模型:
       <xsd:schema ...>
          <xsd:complexType name=″accountType″>
             <xsd:all>
                 <xsd:element name=″name″type=″xsd:string″/>
                 <xsd:element name=″type″type=″xsd:string″/>
             </xsd:all>
             <xsd:attribute name=″id″type=″xsd:string″use=″required″
      mas:type=″pkey″/>
             <xsd:attribute name=″ownerId″type=″xsd:string″use=″required″/>
             <xsd:attribute name=″parentId″type=″xsd:string″/>
         </xsd:complexType>
         <xsd:complexType name=″contactType″>
            <xsd:all>
                <xsd:element name=″first″type=″xsd:string″/>
                <xsd:element name=″last″type=″xsd:string″/>
                <xsd:element name=″email″type=″xsd:string″/>
            </xsd:all>
            <xsd:attribute name=″id″type=″xsd:string″use=″required″
     mas:type=″pkey″/>
            <xsd:attribute name=″ownerId″type=″xsd:string″use=″required″/>
            <xsd:attribute name=″accountId″type=″xsd:string″use=″required″/>
        </xsd:complexType>
        <xsd:element name=″graph″>
           <xsd:complexType>
              <xsd:element name=″root″type=″mas:rootType″/>
              <xsd:sequence>
                 <xsd:element name=″account″type=″accountType″
maxOccurs=″unbounded ″/>
                 <xsd:element name=″contact″type =″contactType″
maxOccurs=″unbounded″/>
           </xsd:sequence>
       </xsd:complexType>
       <xsd:key name=″accountKey″>
           <xsd:selector xpath=″account″/>
           <xsd:field xpath=″id″/>
       </xsd:key>
       <xsd:keyref name=″contactAccountRef″refer=″accountKey″
mas:alias=″account″
           mas:inverseAlias=″contacts″>
           <xsd:selector xpath=″contact″/>
           <xsd:field xpath=″accountId″/>
       </xsd:keyref>
   </xsd:element>
</xsd:schema>
模式文件可以包括三部分:节点类型(复合类型定义)、定义高速缓存“文档”的结构的图定义、和与相对于图(即,文档)结构的关键字/keyref定义。
模式定义
与前面一样,数据模型包括XML模式定义。下面的模式定义account和contact节点类型。
 <xsd:schema...>
    <xsd:complexType name=″accountType″>
        <xsd:all>
            <xsd:element name=″name″type=″xsd:string″/>
        </xsd:all>
        <xsd:attribute name=″id″type=″xsd:string″use=″required″
 mas:type=″pkey″/>
        <xsd:attribute name=″ownerId″type=″xsd:string″use=″required″/>
        <xsd:attribute name=″parentId″type=″xsd:string″/>
    </xsd:complexType>
    <xsd:complexType name=″contactType″>
        <xsd:all>
           <xsd:element name=″first″type=″xsd:string″/>
           <xsd:element name=″last″type=″xsd:string″/>
           <xsd:element name=″email″type=″xsd:string″/>
       </xsd:all>
       <xsd:attribute name=″id″type=″xsd:string″use=″required″
mas:type=″pkey″/>      <xsd:attribute name=″ownerId″type=″xsd:string″
use=″required″/>
        <xsd:attribute name=″accountId″type=″xsd:string″use=″required″/>
    </xsd:complexType>
所有类型可以定义主关键字字段(或属性),声明为关键字。
在例子中,所有类型可以定义外部标识符id,表示外部记录的主关键字;contact类型也定义表示外关键字的属性accountId。
上述模式定义将允许下面的实例数据:
<account id=″1.1″>
   <name>Acme</name>
</account>
<contact id=″1.2″accountId=″1.1″>
   <first>Bob</first>
   <last>Harris</last>
   <email>bobacme.com</email>
</contact>
<contact id=″1.3″accountId=″1.1″>
   <first>Maggie</first>
   <last>Cheung</last>
   <email>maggieacme.com</email>
</contact>
要注意,所示标识符值是说明性的;此外,这些例子没有显示mas属性,后者由框架管理,并且对于编程模型是不可见的。
数据图定义
偶尔连接的数据模型可以作为虚拟XML文档或数据图面向开发者。应用通过指定模式和keyref声明来定义数据图的结构。
然而,关键字keyref声明自身可以包括相对于应用模式的<graph>元素定义的固定文档结构的XPath。
图类型可以定义“扁平”的节点声明序列。
<xsd:complexType name=″rootType″/>
<xsd:element name=″root″type=″rootType″/>
<xsd:complexType name=″graphType″>
   <xsd:sequence>
       <xsd:element ref=″root″/>
   </xsd:sequence>
</xsd:complexType>
<xsd:complexType name=″graphType″>
   <xsd:complexContent>
       <xsd:extension base=″mas:graphType″>
           <xsd:sequence minOccurs=″0″maxOccurs=″unbounded″>
               <xsd:choice>
                   <xsd:element name=″nodeName″type=″nodeType″/>
                </xsd:choice>
            </xsd:sequence>
        </xsd:extension>
    </xsd:complexContent>
</xsd:complexType>
<xsd:element name=″graph″type=″graphType″>
    <key-definitions>
    <keyref-definitions>
</xsd:element>
例子
     <xsd:element name=″graph″>
         <xsd:complexType>
             <xsd:element name=″root″type=″rootType″/>
             <xsd:sequence>
                 <xsd:element name=″account″type=″accountType″
maxOccurs=″uhbounded″/>
                 <xsd:element name=″contact″type=″contactType″
maxOccurs=″unbounded″/>
           </xsd:sequence>
       </xsd:complexType>
这定义了根元素的类型,并且构成应用的所有模式类型的集合。
要注意,图结构很大程度上可以是实现细节—开发者使用关键字/keyref定义遍历数据图。一种建议的图实现是扁平的—即,所有节点类型是<graph>元素的第一级孩子。
上述例子将允许下面的实例数据:
<graph>
   <account id=″1.1″>
       <name>Acme</name>
   </account>
   <contact id=″1.2″accountId=″1.1″>
       <first>Bob</first>
       <last>Harris</last>
       <email>bobacme.com</email>
</contact>
<contact id=″1.3″accountId=″1.1″>
       <first>Maggie</first>
       <last>Cheung</last>
       <email>maggieacme.com</email>
   </contact>
<graph>
关键字和KeyRef定义
模式定义文件还可以包含关键字和keyref定义,它们可以声明数据类型之间的主关键字和外关键字关系。
关键字定义可以定义主关键字。关键字可以包括多个字段声明(即,对于复合关键字)。
keyref定义定义引用关键字定义的外关键字。
例如,下面的关键字和keyref定义定义了从联系人节点到其相关帐户节点的多对一(查找)关系,和从根到帐户的一对多关系。
     <xsd:key name=″accountKey″>
          <xsd:selector xpath=″account″/>
          <xsd:field xpath=″id″/>
      </xsd:key>
      <xsd:keyref name=″contactAccountRef″refer=″accountKey″
mas:alias=″account″>
           mas:inverseAlias=″contacts″>
           <xsd:selector xpath=″contact″/>
           <xsd:field xpath=″accountId″/>
        </xsd:keyref>
    </xsd:graph>
</xsd:schema>
关键字和keyref定义应当具有唯一的名字。下面分别是关键字和keyref的命名传统:
<xsd:key name=″<schema>Key″...
<xsd:keyref name=″<sourceSchema><element|attribute>Ref″...
例如,fooBarRef表示由名为bar的元素或属性定义的foo模式的keyref。即,(通常)keyref的选择器XPath是“foo/bar”或“foo/bar”。
通常,keyref名是由连接keyref的选择器和字段、并且剥去任何mas元素而构建的“camelBack”(驼峰式)破损的名字。例如,
<xsd:keyref name=″contactAccountRef″refer=″accountKey″>
   <xsd:selector xpath=″contact″/>
   <xsd:field xpath=″accountId″/>
</xsd:keyref>
<xsd:keyref name=″messageFromRef″refer=″contactEmailKey″>
    <xsd:selector xpath=″message″/>
    <xsd:field xpath=″from″/>
</xsd:keyref>
<xsd:keyref name=″messageToRef″refer=″contactEmailKey″>
    <xsd:selector xpath=″message/to″/>
    <xsd:field xpath=″.″/>
</xsd:keyref>
要注意,类型可以通常从名字的后一部分推断,这是由于这是元素或属性名,后面的XML指南将说明所包含的数据的用途。
框架可以确保卡keyref名不与顶级元素属性名冲突。
别名
keyref声明可以定义数据图内的节点之间的合法遍历。运算符可以用于遍历该图,并且缺省地使用keyref名。然而,可以定义别名来使代码更易读。
mas:alias属性定义串,它可选地具有两部分:
mas:alias=″[XPath:]name″
其中name表示别名,而可选的XPath前缀表示在运算符和别名之前必须经过的SPath(相对于图)。即,
var refNode=srcNode.SPnth.name
如果不存在冒号分隔符,则别名XPath前缀与keyref的选择器XPath相同。如果没有定义别名,则必须使用keyref名(相对于keyref选择器XPath)。
关键字定义也可以声明mas:alias属性,它指示包含相关节点类型的节点集可从根节点遍历。关键字定义的别名是简单的串,并且这也被运算符使用:
mas:alias=″name″
例子
下面的XML表示帐户节点的实例:
<account id=″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>
</accouht>
帐户节点的关键字定义如下:
<xsd:key name=″accountKey″mas:alias=″accounts″>
   <xsd:selector xpath=″account″/>
   <xsd:field xpath=″id″/>
</xsd:key>
这允许下面的导航句法:
var accounts=$root.accounts.*;
“product”别名定义如下:
<xsd:keyref name=″accountProductsRef″refer=″productKey″mas:alias=″product″>
   <xsd:selector xpath=″account/purchaseOrders/purchaseOrder/lineItem″/>
   <xsd:field xpath=″prodId″/>
</xsd:keyref>
下面的表达式遍历到第一订购单的第一行式项目所引用的产品。
var product=account.purchaseOrders.*[0].lineItems.*[0].product;
“owner”别名定义如下:
<xsd:keyref name=″accountOwnerRef″refer=″UserKey″mas:alias=″owner″>
   <xsd:selector xpath=″account″/>
   <xsd:field xpath=″ownerId″/>
</xsd:keyref>
下面的表达式遍历到“owner”别名所描述的keyref引用的用户节点。
var user=account.owner;
“event”别名定义如下:
<xsd:keyref name=″accountEventsRef″refer=″eventKey″mas:alias=″events″>
   <xsd:selector xpath=″account/events/eventRef″/>
   <xsd:field xpath=″.″/>
</xsd:keyref>
下面的表达式遍历到“event”别名所描述的keyref引用的事件节点。
var events=account.events.*;
要注意,“product”别名也可以定义如下:
<xsd:keyref name=″accountProductsRef″refer=″productKey″
   mas:alias=″account:products″>
   <xsd:selector xpath=″account/purchaseOrders/purchaseOrder/lineItem″/>
   <xsd:field xpath=″prodId″/>
</xsd:keyref>
下面的表达式遍历到所有行式项目(对所有订购单)的所有产品。
var products=account.products.*;
逆向关系
keyref声明可以可选地定义逆向keyref,后者允许在逆方向上导航。典型地,多对一keyref声明逆keyref,允许逆向一对多遍历。
<xsd:keyref name=″name″refer=″keyName″mas:alias=″alias″
   mas:inverseAlias=″inverseAlias″>
逆向属性定义如下:
  属性   含义
  mas:inversaeAlias   逆向关系的别名
例如,下面的keyref定义表示联系人→帐户和帐户→联系人关系:
<xsd:keyref name=″contactAccountRef″refer=″accountKey″mas:alias=″account″
   mas:inverseAlias=″contacts″>
   <xsd:selector xpath=″contact″/>
   <xsd:field xpath=″accountId″/>
</xsd:keyref>
每个联系人节点包含引用account节点的accountId属性(外关键字)。即,
var account=contact.accountId;
逆向关系说明可以使用外关键字从帐户节点遍历到联系人节点。即,
var contacts=account.contacts.*;
在一个实施例中,逆向别名必须只包含属性名(比较上述keyref别名),并且总是相对于顶级节点。
要注意,多个keyref定义必须声明“指回”同一节点类型的逆向关系。在这些情况下,逆向别名对于目标节点类型当然必须是唯一的。例如,bug节点可能具有owner和assignedTo的keyref,分别定义了bugs和assignedBugs的逆向别名。
逆向关系也允许框架确保在双向上的导航与高速缓存一致。
根keyref
可以定义不依赖外关键字值的节点之间的关系。例如,一组节点可以由使用当前用户的信息或其他外部信息(例如,日时、实时数据、外部系统状态)的查询来定义。在这些情况下,节点集可能附属到数据模型内的任意节点类型。然而典型地,这些节点集附属到根节点。
在CRM例子中,特定用户可访问的一组帐户可以由系统变量$user/username定义的用户登录名定义。应用可能希望定义从根节点到该节点集的遍历;即:
var accounts=$root.accounts.*;
我们为每个引用根节点的帐户节点定义可选的人工外关键字。这是通过下面的keyref定义实现的:
<xsd:keyref name=″accountRootRef″refer=″mas:rootKey″
mas:inverseAlias=″accounts″>
   <xsd:selector xpath=″account″/>
   <xsd:field xpath=″rootId″/>
</xsd:keyref>
要注意,帐户模式还必须为有效的keyref定义可选的mas:rootId属性:
<xsd:complexType name=″accountType″>
   <xsd:all>
      <xsd:element name=″name″type=″xsd:string″/>
      <xsd:element name=″type″type=″xsd:string″/>
   </xsd:all>
   <xsd:attribute name=″id″type=″xsd:string″use=″required″mas:type=″pkey″/>
   <xsd:attribute name=″ownerId″type=″xsd:string″/>
   <xsd:attribute name=″parentId″type=″xsd:string″/>
   <xsd:attribute name=″rootId″type=″mas:rootId″use=″optional″/>
</xsd:complexType>
mas:rootId属性引用框架定义的系统定义;通过下面的指令系统的模式定义输入到应用的模式中:
<xsd:import namespace=″urn:bea.mas″schemaLocation=″mas.xsd″/>
运算符
导航是从一个页面移动到页面流内的下一个页面的动作。这可能会或者不会改变$context系统变量。
遍历是在数据图(高速缓存)内移动的动作。SPath表达式使用运算符“遍历”图,例如:
foo.bar
其中foo表示节点(或者节点的子元素),而bar是由keyref定义(名字或别名)或者关键字别名定义为外关键字的子元素名。
例如,假设我们有下面的数据:
<account id=″1.1″type=″Web″>
   <name>Acme</name>
   <contacts>
       <contactRef>1.2</contactRef>
       <contactRef>1.3</contactRef>
   </contacts>
   <purchaseOrders>
       <purchaseOrder>
           <lineItemprodId=″ABC-1234″/>
           <lineItemprodId=″XYZ-3000″/>
           <lineItemprodId=″EOW-2004″/>
       </purchaseOrder>
       <purchaseOrder>
           <lineItemprodId=″XYZ-3000″/>
       </purchaseOrder>
   </purchaseOrders>
</account>
<contact id=″1.2″accountId=″1.1″>
   <email>bobacme.com</email>
</contact
<product id=″ABC-1234″>
   <price>1000.00</price>
</product>
和下面的keyref定义:
<xsd:keyref name=″accountContactsRef″refer=″contactPrimaryKey″
   mas:alias=″.:contacts″>
   <xsd:selector xpath=″account/contacts/contactRef″/>
   <xsd:field xpath=″.″/>
</xsd:keyref>
<xsd:keyref name=″accountProductsRef″refer=″productKey″
   mas:alias=″purchaseOrders/purchaseOrder/lineItem:product″>
   <xsd:selector xpath=″account/purchaseOrders/purchaseOrder/lineItem″/>
   <xsd:field xpath=″prodId″/>
</xsd:keyref>
不使用别名,下面的表达式是合法的:
var contacts=account.contacts.*.contactRef;
var price=account.purchaseOrders.*[0].lineItems.*[0].(prodId).price;
使用别名允许下面的表达式:
var contacts=account.contacts.*;
var email=account.contacts[0].email;
var price=account.purchaseOrders.*.lineItems.*[0].product.price;
关键字和序列号
所有可以表示为数据模型中的节点的外部记录必须定义唯一的主关键字(pkey);主关键字必须显示为Web服务SOAP接口的一部分。在一个实施例中,由于在某些情况下框架可能将一个用户获得的数据放在共享高速缓存中,因此主关键字可以在所有用户的操作调用中一致。
外部系统的Web服务操作可以可选地返回与特定节点相关联的序列号(seq),它允许系统检测更新的记录。典型地,序列号对应于数据库时间戳。如果Web服务不提供序列号,则框架基于记录的XML值计算MD5散列。
模式定义可以定义用于定义外部应用的标识符和(可选的)序列号(或时间戳)的元素。相应模式元素定义mas:type属性,它表示系统特性“pkey”或“seq”。
例如,下面的模式定义应用联系人类型:
<xsd:complexType name=″contactType″>
   <xsd:all>
       <xsd:element name=″first″type=″xsd:string″/>
       <xsd:element name=″last″type=″xsd:string″/>
       <xsd:element name=″email″type=″xsd:string″/>
   </xsd:all>
   <xsd:attribute name=″id″type=″xsd:string″use=″required″mas:type=″pkey″/>
   <xsd:attribute name=″timestamp″type=″xsd:string″mas:type=″seq″/>
   <xsd:attribute name=″ownerId″type=″xsd:string″use=″required″/>
   <xsd:attribute name=″accountId″type=″xsd:string″use=″required″/>
</xsd:complexType>
该模式定义属性id和timestamp,它们分别表示主关键字和序列号。例如,下面的XML表示管道返回的联系人节点的实例:
<app:contact id=″83FEB4C38AB36520″timestamp=″12388832″
accountId=″B3F234AD3342ABA6″>
   <app:first>Bob</app:first>
   <app:last>Harris</app:last>
   <app:email>bobharris.com</app:email>
</app:contact>
模式还可以包括适当的关键字定义,例如:
<xsd:key name=″contactPrimaryKey″>
    <xsd:selector xpath=″contact″/>
    <xsd:field xpath=″id″/>
</xsd:key>
<xsd:key name=″contactEmailKey″>
    <xsd:selector xpath=″contact″/>
    <xsd:field xpath=″email″/>
</xsd:key>
要注意,需要mas:type=“pkey”模式元素声明来标识节点的主关键字。
由于关键字值可能较长,缺省情况下这些值不发送给客户端,对客户端编程模型是不可访问的。可以指定mas:visible属性来禁止该缺省行为。
下面列出模式修饰(decoration):
  属性   值   含义
  mas:type   “pkey”|“seq”   定义被映射到相应mas:pkey或mas:seq属性的特定元素或属性
  mas:visible   boolean   如果为true,则元素或属性值对于客户端编程模型是可用的;缺省值为false
在关键字(不是keyref)字段没有标为可见的情况下,任何在客户端上访问该字段的尝试都将无效(如同访问不存在的字段)。即使在可见的情况下,关键字字段也是只读的。
var x=contact.id;        //returns null
var y=cont
主关键字和序列号值由外部系统设置。对于定义为关键字的任何字段,修改该字段值的尝试将产生运行时错误。当创建新节点时,不应当包含这些字段,例如,
var contact=
   <contact>
      <first>Maggie</first>
      <last>Cheung</last>
      <email>maggieacme.com</email>
</contact>
通过引用赋值外关键字
外关键字值可以通过赋值来设置。如果赋值表达式的RHS求节点的值,则其被自动强迫为节点的主关键字。
在下面的例子中,联系人节点的帐户外关键字(由帐户keyref定义定义为帐户属性)被设置成引用提供的帐户节点。
function setAccount(contact,account)
   contact.accountId=account;
}
通过值赋值外关键字
如果keyref定义应用的模式声明mas:visible主关键字,则可以通过公开值(即,不是节点引用)来设置相应外关键字值。
例如,下面的帐户模式定义可视的pkey属性:
<xsd:complexType name=″accountType″>
   <xsd:complexContent>
       <xsd:all>
          <xsd:element name=″name″type=″xsd:string″/>
       </xsd:all>
       <xsd:attribute name=″id″type=″xsd:string″use=″required″
          mas:type=″pkey″mas:visible=″true″/>
       <xsd:attribute name=″ownerId″type=″xsd:string″use=″required″/>
       <xsd:attribute name=″parentId″type=″xsd:string″/>
   </xsd:complexContent>
</xsd:complexType>
因此,应用可以直接访问该值。
var account=account.id;
也可以通过值设置引用帐户节点的任何外关键字,例如:
function setAccount(contact)
   contact.account=″A-1234″;
}
要注意,外关键字值可能对于当前高速缓存在客户端上的节点是不变的。此外,如果设置了坏值,则相关管道操作将失败。
关系
多对一(查找)
多对一关系可以使用关键字和keyref定义实现,其中主和外关键字平行关系。
<xsd:key name=″accountKey″>
    <xsd:selector xpath=″account″/>
    <xsd:field xpath=″id″/>
</xsd:key>
<xsd:keyref name=″contactAccountRef″refer=″accountKey″>
    <xsd:selector xpath=″contact″/>
    <xsd:field xpath=″accountId″/>
</xsd:keyref>
上述该关键字定义说明在每个<account>节点中出现accountKey(主关键字)(作为称为id的属性)。keyref定义说明contactAccountRef(外关键字)是指<contact>节点的account属性。
例如,给定下面的实例数据:
<account id=″1.1″>
    <name>Acme</name>
</account>
<contact id=″1.2″accountId=″1.1″>
    <first>Bob</first>
    <last>Harris</last>
    <email>bobacme.com</email>
</contact>
下面定义了帐户的主关键字(即,accountKey):
<account id=″1.1″>
下面定义从联系人到相同帐户的外关键字(即,contactAccountRef):
<contact id=″1.2″accountId=″1.1″>
有时我们会想要使用节点内包含的数据作为外关键字值。例如,将CRM例子扩展来包括与联系人相关联的电子邮件消息。下面的模式描述消息节点;它包括由from和to元素表示的两个“天然”的外关键字(注意,每个消息可能具有多个to元素)。
<xsd:complexType name=″messageType″>
   <xsd:sequence>
       <xsd:element name=″from″type=″xsd:string″minOccurs=″1″
maxOccurs=″1″/>
       <xsd:element name=″to″type=″xsd:string″maxOccurs=″unbounded″/>
       <xsd:element name=″subject″type=″xsd:string″/>
       <xsd:element name=″body″type=″xsd:string″/>
   </xsd:sequence>
</xsd:complexType>
我们已经定义了联系人元素包含email元素。
<xsd:complexType name=″contactType″>
   <xsd:all>
       <xsd:element name=″first″type=″xsd:string″/>
       <xsd:element name=″last″type=″xsd:string″/>
       <xsd:element name=″email″type=″xsd:string″/>
   </xsd:all>
   <xsd:attribute name=″id″type=″xsd:string″use=″required″mas:type=″pkey″/>
   <xsd:attribute name=″ownerId″type=″xsd:string″use=″required″/>
    <xsd:attribute name=″accountId″type=″xsd:string″use=″required″/>
</xsd:complexType>
联系人类型已经定义了主关键字:
<xsd:key name=″contactPrimaryKey″>
    <xsd:selector xpath=″contact″/>
    <xsd:field xpath=″id″/>
</xsd:key>
下面的关键字定义定义联系人节点内的email元素也可以用作关键字。
<xsd:key name=″contactEmailKey″>
    <xsd:selector xpath=″contact″/>
    <xsd:field xpath=″email″/>
</xsd:key>
下面的keyref定义定义了消息节点内的外关键字元素。
<xsd:keyref name=″messageFromRef″refer=″contactEmailKey″>
    <xsd:selector xpath=″message″/>
    <xsd:field xpath=″from″/>
</xsd:keyref>
<xsd:keyref name=″messageToRef″refer=″contactEmailKey″>
    <xsd:selector xpath=″message/to″/>
    <xsd:field xpath=″.″/>
</xsd:keyref>
要注意,messageFromRef keyref也可以写成如下(尽管框架总是使用上述形式;注意,messageToRef必须写成上述形式,因为可能有多个<to>元素):
<xsd:keyref name=″messageFromRef″refer=″contactEmailKey″>
    <xsd:selector xpath=″message/from″/>
    <xsd:field xpath=″.″/>
</xsd:keyref>
一对多(集合)
一对多关系既可以实现为反向keyref,也可以实现为数据节点内包含的显式外关键字值。
反向keyref
所有多对一遍历可以声明定义一对多遍历的反向keyref。
显式keyref
确定的节点类型的模式声明可以定义包含重复序列的元素(每个元素可以包含外关键字值)的复合XML文档。
例子
下面的模式定义描述订购单实体。
<xsd:element name=″purchaseOrder″type=″purchaseOrderType″>
<xsd:complexType name=″purchaseOrderType″>
   <xsd:sequence>
      <xsd:element name=″price″type=″xsd:double″/>
      <xsd:complexType name=″lineItems″>
         <xsd:sequence maxOccurs=″unbounded″>
            <xsd:complexType ref=″lineItem″>
               <xsd:sequence>
                  <xsd:element name=″prodId″type=″xsd:string″/>
               </xsd:sequence>
            </xsd:complexType>
         </xsd:sequence>
      </xsd:complexType>
   </xsd:sequence>
   <xsd:attribute name=″id″type=″xsd:string″mas:type=″pkey″/>
</xsd:complexType>
下面的关键字声明定义订购单节点类型的主关键字。
<xsd:key name=″purchaseOrderKey″>
    <xsd:selector xpath=″purchaseOrder″/>
    <xsd:field xpath=″id″/>
</xsd:key>
下面的keyref声明标识订购单内的元素(外关键字应用的产品)。
<xsd:keyref name=″purchaseOrderProductRef″refer=″productKey″
    mas:alias=″purchaseOrder:products″>
    <xsd:selector xpath=″purchaseOrder/lineItems/lineItem″/>
    <xsd:field xpath=″prodId″/>
</xsd:keyref>
该关系可以用图12A来说明。例如,下面的XScript表达式检索订购单的第一行式项目引用的产品。
var product=purchaseOrder.products.*;
多对多
多对多关系作为多对的一对多关系实现。图12B中给出了一个例子。
即,帐户和事件声明下面的模式:
<xsd:complexType name=″accountType″>
   <xsd:all>
      <xsd:element name=″name″type=″xsd:string″/>
   </xsd:all>
   <xsd:attribute name=″id″type=″xsd:string″use=″required″mas:type=″pkey″/>
   <xsd:attribute name=″ownerId″type=″xsd:string″use=″required″/>
   <xsd:attribute name=″parentId″type=″xsd:string″/>
</xsd:complexType>o0
<xsd:complexType name=″eventType″>
   <xsd:all>
      <xsd:element name=″first″type=″xsd:string″/>
      <xsd:element name=″last″type=″xsd:string″/>
   </xsd:all>
   <xsd:attribute name=″id″type=″xsd:string″use=″required″mas:type=″pkey″/>
</xsd:complexType>
并且声明下面的keyref定义:
<xsd:keyref name=″accountEventRef″refer=″eventKey″>
    <xsd:selector xpath=″account″/>
    <xsd:field xpath=″events″/>
</xsd:key>
<xsd:keyref name=″eventAccountRef″refer=″accountKey″>
    <xsd:selector xpath=″event″/>
    <xsd:field xpath=″accounts″/>
</xsd:keyref>
在一个实施例中,多对多keyref不能声明反向keyref,这是由于通常框架没有足够的信息来维持一致。
一对一
在一个实施例中,一对一关系作为成对的多对一关系实现。
例子
假设系统的每个用户也具有如12C所示的联系人记录。
即,联系人和用户定义下面的keyref:
<xsd:keyref name=″userContactRef″refer=″contactKey″mas:alias=″contact″
   mas:inverseAlias=″user″>
   <xsd:selector xpath=″user″/>
   <xsd:field xpath=″contactId″/>
</xsd:key>
一对一keyref应当总是声明反向keyref。
var contact=user.contact;
contact.user==user;
系统数据类型
节点模式定义
下面的XML模式定义节点的结构。
<?xml version=″1.0″?>
<xsd:schema targetNamespace=″urn:bea.mas″
   elementFormDefault=″qualified″attributeFormDefault=″unqualified″
   xmlns:xsd=″http://www.w3.org/2001/XMLSchema″
   xmlns=″urn:bea.mas″>
<xsd:element name=″nodeType″>
   <xsd:complexType>
      <xsd:sequence>
         <xsd:any minOccurs=″0″maxOccurs=″1″/>
      </xsd:sequence>
      <xsd:attribute name=″state″type=″mas:syncStateType″/>
   </xsd:complexType>
</xsd:element>
节点定义可以包括下面的属性。
 属性   类型   描述
 state   syncStateType   确定当前同步状态
根节点
在一个实施例中,对于每个应用存在特定的根节点,其具有节点类型mas:root;该节点不包含应用数据并且不能修改。框架自动创建通过$root变量引用的根节点的实例。keyref可以引用mas:root作为它们的源类型,例如:
<keyref name=″accounts″sourceType=″mas:root″targetType=″app:contact″/>
在一个实施例中,节点可以通过客户端编程或服务器管道来实例化。
节点集模式定义
除了根节点外,所有节点属于对应于keyref的节点集。节点集由下面的XML模式定义:
<?xml version=″1.0″?>
<xsd:schema targetNamespace=″run:bea.com″
   elementFormDefault=″qualified″attributeFormDefault=″unqualified″
   xmlns:xsd=″http://www.w3.org/2001/XMLSchema″
   xmlns=″run:bea.com″>
<xsd:element name=″nodeSet″>
   <xsd:complexType>
      <xsd:sequence>
         <xsd:element ref=″node″maxOccurs=″unbounded″/>
      </xsd:sequence>
      <xsd:attribute name=″keyref″type=″xsd:string″/>
   </xsd:complexType>
</xsd:element>
<nodeset>元素包含无限制的<node>元素的序列。每个节点集对应于用于确定所包含的节点元素的节点类型的keyref(由keyref属性定义的)。
同步状态
所有持久的应用数据可以存储在与服务器同步的节点中。每个数据节点可以具有状态同步属性mas:state,该属性具有由syncStateType类型定义的值。
<xsd:simpleType name=″syncStateType″>
   <xsd:restriction base=″xsd:string″>
       <xsd:enumeration value=″dsync″/>
       <xsd:enumeration value=″modified″/>
       <xsd:enumeration value=″pending″/>
       <xsd:enumeration value=″uptodate″/>
       <xsd:enumeration value=″rejected″/>
       <xsd:enumeration value=″conflict″/>
       <xsd:enumeration value=″deleted″/>
   </xsd:restriction>
</xsd:simpleType>
状态变量可以在客户端和服务器之间传递来协调同步。客户端将节点状态设置为下面的一个值:
  状态   含义
  DSYNC   本地创建或修改,但没准备好同步
  MODIFIED   本地创建或修改的节点
  PENDING   插入/更新送到服务器的同步消息(等待响应)
要注意,在一个实施例中,状态变量不区分创建和修改的节点,因为它们可以由0的全局序列号来区分。
同步进程触发相应的管道操作;一旦完成,服务器为每个节点赋予下面的一个值:
 状态   含义
 UPTODATE   最新的(与服务器同步的)节点
 REJECTED   节点插入/更新被服务器(或Web服务)拒绝
 CONFILICT   Web服务响应用忽略(overridden)值响应
 DELETED   节点在服务器上已被删除(不再存在)
例如,下面的表示出节点可能的生存周期。
  状态   含义
  t0   MODIFIED   在客户端上创建或修改节点
  t1   PENDING   节点送到服务器
  t2   REJECTED   操作被服务器NACK(例如,由于非法值)
  t3   MODIFIED   在客户端上修改节点(例如,为了修正错误)
  t4   PENDING   节点重新送到服务器
  t5   UPTODATE   更新被服务器ACK
管道
在一个实施例中,客户端应用不直接调用Web服务操作—而是管道机制将单独的(受限的)Web服务操作的语义按照客户端的虚拟XML文档映射到编程模型(例如,CRUD语义(创建、读取、更新、删除)、导航、客户操作等)。客户端数据模型改变与服务器同步,服务器然后触发管道管理器来调用外部Web服务操作。
在一个实施例中,管道定义特定keyref的一组协调的Web服务操作。每个keyref可以与恰好一个管道相关联。Web服务可以与现有系统相接,如数据库、LDAP目录、ERP应用和网站。它们也可以是提炼了由过程逻辑(例如,WLI JPD)协调的、复杂的长期运行的异步进程(工作流)的包装(wrapper)。
在一个实施例中,尽管系统使用的Web服务可以具有一定的要求(例如,每个记录必须包括唯一的主关键字,并且最好是序列号或时间戳),但对它们没有偶尔连接的数据模型特定的要求。因此,MAS可以是这些资源的许多消费者之一。
在一个实施例中,管道不假定Web服务是用头脑中的数据模型编写的;即,传递到请求中的类型对于数据模型中的节点类型不能是同构的,并且响应也可以不同。因此,Web服务请求和响应所使用的模式不需要与数据模型中的任何节点模式相同。
管道可以包含元数据来从数据模型映射到Web服务操作调用的请求文档中,并且从Web服务响应映射回数据模型中。这些源数据称为变换,并且可以用XML Query语言表示。实际上,变换模型通用到足够Web服务可以返回映射到数据模型中的几个不同有关节点、并且仍然成功映射回数据模型的响应文档。
对于MAS高速缓存至关重要的元数据(即,记录类型的主关键字和序列号/时间戳)也可以使用变换来映射。
管道文件概述
conduits子目录可以包括多个.jsx文件—所有文件在启动时由框架加载,这些文件包含管道定义。管道文件可以包括实现管道操作的XScript和XQuery函数,这些文件还可以包含在注解块中定义的元数据。注释模型允许开发者使用可视化工具和脚本编辑器来建立管道文件。
每个管道文件可以包含头注解,它可以声明下面的标志(tag):
  标志   描述
  mas:conversational   声明管道是有状态的并且使得成员变量持续。
  common:xmlns   定义管道文件内使用的名字空间。
例如:
    /**
    *mas:conversational shared=″false″
    *common:xmlns namespace=″http://schemas.xmlsoap.org/soap/envelope/″
   prefix=″soap″
    *common:xmlns namespace=″urn:partner.soap.sforce.com″prefix=″sfdc″
    *common:xmlns namespace=″http://example.com/″prefix=″app″
    */
mas:conversational
mas:conversational标志具有下面的属性:
  属性   描述
  shared   如果可选的shared属性为true,则管道可以由多个用户使用。
common:xmlns
common:xmlns标志具有下面的属性:
 属性   描述
 namespace   定义名字空间URN。
 prefix   定义文件内用来指示名字空间的逻辑名。
Web服务控制
管道文件还包括(可能多个)表示Web服务控制的对象声明。控制定义出现在相应变量声明紧前面的头块中。
例子
/**
 *common:control
 *jc:location http-url=″http://enterprise.soap.sforce.com/″
 */
ws=new WebServiceControl();
定义了下列标志:
  标志   描述
  common:control   声明WLW支持的控制
  jc:location   说明Web服务控制的初始URL
jc:location
jc:location标志具有下列属性:
  属性   描述
  http-url   Web服务的初始URL
WebServiceControl对象管理Web服务操作的调用。
WebServiceControl对象实现下列方法:
 方法   描述
 invoke(msg)   向控制定义所定义的Web服务发送指定的消息对象msg;返回响应消息。
消息对象
消息对象被送进Web服务控制的invoke()函数并由此返回。
var response=control.invoke(message);
消息对象具有下列特性:
  特性   描述
  header   XML SOAP头
  body   XML SOAP体
  error   如果在invoke()期间没有出现错误则为null
例如,假设从Web服务返回下列SOAP消息:
<soapenv:Envelope xmlns: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>
       <SessionHeader xmlns=″urn:partner.soap.sforce.com″>
           <sessionId>12345678</sessionId>
       </SessionHeader>
   </soapenv:Header>
   <soapenv:Body>
       <createResponse xmlns=″urn:partner.soap.sforce.com″>
           <result>
              <errors xsi:nil=″true″></errors>
               <id>87654321</id>
               <success>true</success>
           </result>
        </createResponse>
   </soapenv:Body>
</soapenv:Envelope>
下面的函数在打印来自消息头的会话元素和来自消息主体的结果元素之前首先检查invoke()函数调用没有产生错误:
function select($msg){
   var response=ws.invoke($msg);
   if(!response.error){
     print(″Session:″+response.header.SessoinHeader.sessionId);
     print(″ID:″+response.body.createResponse.result.id);
   }
   return response;
}
这将记录下面的输出:
Session:12345678
ID:87654321
操作定义
管道操作可以直接映射到Web服务操作上。在一个实施例中,每个管道操作声明最多三个函数:
1.请求变换:创建输出的消息主体的XQuery函数;
2.响应变换:处理输入的响应体、创建管道管理器处理的MAS节点的XQuery函数;
3.自定义函数:实现自定义的过程逻辑(例如,创建消息头或调用自定义传输或任何其他控制)的XScript(或Java)函数。
自定义函数还可以包括在函数原型紧前面的头块中的注释。例如:
/**
 *mas:operation type=″operationType″keyref=″keyrefName″inverse=″true″
 *mas:transform type=″request″function=″foo_request″
 *mas:transform type=″response″function=″foo_response″
 */
function foo($msg,$source){
   return ws.invoke($msg);
}
自定义函数可以声明下面的标志:
  标志   描述
  mas:operation   声明操作和数据模型之间的绑定
  mas:transform   声明相关联请求和响应变换
  mas:namespace   声明函数的缺省名字空间
  mas:field   声明调用函数所需的自定义源字段
mas:operation
mas:operation标志具有下列属性:
 属性   描述
 type   操作类型(例如,“选择”、“插入”、“更新”等)
 keyref   定义选择关系的keyref名
 inverse   如果为true,则实现反向keyref定义
 node   用于插入/更新/删除操作的节点类型
操作可以引用keyref或模式(节点)定义。
mas:operation type=″operationType″keyref=″keyrefName″
mas:operation type=″operationType″node=″nodeType″
inverse属性指示在反向keyref上调用操作。
mas:operation type=″operationType″keyref=″keyrefName″inverse=″true″
例如,给定下面的keyref和key定义:
<xsd:keyref name=″contactAccountRef″refer=″accountKey″
       mas:alias=″account″mas:inverseAlias=″contacts″>
   <xsd:selector xpath=″contact″/>
   <xsd:field xpath=″account″/>
</xsd:keyref>
<xsd:key name=″accountKey″>
   <xsd:selector xpath=″account″/>
   <xsd:field xpath=″id″/>
</xsd:key>
<xsd:key name=″contactKey″>
   <xsd:selector xpath=″contact″/>
   <xsd:field xpath=″id″/>
</xsd:key>
管道可以实现下面的选择操作:
/**mas:operation type=″select″keyref=″app:contactAccountRef″*/
function selectAccount($msg,$source){
   return ws.invoke($msg);
}
/**mas:operation type=″select″keyref=″app:contactAccountRef″inverse=″true″
*/
funciton selectContacts($msg,$souroe){
   return ws.invoke($msg);
}
遍历contact.account将调用selectAccount(),而account.contacts.*将调用selectContact()。
mas:transform
mas:transform标志具有下列属性:
  属性   描述
  type   声明request|response值
  function   指定当前文件中的函数名
  file   指定包含该单个函数的文件
如果声明相应的mas:transform标志,则框架可以自动调用请求和响应变换。请求变换可以返回XML对象,用于构建$msg变量主体。响应变换可以处理管道操作的响应。
要注意,在Java中,请求和响应Query变换要么被包含在自定义操作的注解块(自动生成的)中,或者包含在由注释应用的单独文件中。
mas:namespace
mas:namespace标志声明函数的缺省名字空间并且具有下列属性:
  属性   描述
  target   指定变换的输出的目标名字空间;使用在文件顶部定义的名字空间前缀
mas:field
mas:field标志声明调用函数所需的自定义源字段;它具有下面的属性:
 属性  描述
 XPath  引用节点对象内的XML元素
生成的函数
自定义函数的主体由WLW生成。用于选择操作的缺省主体如下:
/**
 *mas:operation type=″select″keyref=″keyrefName″
 */
function operationTypeSourceType($msg,$source){
   return control.invoke($msg);
}
$msg变量应用XML消息对象。如果声明了匹配请求变换(见下面),则由查询返回的XML对象创建消息对象的主体。$source变量可以包括源上下文节点(例如,node.keyrefName.*)。
对于插入、更新和删除操作,缺省主体可以如下:
/**
 *mas:operation type=″insert|update|delete″keyref=″keyrefName″
 */
function operationTypeSourceType($msg,$node){
   return ws.invoke($msg);
}
$node变量包括要插入/更新/删除的节点。
对于自定义操作,主体可以如下:
/**
 *mas:operation type=″custom″node=″nodeName″name=″operationName″
 */
function operationTypeSourceType($msg,$source,$node){
   return ws.invoke($msg);
}
这里,$node变量包括通过客户端调用自定义应用创建的查询对象。
变换
操作可以可选地使用mas:transform注释定义请求和响应变换函数。
例如,下面的操作实现给定帐户标识符(即,由contactAccountRef定义的反向keyref)检索联系人的选择操作:
/**
 *select contacts for an account:$account.contacts.*
 *mas:operation type=″select″keyref=″app:contactAccountRef″inverse=″true″
 *mas:transform type=″request″function=″selectContacts_request″
 *mas:transform type=″response″function=″selectContacts_response″
 */
function selectContacts($msg,$source){
   return ws.invoke($msg);
}
可以在调用管道操作之前调用请求变换;它返回输出消息的XML主体,其被插入到消息对象$msg中并传递到管道操作。
/**
 *mas:namespace target=″sfdc″
 *language:body type=″xquery″
 */
function selectContacts_request($source){
   <query>
       <queryString>
           SELECT*FROM Contact
           WHERE AccountId=″{string($source/id)}″
       </queryString>
   </query>
}
可以在管道操作返回之后调用响应变换(除非操作返回<error>对象)。向其传递从服务控制的invoke()函数返回的XML消息主体。响应变换向管道管理器返回应用节点的列表。
/**
 *mas:namespace target=″app″
 *language:body type=″xquery″
 */
function selectContacts_response($response){
    for $i in$response/sfdc:queryResponse/sfdc:result/sfdc:records
    return
       <contact id=″{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>
}
要注意,管道操作能够在响应变换处理主体之前操控服务响应消息的头和主体。
管道操作
管道操作可以将Web服务映射到暴露给应用编程模型的框架操作上。
每个操作可以定义一对查询,用于映射从相关Web服务操作接收和向其发送的相应输入和输出XML消息。这些变换(典型地)包括XQuery表达式,用于将数据从外部系统数据格式变换到模式所定义的MAS应用程序数据格式。
操作类型
在客户端编程模型中,可以在节点(包括$root)或keyref上调用操作。例如:
$root.create(xml);                //create node
node.keyref.create(xml);        //create and link node
node.keyref.*;                  //implicit select
node.keyref.select(spath);      //deep select
node.update();                    //update node
$root.foo(xml);                   //custom operation
取决于操作类型,需要不同的输入参数传递到管道操作。
除了更新和删除以外,所有其他操作都被传递(部分)表示操作上下文(源)的节点(mas:field声明确定将多少源节点传送到服务器)。这是由管道函数使用$source变量引用的。
在更新操作(即,插入、更新和自定义操作)的情况下,用于调用管道操作的数据节点在XQuery变换中使用$node变量引用。此外,所有操作具有对包含关于当前用户的信息的$user系统变量的隐式访问。
对管道操作定义下面的输入参数:
  变量   描述
  $source   操作的源节点
  $node   XML数据节点(即,用于插入、更新、删除和自定义操作)
  $keyset   主关键字集合
  $seq   节点的序列号
  $user   关于当前用户的信息
下面的表示出对于特定管道操作可以定义的不同类型的操作。
  操作类型   输入   描述
  select   $source   给定定义上下文的节点的主关键字,选择节点集
  insert   $source,$node   创建节点并将其与定义的上下文相关联
  update   $node   更新给定的节点(XML文档)
  delete   $node   删除节点
  custom   $source,$node   调用客户Web服务操作
  select_pkey   $source   选择特定关联的主关键字集合
  select-set   $source,$keyset   给定主关键字的集合,选择节点的集合
  select_diff   $source,$seq   从被修改的上下文中选择节点的集合
变换
每个管道操作可以定义一对查询(变换),其创建和处理与从相关Web服务操作接收和向其发送的输入和输出XML消息对应的XML对象。
可以使用相应管道函数上的mas:transform注释声明变换函数。按照惯例,变换函数名可以使用与管道函数相同的、具有_request和_response后缀的名。然而,在某些情况下,响应变换可以由多个管道操作重复使用。
变换可以实现为XQuery(XML Query)函数。
例子
下面的操作实现在给定帐户标识符(即,由contactAccountRef定义的反向keyref情况下检索联系人的选择操作:
/**
 *select contacts for an account:$account.contacts.*
 *mas:operation type=″select″keyref=″app:contactAccountRef″inver
 *mas:transform type=″request″function=″selectContacts_request″
 *mas:transform type=″response″function=″selectContacts_response″
 */
function selectContacts($msg,$source){
   return ws.invoke($msg);
}
/**
 *mas:namespace target=″sfdc″
 *language:body type=″xquery″
 */
function selectContacts_request($source){
   <query>
       <queryString>
           SELECT*FROM Contact
           WHERE AccountId=″{string($source/id))″
       </queryString>
   </query>
}
/**
 *mas:namespace target=″app″
 *language:body type=″xquery″
 */
function selectContacts_response($response){
    for $i in$response/sfdc:queryResponse/sfdc:result/sfdc:records
    return
       <contact id=″{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>
}
请求变换可以构建调用query Web服务操作的SOAP消息的主体。响应变换处理Web服务操作的响应SOAP消息的主体并且构建<contact>节点的集合。
请求变换
请求变换可以由框架和数据模型元素创建输出的Web服务消息。取决于操作类型(见上面的操作表),变换可以参考下面的系统变量,它们提供操作的上下文。
 变量   描述
 $source   节点集的源节点(对更新和删除操作不可用)
 $node   用于插入和更新操作的节点元素
 $user   表示当前用户的对象
上述select管道操作方法调用query Web服务操作,后者预期具有遵从下面XML模式定义的主体的SOAP消息。
<element name=″query″>
    <complexType>
        <sequence>
            <element name=″queryString″type=″xsd:string″/>
        </sequence>
    </complexType>
</element>
下面的变换引用$source系统变量来指定查询所需的AccountId外关键字。
/**
 *mas:namespace target=″sfdc″
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 */
function selectcontacts_request($source){
   <query>
       <queryString>
           SELECT*FROM Contact
           WHERE AccountId=″{string($source/id)}″
       </queryString>
   </query>
}
例如,这可能产生下面的输出SOAP消息主体:
<query xmlns=″urn:enterprise.soap.sforce.com″>
   <queryString>SELECT*FROM Contact WHERE AccountId=1000</queryString>
</query>
响应变换
响应变换可以处理输入的Web服务消息并创建由管道管理器处理的节点(或节点集)。所有响应变换可以引用下面的系统变量。
 变量   描述
 $response   引用输入的SOAP消息主体
 $user   表示当前用户的对象
按照上面的例子,query Web服务操作返回对应于下面XML模式的SOAP消息。
    <element name=″queryResponse″>
        <complexType >
            <sequence>
                <element name=″result″type=″tns:QueryResult″/>
            </sequence>
        </complexType >
    </element>
    <complexType name=″QueryResult ″>
        <sequence>
            <element name=″done″type=″xsd:boolean″/>
            <element name=″queryLocator″type=″tns:QueryLocator″
nillable=″true″/>
            <element name=″records″minOccurs=″0″maxOccurs=″unbounded″
                type=″ens:sObject″/>
            <element name=″size″type=″xsd:int″/>
        </sequence>
    </complexType>
每个<QueryResult>元素包含<sObject>元素的序列,后者是<Contact>模式类型的基本类型:
<complexType name=″sObject″abstract=″true″>
    <sequence>
        <element name=″Id″minOccurs=″0″type=″tns:ID″/>
    </sequence>
</complexType>
<complexType name=″Contact″>
    <complexContent>
        <extension base=″ens:sObject″>
              <sequence>
                  <element name=″AccountId″minOccurs=″0″type=″tns:ID″/>
                  <element name=″Email″minOccurs=″0″type=″xsd:string″/>
                  <element name=″FirstName″minOccurs=″0″type=″xsd:string″/>
                  <element name=″LastName″minOccurs=″0″type=″xsd:string″/>
                  <element name=″SystemModstamp″minOccurs=″0″
type=″xsd:dateTime″/>
                </sequence>
            </extension>
        </complexContent>
    </complexType>
    <element name=″Contact″type=″ens:Contact″/>
例如,输入的SOAP消息主体可能是下面的形式:
<sfdc:queryResponse xmlns:sfdc=″urn:enterprise.soap.sforce.com″>
   <sfdc:result>
       <sfdc:records xsi:type=″urn:Contact″>
           <sfdc:Id>1234</sfdc:Id>
           <sfdc:AccountId>1000</sfdc:AccountId>
           <sfdc:Email>reogeracme.com</sfdc:Email>
           <sfdc:FirstName>Roger</sfdc:FirstName>
           <sfdc:LastName>Reed</sfdc:LastName>
       </sfdc:records>
       <sfdc:records xsi:type=″urn:Contact″>
           <sfdc:Id>5678</sfdc:Id>
           <sfdc:AccountId>1000</sfdc:AccountId>
           <sfdc:Email>sarahacme.com</sfdc:Email>
           <sfdc:FirstName>Sarah</sfdc:FirstName>
           <sfdc:LastName>Smith</sfdc:LastName>
       </sfdc:records>
    </sfdc:result>
</sfdc:queryResponse>
$response系统变量指向(SOAP消息主体内的)顶级<queryResponse>元素。因此,应当使用下面的XPath表达式来引用<Contact>元素的阵列。
$response/sfdc:queryResponse/sfdc:result/sfdc:records
下面的变换处理输入的SOAP消息并创建<contact>元素的列表。
/**
 *mas:namespace target=″app″
 *language:body type=″xquery″
 */
function selectContacts_response($response){
    for $i in$response/sfdc:queryResponse/sfdc:result/sfdc:records
    return
       <contact id=″{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>
}
所有请求变换生成节点,后者可以被服务器高速缓存,并且与客户端的数据模型同步。
容许(Permission)
管道定义的操作确定可以在客户端上相应节点集上调用的操作。例如,如果管道不定义插入操作,则客户端不能尝试对相应节点集创建和插入节点—如果它尝试这样做的话(例如,在自定义操作中),这将触发运行时错误。客户端侧的编程模型将实施这些约束。
例如,假设account指向特定的帐户节点,并且该帐户节点与orders keyref相关联。在这种情况下,除非存在定义的与orders keyref相关联的管道插入操作,否则下面的代码将引起错误。
account.quotes.create(
   <quoteRequest>
       <prodId>A1</prodId><qty>10</qty>
   </quoteRequest>
);
类似地,除非为联系人节点类型定义了更新操作,否则下面的代码也将引起错误。
contact.address.zip=″11201″;
在一个实施例中,客户端操作(例如,create()函数)的实现与管道操作(例如,插入)匹配。例如,管道操作插入不仅插入节点,还使用keyref关系将其遍历到另一节点;因此在客户端上创建节点必须自动与相应节点集的遍历操作成对。
描述实现的管道操作的元数据对用户编程模型是可访问的(通过相关联的keyref)。自动用户接口能够使用该信息生成基本菜单(插入、更新等)。
出错处理
管道机制区分两种类型的错误:系统错误(例如,协议和传输错误)和应用错误(例如,非法的数据)。此外,应用错误可以以两种方式出现:作为SOAP故障(即,协议级错误)以及作为SOAP(或纯XML)响应消息的部分。
  错误类型   系统   应用
  SOAP故障   X   X
  SOAP消息   n/a   X
管道操作实现为SOAP调用。如果在处理消息时存在错误,则出现SOAP故障。这可能是由于基层架构故障(例如,传输故障)、协议失败(例如,错误形成的消息)、或者应用状态错误(例如,更新失败)。如果在创建或处理输出或输入的SOAP消息时存在错误,则出现系统错误(例如,XQuery变换错误)。
如果外部应用拒绝基于被作为消息主体的部分传递的值的操作请求,则出现应用请求(例如,更新失败)。在Web服务控制上的invoke()函数的调用期间,SOAP栈出现SOAP故障。
通常,管道操作返回的XML对象的主体由响应变换处理。然而,如果操作返回系统<mas:error>对象,则该对象被直接传递到管道管理器。要注意,主管道函数或响应变换可以返回<mas:error>对象。
下面给定<mas:error>对象定义:
<xsd:complexType name=″errorType″>
   <xsd:sequence>
       <xsd:element name=″pkey″type=″xsd:any″minOccurs=″0″maxOccurs=″1″/>
       <xsd:element name=″system″type=″mas:systemErrorType″maxOccurs=″1″/>
       <xsd:element name=″message″type=″xsd:string″/>
       <xsd:element name=″field″type=″mas:errorFieldType″
maxOccurs=″unbounded″/>
   </xsd:sequence>
</xsd:complexType>
<xsd:complexType name=″systemErrorType″>
   <xsd:sequence>
       <xsd:element name=″code″type=″xsd:any″/>
       <xsd:element name=″message″type=″xsd:string″/>
   </xsd:sequence>
</xsd:complexType>
<xsd:complexType name=″errorFieldType″>
   <xsd:sequence>
       <xsd:element name=″code″type=″xsd:any″/>
       <xsd:element name=″message″type=″xsd:string″/>
   </xsd:sequence>
   <xsd:attribute name=″xpath″type=″xsd:string″/>
</xsd:complexType>
即,<mas:error>对象具有下面的形式:
<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:field xpath=″spath-expression″>
       <mas:code>error-code</mas:code>
       <mas:message>message-string</mas:message>
   </mas:field>
</mas:error>
每个错误对象可以包括受错误影响的节点的主关键字。对于选择操作,这将是源节点的主关键字;对于更新和删除操作,这将引用更新的节点。
系统错误可以由服务器记录。所有其他错误值可以返回到客户端并且传递到相应调回函数。
将错误对象返回到应用的调回函数;该对象具有对应于上述模式的特性。
例子
如果invoke()函数调用返回错误,则下面的操作返回系统错误。
/**
 *mas:operation type=″select″keyref=″keyrefName″
 */
function operationTypeSourceType($msg,$source){
   var response=control.invoke($msg);
   if(response.error){
      return
          <mas:error>
              <mas:system><mas:message>system-
error</mas:message></mas:system>
          </mas:error>;
   }
   return response;
}
适当的地方,管道操作可以负责重试失败的invoke()调用。在这种情况下,管道需要确保Web服务操作是幂等(idempotent)还是采用某种可靠的通信形式。
下面操作在失败时重试invoke()函数后返回系统错误。
/**
 *mas:operation type=″select″keyref=″keyrefName″
 */
function operationTypeSourceType($msg,$source){
   for(i=0;i<3;i++){
      var response=control.invoke($msg);
      if(!response.error){
        return response;    //OK
      }
   }
   return
      <mas:error>
          <mas:system><mas:message>Retry failed</mas:message></mas:system>
      </mas:error>;
}
如果invoke()函数返回错误,下面的操作首先检查系统错误,否则它返回一般的应用错误。如果invoke()函数成功,但Web服务响应包含应用错误,则它调用效用函数(utility function)来分析错误消息并且返回复合的<error>对象,可能包含多个<field>错误。
/**
 *mas:operation type=″create″keyref=″keyrefName″
 */
function operationTypeSourceType($msg,$source){
   var response=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>;
     }
  }
  //check for application errors
  if(response.body.createResponse.result.errors){
     return process_error(response.body.createResponse.result.errors);
  }
  return response;      //OK
}
//utility function to process field errors
function process_error(errors){
   var fields;
   for(i=0;i<errors.length i++){
      var path=match_path(errors[i].fields[0]);
      fields+=
          <mas:field xpath=″{path}″>
              <code>{$i/statusCode}</code>
              <mas:message>{$i/message}</mas:message>
          </mas:field>
   }
   return<mas:error>{fields}</mas:error>;
}
CRUD操作
CRUD(创建读取更新删除)操作代表四种基本的关系数据操作。这些操作可以直接映射到MAS数据模型和客户端编程模型上。
要注意,Web服务的联系人模式具有与上面定义的应用的联系人模式不同的形式。下面的选择操作的例子说明了如何实现该映射。
选择
select操作可以允许框架对特定源节点检索keyref定义的节点。典型地,所有管道都定义了选择操作,由于这是客户端应用用来检索节点的基本机制。
可以调用随后的选择操作(对不同的keyref)来构建数据图。例如,从帐户节点导航到订购单keyref将调用AccountManager Web服务的getPurchaseOrders操作;然后,从订购单节点导航到行式项目keyref将调用OrderManager Web服务的getLineItems操作。
选择操作具有下面的形式:
/**
 *mas:operation type=″select″keyref=″keyrefName″[inverse=″true″]
 *mas:transform type=″request″function=″functionName_request″
 *mas:transform type=″response″function=″functionNaume_response″
 */
function functionName($msg,$source){
   return ws.invoke($msg);
}
选择操作用来检索对应于为特定源节点类型定义的keyrefName的节点,例如,对特定联系人节点选择外关键字所引用的帐户。反向属性定义操作实现反向关系,例如,选择通过外关键字引用特定帐户的所有联系人。
keyref定义可以具有下面的形式:
<xsd:keyref name=″keyrefName″refer=″targetType″
   mas:alias=″relationName″mas:inverseAlias=″inverseRelationName″>
   <xsd:selector xpath=″sourceType″/>
   <xsd:field xpath=″foreignKey″/>
</xsd:keyref>
在关系项中,选择操作对应于下面的SQL表达式:
       SELECT*FROM keyref.targetType WHERE primary_key=
$source/foreign_key
实现反向keyref的操作对应于下面的SQL表达式:
       SELECT*FROM keyref.sourceType WHERE foreign_key=
$source/primary_key
选择操作的请求变换可以为Web服务操作创建消息主体;它可以引用下面的系统变量,这些系统变量提供操作的上下文:
  变量   含义
  $source   与keyref相关的源节点
  $user   表示当前用户的对象
选择操作的响应变换可以将响应消息主体映射到节点列表上。节点元素对应于keyref定义的相应节点类型的应用定义模式。选择操作的响应变换可以引用下面的系统变量:
  变量   含义
  $response   SOAP消息响应的主体
  $user   表示当前用户的对象
通过外关键字选择(多对一)
关系外关键字实现多对一(或查找)关系。
例如,给定下面的模式和keyref定义,很自然想到联系人节点的accountId属性作为到联系人所属的帐户节点的指针。
<xsd:complexType name=″contactType″>
   <xsd:all>
       <xsd:element name=″first″type=″xsd:string″/>
       <xsd:element name=″last″type=″xsd:string″/>
       <xsd:element name=″email″type=″xsd:string″/>
   </xsd:all>
   <xsd:attribute name=″id″type=″xsd:string″use=″required″mas:type=″pkey″/>
   <xsd:attribute name=″ownerId″type=″xsd:string″use=″required″/>
   <xsd:attribute name=″accountId″type=″xsd:string″use=″required″/>
</xsd:complexType>
<xsd:keyref name=″contactAccountRef″refer=″accountKey″mas:alias=″account″>
   <xsd:selector xpath=″contact″/>
   <xsd:field xpath=″accountId″/>
</xsd:keyref>
这将允许下面的客户端遍历(注意,运算符引用keyref定义的别名):
var account=contact.account;
下面的管道操作实现该keyref关系:
/**
 *mas:operation type=″select″keyref=″contactAcoountRef″
 *mas:transform type=″request″function=″selectAccountByContact_request″
 *mas:transform type=″response″function=″selectAccountByContact_response″
 */
function selectAccountByContact($msg,$source){
   return ws.invoke($msg);
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 *mas:field xpath=″accountId″
 */
function selectAccountByContact_request($source){
   <query>
       <queryString>
           SELECT *FROM Account
           WHERE Id={string($source/accountId)}
       </queryString>
   </query>
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″app″
 */
function selectAccountByContact_response($response){
   let $i:=$response/sfdc:queryResponse/sfdc:result/sfdc:records
   return
       <account id=″{string($i/sfdc:Id)}″>
          <modified>{string($i/sfdc:SystemModstamp)}</modified>
          <name>{string($i/sfdc:Name)}</name>
          <type>{string($i/sfdc:Type)}</type>
       </account>
}
管道操作函数可以由平台自动生成;它可以引用accountOwnerRef keyref定义并且具有对请求和响应变换函数的声明(由工具生成)。
/**
 *mas:operation type=″select″keyref=″contactAccountRef″
 *mas:transform type=″request″function=″selectAccountByContact_request″
 *mas:transform type=″response″function=″selectAccountByContact_response″
 */
function selectAccountByContact($msg,$source){
   return ws.invoke($msg);
}
请求变换
请求变换可以引用表示帐户节点的$source变量。函数注释可以声明输出消息文档的语言(XQuery)和目标名字空间(引用管道文件的头注释中声明的名字空间前缀)。
函数也可以声明指示函数要求联系人节点的accountId属性的字段注释;该声明可以确保外关键字值作为同步请求的部分从调用的客户端送到服务器。
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 *mas:field xpath=″accountId″
 */
function selectAccountByContact_request($source){
   <query>
       <queryString>
           SELECT*FROM Account
           WHERE Id={string($source/accountId)}
       </queryString>
   </query>
}
响应变换
响应变换可以引用$response变量,该变量代表从Web服务返回的消息的XML主体。函数注释也可以声明返回到管道管理器的XML对象的语言(XQuery)和目标名字空间。
函数可以假设Web服务<query>请求返回单个记录。函数可以将其变换成具有相应主关键字(id)和遵从模式定义的数据字段(包括表示序列号的<modified>元素)的单个<account>节点。
/**
 *language:body type=″xquery″
 *mas:namespace target=″app″
 */
function selectOwnerByAccount_response($response){
   let $i:=$response/sfdc:queryResponse/sfdc:result/sfdc:records
   return
       <account id=″{string($i/sfdc:Id)}″>
           <modified>{string($i/sfdc:SystemModstamp)}</modified>
           <name>{string($i/sfdc:Name)}</name>
           <type>{string($i/sfdc:Type)}</type>
       </account>
}
<account>节点被返回到管道管理器并且同步回调用的应用。管道管理器也可以选举来将节点放入服务器的高速缓存中。
反向选择(一对多)
外关键字定义的多对一关系当然可以认为是一对多关系的反方向。
给定与上面部分中相同的模式和keyref定义,很自然想到属于单个帐户节点的联系人节点集:
<xsd:complexType name=″contactType″>
   <xsd:all>
       <xsd:element name=″first″type=″xsd:string″/>
       <xsd:element name=″last″type=″xsd:string″/>
       <xsd:element name=″email″type=″xsd:string″/>
       <xsd:element name=″modified″type=″xsd:string″/>
   </xsd:all>
   <xsd:attribute name=″id″type=″xsd:string″use=″required″mas:type=″pkey″/>
   <xsd:attribute name=″ownerId″type=″xsd:string″use=″required″/>
   <xsd:attribute name=″accountId″type=″xsd:string″use=″required″/>
</xsd:complexType>
<xsd:keyref name=″contactAccountRef″refer=″accountKey″mas:alias=″account″
   mas:inverseAlias=″contacts″>
   <xsd:selector xpath=″contact″/>
   <xsd:field xpath=″accountId″/>
</xsd:keyref>
然而,这时,keyref定义的mas:inverseAlias属性用于反向遍历keyref:
var contacts=account.contacts.*;
下面的管道操作实现该反向keyref关系:
/**
 *mas:operation type=″select″keyref=″contactAccountRef″inverse=″true″
 *mas:transform type=″request″function=″selectContactsByAccount_request″
 *mas:transform type=″response″function=″selectContactsByAccount_response″
 */
function selectContactsByAccount($msg,$source){
   return ws.invoke($msg);
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 *mas:field xpath=″id″
 */
function selectContactsByAccount_request($source){
   <query>
       <queryString>
           SELECT*FROM Contact
           WHERE accountId={string($source/id)}
       </queryString>
   </query>
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″app″
 */
function selectContactsByAccount_response($response){
   for $i:=$response/sfdc:queryResponse/sfdc:result/sfdc:records
   return
       <contact id=″{string($i/sfdc:Id)}″
accountId=″{string($i/sfdc:AccountId)}″>
           <modified>{string($i/sfdc:SystemModstamp)}</modified>
           <fist>{strirg($i/sfdc:FistName)}</first>
           <last>{string($i/sfdc:LastName)}</last>
           <email>{string($i/sfdc:Email)}</email>
       </contact>
}
管道操作函数可以由平台自动生成;它引用accountOwnerRefkeyref定义并且具有对请求和响应变换函数的声明(由工具生成)。操作也可以声明它表示反向keyref关系。
/**
 *mas:operation type=″select″keyref=″contactAccountRef″inverse=″true″
 *mas:transform type=″request″function=″selectContactsByAccount_request″
 *mas:transform type=″response″function=″selectContactsByAccount_response″
 */
function selectContactsByAccount($msg,$source){
   return ws.invoke($msg);
}
请求变换
请求变换可以引用表示联系人节点的$source变量。函数注释声明输出消息文档的语言(XQuery)和目标名字空间(引用管道文件的头注释中声明的名字空间前缀)。
函数也可以声明指示函数要求帐户节点的id属性的字段注释;该声明可以确保外关键字值作为同步请求的部分从调用的客户端送到服务器。
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 *mas:field xpath=″id″
 */
function selectContactsByAccount_request($source){
   <query>
       <queryString>
           SELECT*FROM Contact
           WHERE accountId ={string($source/id)}
       </queryString>
   </query>
}
响应变换
响应变换可以引用$response变量,该变量代表从Web服务返回的消息的XML主体。函数注释也可以声明返回到管道管理器的XML对象的语言(XQuery)和目标名字空间。
函数可以假设Web服务<query>请求返回多个记录。函数迭代结果并且将其变换成<contact>节点集。每个节点可以包含相应主关键字(id)和遵从模式定义的数据字段;这包括帐户外关键字(accountId属性)和序列号(<modified>元素)。
/**
 *language:body type=″xquery″
 *mas:namespace target=″app″
 */
function selectContactsByAccount_response($response){
   for $i:=$response/sfdc:queryResponse/sfdc:result/sfdc:records
   return
       <contact id=″{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>节点可以被返回到管道管理器并且同步回调用的应用。管道管理器也可以选举来将节点放入服务器的高速缓存中。
非关系(上下文无关)选择
可以定义不依赖外关键字值的节点之间的关系。例如,节点集可以由使用当前用户的信息或其他外部信息(例如,日时、实时数据、外部系统状态)的查询来定义。在这些情况下,节点集可能附属到数据模型内的任意节点类型。然而典型地,这些节点集附属到根节点。
管道选择操作可以引用keyref定义;由于按照定义,上下文无关选择不需要源节点的上下文,因此在一个实施例中,它们总是在反向keyref上实现。
下面的例子示出在CRM演示中,管道选择操作是如何检索当前用户的帐户集的。帐户节点类型具有下面的关键字定义。
<xsd:key name=″accountKey″mas:alias=″accounts″>
   <xsd:selector xpath=″account ″/>
   <xsd:field xpath=″id″/>
</xsd:key>
mas:alias属性指示帐户的节点集可从根节点遍历;即,
var accounts=$root.accounts.*;
可以与(上述)反向keyref选择操作相同的方式实现管道。
/**
 *mas:operation type=″select″key=″accountKey″inverse=″true″
 *mas:transform type=″request″function=″selectAccounts_request″
 *mas:transform type=″response″function=″selectAccounts_response″
 */
function selectAccounts($msg,$source){
   return ws.invoke($msg);
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 */
function selectAccounts_request($source){
    <query>
        <queryString>
             SELECT*.Account FROM Account,User
             WHERE User.Alias={string($user/username)}
             AND User.Id=Account.OwnerId
         </queryString>
     </query>
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″app″
 */
function selectAccounts_response($response){
    for $i:=$response/sfdc:queryResponse/sfdc:result/sfdc:records
    return
        <account id=″{string($i/sfdc:Id}}″>
           <modified>{string($i/sfdc:SystemModstamp)}</modified>
           <name>{string($i/sfdc:Name)}</name>
           <type>{string($i/sfdc:Type)}</type>
        </account>
}
请求变换
请求变换可以引用$user系统变量,该变量用于构建送到Web服务的请求查询。
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 */
function selectAccounts_request($source){
   <query>
        <queryString>
            SELECT*.Account FROM Account,User
            WHERE User.Alias={string($user/username)}
            AND User.Id=Account.OwnerId
        </queryString>
    </query>
}
在这种情况下,服务可以实现联合查询(join query),选择当前用户所拥有的所有帐户(即,具有与当前用户的ID匹配的OwnerId外关键字)。要注意,变换不引用$source变量。
响应变换
响应变换可以以与前面部分定义的响应变换相同的方式处理Web服务操作返回的帐户集。
/**
 *language:body type=″xquery″
 *mas:namespace target=″app″
 */
function selectAccounts_response($response){
   for $i:=$response/sfdc:queryResponse/sfdc:result/sfdc:records
   return
       <account id=″{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>节点集返回它时自动计算。
插入
插入操作可以在客户端应用将新创建的节点同步到服务器时由管道管理器调用。
在客户端上,可以以两种方式之一创建节点;即,create()函数既可以在keyref上调用也可以在root节点上调用:
var node =source.keyref.create(<xml>);//contextual create
var node =$root.create(<xml>);          //context free create
在两种情况下,只有节点的XML对象可以传送到服务器(即,不是源节点)。这是因为在上下文创建操作的情况中,节点必须包含引用源节点的外关键字;该值是由框架介于keyref定义自动设置的。
插入操作具有下面的形式:
/**
 *mas:operation type=″insert″node=″nodeName″
 *mas:transformtype=″request″function=″functionName_request″
 *mas:transform type=″response″function=″functionName_response″
 */
function functionName($msg,$source){
   return ws.invoke($msg);
}
插入操作可以用来创建与nodeName声明所引用的模式相对应的节点。
插入操作的请求变换创建Web服务操作的消息主体;它可以引用下面的系统变量,这些系统变量提供操作的上下文:
 变量   含义
 $node   应用创建的节点
 $user   表示当前用户的对象
插入操作的响应变换可以将响应消息主体映射到部分构建的节点上,该节点包含Web服务创建的记录的主关键字(和可选的序列号)。插入操作的响应变换可以引用下面的系统变量:
 变量   含义
 $response   SOAP消息响应的主体
 $user   表示当前用户的对象
节点的主关键字(和可选的序列号)可以被返回到管道管理器,后者将该信息向后同步客户端。节点最初在客户端上是用临时主关键字创建的;必须用外部系统的主关键字来代替这个值。
节点典型地包含引用其他节点的外关键字值。如果在客户端上创建多个相互引用的节点,则系统需要确保以正确的依赖顺序调用插入管道操作,并且使用Web服务返回的主关键字值来替换挂起节点的临时外关键字值。
非关系插入
在一个实施例中,非关系插入操作不具有引用数据模型内的其他节点类型的外关键字。
例如,用户节点类型可以由下面的模式定义:
<xsd:complexType name=″userType″>
   <xsd:all>
       <xsd:element name=″email″type=″xsd:string″/>
   </xsd:all>
   <xsd:attribute name=″id″type=″xsd:string″/>
</xsd:complexType>
假设管理应用程序能够创建系统的新用户;完成这个的客户端代码可能如下:
$root.create(<user><email>bobacme.com</email></user>);
在一个实施例中,这将要求下面的插入管道操作:
/**
 *mas:operation type=″insert″node=″app:user″
 *mas:transform type=″request″function=″insertUser_request″
 *mas:trans form type=″response″function=″insertUseL_response″
 */
function insertUser($msg,$node){
   return ws.invoke($msg);
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 */
function insertUser_request($node){
   <create>
       <sObjects xsi:type=″User″>
           <Email>{string($node/app:email )}</Email >
       </sObjects>
   </create>
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″app″
 */
function insertUser_response($response){
   <user id=″{string($response/sfdc:createResponse/sfdc:result/sfdc:Id)}″/>
}
请求变换
请求变换可以引用表示应用所创建的用户节点的$node变量。函数注释可以声明输出消息文档的语言(XQuery)和目标名字空间(引用管道文件的头注释中声明的名字空间前缀)。
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 */
function insertUser_request($node){
   <create>
       <sObjects xsi:type=″User″>
           <Email>{string($node/app:email)}</Email>
       </sobjects>
   </create>
}
响应变换
响应变换可以引用$response变量,该变量代表从Web服务返回的消息的XML主体。函数注释也可以声明返回到管道管理器的XML对象的语言(XQuery)和目标名字空间。
在成功时,Web服务可以返回遵从下面模式定义的消息主体。
<element name=″createResponse″>
   <complexType>
       <sequence>
           <element name=″result″minOccurs=″1″type=″tns:SaveResult″/>
       </sequence>
    </complexType>
</element>
<complexType name=″SaveResult″>
   <sequence>
       <element name=″id″type=″tns:ID″/>
       <element  name=″success″type=″xsd:boolean″/>
       <element  name=″errors″minOccurs=″0″maxOccurs=″unbounded″
type =″tns:Error″/>
   </sequence>
</complexType>
变换可以创建部分构建的<user>节点,该节点包含由应用的模式定义的主关键字属性(id)。
/**
 *language:body type=″xquery″
 *mas:namespace target=″app″
 */
function insertUser_response($response){
   <user id=″{string($response/sfdc:createResponse/sfdc:result/sfdc:id)}″/>
}
该主关键字值可以由管道管理器处理并且与客户端应用同步。
关系插入
关系插入可以涉及包含引用高速缓存内其他节点的外关键字值的节点。
例如,下面的联系人模式定义了所有者节点(ownerID)和帐户节点(accountId)的外关键字。
<xsd:complexType name=″contactType″>
   <xsd:all>
       <xsd:element name=″first″type=″xsd:string″/>
       <xsd:element name=″last″type=″xsd:string″/>
       <xsd:element name=″email″type=″xsd:string″/>
   </xsd:all>
   <xsd:attribute name=″id″type=″xsd:string″use=″required″mas:type=″pkey″/>
   <xsd:attribute name=″ownerId″type=″xsd:string″use=″required″/>
   <xsd:attribute name=″accountId″type=″xsd:string″use=″required″/>
</xsd:complexType>
最初,联系人XML对象可以由XScript赋值来构建。
var contact=
   <contact>
       <first>Sarah</first>
       <last>Smith</last>
       <email>sarahacme.com</email>
   </contact>;
可以以多种方式创建包含外关键字的节点。给定上述联系人XML对象以及表示所有人和联系人节点的变量,下面的函数通过调用根节点上的create()函数创建联系人节点。要注意,必须在调用create()之前设置外关键字。
function createContact1(account,owner,contact){
   contact.account=account;
   contact.owner=owner;
   return $root.create(contact);
}
然而,下面的函数实现相同的目的:
function createContact2(account,owner,contact){
   contact.owner=owner;
   return account.contacts.create(contact)
}
function createContact3(account,owner,contact){
   contact.account=account;
   return owner.contact=contact;
}
注意在这两种情况下,缺失的外关键字是在节点被同步到服务器之前由框架提供的。因此,不管应用如何创建节点,管道操作只需要绑定到节点类型。管道操作可以以与前面部分中定义的操作相同的方式实现:
/**
 *mas:operation type=″insert″node=″app:contact″
 *mas:transform type=″request″function=″insertContact_request″
 *mas:transform type=″response″function=″insertContact_response″
 */
function insertContact($msg,$node){
   return ws.invoke($msg);
}
/**
 *mas:namespace target=″sfdc″
 *language:body type=″xquery″
 */
function insertContact_request($node){
   <create>
      <sObjects xsi: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:namespace target=″app″
 *language:body type=″xquery″
 */
function insertContact_response($response){
   <contact id=″{string($response/sfdc:createResponse/sfdc:result/sfdc:id)}″/>
}
响应变换返回的该主关键字值可以由管道管理器处理并且与客户端应用同步。当最初创建了节点时用该值替换应用程序分配的临时主关键字。
然而,在一个实施例中,如果应用创建了相互引用的多个节点,则也必须使用服务器返回的主关键字值来更新引用新插入节点的节点的外关键字值。
例如,下面的函数首先创建所有者节点,然后创建引用它的联系人节点。
function createContact4(account){
   var owner=$root.create(<user><email>sarahacme.com</email></user>);
   var contact=
       <contact>
           <first>Sarah</first>
           <last>Smith</last>
           <email>sarahacme.com</email>
       </contact>;
   contact.owner=owner;
   return account.create(contact);
}
用户节点的管道插入操作在联系人节点的管道插入操作之前调用,并且联系人节点的ownerId属性包含从第一管道操作返回的适当外关键字值。
序列号
在某些情况下被调用来创建节点的Web服务方法可能不返回序列号。管道能够在单个管道操作内进行多个Web服务调用来检索该信息。
例如,前面部分中定义的管道操作如下扩展:
/**
 *mas:operation type=″insert″node=″app:contact″
 *mas:transform type=″request″function=″insertContact_request″
 *mas:transform type=″response″function=″insertContact_response″
 */
function insertContact($msg,$source){
   var response=ws.invoke($msg);
   var id=response.sfdc:createResponse.sfdc:result.sfdc:id;
   //retrieve sequence number
   var msg2=createMessage(requestTimestamp(id));
   var response2=ws.invoke(msg2);
   //return both responses
   response.body+=response2.body.sfdc:queryResponse;
   return response;
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 */
function requestTimestamp($id){
   <query>
       <queryString>
           SELECT Id,SystemModstamp FROM Contact
           WHERE Id=″{$id}″
       </queryString>
    </query>
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 */
function insertContact_request($node){
   <create>
       <sObjects xsi: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:body type=″xquery″
 *mas:namespace target=″app″
 */
function insertContact_response($response){
   <contact id=″{string($response/sfdc:createResponse/sfdc:result/sfdc:id)}″>
       <modified>
   {string($response/sfdc:queryResponse/sfdc:records/sfdc:SystemModstamp)}
       </modified>
   </contact>
}
请求变换
请求变换可以创建与前面部分中定义的相同的Web服务消息:
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 */
function insertContact_request($node){
   <create>
       <sObjects xsi: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>
}
管道函数
然而在这种情况下,可以修改管道的自动生成的Xscript函数来调用两个Web服务调用。首先,可以使用从请求变换返回的消息来插入节点以及检索插入的节点的主关键字。
/**
 *mas:operation type=″insert″node=″app:contact″
 *mas:transform type=″request″function=″insertContact_request″
 *mas:transform type=″response″function=″insertContact_response″
 */
function insertContact($msg,$source){
   var response=ws.invoke($msg);
   var id=response.sfdc:createResponse.sfdc:result.sfdc:id;
接着,通过将插入节点的主关键字id传递进管道中定义的辅助XQuery函数requestTimestamp(),来创建新消息对象。
//retrieve sequence number
var msg2=createMessage(requestTimestamp(id));
var response2=ws.invoke(msg2);
辅助函数声明与变换相同的语言和名字空间注释,然而它们不被管道操作的注释引用。函数构建适当的消息来调用管道操作,以返回新创建的节点的序列号:
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 */
function requestTimestamp($id){
   <query>
       <queryString>
           SELECT Id,SystemModstamp FROM Contact
           WHERE Id=″{$id}″
       </queryString>
   </query>
}
最终,可以通过创建由两个消息主体构成的单个XML对象来合并两个Web服务操作的结果。
   //return both responses
   response.body+=response2.body.sfdc:queryResponse;
   return response;
}
响应变换
响应变换可以处理管道函数创建的XML对象,并且返回包含主关键字和节点序列号的单个<contact>节点。
/**
 *language:body type=″xquery″
 *mas:namespace target=″app″
 */
function insertContact response($response){
   <contact id=″{string($response/sfdc:createResponse/sfdc:result/sfdc:id)}″>
       <modified>
   {string($response/sfdc:queryResponse/sfdc:records/sfdc:SystemModstamp)}
       </modified>
    </contact>
}
更新
更新操作可以由管道管理器在客户端应用修改节点时调用。
当企业被请求更新数据时,它可能会拒绝—因为有拒绝它的策略/进程或者因为其他人先改变了数据。第一种问题是无法避免的,并且要求更新操作和所有其他的一样,能够处理失败。框架可以实现第二种情况的最优并发模型。
当更新请求被送到Web服务操作时,它可以不仅包括改变后的值,还包括可用来在修改时确定记录是否为最新的序列号。(如果选择操作上的Web服务不返回它自己的序列号,则管道管理器可以计算基于节点值的MD5散列。)
在客户端上,节点可以通过脚本表达式修改,然而,直到在特定节点上调用update()函数时更新才同步到服务器,例如,:
function modify(contact,address){
   contact.email=address;
   contact.update();
}
在一个实施例中,客户端应用或更新操作都不能修改关键字值(即,关键字定义描述的任何字段)。
更新操作可以具有下面的形式:
/**
 *mas:operation type=″update″node=″nodeName″
 *mas:transform type=″request″function=″functionName_request″
 *mas:transform type=″response″function=″functionName_response″
 */
function functionName($msg,$source){
   return ws.invoke($msg);
}
操作注释声明对应于应用模式的节点类型。
更新操作的请求变换可以创建Web服务操作的消息主体;它可以引用下面的系统变量,这些系统变量提供操作的上下文:
 变量   含义
 $node   应用创建的节点
  $user   表示当前用户的对象
更新操作的响应变换可以将响应消息主体映射到部分构建的节点上,该节点包含修改后记录的序列号。更新操作的响应变换可以引用下面的系统变量:
 变量   含义
 $response   SOAP消息响应的主体
 $user   表示当前用户的对象
例子
下面的函数实现联系人节点的更新管道操作:
/**
 *mas:operation type=″update″node=″app:contact″
 *mas:transform type=″request″function=″updateContact_request″
 *mas:transform type=″response″function=″updateContact_response″
 */
function updateContact($msg,$source){
   ws.invoke($msg);
   //retrieve sequence number
   var msg2=createMessage(requestTimestamp($source/id));
   var response2=ws.invoke(msg2);
   return response2;
}
  /**
   *language:body type=″xquery″
   *mas:namespace target=″sfdc″
   */
  function updateContact_request($node){
     <update>
         <sObjects xsi: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:body type=″xquery″
 *mas:namespace target=″app″
 */
function updateContact_response($response){
   let $i:=$response/sfdc:queryResponse/sfdc:result/sfdc:records
   return
       <contact id=″{string($i/sfdc:Id)}″>
           <modified>{string($i/sfdc:SystemModstamp)}</modified>
       </contact>
}
请求变换
请求变换可以创建用来调用更新操作的Web服务消息:
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 */
function updateContact_request($node){
   <update>
       <sObjects xsi: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>
}
请求变换可以在节点的主关键字和元素LastModifiedDate中传递,该元素表示当从服务检索到记录时的时间戳。这允许Web服务操作实现最优并发;即,如果送到操作的时间戳值与当前系统时间戳值不匹配,则操作失败。
管道函数
与插入操作一样,可以修改管道的自动生成的XScript函数来调用两个Web服务调用。首先,使用从请求变换返回的消息来更新节点。
/**
 *mas:operation type=″update″node=″app:contact″
 *mas:transform type=″request″function=″updateContact_request″
 *mas:transform type=″response″function=″updateContact_response″
 */
function updateContact($msg,$source}{
   ws.invoke($msg);
接着,可以通过将更新的节点的主关键字id传递进管道中定义的辅助XQuery函数requestTimestamp()来创建新消息对象(这是与上面插入操作定义的相同函数)。
//retrieve sequence number
var msg2=createMessage(requestTimestamp(id));
var response2=ws.invoke(msg2);
最终,可以返回第二个Web服务操作的结果来由响应变换处理。
   return response2;
}
响应变换
响应变换可以处理管道函数创建的XML对象,并且返回包含主关键字和节点序列号的单个<contact>节点。
/**
 *language:body type=″xquery″
 *mas:namespace target=″app″
 */
function updateContact_response($response){
   let $i:=$response/sfdc:queryResponse/sfdc:result/sfdc:records
   return
       <contact id=″{string($i/sfdc:Id)}″>
           <modified>{string($i/sfdc:SystemModstamp)}</modified>
       </contact>
}
冲突管理
当客户端试图修改和同步已经被更新(由另一客户端或其他外部改变进程)的“失效”节点时,可能发生节点冲突。失效节点是具有与服务器保存的当前序列号不同的序列号的节点。
如果MAS高速缓存了比客户端尝试更新的节点版本更新的节点,则它可以用更新的节点直接响应(即,不调用管道操作),将mas:state属性设置为“conflict”。
如果管道操作由于节点失效而拒绝更新,则可以返回具有适当的mas:state属性的最新节点;这可以调用另一个往返(round-trip)来选择最新节点。
例子
下面的更新操作函数检测Web服务返回的错误值。请求变换与上面定义的相同。
/**
 *mas:operation type=″update″node=″app:contact″
 *mas:transform type=″request″function=″updateContact_request″
 *mas:transform type=″response″function=″updateContact_response″
 */
function updateContact($msg,$source){
   var response=ws.invoke($msg);
   //check for error
   if(!response.body.sfdc:updateResponse.sfdc:result.sfdc:success){
      //retrieve server′s record
      msg=createMessage(selectContact_request($source/id));
      response=ws.invoke(msg);
      //set state expando
      var node =response.body.sfdc:queryResponse.sfdc:result.sfdc:records;
      node.state=″conflict″;
   }
   else{
      //retrieve sequence number
      msg=createMessage(requestTimestamp($source/id));
      response=ws.invoke(msg);
   }
   return response;
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″app″
 */
function updateContact_response($response){
   let $i:=$response/sfdc:queryResponse/sfdc:result/sfdc:records
   if($i.!=null)
   then
      <contact id=″{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
       <contact id=″{string($i/sfdc:Id)}″>
           <modified>{string($i/sfdc:SystemModstamp)}</modified>
       </contact>
}
管道函数
管道函数可以首先检查Web服务返回的错误值。
function updateContact($msg,$source){
   var response=ws.invoke($msg);
   //check for error
   if(!response.body.sfdc:updateResponse.sfdc:result.sfdc:success){
如果返回错误,则函数可以向Web服务发送对整个节点的请求查询;这里,操作重新使用上下文无关选择操作的请求变换:
//retrieve server′s record
msg=createMessage(selectContact_request($source/id));
response=ws.invoke(msg);
操作然后创建扩展state属性,从而响应变换可以检测到已经从服务器检索到冲突记录。
//set state expando
var node=response.body.sfdc:queryResponse.sfdc:result.sfdc:records;
node.srate=″conflict″;
如果原始的Web服务方法成功,则函数只请求更新的序列号(如上)。
//retrieve sequence number
msg=createMessage(requestTimestamp($source/id));
response=ws.invoke(msg);
不管更新是否成功,任何响应都由响应变换处理。
    return response;
}
响应变换
响应变换可以首先检查来看管道操作是否创建了state扩展属性。如果是的话,则变换可以构建完整的节点元素;否则它可以只返回如上的主关键字和序列号。
function updateContact_response($response)(
   let$i:=$response/sfdc:queryResponse/sfdc:result/sfdc:records
   if($i.state!=null)
   then
       <contact id=″{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
       <contact id=″{string($i/sfdc:Id)}″>
           <modified>(string($i/sfdc:SystemModstamp)}</modified>
       </contact>
}
链接和解除链接(修改外关键字)
节点可以通过XScript表达式修改。这也适用于外关键字值。这部分中的例子使用声明了下面关键字定义的帐户和联系人节点类型。
<xsd:key name=″accountKey″>
   <xsd:selector xpath=″account″/>
   <xsd:field xpath=″id″/>
</xsd:key>
<xsd:key name=″contactPrimaryKey″>
   <xsd:selector xpath=″contact″/>
   <xsd:field xpath=″id″/>
</xsd:key>
<xsd:key name=″contactEmailKey″>
   <xsd:selector xpath=″contact″/>
   <xsd:field xpath=″email″/>
</xsd:key>
下面的函数由于尝试修改节点的关键字值,因此将产生运行时错误。
function foobar(contact){
   contact.first=$context.first;
   contact.last=$context.last;
   contact.email=$context.email;      //runtime error
}
然而,下面的函数成功地改变了帐户属性,其改变了引用帐户节点的外关键字值。
function foo(contact,account){
   contact.first=$context.first;
   contact.last =$context.last;
   contact.accountId=account;     //changes account foreign key
   contact.update();
}
这里,外关键字由下面的keyref声明定义:
<xsd:keyref name=″contactAccountRef″refer=″accountKey″mas:alias=″account″>
   <xsd:selector xpath=″contact″/>
   <xsd:field xpath=″accountId″/>
</xsd:keyref>
类似地,下面的函数使用+=运算符(也叫做link()函数)来向帐户的联系人集添加联系人节点:
function bar(account,contact){
   account.contacts+=contact;
}
这种一对多关系由下面的keyref声明定义,其包括反向关系:
<xsd:keyref name=″contactAccountRef″refer=″accountKey″
       mas:alias=″account″mas:inverseAlias=″contacts″>
   <xsd:selector xpath=″contact″/>
   <xsd:field xpath=″accountId″/>
</xsd:keyref>
在实际中(即,外部数据库)该操作可以通过将联系人实体的account外关键字设置为帐户的主关键字来实现。设置源节点中的外关键字(例如,contact.accountId)将自然地允许从目标节点遍历回源节点(例如,account.contacts.*),反之亦然。
给定上述定义,下面的函数是等效的。
function foo1(contact,account){
   contact.first=$context.first;
   contact.last=$context.last;
   contact.accountId=account;
   update(contact);
}
function foo2(contact,account){
   contact.first=$context.first;
   contact.last=$context.last;
   account.contacts+=contact;
   update(contact);
}
在一个实施例中,模式的外关键字元素(或属性)声明与外部系统的约束(或Web服务操作的语义所暗示的约束)匹配。特别地,NOT NULL外关键字值(例如,在数据库表字段上声明的)在属性的情况下应当由xsd:use″required″镜像,而在元素的情况下应当由minOccurs=″1″maxOccurs=″1″镜像。
例如,给定上述定义,下面的函数将产生运行时错误。
function foo(contact){
   contact.first=$context.first;
   contact.last=$context.last;
   contact.accountId=null;
   update(contact);
}
自定义查询
可以通过实现与两个节点之间定义的keyref关系有关的选择管道操作来检索数据;即,一个节点内包含的外关键字值标识有关节点的主关键字。这些选择操作的输出可以是由框架合并到本地高速缓存中的节点。
自定义查询可以是对客户端编程模型不透明的管道查询(或其他过程逻辑);即,不排他地基于主和外关键字关系显式地选择(或修改)数据。例如,搜索操作可以返回匹配自然语言表达式的XML对象的集合。
不同种类的操作表现为图8的矩阵800。操作具有归类为临时数据或永久数据的输入和输出。在一个实施例中,临时数据不是应用的节点图的部分;即,它未被模式、关键字或keyref声明定义,并且没有被框架自动合并到本地高速缓存中。临时数据尽管可以被系统$context或$session变量(具有由客户端应用框架确定的生命期)引用,但并不假定它是持久的。永久数据可以完全由模式定义的应用数据节点构成。
在一个实施例中,存在两个实现自定义查询的机制:
1.自定义操作可以允许客户端向特定管道操作传递不透明、临时的XML对象(文档)。该操作可以异步地返回临时XML文档给客户端回叫(callback)
例如,下面的自定义操作myQuery以XML对象<myRequest>作为输入,并且myCallback()函数返回XML对象:
$root.myQuery(<myRequest>product mobile application</myRequest>,
myCallback);
function myCallback(myOutput}{
}
2.自定义对象可以包括作为图的一部分的(模式定义的)非永久节点的创建。可以在客户端“遍历”相应keyref时调用操作,在这种情况下,客户端对象作为$source节点传递进相应选择管道操作中。
例如,下面的自定义对象<taskQuery>被送到为将task节点与taskQuery节点相关联的keyref定义的选择管道操作:
var query=$root.taskQueries.create(<taskQuery priority=″1″/>);
var tasks=query.tasks.*;
自定义操作
自定义操作可以是用于调用自定义管道操作(函数)的机制。函数输入和输出都可以是XML文档直接量(literal)(不是由模式定义)。在一个实施例中,框架不将结果直接合并到本地高速缓存中。
例如,假设我们希望在电子邮件地址集合中检索没有退出接收邮件的联系人(对特定帐户)。
下面的代码客户端代码调用自定义操作getList,该操作被传递XML对象<query>。
function bar(){
   account.getList(<query optedOut=″false″/>,callback);
}
function callback(result){
   for(i=0;i<result.length;i++){
      addAddress(result[i].email);
   }
}
一旦从MAS返回结果,回叫(callback)处理该结果。
下面的XQuery函数实现自定义请求:
/**
 *mas:namespace target=″sfdc″
 *mas:field xpath=″id″
 *language:body type=″xquery″
 */
function foo_request($source,$query){
   <query>
       <queryString>
           SELECT Id,Email FROM Contact
           WHERE AccountId=″{string($source/id)}″
           AND HasOptedOutOfEmail={boolean($query/optedOut)}
       </queryString>
   </query>
}
来自Web服务的响应可以由下面函数处理。要注意,结果作为单个XML文档返回到客户端回叫—即,这不被解释为合并到本地高速缓存中的节点。
/**
 *mas:namespace target=″app″
 *language:body type=″xquery″
 */
function foo_response($response){
   for $i in$response/sfdc:queryResponse/sfdc:result/sfdc:records
   return
       <contact id=″{string($i/sfdc:Id)}″>
           <email>{string($i/sfdc:Email)}</email>
       </contact>
}
自定义操作定义可以声明该操作的客户端函数名和上下文。
/**
 *custom operatoin on contact:account.getList(<query optedOut=″false″/>);
 *mas:operation type=″custom″node=″app:account″name=″getList″
 *mas:transform type=″request″function=″foo_request″
 *mas:transform type=″response″function=″foo_response″
 */
function foo($msg,$source,$query){
   $msg.header+=createHeader();
   return ws.invoke($msg);
}
自定义对象
自定义对象可以包括作为图的一部分的(模式定义的)非永久节点的创建。可以在客户端“遍历”相应keyref时调用操作,在这种情况下,自定义对象可以作为$source节点传递进相应选择管道操作中。
实质上,自定义操作可以包括将返回绑定到自定义对象的节点的管道操作的输入数据。这可以允许结果成为客户端高速缓存的一部分—以便这些节点被随后的客户端面板和行动引用,并且以便返回操作来保持这些结果最新。
例如,下面的模式声明可以定义自定义对象taskQuery,其用于基于priority属性的值选择task节点的子集。
<xsd:complexType name=″taskQuery″>
    <xsd:attribute name=″priority″type=″xsd:string″/>
</xsd:complexType>
下面的关键字定义确保每个taskQuery对象是唯一的:
<xsd:keyref name=″taskQueryKey″>
    <xsd:selector xpath=″taskQuery″/>
    <xsd:field xpath=″priority″/>
</xsd:keyref>
下面的keyref定义用于将taskQuery节点绑定到根节点;它声明应用根节点的虚外关键字属性mas:root;inverseAlias属性声明从根节点到taskQuery节点集合的遍历;即,$root.taskQueries.*。
<xsd:keyref name=″taskQueryRootRef″refer=″mas:rootKey″
       mas:inverseAlias=″taskQueries″>
    <xsd:selector xpath=″taskQuery″/>
    <xsd:field xpath=″mas:rootId″/>
</xsd:keyref>
下面的keyref定义管道查询操作返回的taskQuery节点和task节点之间的关系。每个task节点声明虚taskQuery外关键字属性,用于标识选择它的相应查询;inverseAlias属性声明从taskQuery节点到task节点集合的遍历,即,query.tasks.*。
<xsd:keyref name=″taskTaskQueryRef″refer=″TaskQueryKey″
       mas:inverseAlias=″tasks″>
    <xsd:selector xpath=″task″/>
    <xsd:field xpath=″taskQuery″/>
</xsd:keyref>
这些keyref定义定义了下面图12D所示的根节点与taskQuery和task节点之间的关系。
taskQuery节点可以由客户端脚本使用标准create()函数创建。
function init(){
   var f=$root.taskQueries.create(<taskQuery priority=″1″/>);
}
在一个实施例中,没有为taskQueryRootRef keyref定义的管道插入操作,因此该客户端脚本不触发任何服务器活动。
下面的模板遍历反向的taskTaskQueryRef keyref定义。
<netui:repeater id=″$s″
   source=″$root.taskQueries.where(priority==′1′).tasks.*″>
   <p>{$s}</p>
</netui:repeater>
这导致在相关管道操作上的隐式选择;repeater(重复器)的source属性引用上面创建的taskNode,并且这用作遍历的source上下文;即,节点<taskQuerypriority=’1’/>被作为$source变量传递到操作中。
相应管道选择操作由下面函数定义:
/**
 *mas:operation type=″select″keyref=″app:taskTaskQueryRef″inverse=″true″
 *mas:transform type=″request″function=″selectTasks_request″
 *mas:transform type=″response″function=″selectTasks_response″
 */
function selectTasks($msg,$source){
   return ws.invoke($msg);
}
/**
 *mas:namespace target=″sfdc″
 *mas:field xpath=″priority″
 *language:body type=″xquery″
 */
function selectTasks_request($source){
   <query>
       <queryString>
           SELECT Id,Priority,Subject FROM Task
           WHERE Priority=″{string($source/priority})″
       </queryString>
   </query>
}
/**
 *mas:namespace target=″app″
 *language:body type=″xquery″
 */
function selectTasks_response($response){
   for $i in$response/sfdc:queryResponse/sfdc:result/sfdc:records
   return
       <task id=″{string($i/sfdc:Id)}″
          priority=″{string($i/sfdc:Priority)}″>
          <subject>{string($i/sfdc:Subject)}</subject>
       </task>
}
应用也可以定义管道选择操作来“产生”(seed)代表“预罐装”(pre-canned)的查询的自定义对象。例如,下面的操作实现选择操作,选择操作当客户端遍历$root.taskQueries.*时返回taskQuery对象的(恒定)集合。
/**
 *mas:operation type=″select″keyref=″app:taskQueryRootRef″inverse=″true″
 */
function selectTasks($msg,$source){
   return<taskQuery priority=′1′/><taskQuery priority=′2′/>;
}
该查询可能例如由下面的模板引用:
<td>
   <netui:repeater id=″s1″source=″$root.taskQueries.*″>
       <a href=″s1.select(s1.iterator)″>Priority{s1}</a>
   </netui:repeater>
</td>
<td>
   <netui:repeater id=″s2″source=″s1.selected.tasks.*″>
       <p>{s2}</p>
   </netui:repeater>
</td>
第一repeater s1显示taskQuery对象的集合;第二repeater s2显示从第一repeater选择的taskQuery检索的最终得到的task。
 ·优先级1   ·准备RFP
 ·优先级2   ·销售会议·年报
当然,也可以通过实现持续这些查询对象的Web服务来定义插入、更新和删除自定义对象的管道操作—实际上,将这些查询对象作为数据模型内的普通节点对待。
当修改自定义对象节点时—不管是通过客户端应用直接修改还是通过同步选择操作间接修改,所有相应有关节点可以自动与自定义对象解除链接;即,通过外关键字值引用对象的节点将该外关键字设为空(null)。这确保通过自定义对象遍历到的节点精确地反映自定义对象的状态。
高级选择操作
选择操作可以允许框架检索特定keyref的节点。由于这是客户端应用用来检索节点的基本机制,因此管道可以定义选择操作。
正常的选择操作可以在当客户端应用导航数据模型时由应用自动触发。例如,下面的客户端SPath表达式导致调用accounts keyref的选择操作。
$account.contacts.*
管道选择操作可以被传递相应帐户对象的主关键字。这部分详细说明其他形式的选择操作。
高速缓存和优化
客户端和MAS都可以高速缓存管道管理器返回的数据。因此,不是每个数据图遍历都不需要生成选择请求。客户端和服务器都可以在生成新选择请求之前维持每个节点和节点集的元数据,该元数据用于确定相应数据的集合可以依靠多久来更新。
通常,需要根据选择操作传输的数据量是很大的。因此,给定适合的Web服务操作的可用性,可以由框架实现特定的优化。
以与select操作相同的方式调用select_pkey操作,然而,它仅返回主关键字集。例如,在上面联系人keyref上的相应选择操作的select_pkey操作将实现下面的响应变换。
/**
 *language:body type=″xquery″
 *mas:namespace target=″app″
 */
function selectContactsByAccount_response($response){
   for $i:=$response/sfdc:queryResponse/sfdc:result/sfdc:records
   return
      <contact id=″{string($i/sfdc:Id)}″>
          <modified>{string($i/sfdc:SystemModstamp)}</modified>
      </contact>
}
MAS于是能够确定哪个节点元素(如果有的话)当前在高速缓存中。
对于未包含在高速缓存内的任何节点,框架然后可以调用select_set操作,象正常的选择操作那样返回请求的pkey值集合的完整节点。上面例子的select_set操作将实现下面的请求变换:
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 */
function selectContacts_request($keyset){
   <query>
       <queryString>
           SELECT*FROM Contact
           WHERE Id IN{
               {
                  for $x in $keyset
                  return
                      {$x},
               }
           }
       </queryString>
   </query>
}
响应变换可以与正常的选择操作相同。
选择复合模式
选择操作可以返回定义为包含重复元素的复合文档的节点。对节点类型的模式定义的复杂度没有限制。然而,可能有对节点记录大小的实际限制。下一部分将详细说明当复合文档可能被分成多个节点时的情况。
例子
下面的模式示出包含多个lineItem元素的purchaseOrder节点类型。
<xsd:element name=″purchaseOrder″type=″purchaseOrderType″>
<xsd:complexType name=″purchaseOrderType″>
   <xsd:sequence>
       <xsd:element name=″price″type=″xsd:double″/>
       <xsd:complexType name=″lineItems″>
           <xsd:sequence maxOccurs=″unbounded″>
               <xsd:complexType ref=″lineItem″>
                   <xsd:sequence>
                      <xsd:element name=″prodId″type=″xsd:string″/>
                   </xsd:sequence>
               </xsd:complexType>
           </xsd:sequence>
       </xsd:complexType>
   </xsd:sequence>
</xsd:complexType>
例如,下面的XML文档示出订购单模式。
<purchaseOrder>
   <price>1000.00</price>
   <lineItems>
       <lineItem>
           <prodId>Widget-X</prodId>
        </lineItem>
        <lineItem>
            <prodId>Widget-Y</prodId>
        </lineItem>
   </lineItems>
</purchaseOrder>
下面的管道函数包含生成订购单集合的嵌套循环,每个具有嵌套的行式项目的集合。
/**
 *mas:operation type=″select″keyref=″purchaseOrderAccountRef″
inverse=″true″
 *mas:transform type=″request″function=″selectPurchaseOrders_request″
 *mas:transform type=″response″function=″selectPurchaseOrders_response″
 */
function selectPurchaseOrders($msg,$source){
   var response=ws.invoke($msg);
   var pos=response.sfdc:queryResponse.sfdc:result.sfdc:records;
   //retrieve line items for each purchase order
   for(i=0;i<pos.length-1;i++){
      var msg2=createMessage(requestLineItems(pos[i].sfdc:Id));
      var response2=ws.invoke(msg2);
      pos[i]+=response2.body.sfdc:queryResponse.sfdc:result.sfdc:records;
   }
   return response;
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 *mas:field xpath=″id″
 */
function selectPurchaseOrders_request($source){
   <query>
       <queryString>
           SELECT*FROM PurchaseOrder
           WHERE PurchaseOrder.AccountId={string($source/id)}
       </queryString>
    </query>
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 */
function selectLineItems($id){
   <query>
       <queryString>
            SELECT*FROM LineItem
            WHERE LineItem.PurchaseOrderId=$id
       </queryString>
   </query>
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″app″
 */
function selectPurchaseOrders_response($response){
   for $po:=$response/sfdc:queryResponse/sfdc:result/sfdc:records
   return
      <purchaseOrder id=″{string($po/ws:Id)}″>
          <price>{string($po/ws:Price)}</price>
          <lineItems>
          {
             for $li in $po/ws:records
             return
                <lineItem>
                    <prodId>{string($li/ws:ProdId)}</prodId>
                </lineItem>
          }
          </lineItems>
       </purchaseOrder>
}
选择节点树
选择操作可以返回定义为包含重复元素的复合文档的节点。对节点类型的模式定义的复杂度没有限制。
在某些情况下,希望将复合文档的部分分成由keyref关系绑定的独立的节点。这些节点形成树,其向后同步客户端并且合并到高速缓存的数据图中。
将复合文档分成多个节点的好处是通过在单个操作中检索多级keyref(即,选择特定帐户的所有联系人以及所有相关任务)来提高性能。
例子
在下面的模式定义中,purchaseOrderType和lineItemType都被声明为具有下面模式定义的节点类型。
<xsd:complexType name=″purchaseOrderType″>
   <xsd:complexType>
       <xsd:sequence>
           <xsd:element name=″price″type=″xsd:double″/>
       <xsd:sequence>
   </xsd:complexType>
<xsd:complexType>
<xsd:element name=″lineItemType″>
   <xsd:complexType>
       <xsd:sequence>
           <xsd:element name=″prodId″type=″xsd:string″/>
       </xsd:sequence>
   </xsd:complexType>
</xsd:element>
模式还声明下面的关键字和keyref定义:
<xsd:key name=″purchaseOrderKey″>
   <xsd:selector xpath=″purchaseOrder″/>
   <xsd:field xpath=″id″/>
</xsd:key>
<xsd:key name=″lineItemKey″>
   <xsd:selector xpath=″lineItem″/>
   <xsd:field xpath=″id″/>
</xsd:key>
<xsd:keyref name=″lineItemPurchaseOrderRef″refer=″purchaseOrderKey″
   mas:inverseAlias=″lineItems″>
   <xsd:selector xpath=″lineItem″/>
   <xsd:field xpath=″purchaseOrderId″/>
</xsd:keyret>
图12D表示相应的keyref。
一旦复合文档被分成单独的节点,框架就可以确保管道支持组成节点(例如,行式项目)上的客户端操作。例如,可以防止客户端应用创建新的行式项目对象,除非存在lineItem keyref的相应插入操作。
下面的管道定义是上面例子的修改版本。这里,内部循环创建nodeset元素内的节点元素。要注意,每个内部对象也必须都定义主关键字。
/**
 *mas:operation type=″select″keyref=″purchaseOrderAccountRef″
inverse=″true″
 *mas:transform type=″request″function=″selectPurchaseOrders_request″
 *mas:transform type=″response″function=″selectPurchaseOrders_response″
 */
function selectPurchaseOrders($msg,$source){
   var response=ws.invoke($msg);
   var pos=response.sfdc:queryResponse.sfdc:result.sfdc:records;
   //retrieve line items for each purchase order
   for(i=0;i<pos.length-1;i++){
      var msg2=createMessage(requestLineItems(pos[i].sfdc:Id));
      var response2=ws.invoke(msg2);
      pos[i]+=response2.body.sfdc:queryResponse.sfdc:result.sfdc:records;
   }
   return response;
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″sfdc″
 *mas:field xpath=”id″
 */
function selectPurchaseOrders_request($source){
   <query>
       <queryString>
           SELECT*FROM PurchaseOrder
           WHERE PurchaseOrder.AccountId={string($source/id)}
       </queryString>
   </query>
}
/**
 *language:body type=″xquery″
 *mas:namespace target=″app″
 */
function selectPurchaseOrders response($response){
   for $po:=$response/sfdc:queryResponse/sfdc:result/sfdc:records
   return
      <purchaseOrder id=″{string($po/ws:Id)}″>
          <price>{string($po/ws:Price)}</price>
          <mas:nodeset keyref=″lineItemPurchaseOrderRef″>
          {
              for $li in $po/ws:records
              return
                  <lineItem id=″{string($li/ws:Id)}″>
                      <prodId>{string($li/ws:ProdId)}</prodId>
                  </lineItem>
          }
          </mas:nodeset>
       </purchaseOrder>
}
深选择(deep select)
如上面所讨论的,应用可以使用SPath表达式遍历数据图,这些遍历可以使框架同步背景中所要求的数据。在一个实施例中,由于同步机制是被异步调用的,因此可能经常出现不能根据当前高速缓存的数据图充分估值SPath表达式的情况。
例如,如果客户端没有预先同步和高速缓存keyref accounts和contacts,则下面的SPath表达式将返回空列表。
$root.accounts.*.contacts.*.tasks.*;
在一个实施例中,除非在前的节点当前位于高速缓存中,否则不能启动后面的keyref遍历。在一个实施例中,客户端代码将首先遍历$root.accounts.*,然后等待同步通知,然后选择$root.accounts.*.contacts.*,等待另一同步通知,最后表达式将调用所有帐户的所有联系人的所有任务的同步。
select()函数可以使客户端能请求服务器来代表它估值SPath表达式,然后将得到的节点图同步到客户端。例如:
$root.select(accounts.*.contacts.*.tasks.*);
这里,整个Spath表达式被传递给服务器,后者调用连续的keyref遍历并且管理节点的同步。要注意,服务器可以在一个同步消息或在多个同步消息上返回整个图。
SPath表达式还可以包含使用where()函数的谓词(predicate)。例如:
$root.select(accounts.*.contacts.*.tasks.*.where(.priority==1));
可以在得到的节点被同步到客户端之前在服务器上解析谓词表达式。
下面的表达式可以对所有具有type=“Direct”元素的所有帐户检索所有联系人和通知。
$root.select(accounts.where(.type=″Direct″).keyref(″contacts″,″notes″).*;
                          会话管理
会话状态可以由管道的自定义过程代码管理。
管道可以定义变量来存储会话标识符。这可以由管道创建,或者由Web服务返回—就像在这种情况下这样:
//session object returned from Web service
var sessionId=null;
管道可以定义函数来创建和发送用来启动会话的消息;然后该函数可以处理响应来提取服务返回的任何有关会话的信息。
下面的函数向Web服务发送<login>消息并且从响应主体中提取会话标识符。它也可以设置服务返回的Web服务控制的URL。
//create and send logln message and process results
function login(){
    var body=
       <login>
            <username>{$user.username}</username>
            <password>{$user.password}</password>
       </login>;
    var response=ws.invoke(body);
    //set session id
    sessionId=string(response.body.sfdc:result.sfdc:sessionId);
    //set URL for subsequent calls(from this conduit)
    ws.endPoint=string(response.body.sfdc:result.sfdc:serverUrl);
}
$user XML变量包含关于当前用户的信息;它是所有函数可访问的系统变量。
每个对话式方法可以指定包含会话标识符的头,下面(普通)的管道函数首先检查对话是否开始(如果还没有的话,调用login),然后返回恰当的头XML片断。
//create conversational header
function createHeader(){
    if(sessionId==null){
      login();
    }
    return
       <SessionHeader>
           <sessiondId>{sessionId}</sessiondId>
       </SessionHeader>;
}
例如,下面的XScript函数实现Web服务所需要的自定义会话管理。
/**
 *mas:operation type=″select″keyref=″app:contactAcoountRef″inverse=″true″
 *mas:transform type=″request″function=″selectContacts_request″
 *mas:transform type=″response″function=″selectContacts_response″
 */
function selectContacts($msg,$source){
   $msg.header+=createHeader();
   return ws.invoke($msg);
}
函数被传递进消息对象$msg中,该对象包含由请求变换创建的主体。
接着,函数调用createHeader()函数来获得包含必要头信息的XML对象。如果会话当前还没有开始,则该函数触发(上述)login()函数。然后将头对象添加到消息中。
invoke()函数然后发送消息(包含头)给Web服务;它使用指定控制所提供的传输。
用户信息
$user变量包含关于正调用管道操作所代表的用户的数据。
  特性   描述
  username   当前用户的名字(即,登录/别名)
  password   当前用户的密码
客户端编程模型
用户可以通过在MAS上引用应用的URL来访问应用。用户第一次从客户机进行该操作,应用的所有组件都可以从服务器自动“下载”。如果应用开发者只指定了应用的一个数据模型,则可以下载该数据模型的元数据。元数据可以包含足够的信息来让移动浏览器提供应用的最小用户接口。使用元数据,移动浏览器可以最初显示根节点及其keyref。用户可以通过点击这些keyref来导航应用数据。当用户选择keyref时,数据同步引擎异步地取出该keyref的节点并自动显示数据(当可用时)。例如,用户可以遍历Account链接来使得取出Account节点;然后遍历Account的Contacts keyref来浏览该Account的Contacts。该模型能起到作用,但不是特别令人满意—UI生硬,并且由于没有预取出数据而经历“不平稳”(jerkey)。这部分描述应用程序员如何才能自定义用户接口。
程序员有两种基本物件用来自定义客户端应用。第一种是“模板”,它可以用来提供数据集的自定义用户接口。程序员可以使用“模板”附加自定义的方法来呈现(render)节点和节点集,“模板”可以是具有嵌入的SPath表达式的XHTML模板,用来从数据模型和嵌入元素访问数据以在节点集上重复。偶尔连接的数据模型自身作为源自魔术变量$root的大的虚拟XML文档提供。在一个实施例中,数据模型中存在“当前”位置(例如,Account或Account的Contacts),并且模板可以通过另一魔术变量$current可得到它。URL可以表示分支到另一模板和该模板内的新“当前”数据(例如,到Account、到其Contacts)。尽管模板可以以XHTML表示,它们可以包含对XHTML模型自身的重要扩展,这“部分”将在下面说明。它允许比HTML通常所提供的(但当客户端也是控制器时也是可以的)更丰富的交互UI。
第二种物件让程序员脱机地完成页面中的按钮和URL。每个URL可以引用以(也放在客户目录中的)页面流文件(controller.xpf)中的XML的ECMAScript(又称为JavaScript)编写的“action”(动作)。该文件包含一组脚本“动作”。动作具有对数据模型的完全访问权,从而它们可以计算值、修改客户端上的数据,从而触发延迟的同步,显式地触发同步和深选择,调用自定义操作,或者引起导航来将当前值(currency)设置为数据模型的另一部分。控制器中的每个“动作”可以返回数据模型内的新当前值(或者如果动作实际上不改变数据模型内的“当前值”,则返回CONTINUE)和通常该当前值的上下文中使用的特定模板。例如,页面中列出Contacts来查看有关Contacts的动作可以仅仅是一个liner,用来将当前值设为有关Contacts并且使用Contact列表模板来显示它们,大致像下面这样:
function showContactsForAccount($account){
   $context.account=$account;
   return[$account.contacts.*,″ContactsTemplate.tmpl″];
}
模型视图控制器
MAS客户端应用可以由页面流文件(controller.xpf)和一组页面模板(.tmpl)构成,页面流文件可以包含XScript动作和函数。
客户端可以维持应用数据的本地高速缓存。该数据是由偶尔连接的数据模型描述并且使用SPath引用和操控的。
面板是包含嵌入的SPath表达式的XHTML页面。这些表达式可以引用高速缓存中的任何数据和系统变量及函数。由于模板只能引用本地数据,因此它们可以独立于机器的网络连接状态提供(即,允许用户脱机运行应用)。
系统变量$current可以为数据加入光标;$current引用单个节点或节点列表。$current的值可以由调用系统函数的动作和锚(anchor)改变。系统变量$context可以提供动作和模板交换临时变量的机制。例如,模板可以将输入字段绑定到context变量或高速缓存内的节点元素。
模板也可以包括重复器,后者在数据或数据模式的指定部分上迭代。重复器允许模板自动建立复杂的列表和表格,并且允许用户选择各个记录并且对它们调用动作。
页面流机制响应于用户接口和外部事件调用动作。用户接口事件可以由模板内的<a>锚触发;外部事件可以由到数据的外部同步更新触发。当应用首次开始时,它可以调用页面流内的begin()动作,确定要显示的第一模板。
动作可以是由模板和外部事件调用的XScript函数。动作可以修改数据,以及模板可访问的$current和$context变量。系统变量$page引用当前可见的页面文档;这允许动作访问页面控制特性。
当$page或$current系统变量被动作改变时可以发生导航。客户端cab保存<$page x $current x $context>变量的历史栈。这允许用户在历史中来回导航,并且允许模板保存它们的上下文(以及,例如,输入元素的边界值)。
XScript
SPath表达式
客户端编程模型可以使用XML的ECMAScript(E4X,XScript),后者本质上是自然支持XML的JavaScript;SPath是类似XPath的语言,它允许应用查询XML数据图。它使用“点”运算符来“遍历”图内的元素。元素可以常规XML元素或数据节点。
XML操作
系统变量可以用‘$’符号作前缀,并且是无法归类的(untyped)。其他变量的使用由XScript规范定义。
下面的声明创建变量foo和bar。
foo=100;
var bar=″Alchemy″;
Var关键字将变量放在当前函数的局部范围之内,未声明Var的变量被放在全局范围中。
下面的声明将foo的值设为新创建的XML对象:
var foo=<foo>Alchemy</foo>;
也可以如下创建和引用复合的XML对象:
var foo=<foo><bar>Alchemy</bar></foo>;
var bar=foo.bar
bar==″Alchemy″
XML对象也可以声明属性,后者使用‘’运算符引用,例如:
var foo=<foo id=″100″><bar>Alchemy</bar></foo>;
var id=foo.id;
可以隐式地添加属性(即,扩展):
foo.ping=″200″;
下面的例子改变<bar>元素的文本值:
var foo=<foo><bar>Alchemy</bar></foo>;
foo.bar=″MAS″;
foo==<foo><bar>MAS</bar></foo>
下面的例子取代整个<bar>元素:
var foo=<foo><bar>Alchemy</bar></foo>;
for.bar=<foobar>Mobilized</foobar>
foo==<foo><foobar>Mobilized</foobar></foo>
+=运算符用于向已有父元素添加或插入新的XML元素,例如:
var foo=<foo><bar>Alchemy</bar></foo>;
for.bar+=<bar>Mobilized</bar>
foo==<foo><bar>Alchemy</bar><foobar>Mobilized</foobar></foo>
相反,使用delete(删除)运算符来移除元素。
var foo=<foo><bar>Alchemy</bar></foo>;
delete foo.bar
foo==<foo></foo>
数据图操作
偶尔连接的数据模型可以作为具有显式变量$root的虚拟XML文档面向开发者,变量$root指向数据模型中的根节点。可以通过keyref定义并且使用运算符在虚拟XML文档中建模到相关节点的导航。
节点操控
在本文档中,术语节点用于指示数据模型节点。例如,下面的例子创建XML元素。
var account=
   <account>
      <name>Acme</name>
      <type>Direct</type>
   </account>
在一个实施例中,当将XML元素插入(当前使用create()函数)数据高速缓存中时,将其当作节点。
可以通过在keyref上调用create()函数创建新节点。例如,下面的例子创建了新account节点。
$root.accounts.create(<account><name>Brooklyn Industries</name></account>);
可以使用常规SPath表达式引用和修改节点元素内包含的数据。下面的例子改变$contact节点内的元素的字面值。
account.name=″Acme Ltd″;
也可以通过赋值在节点内创建新XML元素,例如:
account.address=<address><street>335
Madison</street><zip>11211</zip></address>
数据操作
节点类型之间的关系可以由偶尔连接的数据模型中的keyref定义来定义。例如,下面的声明指定accouts keyref源自根节点,并且包含由模式定义的account类型的节点。
<keyref name=″accounts″sourceType=″mas:root″targetType=″app:account″>
在客户端编程模型中,可以使用运算符遍历keyref。例如:
$root.accounts
keyref()函数也可以用于引用指定的keyref。
下面的例子与下面例子等效:
$root.keyref(″accounts″)
keyref可以认为是对指定的父节点引用keyref。下面的例子引用$root节点的accounts keyref的所有account节点。
$root.accounts.*
$root.keyref(″accounts″).*
该表达式返回节点集,其中每个节点将是account类型,例如:
<account>
   <name>Acme</name>
</account>
<account>
   <name>Bancroft</name>
</account>
运算符可以用于访问节点集内的特定节点。下面的表达式返回accounts节点集中的第一个节点。
$root.accounts.*[0]
length()函数可以用来返回节点集中的节点数。
$root.accounts.*.length()
要注意,这与下面返回值1(一)的表达式非常不同。
$root.accounts.length()
即,$root.accounts返回单个元素<accounts>。
可以使用采用SPath表达式作为参数的where()函数过滤数据图。例如,下面的语句将accountskeyref中的所有contact节点与指定的姓匹配并且返回节点列表。
$root.accounts.*.where(.name==″Acme″);
要注意,这与下面的表达式等效。
$root.accounts.*.(thisXML.name==″Acme″);
where子句可以求出节点列表,并且后面可以跟有SPath表达式。例如,下面的表达式返回名为“Acme”的所有帐户的联系人的节点列表。
$root.accounts.*.where(.name==″Acme″).contacts.*;
标签
每个节点类型声明可以定义标签,标签是引用节点的SPath表达式。lable()函数返回计算出的串。
<p>{$context.account.label()}</p>
Keyref也可以定义由label()函数返回的标签。
<p>{$root.accounts,label()}</p>
节点的标签是由label()函数获得的。例如:
当节点或keyref被其自身引用时,强制自动调用label()函数。下面的例子与上面例子等效。
<p>{$context.account}</p>
<p>{$root.accounts}</p>
名字空间
在客户端编程模型中,可以在应用自己的缺省名字空间中实现所有的操作。
缺省名字空间是使用setDefaultNamespace函数设置的。
function begin(){
   $pageFlow.setDefaultNamespace(″http://example.com/″);
}
这将缺省应用名字空间自动加到所有XML操作中。例如,下面的表达式:
var account=<account><name>Acme</name></account>;
生成下面的XML:
<account xmlns=″http://example.com/″>
   <name>Acme</name>
</account>
系统变量和函数引用
这一节说明可以扩展ECMAScript以用于XML标准的系统变量和函数。
系统变量
所有的系统变量可以用‘$’符号作前缀;用户变量按照惯例也可以使用‘$’符号。
框架定义下面的系统变量,它们可以从模板和动作引用:
  变量  含义
  $root  图的根节点
  $current  当前节点或节点列表
  $context  模板的当前上下文
  $session  在应用的生存期内维持的全局变量
  $page  当前页面模板
  $pageFlow  当前页面流
  $globalApp  应用的全局app对象
  .user  当前用户
  .device  当前设备简档
  .history  导航帧<$current x$context x$page>的栈
客户端数据模型可以表示应用的持久数据。然而,应用可能需要临时存储在页面变换过程中维持的信息,而不是同步到MAS;这可能例如用于实现“剪贴板”、“向导”和其他多页面进程。开发者能够创建$context和$session内的新变量。
$context
$context变量表示调用动作可能希望传递到模板的额外数据。这与JPF中的前向豆(forward bean)或者HTTP GET属性类似。上下文变量可以作为历史的一部分预留。
$session
$session变量表示应用的“会话”状态;与$context对象不同,它不作为历史的一部分存储。它典型地用于存储与整个应用(即,不是特定页面)有关的信息。这些变量在应用的生存期内存活,并且当应用(和浏览器)关闭和启动时不变和消失(dehydrate)。
例如,下面的函数可以用于设置用户定义的count状态变量。
function onExternalSync(){
   $session.count=$root.messages.*.length();
}
每个页面于是可以包括下面的XHTML片断,每当约束状态变量改变时其将自动被更新。
<p>You have{$session.count}messages.</p>
<p>Click
<a href=″$pageFlow.navigate($root.messages.*,
′showMessages.tmpl′)″>here</a>
to see them</p>
$current
$current变量表示节点(或节点列表),并且典型地由模板将其与相对SPath表达式一起用来将UI元素绑定到数据。
$user
$user变量包含关于正调用管道操作所代表的用户的数据。该对象包括下面字段。
  字段   含义
  username   当前用户的名字(登录)
  password   当前用户的密码
$history
$history变量可以由控制器修改。
$history变量可以实现下面的函数。
  函数   含义
  home()   移到历史的开始处
  end()   移到历史栈的结尾
  back()   移到前一历史状态
  forward()   移到下一历史状态
  length()   历史栈的长度
  position()   历史栈中的当前位置
$pageflow
$pageFlow对象支持下面的函数。
  函数   含义
  reset()   应用的$history,$context和$session变量
  navigate(SPath[,template])   子句导航和设置$context和$page变量
  addTimer(callback,delay[,period])   创建可选的重复定时器,其调用用户的callback函数。delay和period以毫秒为单位。
  cancelTimer(timerId)   取消timerId变量所标识的定时器。
$globalApp
$globalApp变量实现下面的函数。
 函数   含义
 setMessage(message)   设置客户端的状态条消息;message参数是可以包含约束SPath表达式(例如,″{$root.messages.*.length}messages″的串;对于模板,当底层数据改变时该表达式被重新估值。
数据模型函数
在节点上定义下面的函数:
  函数   含义
  update([callback,id])   使用与SPath参数定义的keyref相关的更新操作使指定的节点同步到服务器;可选的callback参数指定在同步机制接收到来自服务器的应答时调用的函数名。
  select(spath,[callback,id])   调用相对于源节点由SPath表达式描述的节点图的选择机制;可选地定义在同步进程完成时调用的
  callback句柄和cookie。
 keyref(“keyrefName”)keyref(“11”[,“12”,...])keyref(“*”)   等效于.keyrefName;keyref(″*″)返回keyref的XMLList。
 label()   返回由模式定义构造的标签。
 meta()   返回包含数据模型元数据的对象。
 syncState()   返回节点的同步状态串。
在keyref上定义下面的函数:
  函数   含义
  create(xml[,callback,id])   向keyref添加节点;可选的callback参数指定在同步机制接收到来自服务器的应答时调用的函数名。
  where(spath-expr)   在节点集上将SPath表达式作为谓词(或过滤器)估值。
  link(node)+=node 将(keyref定义的)节点的外关键字值设为节点集的源节点的值。
  unlink(node)-=node 将(keyref定义的)节点的外关键字值设为null
  meta()   返回包含系统状态的对象
元数据函数
客户端编程模型可以允许开发者访问描述应用的部分元数据。
meta()
数据模型元数据可以通过在节点或keyref上调用meta()函数来访问,例如:
$root.meta();
$root.keyref(″accounts″).meta();
在meta对象上定义下面的函数:
  函数   含义
  schema()   返回节点或keyref的模式对象
schema()
在schema对象上定义下面的函数:
  函数   含义
  getFieldLabel(spath)   返回字段名;该值用于构建具有对应于XML文档元素的可读标签的表格。
  keyref(″*″)   返回引用该模式的keyref的列表;该函数允许客户端应用导航keyref图,而不要求来自本地高速缓存的实例数据。
例如,下面的模板例子使用嵌套重复器构造标识keyref层次的表。
<netui:repeater id=″s1″source=″$root.keyref(′*′)″iterator=″$i ″>
  <p>{$i}</p>
  <ul>
  <netui:repeater id=″s2″
source=″$sl.selected.meta().schema().keyref(′*′)″
     iterator=″$j″>
     <li>{j}</li>
  </netui:repeater>
  </ul>
</netui:repeater>
对于CRM用途的情况将产生下面的输出。
accounts
·owner
·subAccounts
·quoteRequests
·contacts
·notes
·events
·tasks
偶尔连接的数据模型
上面部分中描述的数据模型可以作为虚拟的XML文档面向开发者,具有指向根节点的显式变量$root。在一个实施例中,移动浏览器总是具有数据模型内的当前位置(作为上下文)(例如,特定帐户或帐户集)。模板和脚本可以通过另一显式变量$current访问该当前位置。
图中示出CRM应用的示意图900;应用定义了六种节点类型:Account,Contact,Note,Event,Task和QuoteRequest。框架生成描述整个应用数据模型的XML模式。这可以使用应用模式和keyref定义来生成。
例如,CRM应用具有下面的模式:
<?xml version=″1.0″?>
<xsd:schema targetNamespace=″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:element name=″graph″>
   <xsd:complexType>
       <xsd:sequence>
           <xsd:element ref=″root″minOccurs=″1″maxOccurs=″1″>
           <xsd:element ref=″account″maxOccurs=″unbounded″>
           <xsd:element ref=″contact″maxOccurs=″unbounded″>
           <xsd:element ref=″note″maxOccurs=″unbounded″>
           <xsd:element ref=″event″maxOccurs=″unbounded″>
           <xsd:element ref=″task″maxOccurs=″unbounded″>
           <xsd:element ref=″quoteRequest″maxOccurs=″unbounded″>
       </xsd:sequence>
   </xsd:complexType>
</xsd:element>
</xsd:schema>
<graph>元素可以表示应用数据模型的顶级元素;这可以包含恰好一个<root>节点声明,加上每个应用模式的每个节点的无限实例(account,contact,note,event,task和quoteRequest)。
<root>元素可以被$root系统变量引用。由于根节点是特殊的系统类型,因此根节点内不包含用户数据对象。
$root.accounts.*;
偶尔连接的数据模型可以定义应用节点类型,这些可以从应用模式和keyref定义构建。例如,下面的例子详述account节点类型;它包含模式元素(name和type)和keyref定义(owner,subAccounts,contacts,notes,events,tasks和quotes)。
<xsd:element name=″account″>
   <xsd:complexType>
       <xsd:sequence>
           <xsd:element name=″name″type=″xsd:string″/>
           <xsd:element name=″type″type=″accountType″/>
       </xsd:sequence>
       <xsd:attribute name=″ownerId″/>
       <xsd:attribute name=″parentAccountId″/>
   </xsd:complexType>
</xsd:element>
帐户节点定义定义了在服务器上定义的相应模式所描述的元素(和可能的属性)。如上所述,keyref定义确定从帐户节点的可能的遍历。例如:
var user=account.owner;
var contacts=$root.accounts.*.contacts.*;
类似地,下面的例子定义contact节点类型。
<xsd:element name=″contact″>
   <xsd:complexType>
       <xsd:sequence>
           <xsd:element name=″salutation″type=″contactSalutationEnum″/>
           <xsd:element name=″first″type=″xsd:string″/>
           <xsd:element name=″last″type=″addressType″/>
           <xsd:element name=″email″type=″xsd:string″/>
       </xsd:sequence>
       <xsd:attribute name=″accountId″/>
       <xsd:attribute name=″ownerId″/>
   </xsd:complexType>
</xsd:element>
下面的XML示出用户如何访问该数据的客户端模型(尽管决不会有实际的XML文件看起来像这样)。
<graph>
<root accounts=″a1 a2″/>
<account id=″a1″owner=″bob″contacts=″c1 c2″notes=″n1″events=″e1″
tasks=″t1″>
   <name>Acme</name>
   <type>Direct</type>
</account>
<account id=″a2″owner=″bob″contacts=″c3″>
   <name>Bancroft</name>
   <type>Web</type>
</account>
<contact id=″c1″owner=″bob″events=″e2″tasks=″t2″>
   <salutation>Mr</salutation>
   <first>Roger</first>
   <last>Reed</last>
   <email>rogeracme.com</email>
</contact>
<contact id=″c2″owner=″bob″notes=″n2″>
   <salutation>Ms</salutation>
   <first>Sarah</first>
   <last>Smith</last>
  <email>sarahacme.com</email>
</contact>
<contact id=″c2″owner=″bob″notes=″n2″>
   <salutation>Ms</salutation>
   <first>Sarah</first>
   <last>Smith</last>
   <email>sarahacme.com</email>
</contact>
<note id=″n1″>
   <title>ROI information</title>
   <body>Attached document details ROI for product</body>
</note>
<note id=″n2″>
   <title>Customer requirements</title>
   <body>Attached document presents customer′s current and anticipated
needs</body>
</note>
<event id=″e1″assigned=″fred″>
   <title>Sales meeting</title>
</event>
<event id=″e2″assigned=″fred″>
   <title>Product demonstration</title>
</event>
<task id=″t1″assigned=″fred″>
   <title>Prepare RFP for sales call</title>
   <status>Not started</status>
</task>
<task id=″t2″assigned=″fred″>
   <title>Send white paper to customer</title>
   <status>Completed</status>
</task>
</graph>
概述
在一个实施例中,客户端有两种方式修改数据图。第一,可以将模板中的输入元素直接绑定到数据节点;该机制允许用户修改属于已有节点的XML元素而不需要代码。第二,(并且是典型地)模板调用修改数据的动作。
在一个实施例中,这些对数据的改变并不同步地送到服务器。相反,后台进程同步与服务器的更新。实际上,由于整个页面流机制可以独立于网络(服务器)连接运行,因此将典型地存在多个对数据的脱机改变,其将在一旦建立连接时与服务器同步和协调。
编程模型也可以实现用于拖延更新或插入的记录的同步。例如,可以创建表示订购单的节点,但用户可能不想将其同步,直到所有行式项目被添加并点击“提交”按钮为止。
服务器可能由于与其他用户的乐观的并发冲突,或者由于外部应用错误而拒绝同步请求。每个节点具有由框架管理的同步状态。这可以允许应用显示标记,该标记指示哪个记录是挂起同步、最新或被服务器拒绝。
模式确认
当create()和update()函数被调用时,框架进行下面操作:
A)按照应用模式确认对象,并且确认所有要求的外关键字;
B)确保高速缓存与可以在反方向上遍历的关系(即,反向关系)一致。
如果任一条件不满足,则产生运行时错误。
此外,当调用link()或unlink()函数(+=/-=运算符)时实施关键字/keyref一致。
创建节点
下面的动作可以使用create()函数创建节点。
var po=<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>
节点po可以通过XML赋值表达式(第一行)构建。第二和第三表达式修改XML节点。然而,节点直到create()函数被调用之前不需要被确认。
更新节点
类似地,应用可以通过直接访问节点的数据来修改已有节点。例如,下面的节点检索特定订购单,然后改变状态并添加新的行式项目:
po=$account.purchaseOrders.where(.date==″03/12/05″).*[0];
po.status=″getQuote″;
po.lineItems+=<lineItem><prodId>DEF</prodId><qty>300</qty></lineItem>
$po.update();
再次调用update()函数来确认节点。
创建节点
可以使用create()函数来在客户端上创建新节点。
var node=sourceNode.keyref.create(<node>[,callback,id]);
可以在支持插入管道操作的keyref上调用该函数。该函数返回节点对象。
  参数   类型   描述
  node   xml   遵从节点类型的应用模式的合式的XML对象
  callback   函数   可选的callback函数指定同步机制在接收到来自服务器的应答时调用的函数名。
  id   值   可选的id参数被传递到callback函数中来标识调用上下文。
例子
例如,下面的XScript构建指定$account对象的contacts keyref内的新contact节点。
var contact=
   <contact>
      <salutation>Mr</salutation>
      <first>Sydney</first>
      <last>James</last>
      <email>sydneyjames.com</email>
   </contact>;
node=account.contacts.create(contact);
典型地用三个阶段创建节点:首先动作创建context变量,然后使得显示模板。
function init(){
   $context.contact=<contact><salutation/><first/><last/><email/></contact>;
   return[″editContact.tmpl″];
}
接着,模板将输入控制绑定到各个context元素。
<input type=″text″netui:bind=″$context.email″/>
接着,模板调用第二动作;框架在调用动作之前自动将HTML输入值变换回context变量。动作然后创建新节点。
function create(){
   $context.contact=$account.contacts.create($context.contact);
   return[″showContact.tmpl″];
}
在上面的例子中,动作用create()函数构建的节点取代当前context变量($context.contact);这允许下一模板(showContact.tmpl)引用创建的节点。要注意,在调用create()函数之前,$context.contact只包含合式的XML元素;然后,它指向确认的节点(例如,支持各个节点函数的节点)。
在一个实施例中,定义insert管道操作的keyref允许创建节点,并且尝试在无效节点集上创建节点将引起运行时错误。
回叫
create()函数也可以指定回叫函数,在同步机制接收到来自服务器的关于节点已被创建的应答(即,相关管道操作成功返回新主关键字)时调用回叫函数。例如:
function foo(account,quote){
   node=account.requests.create(quote,bar);
}
function bar(request){
   $context.lastRequest=request;
}
回叫函数可以被传递作为参数的所创建节点。
更新节点
update()函数可以用于同步在客户端上修改的节点。
node.update([callback,id]);
在支持更新管道操作的keyref上调用函数。
  参数   类型   描述
  callback   函数   可选的callback函数指定同步机制在接收到来自服务器的应答时调用的函数名。
  id   值   可选的id参数被传递到callback函数中来标识调用上下文。
可以使用常规XScript表达式修改节点。对于创建的节点,同步作为后台进程运行。然而,除非调用update()函数,否则修改的节点不会被标记同步。
update()函数可以将相关节点的syncState属性设置为MODIFIED(修改后的)。该机制可以允许在节点被同步之前对单个节点进行多次编辑。
例子
在下面的代码中,头两个表达式可以将$contact节点的syncState设置为DSYNC;而后一个表达式可以将syncState设置为MODIFIED。
contact.first=″Bob″;
contact.address=<address><zip>10017</zip></address>;
$contact.update();
回叫
update()函数也可以指定回叫函数,在同步机制接收到来自服务器的关于节点已被更新的应答(即,相关管道操作成功)时调用回叫函数。例如:
function foo(account,quote){
   quote.update(bar);
}
function bar(request){
   $context.lastRequest=request;
}
回叫函数可以被传递作为参数的所创建节点。
冲突管理
在一个实施例中,当客户端试图修改和同步已经被更新(由另一客户端或其他外部改变进程)的“失效”节点时,发生节点冲突。失效节点是具有与服务器保存的当前序列号不同的序列号的节点。
如果服务器由于节点失效而拒绝更新,则它返回最新节点,同步状态属性设置为“conflict”。
更新操作可以设置回叫,当从服务器返回节点时(不管是否有冲突)调用回叫。如果没有设置回叫,则客户端框架自动用服务器返回的最新节点替代客户端的失效节点。
呼叫函数应当首先使用syncState()系统函数测试冲突状态。它必须设置应用的全局变量(即,$session),例如,
function updateCallback(node){
   if(node.syncState()==CONFLICT){
     $session.message=″<a href=′showConflict()′>edit conflicts</a>″;
     $session.conflict=node;
   }
}
为了通知用户发生了冲突,每个模板可以包括状态区域,该区域引用该全局变量,例如,
<netui:html>{$session.message}</netui:html>
这里,全局变量包含HTML锚,其允许用户导航到用来显示冲突编辑器页面的动作:
function showConflict(){
   $context.node=$session.conflict;
   return[″showConflict.tmpl″];
}
下面showConflict模板并排显示失效节点和最新节点的值。
Spath表达式调用对数据节点定义的conflict()函数;这返回最新节点。注意,尽管冲突节点可能包含外关键字值,但运算符不能从冲突节点遍历。
<p>Contact record conflicted with server.</p>
<form netui:action=″$pageFlow.updateConflict()″>
   <table><tbody>
      <tr>
          <td>First</td>
          <td>{$context.node.conflict().first}</td>
          <td><input type=″text″netui:bind=″$context.node.first″/></td>
      </tr>
      <tr>
          <td>Last</td>
          <td>($context.node.conflict().last}</td>
          td><input type=″text″netui:bind=″$context.node.last″/></rd>
      </tr>
      <tr>
          <td>Email</td>
          <td>{$context.node.conflict().email}</td>
          <td><input type=″text″netui:bind=″$context.node.email″/></rd>
      </tr>
      <tr colspan=″3″>
          <td><input type=″submit″value=″Create″/></td>
      </tr>
   </tbody></table>
</torm>
<a href=″copyValues($context.node)″>Copy server′s record.</a>
如果按下提交按钮,则窗体调用下面的updateConflict()动作:
function updateConflict(){
   $context.node.update();
   $status.message=null;
   $status.conflict=null;
   return[″BACK″];
}
这调用当前节点上的update()函数,其触发同步机制来再次尝试。这里,控制器立即返回到在用户点击状态区域之前显示的前一页面。
上面模板还定义在点击时调用下面copyValues()动作的锚:
function copyValues(node){
   node.copy(node.conflict());
   return[″CONTINUE″];
}
该动作将最新节点值复制到失效节点中,并且返回到showConflict页面。
链接和解除链接节点
在一个实施例中,使用link()函数来将节点(或节点列表)添加到表示一对多关系的keyref。
node.keyref.link(nodeList);
要注意,nodeList参数必须引用已经创建的节点。
使用unlink()函数来从表示一对多关系的keyref中移除节点(或节点列表)。
node.keyref.unlink(nodeList);
例子,下面的函数从current(contact)节点的相关keyref中移除所有“Web”帐户。然后它链接传递进函数的单个newAccount节点。
function foo(newAccount){
   contact=$current.accounts.*.where(.type==″Web″);
   current.accounts.unlink($contact);
   contact.account.link(newAccount);
}
错误处理
当管道操作失败时,服务器可以生成错误对象并将其返回到客户端。
该错误对象被返回到应用的回叫函数;该对象具有对应于上述模式的特性。
错误对象被返回到应用的回叫函数;该对象具有对应于上述模式的特性。
function updateNode(node){
   node.update(updateCallback,<token/>)
}
function updateCallback(id,error){
   var msg=error.message;
   var node=error.node();
   var fields=error.field.*;
}
该错误对象还可以实现field()函数,该函数用于访问各个错误字段,例如,
var msg=error.field(spath).message;
自定义对象
模板和动作都不能直接存取外部资源(例如,Web服务)。相反,外部进程被模型化为由MAS框架同步的数据对象。
多数管道操作可以映射到节点实体上的CRUD操作(即,选择、创建、更新等),这些操作直接对应于客户端编程模型函数(导航、创建、更新等)。然而,典型地,不可能将所有Web服务操作映射到框架的标准操作上。例如,Web服务操作可能需要从多个节点元素构成或者包含用户输入的临时值的参数集。在这些情况下,应用定义包含Web服务操作的输入和输出参数的自定义节点类型。这种机制称为自定义草走。create()函数可以用来与创建普通节点相同的方式创建新的自定义对象。
var resultNodes=customNode.keyref-B.*;
自定义操作典型地不实现相应keyref的插入管道操作。相反,自定义对象被用作触发选择管道操作的随后遍历的上下文。例如,
var resultNodes=customNode.keyref-B.*;
下面的图示出keyref声明:
Figure G05801602820060622D001001
例子
下面的例子假设具有下面原型的Web服务操作:
xsd:double submitQuote(xsd:string prodId,xsd:integer qty);
操作采用prodId和qty输入参数,并且返回price值。
这需要包含prodId和qty参数以及price响应字段的节点类型的自定义XML模式定义。
与普通节点一样创建自定义节点。例如,下面的XML表示合式的quoteRequest元素。
<quoteRequest><prodId/><qty>0</qty></quoteRequest>
典型地,调用动作通过赋值包含缺省值的合式XML对象来创建context变量。下面的例子创建quoteRequest元素并且使控制器导航到inputRequest模板。
function initiateRequest(){
   $context.request=<quoteRequest><prodId/><qty>0</qty></quoteRequest>;
   return[″inputRequest.tmpl″];
}
模板将<input>元素绑定到各个字段值。
<table><tbody>
   <tr>
       <td>Product ID</td>
       <td><input netui:bind=″$context.quoteRequest.prodId″/></td>
   </tr>
   <tr>
       <td>Quantity</td>
       <td><input netui:bind=″$context.quoteRequest.qty″/></td>
   </tr>
   <tr>
       <td colspan=″2″>
          <input type=″submit″value=″Submit″
onClick=″submitQuoteRequest()″/>
       </td>
   </tr>
</tbody></table>
模板具有提交按钮,其调用submitRequest动作来从合式的quoteRequest元素创建节点。
function submitQuoteRequest(){
   $current.quotes.create($context.request);
   return[″showRequests.tmpl″];
}
create()函数立即返回标记为新创建的节点以便同步。与创建普通节点一样,同步作为后台进程进行。因此,动作使导航器显示当前quote request集。
showRequests模板引用模板的输入和输出值。要注意,新创建的请求的response.price元素将最初返回空值。
<netui:repeater id=″$quotes″source=″$current.quotes.*″iterator=″$i″>
   <tr>
       <td>($i.prodId}</td>
       <td>{$i.qty}</td>
       <td>{$i.response.price}</td>
   </tr>
</netui:repeater>
Widget-Z 1000
有时同步机制可以将创建的节点发送给服务器,后者将调用相关自定义操作。如果成功,则创建<response>元素并且将节点同步回服务器。
<quoteRequest>
   <prodId>Widget-Z</prodId>
   <qty>1000</qty>
   <response>
       <price>2000.00</price>
   </response>
</quoteRequest>
如果showRequests模板仍然可见,则客户端框架使得再次提出模板,这将更新相应表行。
  Widget-Z   1000   2000.00
选择节点
可以在任何keyref上调用select()函数并且不立即返回值。该函数不能在模板内调用。
node.keyref.select(spath,[callback,id]);
也可以在根节点上调用select()函数:
$root.select(spath,[callback,id]);
该机制允许客户端请求由SPath表达式描述的虚拟XML文档的部分的同步。
例如,下面表达式请求当前高速缓存内的所有帐户的所有联系人。
$root.accounts.*.select(contacts.*);
下面表达式请求从根节点可访问的所有帐户的所有联系人。
$root.select(accounts.*.contacts.*);
在一个实施例中,SPath表达式不引用局部函数,并且,表达式不引用无法被解析成非纯量值的局部变量。表达式被传递给服务器,后者将表达式转换成相应XPath表达式。
用谓词选择
某些keyref可能较大而难以完全同步到客户端。在这些情况下,客户端能够使用where()函数过滤keyref。
例如,下面的选择表达式使得只同步匹配where()谓词的帐户节点。
$root.select(acounts.*.where(.type==″Web″));
下面表达式选择匹配上述帐户的所有联系人。
$root.select(acounts.*.where(.type==″Web″)).contacts.*;
下面表达式选择(所有帐户的)具有匹配的电子邮件地址的所有联系人。
$root.select(accounts.*.contact.*.where(.email==″bobacme.com″));
谓词选择机制也可以用于允许用户预选择将要同步的节点。例如,我们可以将选中的Boolean属性添加到帐户节点类型并且将其绑定到模板内的复选框元素。
<netui:repeater id=″S1″source=″$root.accounts.*″iterator=″i″>
   <tr>
       <td><input type=″checkbox″netui:bind=″i.checked″></a></td>
       <td>{i}</td>
   </tr>
</netui:repeater>
下面表达式(包含在模板调用的动作内)将使得同步机制对所有选中的帐户检索所有联系人。
$root.select(acounts.*.where(.checked==true).contacts.*);
回叫
回叫机制允许调用者指定在SPath的整个同步完成时要调用的函数。例如:
$root.select(accounts.*.contacts.*,$id,callbackFn);
这个例子向服务器发送同步脚本来检索所有帐户的所有联系人,并且将函数callbackFn登记为客户端框架在同步完成时调用的回叫。$id变量被送到函数中以便表示特定的选择调用。
例子
例如,本机制的一个应用可以是让特定应用的所有模板包含每个页面的底部处的“状态条”元素,其绑定到临时数据值(例如,$session.message)。
<p>Status:<span>{$session.message}</span></p>
可以从用回叫启动选择的一个模板调用动作。
q1=″Q1″;
function beginSearch(email){
   $root.select(accounts.*.contact.*.where(.email==email),q1,
onUpdate};
}
在这种情况下,beginSearch()函数采用表示联系人电子邮件地址的参数,并且选择(所有帐户的)具有匹配电子邮件地址元素的所有联系人。
用户定义的回叫函数onUpdate()在同步请求完成时被调用。
function onUpdate(id){
   if(id==q1){
     $session.message=+″Received results.″;
   }
}
该函数将id输入变量与传递进上述select()函数的请求常数匹配;然后它改变$session.message变量,使得任何绑定到该变量的模板被刷新。
同步
通常,同步可以在后台运行。在一个实施例中,用户对同步有影响的唯一控制是当选择操作完成时登记回叫。
然而,当创建或修改节点时,有时需要确保将一组操作作为逻辑上完整的单元来执行。要注意,这比起要求完全交互语义来是较低的限制。
例如,下面的函数改变联系人的名和姓,以及引用该帐户节点的外关键字。
function foo(contact,account){
   contact.first=$context.first;
   contact.last=$context.last;
   contact.accountId=account;
}
在一个实施例中,当创建或修改节点时,它们自己的同步状态设为DSYNC(延迟同步)。然而,直到控制器调用的原始动作没有错误地返回,才安排它们同步。这时所有标为DSYNC的节点被改为MODIFIED。
动作可以调用后继动作,在这种情况下,最外面的动作形成该隐式转换的范围。
客户端框架实现(每个应用)单线程的动作模型。这包括由输入的同步消息调用的动作和由框架进行的同步消息的处理。因此,可以在动作内操作到“乱码”(clobber)数据的输入同步更新。
在一些情况下,高速缓存将被调用一系列模板的页面流(例如,“向导”)更新。在这些情况下,为了将同步延迟直到整个页面流成功完成为止,应用必须创建或将复制相关数据到上下文变量中。然后最终页面流动作更新高速缓存。
用户延迟的同步
有时,用户将希望延迟明显的同步,直到准备好提交记录为止(例如,通过按下提交按钮)。
例如,下面的模板显示(帐户的)订购单列表以及每个项目的复选框。复选框被绑定到用于确定项目状态的属性。
<netui:repeater id=″s1″source=″$account.purchaseOrders.*″iterator=″i″>
   <tr>
       <td><input type=″checkbox″netui:bind=″i.complete″></a></td>
       <td>{i}</td>
   </tr>
</netui:repeater>
<input type=″submit″onClick=″$pageFlow.submit()″/>
提交按钮调用submit()动作,后者对所有被设置为完成的订购单调用update()。
funciton submit(){
   for(i=0;i<$accounts.purchaseOrders.*.length();i++){
      var po=$account.purchaseOrders.*[i];
      if(po.syncState()==″DSYNC″&&po.complete==true){
        $po.update();
      }
   }
}
这个例子需要外部系统解释complete属性的含义;即,延迟处理记录(同时管理持久性),直到用户设置了适当的值为止。
模板
模板可以是构成应用的用户接口的合式(并且有效)的XHTML页面。模板典型地引用高速缓存中的数据,它们也可以导致调用动作。在一个实施例中,模板不包含可直接修改数据图的脚本表达式。
模板可以引用用作光标的$current系统变量;$current引用单个节点或节点列表。在一个实施例中,$current的值只能由调用系统函数的动作和锚改变,这称为导航。
模板还包含重复器,其在指定部分数据或数据模型上迭代。重复器允许模板自动建立复杂的列表和表格,并且允许用户能够选择各个记录并对它们调用动作或导航。
系统变量$context可以提供一种动作和模板交换临时变量的机制。例如,模板可以将输入字段绑定到上下文变量或数据节点元素。当模板调用动作时,页面的输入值被自动同步回到绑定的变量。
模板可以通过定义HTML<a>锚来生成事件,当用户电极它们时触发。在一个实施例中,锚具有三种不同的用途:
1)导航
锚可以指定SPath表达式(例如,$current.orders.*),这导致控制器改变$current变量指向不同的节点或节点集,这称为导航。系统可以提供可将特定模板与一定节点类型和keyref相关联的元数据,允许浏览器自动选择适当的模板。
2)调用系统函数
框架可以实现各种修改应用的行为的系统函数。例如,navigate()函数导航到特定模板并且设置$current变量;select()函数(在重复器内调用)用于从列表或表格中选择特定节点。
3)调用动作
4)动作可以处理绑定到在前模板的上下文变量并且执行计算或修改数据。然后动作可以直接返回到当前页面,在这种情况下,更新任何数据绑定式控制并且刷新显示。动作也可以使控制器改变$current和$page变量,导致发生导航。
同步可以在后台进行。客户端创建和修改的节点经过各种同步状态,这些状态对于模板也是可以通过系统函数访问的,并且可以显示给用户。此外来自服务器的同步更新使绑定到相关节点的模板立即更新。
表达式估值
在一个实施例中,模板可以通过引用花括号内的SPath表达式将来自高速缓存的数据直接并入页面。估值的表达式的结果作为常规XHTML对待。
例如,下面的表达式显示当前节点的标签。
<p>{$current.label()}</p>
在一个实施例中,在每次刷新页面时估值花括号内包含的表达式。当从动作控制传回控制时刷新页面。因此,花括号内包含的表达式可以用于定义XHTML标志的动态值。
例如,下面的表达式估值变量$context.address的内容并且将结果放入锚标志的href属性中:
<a href=″{$context.address}″>Click</a>
动作可以改变该上下文变量的值:
$context.address=″mailto:alchemybea.com″;
这将导致当控制传回到页面时生成下面的XHTML表达式:
<a href=″mailto:alchemybea.com″>Click</a>
系统变量
这部分详细说明在一个实施例中历史栈上维持的三个系统变量($current,$context,和$page)。
$current
$current变量引用节点列表(一个或多个节点)。这可以是对节点或节点集的显式引用,或者是产生节点列表的估值SPath表达式。
设计模板来处理单个节点或节点列表。$current[0]保证指向单个节点。此外,$current.length()表达式可以用来检测节点列表中的节点数。
例如,CRM应用可以实现accountDetail.tmpl页面,期望$current指向单个帐户节点。
<html>
<head>
  <meta current=″node″/>
  <title>Account Detail</title>
</head>
<body>
<p>Account:{$current}</p>
<a href=″$pageFlow.navigate($current.contacts.*,
′contacts.tmpl′)″>Contacts</a>
</body>
</html>
相反,contacts.tmpl页面期望$current包含所有帐户的整个联系人集合。
<html>
<head>
  <meta current=″nodelist″/>
  <title>Contacts</title>
</head>
<body>
<table><tbody><tr>
<netui:repeater id=″$contacts″source=″$current″iterator=″$i″focused=″true″>
   <td>first</td><td>{$i.first}</td>
   <td>last</td><td>{$i.last}</td>
   <td>email</td><td>{$i.email}</td>
   <td><a href=″$s.previous()″>Previous</a></td><td><a
href=″$s.next()″>Next</a></td>
</netui:repeater>
</tr></tbody></table>
</body>
</html>
这里,重复器允许用户在联系人节点的集合中循环。
$context
上下文变量为模板和动作提供“便笺”来协调多页面进程;它们在概念上与会话变量相似。
上下文变量是通过在动作内执行的赋值操作创建的。
$context.foo=100;
$context.foo.bar=<bar>FooBar</bar>
模板使用表达式语言句法引用上下文变量。
<p>{$context.foo}</p>
<p>{$context.foo.bar}</p>
动作可以在$context对象上调用reset()函数来移除所有当前上下文变量。
$context.reset();
$page
$page变量包含当前提供的模板。动作使用它来访问当前提供的页面内的HTML控制的状态。
XHTML标志扩展
这部分详细说明客户端框架支持的XHTML的扩展。
在一个实施例中,模板必须包含合式和有效的XHTML。这部分中描述的XHTML扩展定义在netui名字空间中;所有例子需要下面的名字空间声明。
<html xmlns=″http://www.w3.org/1999/xhtml″
xmlns:netui=″http://www.bea.com/netui″>
锚标志
<a>(锚)标志创建超链接,用户可以点击该超链接来使事件触发。锚用于导航、调用系统函数(包括选择项目)以及调用动作。
锚可以指定SPath表达式(例如,$current.orders.*),其导致控制器改变$current变量的值来指向不同节点或节点集,这称为导航。
锚可以调用各种系统函数之一。例如,navigate()函数导航到特定模板并且设置$current变量,在重复器内调用的select()函数用于从列表或表格中选择特定节点。
锚可以调用动作,该动作可以处理绑定到模板的上下文变量来执行计算或修改数据。然后动作可以直接返回到当前页面,在这种情况下,更新任何数据绑定式控制并且无缝地刷新显示。动作也可以使控制器改变$current和$page变量,导致发生导航。
<a href=″url″/>
锚可以使用下面的属性。
  属性   类型  描述
  href   url  当用户点击锚时调用的SPath表达式、系统函数或动作名
url属性可以具有下面的格式:
  类型   格式   描述
  导航   spath-expr,或$pageFlow.navigate(spath-expr,template)   使用必须对节点或节点列表估值的表达式来对引起导航的$current设置值。
  选择   $repeater.function(...)   调用所标识的重复器控制上的系统函数。
  函数   $pageFlow.function(...)   调用系统函数
  动作   $pageFlow.actionName(...)   调用在控制器中定义的用户定义的动作。
锚典型地用于导航到不同的页面或者选择数据。
导航
可以通过各种方式实现导航;下面的例子都使浏览器导航到根节点。
<a href=″$root″>Example 1</a>
<a href=″$pageFlow.navigate($root,′bar.tmpl′)″>Example 2</a>
<a href=″$pageFlow.foo($root,′bar.tmpl′)″>Example 3</a>
function foo($s,$p){
   return[$s,$p];
}
<a href=″$globalApp.history.home()″>Example 4</a>
例1声明SPath表达式,该表达式由控制器直接估值并且用于设置$current的值。
例2调用系统navigate()函数,该函数将$current设为估值的SPath表达式,并且使用可选的第二参数来设置模板。
例3调用(控制器文件中定义的)用户动作,该动作使用送入的参数来创建前向对象(数组);这与例2效果相同。
例4调用home()系统函数,该函数是在$history对象上调用的。
选择
下面的例子显示列出订单集和通过点击来“选择”它们中的一个作为“所选”订单。
<netui:repeater id=″foo″source=″$current.orders.*″iterator=″$thisorder″>
   <a href=″$foo.select($thisorder)″>{$thisorder.label()}</a>
</netui:repeater>
下面例子一次显示一个订单,并且让用户在它们之间前后移动。
<netui:repeater id=″foo″source=″$current.orders.*″iterator=″$thisorder″
focused=″true″>
   <tr>
       <td>OrderID:</td><td>{$thisorder.id}</td>
       <td>OrderDate:</td><td>{$tbisorder.date}</td>
       <td>OrderAmount:</td><td>{$thisorder.amcunt}</td>
   </tr>
   <tr>
       <td><a href=″$foo.previous()″>Previous</a></td>
       <td><a href=″$foo.next()″>Next</a></td>
   </tr>
</netui:repeater>
窗体
在一个实施例中,为了显示数据,所有需要的是包含在花括号中的SPath。
例如,如果$current指向联系人,则下面将显示联系人的名字和地址:
<tr>
   <td>First:</td><td>{$current.name.first}</td>
   <td>Last:</td><td>{$current.name.last}</td>
</tr>
但这是只读模型。
在一个实施例中,为了写变量,除了将用户输入映射到数据模型的netui:bind属性,还支持HTML窗体元素。
  绑定   提交数据   不提交数据
  绑定到高速缓存   随同提交创建窗体,窗体动作指定提交数据动作。   随同提交创建窗体,窗体动作不指定提交数据动作。
  不绑定到高速缓存   无法进行,必须改变节点来提交它们   使用提交/绑定到高速缓存的情况,除了不点击提交按钮外
支持下面的HTML窗体元素来绑定读/写变量。
  HTML标志   描述
  <form>   装入窗体元素并指定动作。
  <input>   通用的输入标志,用于基于type属性值实现各种简单控制。
  <textarea>   允许用户输入多行文本。
  <select>   允许用户从组合列表中选择。
这些标志的每一个都支持netui:bind属性,该属性使用SPath表达式引用读/写变量。
<input type=″intputType″netui:bind=″SPath″/>
SPath表达式典型地应用$context变量。例如:
<input type=″text″netui:bind=″$context.address.name″/>
该变量用于在提供页面时设置输入字段的值。
当调用提交动作(包括通过下面的<input type=″submit″>标志)时或者当导航发生(见上面的锚)时,绑定值被写回到该变量。
输入标志
<input>标志是通用的输入标志,用于基于其type属性值实现各种简单控制。
<input type=″inputType″netui:bind=″spath-expr″/>
框架将netui:bind属性添加到XHTML中支持的标准属性。
支持下面类型的<input>标志。
  输入类型   变量类型  描述
  text   串  允许用户输入/编辑一行文本。
  radio   Boolean  允许用户从选择列表中选择单个值。通过共同的公用的netui:bind变量将radio输入连在一起。
  checkbox   Boolean  允许用户复选一个框来将复选框“值”加到绑定变量。
  password   串  允许用户输入串,显示一系列“*”内容,而不是实际的串内容。
  hidden   串  允许绑定隐藏值。
  readonly   串  允许绑定只读值。
  image   坐标  触发窗体提交并且可以可选地绑定点击图像的坐标来绑定变量。
  button   n/a  创建不触发窗体提交的按钮。
  submit   n/a  创建提交按钮。
  reset   n/a  将输入元素的值重置到初始值。
下面的例子示出各种形式的<input>标志。
<input type=″text″netui:bind=″$context.contact.email″/>
<input type=″radio″netui:bind=″$context.contact.selected″value=″yes″/>
<input type=″radio″netui:bind=″$context.contact.selected″value=″no″/>
<input type=″checkbox″value=″chinese″
netui:bind=″$context.contact.langsSpoken″/>
<input type=″password″netui:bind=″$context.login.password″/>
<input type=″hidden″netui:bind=″$context.contact.MailingCountry″
value=″USA″/>
<input type=″button″value=″press this button″/>
radio
radio标志可以被分组从而可以只选择一个值;同一逻辑组中的每个radio标志必须绑定到相同的SPath表达式。
<p>Selected:
<input type=″radio″netui:bind=″$context.contact.selected″
value=″yes″>Yes</input>
<input type=″radio″netui:bind=″$context.contact.selected″
value=″no″>No</input>
</p>
当前选择的控制将value属性所指定的值绑定到SPath表达式。如果没有指定value属性,则设置布尔值true。
提交
提交类型定义onClick属性,其与锚的方式相同(见上面)。
<input type=″submit″onClick=″$pageFlow.submitContact()″/>
当点击时,这导致用当前输入标志值写(页面上的)所有绑定变量。
TextArea标志
<textarea>标志允许用户输入和编辑多行文本,可以包括显示滚动条。
<textarea netui:bind=″spath-expr″/>
框架将netui:bind属性添加到XHTML中支持的标准属性。
例如,下面的XHTML元素创建<textarea>元素,其绑定到$context变量所引用的note节点的comments子元素。
<textarea netui:bind=″$current.note.comments″/>
select标志
<select>标志允许用户从下降(dropdown)控制中选择多个应用定义的值之一。
<select netui:bind=″spath-expr″/>
框架将netui:bind属性添加到XHTML中支持的标准属性。
contactType模式定义包含salutation元素,它定义有contactSalutationEnum类型。
<xsd:complexType name=″contactType″>
   <xsd:sequence>
       <xsd:element name=″salutation″type=″contactSalutationEnum″/>
       <xsd:element name=″first″type=″xsd:string″/>
       <xsd:element name=″last″type=″xsd:string″/>
       <xsd:element name=″email″type=″xsd:string″/>
   </xsd:sequence>
</xsd:complexType>
<xsd:simpleType name=″contactSalutationEnum″>
   <xsd:restriction base=″xsd:string″>
       <xsd:enumeration value=″Mr″/>
       <xsd:enumeration value=″Mrs″/>
       <xsd:enumeration value=″Ms″/>
       <xsd:enumeration value=″Dr″/>
   </xsd:restriction>
</xsd:simpleType>
下面的XHTML用于创建<select>元素。
<select netui:bind=″$context.contact.salutation″>
可以显式地声明选项值:
<select netui:bind=″$context.contact.salutation″>
   <option value=″Mr″>Mr</option>
   <option value=″Ms″>Ms</option>
   <option value=″Mrs″>Mrs</option>
   <option value=″Dr″>Dr</option>
</select>
或者,可以使用重复器创建选项值:
<select netui:bind=″$context.contact.salutation″iterator=″i″>
   <netui:repeater source=″$globalApp.schema(′contactSalutationEnum′)″>
   <option value=″{$i.value}″>{$i.value}</option>
   </netui:repeater>
</select>
要注意,选择匹配netui:bind表达式的值作为缺省值。如果绑定值为null,则选择第一选项。
例子
下面的例子将email上下文变量绑定到文本输入字段。可以使用窗体的action属性或者嵌套的锚标志调用相应操作。
<form netui:action=″$pageFlow.inputEmailAddress()″>
   <input type=″text″netui:bind=″$context.email″/>
   <input type=″submit″value=″Submit″/>
</form>
典型地,上下文变量首先在前面导致显示模板的动作中被实例化。下面的锚调用addContact()动作:
<a href=″$pageFlow.addContact()″/>Create New Contact</a>
然后动作创建三个上下文变量,然后命令控制器显示addContact模板。动作首先重置所有的已有上下文变量,然后使用赋值运算符创建新变量。
function addContact(){
   $context.reset();
   $context.account=$current;
   $context.salutation=″″;
   $context.first=″″;
   $context.last=″″;
   $context.email=″″;
   return[″addContact.tmpl″];
}
addContact模板显示具有绑定输入字段的窗体。
<form netui:action=″$pageFlow.createContact()″>
   <table><tbody>
       <tr>
           <td>Title</td>
           <td>
               <select netui:bind=″$context.salutation″>
                   <option value=″Mr″>Mr</option>
                   <option value=″Ms″>Ms</option>
                   <option value=″Mrs″>Mrs</option>
                   <option value=″Dr″>Dr</option>
               </select>
           </td>
       </tr>
       <tr>
            <td>First</td><td><input type=″text″
netui:bind=″$context.first″/></td>
       </tr>
       <tr>
            <td>Last</td><td><input type=″text″
netui:bind=″$context.last″/></td>
       </tr>
       <tr>
            <td>Email</td><td><input type=″text″
netui:bind=″$context.email″/></td>
       </tr>
       <tr colspan=″2″>
            <td><input type=″submit″value=″Create″/></td>
       </tr>
   </tbody></table>
</form>
当包含绑定变量的模板调用动作时,可以使用当前XHTML窗体值设置变量。在这种情况下,提交的<input>元素调用下面的窗体的createContact动作。
function createContact(){
   $context.acccunt.contacts.create(
       <contact>
           <salutation>{$context.salutation}</salutation>
           <first>{$context.first}</first>
           <last>{$context.last}</last>
           <email>{$context.email}</email>
       </contact>
   );
   return[″showContacts.tmpl″];
}
有条件的标志
可以使用<netui:if>标志来基于计算出的条件有条件地包括XHTML段。
<netui:if cond=″spath-expr″>...</netui:if>
cond属性定义当呈现页面时估值的SPath表达式。如果该表达式估值为true,则<netui:if>元素内包含的XHTML段被插入XHTML页面。
表达式使用标准XScript强制来估值布尔结果。下面的表达式全部估值为true:
{true}
{100}
{″some string″}
{<xml>}
{$root}
下面的例子包括用来实现条件模板的<if>标志。这里,仅当变量为非null(即,空或零长度、文本)时,才显示$current.email表列;所有其他值强制为true。
<table><tbody>
   <tr>
       <td>{$current.salutation}</td>
       <td>{$current.first}</td>
       <td>{$current.last}</td>
<netui:if cond=″$current.email″>
       <td>{$current.email}</td>
</netui:if>
   </tr>
</tbody></table>
要注意,条件模板可以表示为模板设计器中的性质页。
Repeater标志
模板合并来自数据图和系统变量的规则XHTML元素和数据。它们页可以包含当呈现时生成XHTML的元素(与JSP中的Taglibs相似)。
repeater是HTML生成器标志,其在元素列表上重复(例如,帐户的节点列表)。<netui:repeater>是用于重复元素的相同HTML的标志;对在估值的SPath表达式中的每个元素重复<netui:repeater>元素的所有子元素。
句法
<netui:repeater
   id=″tag-id″
   source=″spath-expr″
[iterator=″variable-name″]
[selected=″spath-expr″]
[orderBy=″orderBy-expr″]/>
每个<netui:repeater>元素具有source属性,描述它应当在其上迭代的节点集合。从概念上说,对于source属性描述的每个节点,模板内的所有XHTML被重复。重复的XHTML段可以访问iterator属性引用的迭代的节点实例。
repeater定义下面的属性。
  属性   类型   描述
  id   标识符   唯一定义repeater标志
  repeater   SPath   指定SPath表达式,其得到节点列表(例如,$root.accounts.*)
  iterator   迭代变量   定义包含迭代的节点的变量;该变量只具有所包含的XHTML内的范围
  selected   SPath   包含当前所选的节点;由select()函数设置;当源表达式的值改变时重新设置
  orderBy   串   指定类似XQuery的BNF表达式,确定排序顺序。
可以在repeater对象上调用下面的函数。
  函数  描述
  select($i)  将selected属性设为$i
  position($node)  返回repeater源中的节点的次序位置(或者如果没有找到返回-1)
  length()  返回列表中的项数
重复部分
下面的模板段定义显示由accounts keyref定义的节点列表的repeater。
<ul>
<netui:repeater id=″$repeater1″source=″$current.accounts.*″iterator=″$i″>
   <li>{$i.label()}</li>
</netui:repeater>
</ul>
这产生了下面的输出:
Figure G05801602820060622D001151
对source属性定义的节点列表中的每个节点(即,每个account节点)重复<netui:repeater>元素内包含的所有XHTML元素。
导航和选择
重复的部分可能包含调用动作或系统函数的锚。例如,下面的repeater显示account的列表,显示具有每个account标签的锚(超链接)。
<ul>
<netui:repeater id=″$repeater1″source=″$current.accounts.*″iterator=″$i″>
   <li><a href=″$pageFlow.navigate($i,
′showDetail.tmpl′)″>{$i.label()}</a></li>
</netui:repeater>
</ul>
点击所述锚中的一个导致调用系统导航函数,导致控制器导航到showDetail.tmpl模板,$current设为指到相应重复的元素的$i值所引用的节点。
repeater实现内置函数select(),该函数允许用户从列表中选择特定元素。例如,下面的模板段将上述节点列表表示为HTML锚的列表。
<ul>
<netui:repeater id=″$repeater1″source=″$current.accounts.*″iterator=″$i″>
   <li><a href=″$repeaterl.select($i)″>{$i.label()}</a></li>
</netui:repeater>
</ul>
点击特定锚导致repeater的selected属性被设为$i变量的当前值。面板的其他部分可以引用repeater的当前所选值。
<ul>
<netui:repeater id=″$repeater1″source=″$current.accounts.*″iterator=″$i″>
   <li>
       <a href=″$repeater1.select($i)″
          style=″{$repeater1.selected.contains($i)?″background-
color:yellow″:″″}>
       {$i.label()}</a>
   </li>
</netui:repeater>
</ul>
这产生下面的输出:
  ·Acme·Bancroft·Cyberdine
  Type:Direct
要注意,上面的<a>锚声明style属性,其包含SPath表达式,如果选择相关项,则改变元素的背景颜色。
selected属性可以由其他repeater(称为链式)和随后调用的动作访问。重复的HTML部分也可以引用selected属性来可视地指示当前所选项。
链式repeater
repeater可以链接在一起,从而对父repeater中的元素的选择影响子repeater中的显示。例如,下面的repeater显示与前面repeater中所选节点(Contact)相关联的消息列表。
<ul>
<netui:repeater id=″$repeater1″source=″$current.accounts.*″iterator=″$i″>
   <li><a href=″$repeater1.selecr($i)″>{$i.label()}</a></li>
</netui:repeater>
</ul>
<br/>
<ul>
<netui:repeater id=″$repeater2″source=″$repeater1.selected.contacts.*″
iterator=″$j″>
   <li>$j.label()</li>
</netui:repeater>
</ul>
下面的模板示出嵌套的repeater,创建多列的显示(在下面示出)。
<table><tbody>
   <tr>
       <td>App</td><td>Repeater 1</td><td>Repeater 2</td><td>Contacts</td>
   </tr>
   <tr>
       <td>{$current}</td>
       <td><ul>
           <netui:repeater id=″$x″source=″$current.keyref(′*′)″
iterator=″$i″>
               <li><a href=″$x.select($i)″>{$i}</a></li>
            </netui:repeater>
        </ul></td>
        <td><ul>
            <netui:repeater id=″$y″source=″$x.selected.*″iterator=″$j″>
                <li><a href=″$y.select($j)″>{$j}</a></li>
            </netui:repeater>
        </ul></td>
        <td><ul>
            <netui:repeater source=″$y.selected.contacts.*″iterator=″$k″>
                <li>{$k}</li>
            </netui:repeater>
        </ul></td>
     </tr>
  </tbody></table>
第一repeater生成keyref锚的列表;第二repeater将其source变量绑定到前一repeater的所选节点,并且产生节点锚的列表。最后的repeater产生contact节点的列表。要注意,该repeater的source属性专门遍历到contacts keyref-跳过了自动keyref列。
当调用repeater的select()函数时,它自动地触发模板重新显示—修改相关repeater的source,并且将相关repeater的所选变量设为null。模板必须避免repeater之间的循环依存关系。由于模板的当前光标没有改变,因此不认为选择机制是导航。
上面的例子导致下面的显示:
 App   Repeater1   Repeater2   Contacts
  ■root   ■accounts   ■Acme■Bancroft■Cyberdine   ■Sarah Smith■David Davies
上述模板表示UI的导航部分—允许最终用户遍历一系列keyref。
我们还可以修改UI来表示节点的表。例如:
<td>
    <table><tbody>
       <netui:repeater source=″$y.contacts.*″iterator=″$k″>
           <tr>
               <td>{$k.email}</td>
               <td>{$k.label()}</td>
           </tr>
       </netui:repeater>
    </tbody></table>
</td>
这产生下面的输出:
Figure G05801602820060622D001171
聚焦的repeater
repeater也可以被定义为“聚焦”,意味着repeater在一个时刻仅显示一个元素并且保持光标,而不是在source属性定义的整个元素集合上迭代。
可以在聚焦的repeater对象上调用下面的额外函数。
  函数   描述
  next()   如果聚焦,则移动到下一项
  previous()   如果聚焦,则移动到前一项
  begin()   如果聚焦,则移动到第一项
  end()   如果聚焦,则移动到最后一项
  position()   返回节点集内的索引位置
在下面的例子中,focus属性声明要显示的节点集中的单个节点。下面的动作调用包含聚焦的repeater的模板并且将$current设为与指定帐户的contactkeyref有关的节点列表:
function selectContacts($account){
   $context.cursor=$account.*[0];
   return[$account.*,″focusedContacts.tmpl″];
}
锚调用repeater上的函数,该函数移动repeater的光标。
<netui:repeater id=″$s″source=″$current″iterator=″$i″>
   <netui:if cond=″$s.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:if cond=″$s.position($context.cursor)>0″>
   <a href=″$context.cursor=$current[$s.position($context.cursor}-
1]″>previous</a>
</netui:if>
<netui:if cond=″$s.position($context.cursor)<($s.length()-1)″>
   <a href=″$context.cursor=
$current[$s.position($context.cursor)+1]″>next</a>
</netui:if>
这产生下面的输出:
Figure G05801602820060622D001181
默认地,聚焦的repeater设置光标指向$current节点列表中的第一节点。如果定义了selected属性,则使用它来将光标涉到适当的节点(通常由通过前一动作设置的上下文变量定义)。
<netui:repeater id=″$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>
排序的repeater
repeater可以通过声明orderBy属性来指定枚举元素的顺序。orderBy属性是包含类似XQuery的表达式的串:
<netui:repeater id=″id″source=″source″iterator=″var″
orderby=″OrderByClause″>
其中OrderByClause遵从下面的BNF语法(SPath表达式表示特定repeater项的字段值):
OrderByClause::=OrderSpec(″,″OrderSpec)*
OrderSpec    ::=SPath OrderModifier
OrderModifier::=(″ascending″|″descending″)?
                      ((″empty″″greatest″)|(″empty″″least″))?
                           (″collation″StringLiteral)?
要注意,表达式假设稳定顺序(即,应当在多个调用上预留相等值的顺序)。
例如,下面的repeater通过contact的姓(即,$i.last)的降序值列出contact。
<netui:repeater id=″$s″source=″$current.contacts.*″iterator=″$i″
   orderby=″$i.last descending″>
   <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:repeater id=″$s″source=″$current.contacts.*″iterator=″$i″
   orderBy=″$i.last empty least,$i.first descending″>
要注意,在上面的例子中,空的姓值被认为是最低的。
元数据Repeater
repeater也可以用于在数据模型定义的元数据上重复。
例如,node.keyref(′*′)函数返回keyref元素的列表,该元素描述从相应节点类型可能的导航。这可以用作repeater用来显示keyref列表的source。
<ul>
<netui:repeater id=″$repeaterl″source=″$current.keyref(′*′)″iterator=″$i″>
   <li>{$i.label()}</li>
</netui:repeater>
</ul>
如果$current指向account节点,上面的例子将返回下面的输出:
·owner
·subAccounts
·contacts
·notes
·events
·qutotes
node.schema()函数返回表示相应节点类型的XML模式定义的XML文档。这可以用作repeater用来构建输入窗体的source。
<netui:repeater id=″repeaterl″source=″$current.meta().schema()″
   showNull=″true″iterator=″$i″>
   <tr>
       <td>{$current.meta().schema().getFieldLabel($i)}</td>
       <td>{$i)</td>
   </tr>
</netui:repeater>
上面的例子产生下面的输出:
 salutataion   Ms
 first   Sarah
 last   Smith
 email   sarahacme.com
图像标志
标准XHTML<img>标志用于显示图像。
<img
  [src=″filename″]
  [netui:content=″spath-expr″]
  [netui:type=″content-type″]/>
图像标志定义下面的属性。
  属性   类型   描述
  src   串   文件名
  netui:content   SPath   原始二进制
  netui:type   串   浏览器支持的图像类型(例如,“bmp”,“gif”)
除了标准XHTML属性外,框架支持netui:content和netui:type属性来声明SPath表达式,引用包含图像的二进制源的元素。这要求节点类型之一在其XML模式定义内定义适合的元素。
例如,扩展下面的contact模式来并入<image>数据元素。
<xsd:complexType name=″contactType″>
   <xsd:sequence>
       <xsd:element name=″salutation″type=″contactSalutationEnum″/>
       <xsd:element name=″first″type=″xsd:string″/>
       <xsd:element name=″last″type=″xsd:string″/>
       <xsd:element name=″email″type=″xsd:string″/>
       <xsd:element name=″image″type=″xsd:base64Binary″/>
   </xsd:sequence>
</xsd:complexType>
这将被认为使用下面的XHTML:
<img netui:content=″$current.contact.image″netui:type=″bmp″/>
include标志
标准<netui:include>标志用于插入引用的
<netui:include template=″templateFile″[$current=″spath-expr″]/>
include标志定义template属性,该属性为要插入到当前页面的模板名命名。可选的current属性用于在插入的模板的范围内设置$current变量。
例如,下面的XHTML段扩展链式repeater示例,并且并入新的显示(对特定Acccount,$y)的Contacts列表的repeater($z)。<netui:include>标志包括detail.tmpl模板,并且将其$current变量定义为repeater的所选节点(即,contact节点)。
<td><ul>
    <netui:repeater id=″$z″source=″$y.contacts.*″iterator=″$k″>
        <li><a href=″select($k)″>{$k}</a></li>
    </netui:repeater>
</ul></td>
<td>
    <netui:include current=″$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>
这产生下面的输出。
  App   Repeater 1   Repeater 2   Contacts   Detail
  ■root   ■accounts   ■Acme■Bancroft■Cyberdine   ■SarahSmith■DavidDavies   David DaviesdavidAcme.com
HTML标志
<netui:html>标志用于将原始XHTML插入到当前页面。
<netui:html>{spath-expr}</netui:html>
通常,估值SPath表达式并且结果值被转换为串,而不是处理为HTML。然而,在开和闭<netui:html>标志之间包含的所有估值SPath表达式作为要由浏览器处理的HTML插入到页面中。
例如,给定下面的动作代码:
$current.productDesc=″<p>A<b>great</b>new product.</p>″;
下面的模板HTML将返回下面的输出:
<netui:html>{$current.productDesc}</netui:html>
                          A great new product.
可以在<netui:html>元素内组合HTML和表达式。例如,下面的模板HTML将返回下面的输出:
<netui:html>
   <ul><li>{$current.productDesc}</li><li>{$current.productDetail}</li><ul>
</netui:html>
                        ·A great new product.
                        ·From the people who brought you WebLogic.
控制器
控制可以负责响应于外部同步消息处理用户接口和数据库引起的事件。控制器可以使得执行动作脚本并且浏览器实例化和显示模板。控制器的缺省行为可以通过实现controller.xpf来扩展,后者是用XML的ECMAScript书写,并且本质上是JPF的EMACScript版本。
控制器文件可以包含动作和规则ECMAScript函数和全局变量定义。
页面流
controller.xpf文件可以定义应用的页面流。应用的客户端部分包括控制器定义、动作和面板集。
控制器文件可以包括XScript函数和动作定义。动作由面板(和其他动作)调用,并且可以访问相同的$root、$current和$context变量;它们不能直接修改$current变量—相反,它们返回前向阵列(forward array),其被控制器转换用来确定$current和$page的值。动作能够修改和添加新$context变量,该变量用于向/从页面传递状态。该上下文状态也存储在历史栈上。
每个应用定义控制器文件,后者至少应当包括开始函数(或动作)的定义;当运行应用时调用它。至少,开始函数应当返回包含要显示的第一模板的文件名的前向阵列。
function begin()
{
   return[″home.tmpl″];
}
前向阵列
前向阵列是XScript对象(即,串、变量、SPath表达式)的阵列,被控制器转换用来确定要显示的下一模板(即,$page变量),以及设置$current系统变量的值。
定义了下面的前向对象的类型:
  前向对象  控制器动作
  template-filename  导航到指定的模板;即,设置$page=template-filename
  spath-expression  导航到指定节点或节点集;即,设置$current=spath-expression
  action-name  调用另一niladic动作(动作可以是“链式”)
  CONTINUE  重新显示当前面板
  BACK  回到历史栈中
  FORWARD  前进到历史栈中
前向阵列可以包括任意顺序的前向对象。它不能包括多个SPath表达式、多个模板文件名或者模板文件名和导航串常数(例如,“CONTINUE”)。下面的都是合法的前向阵列。
return[″BACK″]
return[″home.tmpl″];
return[″home.tmpl″,$root.accounts.*];
return[nextAction];
return[];
要注意,什么也不返回或者返回空的前向阵列的动作不修改$page和$current变量;这与返回[“CONTINUE”]是等效的。
在下面的例子中,动作使用上下文变量来执行计算并且在成功的情况下导航到showOrder模板。出错的情况下,动作设置错误上下文变量并且指示控制器来保持在当前模板。
function calulateTotal(){
   if($context.order.qty<=0){
      $context.error=″Error:Quantity not set.″;
      return[″CONTINUE″];
   }
   $context.order.total=$context.order.price*$context.order.qty;
   return[″showorder.tmpl″];
}
动作
动作可以提供用于应用修改数据、修改当前模板或影响导航的机制。例如,动作可以创建或更新数据节点,计算特定节点集上的总数或将浏览器重定向到数据模型的另一部分。由于在一个实施例中,模板只能访问存储在本地数据高速缓存(或$context)中的数据,因此动作提供一种(通过因特网)与外部系统交互的机制。
动作由模板锚调用。动作调用使用与常规ECMAScript函数相同的句法,除了它们作为$pageFlow(控制器)对象上的方法被调用外。
$pageFlow.actionName([param1[,param2[,...]]])
例子
下面的锚声明调用foo()动作,传递进串参数。
<a href=″$pageFlow.foo(′World′)″>Foo</a>
下面示出动作定义(在controller.xpf中定义)。
function foo($p){
   $context.bar=<hello>{$p}</hello>;
   return[″CONTINUE″];
}
在这种情况下,动作设置$context变量(包含输入参数的XML对象)并且返回控制到当前模板。
下面的例子返回前向对象,改变$current变量来指向accounts keyref所包含的节点集处。
function example1($p){
   return[$root.accounts.*];
}
下面的例子改变$current来指向根节点处,并且还改变当前模板。
function example2($p){
   return[$root,″bar.tmpl″];
}
定时器
定时器实现简单的事件机制。addTimer()函数用于登记回叫函数,后者是在经过指定延迟后(或者以一定间隔)调用的。
var timerId=$pageFlow.addTimer(callback,delay[,period]);
在$pagefolow对象上调用该函数,并且返回唯一标识定时器实例的标识符。
  参数   类型   描述
  callback   函数   指定要调用的函数名;callback被传递定时器ID和计数器。
  delay   整数   指定初始延迟(毫秒)。
  period   整数   可选地,指定重复间隔(毫秒)。
cancelTimer()函数用于取消定时器。
$pageFlow.addTimer(timerId);
在$pagefolow对象上调用该函数,并且返回唯一标识定时器实例的标识符。
 参数   类型   描述
 timerId   整数   定时器对象的标识符。
例子
在下面的例子中,函数foo()设置定时器,这立即调度bar()函数,然后以1秒间隔重复。
function foo(){
   var timerId=$pageFlow.addTimer(bar,0,1000);
}
function bar(timerId,count){
   $root.select(accounts.*.contacts.*.tasks.*.where(.priority==1));
   if(count==10){
     $pageFlow.cancelTimer(timerId);
   }
}
这里,回叫函数bar()调用深选择操作,轮询服务器以便更新SPath表达式所定义的数据集。在第10次调用时通过调用cancelTimer()系统函数取消定时器。
浏览器实现单线程的执行模型;因此,至少直到调用函数返回时才执行回叫函数。
历史
每次发生导航时,<$current x $context x $page>元组(tuple)被放到历史栈上,可通过$history系统变量访问。
调用back()系统动作使得这些值被退回到前一历史状态。类似地,forward()将这些值移动到下一历史状态。如果用户向后移动然后引起发生另一导航(即,不是向前移动),则整个前向的历史被截断。
在历史栈中向后和向前移动保留所有repeater的当前所选值;由于$context变量是历史帧的部分,因此也保留了窗体变量。
对$history对象定义的函数如上定义。
页面流例子
图10示出CRM应用1000的一部分的简单页面流;图a)表示数据模型(模式和keyref)的部分;图b)表示页面流,它包括四个模板,每个具有指示$current节点类型的虚线。该情况实现自定义操作来启动对特定帐户的报价请求。这个例子输出创建用作选择操作的上下文的自定义对象(报价请求)的处理。
Home模板包含允许用户导航到调用AccountDetail模板的特定帐户的repeater(见下面)。AccountDetail模板示出前面报价列表,并且允许用户调用createQuoteRequest动作(A)。
<a href=″$pageFlow.createQuoteRequest()″>Create Quote Request</a>
这引起下面的动作被调用。
function createQuoteRequest(){
   $context.quoteRequest.prodId=″″;
   $context.quoteRequest.qty=0;
   return[″createQuoteRequest.html″];
}
该动作在当前上下文内创建<quoteRequest>XML对象,并且设置prodId和qty子元素的值。要注意,这创建合式的<quoteRequest>元素并且与下面表达式等效:
$context.quoteRequest=<quoteRequest><prodId/></qty>0<qty></quoteRequest>;
动作然后返回“templeate”前向路径,调用createQuoteRequest模板而不改变$current变量。下面示出createQuoteRequest模板。要注意,$current仍然指向account节点。
<p>Quote Request for{current.label()}</p>
<table><tbody>
   <tr>
       <td>Product ID</td>
       <td><input netui:bind=″$context.quoteRequest.prodId″/></td>
   </tr>
   <tr>
       <td>Quantity</td>
       <td><input netui:bind=″$context.quoteRequest.qty″/></td>
   </tr>
   <tr>
       <td colspan=″2″>
           <input type=″submit″value=″Submit″
onClick=″submitQuoteRequest()″/>
       </td>
   </tr>
</tbody></table>
Figure G05801602820060622D001251
Figure G05801602820060622D001252
该模板允许用户编辑前面动作创建的<quoteRequest>元素。窗体提交动作将当前的窗体值复制到绑定$context变量,然后调用下面的submitQuoteRequest动作(B)。
function submitQuoteRequest(){
   if($context.quoteRequest.prodId!=″″″||$context.quoteRequest.qty<=0){
      return[″CONTINUE″];
   }
   else{
      $current.quoteRequests.create($context.quoteRequest);
      return[″BACK″];
   }
}
动作执行对<quoteRequest>元素值的验证,并且如果有错误则返回模板(CONTINUE)。否则,它将<quoteRequest>元素添加到当前account的quoteRequests keyref。要注意,$context.quoteRequest变量是包含由窗体绑定的值的合式的<quoteRequest>元素,例如:
<quoteRequest>
   <prodId>Widget-Z</prodId>
   <qty>1000</qty>
</quoteRequest>
一旦成功,动作导航“BACK”到前一AccountDetail模板(BACK)。下面的AccountDetail模板显示同步的priceQuote的列表。
<p>Account:{$current}</p>
<td>Product ID</td><td>Quantity</td><td>Price</td>
<netui:repeater source=″$current.quoteRequests.*″iterator=″i″>
   <td>{$i.prodId}</td>
   <td>{$i.qty}</td>
   <td>{$i.quote.price}</td>
</netui:repeater>
<a href=″$pageFlow.CreateQuoteRequest()}″>Create Quote Request</a>
该模板将产生下面的显示:
Figure G05801602820060622D001261
要注意,上面的submitQuoteRequest动作立即返回,从而新的quoteRequest节点将直到服务器用同步的quote节点响应时才显示价格字段。
构建原型
为了构建并运行圆形,需要安装下面的应用:Apache Ant,Sun java JDK,Perforce客户端,BEA Workshop 8.1。还应当设置下面的环境变量。
 环境变量   典型值   含义
 ANT_HOME   C:\java\apache-ant-1.5.3-1   ant主目录
 BEA_HOME   C:\bea\weblogic81   BEA平台目录
 JAVA_HOME   C:\java\j2sdk1.4.2   Java主目录
 Path   ant、java、perforce的bin路径
该指南假设Perforce客户端已经被安装,并且具有//alchemy/mas到C:\alchemy\mas的映射。使用下面的命令同步最近的源代码并且重建框架。
c:\alchemy\mas>p4 sync
c:\alchemy\mas>ant rebuild
运行应用
可以通过浏览器的ant build文件(\alchemy\mas\src\browser\build.xml)调用原型浏览器。
定义下面的运行时变量:
  运行时变量   含义
  mas.appname   在启动时运行的应用名或“”
  client.geometry   浏览器窗口大小(例如,400x200)
例如,下面的命令调用浏览器,运行具有指定窗口大小的导航器应用。
ant-f..\..\src\browser\bulid.xml-Dmas.appname=crm-Dclient.geonetry=400x200
run
创建批处理文件(例如,run.bat)来调用该命令是很方便的。
还可以通过设置下面的环境变量来配置浏览器:
 环境变量   含义
 MAS_APPNAME   缺省应用名
 MAS_PROPS   应用特性
特性变量可以包括下面的设置:
  特性   缺省值   含义
  mas.appname   无   指定要允许的应用
  mas.approot   无   指定服务器部分的应用目录(仅当mas.singleproc设为false时可用);要注意,客户端和服务器应用目录应当不同。
  mas.client.appname   与mas.appname相同   指定相对服务器应用运行的另一客户端;该操作允许普通客户端的(例如,导航器)转换应用的元数据。
  mas.client.approot   \alchemy\mas\apps   指定客户端的应用目录。
  mas.client.clobber   false   如果为true,则服务器更新本地修改的节点。
  mas.singleproc   true   如果为true,则浏览器和服务器在单
  个JVM中单独运行;这要求应用已经本地部署。
  mas/persistent  false   确定客户端高速缓存是否是永久的。
  mas.serverCache  true   确定是否使用服务器高速缓存。
mas.username 提供用户的登录名。
  mas.password  无   提供用户的密码
例如,下面的命令在客户端模式中运行浏览器并且打开数据持久性。
set MAS_PROPS=-Dmas.singleproc=false-Dpersistent=true
要注意,通过在Windows hosts文件(C:\WINDOWS\SYSTEM32\DRIVERS\ETC\hosts)中声明物理IP地址,可以将服务定义(管道元文件)中定义的Web服务URL映射到物理服务器上,例如,下面的hosts文件声明将上面的Web服务映射到alchemy测试服务器。
172.17.33.34 example.com
调试
所有出错和跟踪信息被写入到\alchemy\mas\alchemy.log文件中。
应用封装
下面的表表示对单独的MAS应用的文件和目录结构。
apps/                                     应用根目录
        appName/                          应用子目录
                 run.bat                  客户端启动脚本
                 schemas/    *.xsd        应用节点类型
                 metadata/   *.xml        管道元和keyref
                 client/                  客户端应用文件
                             control.xpf  页面流文件
                             *.tmpl       模板文件
                 .mas/                    高速缓存文件(客户端/服务器)
                 workshop/                演示的WS项目
原型加载shemas和meta目录中的所有文件。
应用根目录(/apps)对应于mas.approot和mas.client.approot运行时特性(上述)。
部署和管理应用
可以从(Workshop内运行的)MAS将应用部署到客户端。
1.Workshop必须在运行应用管理服务器(见下面)。
2.应用组件(上述控制器模板、元文件和模式文件)必须首先被zip压缩成单个文件(app.zip);为了进行压缩,创建新的zip文件,然后将整个app文件夹(例如,\mas\apps\crm)拖入WinZip中(确定没有选中“save full pathinfo”)。
3.查看应用管理页面:http://www.localhost.com:7001/mas。注意,这可能要花一段时间。
a.点击“Browse...”并选择zip文件;
b.点击“Deploy”将应用上载到服务器(在上面mas.approot特性定义的位置)。
4.管理页面显示每个应用的部署URL。
5.为了在客户端上“install”应用,在单进程模式中运行移动浏览器(不指定mas.app特性);这将调用app选择器对话框。
set MAS_PROPS=-Dmas.singleproc=false
ant-f..\..\src\browser\bulid.xml run
6.输入应用URL到适当的编辑框中并且点击OK。
运行应用管理服务器
1.设置下面的全局环境变量
set JAVA_OPTIONS=-Dmas.approot=c:\alchemy\mas\apps
2.将\alchemy\mas\src\masiws.work加载到workshop中。
3.在project窗格中双击controller.jpf文件。
4.如果提醒库升级,回答yes然后点击Install。忽略红色的“could not bereplaced”警告是安全的。
5.启动服务器(Tools→WebLogic Server→Start WebLogic Server)。
6.在服务器被启动后,运行下面的命令(忽略WebLogic的部署错误是安全的)。
C:\alchemy\mas>ant deploy
7.从Workshop在选择controller.jpf的情况下点击运行按钮(绿三角)。最后(在标准慢服务器引导程序填充之后)你将看到枚举安装的应用及其URL以及用于上载新应用的Deploy按钮的网页。
8.为客户端应用部署创建c:\temp\apps。
9.设置下面的环境变量:
set MAS_PROPS=-Dmas.client.approot=c:\temp\apps-Dmas.singleproc=false
10.运行下面的命令
C:\alchemy\mas\src\browser>ant run
11.将(上面)网页中列出的任何URL粘贴到对话框中并点击Install。最后,该应用将在最顶的组合框中列出,你可以登录。
MAS模式定义
应用模式定义应当使用下面模式指令将公共的MAS模式文件导入:
<xsd:import namespace=″urn:bea.mas″schemaLocation=″mas.xsd″/>
MAS模式文件包含对所有框架XML类型的定义。
<?xml version=″1.0″encoding=″UTF-8″?>
<xsd:schema targetNamespace=″urn:bea.mas″xmlns=″urn:bea.mas″
   xmlns:xsd=″http://www.w3.org/2001/XMLSchema″
   elementFormDefault=″qualified″attributeFormDefault=″unqualified″>
   <xsd:simpleType name=″idType″>
       <xsd:restriction base=″xsd:anySimpleType″/>
   </xsd:simpleType>
   <xsd:complexType name=″nodeSetType″>
       <xsd:sequence>
           <xsd:any minOccurs=″1″maxOccurs=″1″/>
       </xsd:sequence>
       <xsd:attribute name=″keyref″type=″xsd:string″use=″required″/>
   </xsd:complexType>
   <xsd:complexType name=″rootType″/>
   <xsd:element name=″root″type=″rootType″/>
   <xsd:complexType name=″graphType″>
       <xsd:sequence>
           <xsd:element ref=″root″/>
       </xsd:sequence>
   </xsd:complexType>
   <xsd:complexType name=″errorType″>
       <xsd:sequence minOccurs=″0″maxOccurs=″unbounded″>
           <xsd:choice>
               <xsd:element name=″pkey″type=″idType″/>
               <xsd:element name=″system″type=″systemErrorType″/>
               <xsd:element name=″message″type=″xsd:string″/>
               <xsd:element name=″field″type=″fieldErrorType″/>
           </xsd:choice>
       </xsd:sequence>
   </xsd:complexType>
   <xsd:complexType name=″systemErrorType″>
       <xsd:sequence>
           <xsd:element name=″code″type=″xsd:anySimpleType″/>
           <xsd:element name=″message″type=″xsd:string″/>
       </xsd:seguence>
   </xsd:complexType>
   <xsd:complexType name=″fieldErrorType″>
       <xsd:sequence>
           <xsd:elementname=″code″type=″xsd:anySimpleType″/>
           <xsd:element name=″message″type=″xsd:string″/>
       </xsd:sequence>
       <xsd:attribute name=″xpath″type=″xsd:string″/>
   </xsd:complexType>
</xsd:schema>
自动用户接口
框架集成了自动浏览器(称为导航器),它可以用于遍历节点图。下面的输出是使用下面的命令行句法由CRM例子产生的。
ant-f..\..\src\browser\bulid.xml-Dmas.app=crm-Dmas.client.app=navigator
run
导航器首先示出所有与root节点相关联的keyref(即,accounts)。
  Node   Keyref
  ■root   ■accounts
当选择keyref的情况下,显示对应节点;在这种情况下,选择accountskeyref并且显示对应的account节点。
  Node   Keyref   Node
  ■root   ■accounts   ■Acme■Bancroft■Cyberdine
接着,选择account节点,并且显示与account节点类型(即,sourceType=″account″)相关联的keyref。
  Node   Keyref   Node   Keyref
  ■root   ■accounts   ■Acme■Bancroft■Cyberdine   ■owner■subAccounts■contacts■notes■events■tasks■quotes
现在,当选择contacts keyref时,显示对应的contact节点列表。
  Node Keyref   Node   Keyref   Node
  ■root accounts Acme■Bancroft■Cyberdine   ■owner■subAccounts■contacts■notes■events■tasks■quotes   ■Sarah Smith■Roger Reed■David Davies
该导航器使用与上面所述相同的模板repeater和导航机制。因此,可以用自定义模板、动作和页面流逐渐扩展缺省导航器。
自动UI包括两个模板:第一个是“nayigator”模板,其显示当前“聚焦的”节点($current)和用户可以导航到的keyref的列表;第二个模板是特定节点的“具体”形式图。
在导航器模板中,一旦选择了keyref,就将相关节点集的节点列表作为列表显示。
<table><tbody>
   </tr>
       <td><b>{$current}</b></td>
   </tr>
   <tr>
       <netui:repeater id=″$x″source=″$current.keyref(′*′).*″iterator=″$i″>
           <td><imgsrc=″bullet.gif″></td>
           <td><a href=″select($i)″>{$i}</a></td>
       </netui:repeater>
   </tr>
   <tr>
       <netui:repeater id=″$y″source=″$x.selected.*″iterator=″$j″>
           <td><a href=″$pageFlow.navigate($j,′navigator.tmpl′)″>NAV</a></td>
           <td><a href=″$pageFlow.navigate($j,′detail.tmpl′)″>{$j}</a></td>
       </netui:repeater>
   </tr>
</tbody></table>
在节点列表中每节点显示两个锚(超链接):第一个锚“NAV”允许用户导航到相关联的节点,在所选节点Sj作为$current的情况下重新显示当前导航器模板;第二个锚(显示强制的节点Sj的标签)导航到下面的具体模板。
<table><tbody>
   <tr colspan=″2″>
       <td><b>{$current.label()}</b></td>
   </tr>
   <netui:repeater id=″$il″source=″$current.*″iterator=″$i″>
       <tr>
           <td>{$current.name()}</td>
           <td>{$i}</td>
       </tr>
   </netui:repeater>
</tbody></table>
具体模板显示当前节点标签并且包括repeater,其在节点的XML文档中迭代,并且显示元素标志名和对应值。
导航CRM例子的自动浏览器的输出如下所示。
Figure G05801602820060622D001321
第一页面流显示聚焦在根节点上的导航器模板;用户选择accountskeyref,然后向下到“Acme”帐户。这导航到同一导航器模板,设置$current指向“Acme”帐户节点。用户然后选择contacts keyref并且点击“Sarah Smith”的联系人记录;这时,导航器显示具体模板,$current设为表示联系人的节点。
浏览器的后退按钮允许用户从具体模板导航回导航器模板。
CRM使用情况数据模型定义
这部分详细说明示例CRM应用的应用组件。
数据模型
如上所述,图5示出CRM应用的实体关系图(ERD)。
根和用户节点是系统节点类型。根节点表示虚拟XML文档(表示单个用户能访问的数据)的根。用户节点表示系统的单个用户,并且由系统自动生成。
根节点包括account节点并且定义accounts keyref。每个account节点可以包括contact、event、note和task节点,并且定义相应keyref。类似地,每个contact节点可以包括event、note和task节点。account节点还可以包括sub-account并且定义subAccounts keyref。
account和contact节点都包括引用系统用户的owner keyref。类似地,task和event节点定义分配的(用户)keyref。所有这些keyref具有基数1。
模式和keyref定义
下面的部分详细说明五个应用模式,这些都定义在/schemas/crm.xsd文件中。
<?xml version=″1.0″?>
<xsd:schema targetNamespace=″http://example.com/″
   elementFormDefault=″qualified″attributeFormDefault=″unqualified″
   xmlns:xsd=″http://ww.w3.org/2001/XMLSchema″
   xmlns:mas=″urn:bea.com″
   xmlns=″http://example.com/″>
Account类型
account节点类型由下面的模式定义。
<xsd:complexType name=″accountType″>
    <xsd:all>
        <xsd:element name=″name″type=″xsd:string″/>
        <xsd:element name=″type″type=″accountTypeEnum″/>
    </xsd:all>
    <xsd:attribute name=″id″type=″xsd:string″mas:type=″pkey″/>
    <xsd:attribute name=″timestamp″type=″xsd:string″mas:type=″seq″/>
    <xsd:attribute name=″ownerId″type=″xsd:string″/>
    <xsd:attribute name=″parentAccountId″type=″xsd:string″/>
</xsd:complexType>
<xsd:simpleType name=″accountTypeEnum″>
    <xsd:restriction base=″xsd:string″>
        <xsd:enumeration value=″Direct″/>
        <xsd:enumeration value=″Web″/>
        <xsd:enumeration value=″Channel″/>
        <xsd:enumeration value=″Partner″/>
    </xsd:restriction>
</xsd:simpleType>
要注意,account类型定义简单的标签声明,它包括name元素。此外,type字段具有由accountType简单类型定义所定义的约束值的集合。
下面的部分示出显示第一声明的keyref的/conduit/crm.jsx文件的上部。要注意,该应用是在app名字空间中声明的。
<?xml version=″1.0″?>
<graphMeta xmlns=″run:bea.com″
   xmlns:mas=″run:bea.com″
   xmlns:app=″http://example.com/″>
<keyref name=″account″sourceType=″mas:root″targetType=″app:account″>
</keyref>
</graphMeta>
accounts keyref将用户的root节点与account节点集合相关联。在CRM应用中,这是绑定到root节点的唯一keyref。
<keyref name=″accounts″sourceType=″mas:root″targetType=″app:account″/>
下面的keyref定义与account节点类型(即,所有app:account被声明为sourceType属性)有关。帐户包括子帐户(subAccounts)和联系人、通知、事件、任务和报价请求的节点集合。
<keyref name=″subAccounts″sourceType=″app:account″targetType=″app:account″/>
<keyref name=″contacts″sourceType=″app:account″targetType=″app:contact″/>
<keyref name=″notes″sourceType=″app:account″targetType=″app:note″/>
<keyref name=″events″sourceType=″app:account″targetType=″app:event″/>
<keyref name=″tasks″sourceType=″app:account″targetType=″app:task″/>
<keyref name=″quotes″sourceType=″app:account″targetType=″app:quoteRequest″/>
account节点类型还包括对单个user节点的引用(查找),它表示该节点的当前所有者。这是通过下面指定基数约束(正好为1)的声明表达的。
<keyref name=″owner″sourceType=″app:account″targetType=″mas:user″
   minOccurs=″1″maxOccurs=″1″/>
Contact类型
contact节点类型由下面的模式定义。
<xsd:element name=″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:complexType name=″contactType″>
   <xsd:sequence>
       <xsd:element name=″salutation″type=″contactSalutationEnum″/>
       <xsd:element name=″first″type=″xsd:string″/>
       <xsd:element name=″last″type=″xsd:string″/>
       <xsd:element name=″email″type=″xsd:string″/>
   </xsd:sequence>
</xsd:complexType>
<xsd:simpleType name=″contactSalutationEnum″>
   <xsd:restriction base=″xsd:string″>
       <xsd:enumeration value=″Mr″/>
       <xsd:enumeration value=″Mrs″/>
       <xsd:enumeration value=″Ms″/>
       <xsd:enumeration value=″Dr″/>
   </xsd:restriction>
</xsd:simpleType>
要注意,account节点类型定义标签声明,它包括first和last名字元素。此外,salutation字段具有由contactSalutationEnum简单类型定义所定义的约束值集合。
下面的keyref定义与contact节点类型(即,所有app:contact被声明为sourceType属性)有关。帐户包括通知、事件和任务的节点集合。
<keyref name=″notes″sourceType=″app:contact″targetType=″app:note″/>
<keyref name=″events″sourceType=″app:contact″targetType=″app:event″/>
<keyref name=″tasks″sourceType=″app:contact″targetType=″app:task″/>
contact节点类型还包括对单个user节点的引用(查找),它表示该节点的当前所有者。这是通过下面指定基数约束(正好为1)的声明表达的。
<keyref name=″owner″sourceType=″app:contact″targetType=″mas:user″
   minOccurs=″1″maxOccurs=″1″/>
Note类型
note节点类型由下面的模式定义。
<xsd:element name=″note″type=″noteType″>
   <xsd:annotation>
       <xsd:appinfo>
           <mas:nodeAnnotation>
               <mas:label>$node.title</mas:label>
           </mas:nodeAnnotation>
       </xsd:appinfo>
   </xsd:annotation>
</xsd:element>
<xsd:complexType name=″noteType″>
   <xsd:sequence>
       <xsd:element name=″title″type=″xsd:string″/>
       <xsd:element name=″body″type=″xsd:string″/>
   </xsd:sequence>
</xsd:complexType>
note不包括keyref定义。
Event类型
event节点类型由下面的模式定义。
<xsd:element name=″event″type=″eventType″>
   <xsd:annotation>
       <xsd:appinfo>
           <mas:nodeAnnotation>
               <mas:label>$node.title</mas:label>
           </mas:nodeAnnotation>
       </xsd:appinfo>
   </xsd:annotation>
</xsd:element>
<xsd:complexType name=″eventType″>
   <xsd:sequence>
       <xsd:element name=″title″type=″xsd:string″/>
   </xsd:sequence>
</xsd:complexType>
event节点类型还包括对单个user节点的引用(查找),它表示事件的当前assigned用户。这是通过下面指定基数约束(正好为1)的声明表达的。
<keyref name=″assigned″sourceType=″app:event″targetType=″mas:user″
minOccurs=″1″maxOccurs=″1″/>
Task类型
task节点类型由下面的模式定义。
<xsd:element name=″task″type=″taskType″>
   <xsd:annotation>
       <xsd:appinfo>
           <mas:nodeAnnotation>
               <mas:label>$node.title</mas:label>
           </mas:nodeAnnotation>
       </xsd:appinfo>
    </xsd:annotation>
</xsd:element>
<xsd:complexType name=″taskType″>
   <xsd:sequence>
       <xsd:element name=″title″type=″xsd:string″/>
       <xsd:element name=″status″type=″taskStatusEnum″/>
   </xsd:sequence>
</xsd:complexType>
<xsd:simpleType name=″taskStatusEnum″>
   <xsd:restriction base=″xsd:string″>
       <xsd:enumeration value=″Not started″/>
       <xsd:enumeration value=″In progress″/>
       <xsd:enumeration value=″Completed″/>
       <xsd:enumeration value=″Deferred″/>
   </xsd:restriction>
</xsd:simpleType>
task节点类型还包括对单个user节点的引用(查找),它表示事件的当前assigned用户。这是通过下面指定基数约束(正好为1)的声明表达的。
<keyref name=″assigned″sourceType=″app:task″targetType=″mas:user″
minOccurs=″1″maxOccurs=″1″/>
QuoteRequest类型
quoteRequest节点类型由下面的模式定义。
<?xml version=″1.0″?>
<xsd:schema targetNamespace=″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:element name=″quoteRequest″type=″quoteRequestType″/>
<xsd:complexType name=″quoteRequestType″>
   <xsd:sequence>
       <xsd:element name=″prodId″type=″xsd:string″/>
       <xsd:element name=″qty″type=″xsd:integer″/>
       <xsd:element name=″response″minOccurs=″0″
type=″quoteRequestResponseType″/>
   </xsd:sequence>
</xsd:complexType>
<xsd:complexType name=″quoteRequestResponseType″>
   <xsd:sequence>
       <xsd:element name=″price″type=″xsd:double″/>
   </xsd:sequence>
</xsd:complexType>
</xsd:schema>
示例应用模式
下面的部分示出客户端变成模型访问的虚拟数据图的应用数据。
框架生成下面对应用数据的XML模式定义。
<?xml version=″1.0″?>
<xsd:schema targetNamespace=″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:element name=″graph″>
   <xsd:complexType>
       <xsd:sequence>
           <xsd:element ref=″root″minOccurs=″1″maxOccurs=″1″>
           <xsd:element ref=″account″maxOccurs=″unbounded″>
           <xsd:element ref=″contact″maxOccurs=″unbounded″>
           <xsd:element ref=″note″maxOccurs=″unbounded″>
           <xsd:element ref=″event″maxOccurs=″unbounded″>
           <xsd:element ref=″task″maxOccurs=″unbounded″>
       </xsd:sequence>
   </xsd:complexType>
</xsd:element>
</xsd:schema>
graph元素表示应用数据模型的顶级元素;这包括正好一个root节点声明加上对每个应用模式的每个节点的无限声明(account、contact、note、event和task)。
下面的类型定义是由应用模式和keyref定义生成的。
<xsd:element name=″account″>
   <xsd:complexType>
       <xsd:sequence>
           <xsd:element name=″name″type=″xsd:string″/>
           <xsd:element name=″type″type=″accountType″/>
       </xsd:sequence>
   </xsd:complexType>
</xsd:element>
<xsd:element name=″contact″>
   <xsd:complexType>
       <xsd:sequence>
           <xsd:element name=″salutation″type=″contactSalutationEnum″/>
           <xsd:element name=″first″type=″xsd:string″/>
           <xsd:element name=″last″type=″addressType″/>
           <xsd:element name=″email″type=″xsd:string″/>
       </xsd:sequence>
   </xsd:complexType>
</xsd:element>
<xsd:element name=″note″>
   <xsd:complexType>
       <xsd:sequence>
           <xsd:element name=″title″type=″xsd:string″/>
           <xsd:element name=″body″type=″xsd:string″/>
       </xsd:sequence>
   </xsd:complexType>
</xsd:element>
<xsd:element name=″event″>
   <xsd:complexType>
       <xsd:sequence>
           <xsd:element name=″title″type=″xsd:string″/>
       </xsd:sequence>
   </xsd:complexType>
</xsd:element>
<xsd:element name=″task″>
   <xsd:complexType>
       <xsd:sequence>
           <xsd:element name=″title″type=″xsd:string″/>
           <xsd:element name=″status″type=″taskStatusEnum″/>
       </xsd:sequence>
   </xsd:complexType>
</xsd:element>
示例应用数据
系统具有三个用户:“alex”、“bob”和“carol”(这些是虚拟图中未示出的系统对象。
<graph>
<root accounts=″a1 a2″/>
<account id=″a1″owner=″bob″contacts=″c1 c2″notes=″n1″events=″e1″
tasks=″t1″>
   <name>Acme</name>
   <type>Direct</type>
</account>
<account id=″a2″owner=″bob″contacts=″c3″>
   <name>Bancroft</name>
   <type>Web</type>
</account>
<contact id=″c1″owner=″bob″events=″e2″tasks=″t2″>
   <salutation>Mr</salutation>
   <first>Roger</first>
   <last>Reed</last>
   <email>rogeracme.com</email>
</contact>
<contact id=″c2″owner=″bob″notes=″n2″>
   <salutation>Ms</salutation>
   <first>Sarah</first>
   <last>Smith</last>
   <email>sarahacme.com</email>
</contact>
<contact id=″c2″owner=″bob″notes=″n2″>
   <salutation>Ms</salutation>
   <first>Sarah</first>
   <last>Smith</last>
   <email>sarahacme.com</email>
</contact>
<note id=″n1″>
   <title>ROI information</title>
   <body>Attached document details ROI for product</body>
</note>
<note id=″n2″>
   <title>Customer requirements</title>
   <body>Attached document presents customer′s current and anticipated
needs</body>
</note>
<event id=″e1″assigned=″fred″>
   <title>Sales meeting</title>
</event>
<event id=″e2″assigned=″fred″>
   <title>Product demonstration</title>
</event>
<task id=″t1″assigned=″fred″>
   <title>prepare RFP for sales call</title>
   <status>Not started</status>
</task>
<task id=″t2″assigned=″fred″>
   <title>Send white paper to customer</title>
   <status>Completed</status>
</task>
</graph>
示例SPath表达式
下面的部分示出一些SPath表达式和基于上面示例数据的期望值。
下面的表达式返回accounts keyref的节点集(节点列表)。
$root.accounts.*
<account id=″a1″owner=″bob″contacts=″c1 c2″notes=″n1″events=″e1″
tasks=″t1″>
   <name>Acme</name>
   <type>Direct</type>
</account>
<account id=″a2″owner=″bob″contacts=″c3″>
   <name>Bancroft</name>
   <type>Web</type>
</account>
下面的表达式返回所有account节点的name元素集合。
$root.accounts.*.name
Acme
Bancroft
下面表达式返回所有名为Acme的所有account的所有contact。
$root.accounts.*.where(name==″Acme″).contacts.*
<contact id=″c1″owner=″bob″events=″e2″tasks=″t2″>
   <salutation>Mr</salutation>
   <first>Roger</first>
   <last>Reed</last>
   <email>rogeracme.com</email>
</contact>
<contact id=″c2″owner=″bob″notes=″n2″>
   <salutation>Ms</salutation>
   <first>Sarah</first>
   <last>Smith</last>
   <email>sarahacme.com</email>
</contact>
下面表达式返回具有指定电子邮件地址的所有contact(对所有account)。
var $contactX=$root.accounts.*.contacts where(email==″sarahacme.com″)
<contact id=″c2″owner=″bob″events=″e2″tasks=″t2″>
   <salutation>Ms</salutation>
   <first>Sarah</first>
   <last>Smith</last>
   <email>sarahacme.com</email>
</contact>
下面表达式设置$contactX节点内的<salutation>元素的值。
$contactX.salutation=″Mrs″
<contact id=″c2″owner=″bob″events=″e2″tasks=″t2″>
   <salutation>Mrs</salutation>
   <first>Sarah</first>
   <last>Smith</last>
   <email>sarahacme.com</email>
</contact>
下面的表达式创建指定帐户的新联系人。要注意,它使用系统变量来设置owner属性。
$accountX.contacts.create(
   <contact ownerId=″$globalApp.user″>
       <salutation>Dr</salutation>
       <first>David</first>
       <last>Daniels</last>
       <email>davidacme.com</email>
   </contact>
};
下面表达式创建对指定的contact创建新task;然后它修改assignedKeyref。
var $newTask=<task>
   <title>Perpare RFP</title>
   <status>Not started</status>
</task>
$contactX.tasks.create($newTask);
$newTask.assigned =$root.users.*.where(.username==″fred″);
CRM情况数据模型定义
这部分示出示例CRM Web服务的(由Workshop生成的)WSDL的部分。
<?xml version=″1.0″encoding=″utf-8″?>
<definitions xmlns=″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包括两种类型定义:消息参数的输入和输出类型定义;和(对单独的复合类型)字段类型定义。
<types>部分包括对操作输入和输出类型以及对作为操作参数传递的复合元素的模式定义。
下面的类型定义与getAccountsByUser Web服务操作的输入(getAccountsByUser)和输出(getAccountsByUserResponse)消息类型有关。
<types>
   <s:schema xmlns:s=″http://www.w3.org/2001/XMLSchema″
      mlns:ope=″http://www.openuri.org/″elementFormDefault=″qualified″
      trgetNamespace=″http://www.openuri.org/″>
   <s:element name=″getAccountsByUser″>
      <s:complexType>
         <s:sequence>
            <s:element name=″userId″type=″s:string″minOccurs=″0″/>
         </s:sequence>
      </s:complexType>
   </s:element>
   <s:element name=″getAccountsByUserResponse″>
      <s:complexType>
         <s:sequence>
            <s:element name=″getAccountsByUserResult″
type=″ope:ArrayOfAccount″
                    minOccurs=″0″/>
            </s:sequence>
         </s:complexType>
     </s:element>
下面的类型定义定义在上面输入/输出操作定义中引用的参数的复合类型。
<s:complexType name=″ArrayOfAccount″>
    <s:sequence>
        <s:element name=″Account″type=″ope:Account″nillable=″true″
            minOccurs=″0″maxOccurs=″unbounded″/>
    </s:sequence>
</s:complexType>
<s:element name=″Account″nillable=″true″type=″ope:Account″/>
<s:complexType name=″Account″>
    <s:sequence>
        <s:element name=″id″type=″s:string″/>
        <s:element name=″timestamp″type=″s:string″/>
        <s:element name=″name″type=″s:string″minOccurs=″0″/>
        <s:element name=″type″type=″s:string″minOccurs=″0″/>
        <s:element name=″ownerId″type=″s:string″minOccurs=″0″/>
    </s:sequence>
</s:complexType>
</s:schema>
下面的类型定义全部与getContactsByAccount和addContactToAccountWeb服务操作有关。
<s:element name=″getContactsByAccount″>
    <s:complexType>
        <s:sequence>
            <s:element name=″accountId″type=″s:string″minOccurs=″0″/>
        </s:sequence>
    </s:complexType>
</s:element>
<s:element name=″getContactsByAccountResponse″>
        <s:complexType>
            <s:sequence>
                <s:element name=″getContactsByAccountResult″
type=″ope:ArrayOfContact″
                    minOccurs=″0″/>
             </s:sequence>
         </s:complexType>
     </s:element>
     <s:element name=″addContactToAccount″>
        <s:complexType>
           <s:sequence>
               <s:element name=″accountId″type=″s:string″minOccurs=″0″/>
               <s:element name=″contact″type=″ope:Contact″minOccurs=″0″/>
           </s:sequence>
         </s:complexType>
     </s:element>
     <s:element name=″addContactToAccountResponse″>
         <s:complexType>
             <s:sequence>
                 <s:element name=″addContactToAccountResult″type=″s:string″
                    minOccurs=″0″/>
             </s:sequence>
         </s:complexType>
     </s:element>
     <s:complexType name=″ArrayOfContact″>
        <s:sequence>
            <s:element name=″Contact″type=″ope:Contact″nillable=″true″
               minOccurs=″0″maxOccurs=″unbounded″/>
        </s:sequence>
     </s:complexType>
     <s:element name=″Contact″nillable=″true″type=″ope:Contact″/>
     <s:complexType name=″Contact″>
        <s:sequence>
            <s:element name=″id″type=″s:string″/>
            <s:element name=″timestamp″type=″s:string″/>
            <s:element name=″first″type=″s:string″minOecurs=″0″/>
            <s:element name=″last″type=″s:string″minOccurs=″0″/>
            <s:element name=″email″type=″s:string″minOccurs=″0″/>
        </s:sequence>
    </s:complexType>
    </s:schema>
</types>
消息定义
每个Web服务操作定义一对消息,这对消息定义输入和输出类型。
<message name=″getAccountsByUserSoapIn″>
   <part name=″parameters″element=″s0:getAccountsByUser″/>
</message>
<message name=″getAccountsByUserSoapOut″>
   <part name=″parameters″element=″s0:getAccountsByUserResponse″/>
</message>
PortType、绑定和服务定义
管道在结构上与portType定义相似;portType操作被映射到管道操作上;input和output元素对应于transformOut和transformIn Xquery声明。
<portType name=″CRMSoap″>
   <operation name=″getAccountsByUser″>
       <input message=″s0:getAccountsByUserSoapIn″/>
       <output message=″s0:getAccountsByUserSoapOut″/>
   </operation>
</portType>
<binding name=″CRMSoap″type=″s0:CRMSoap″>
   <soap:binding transport=″http://schemas.xmlsoap.org/soap/http″
style=″document″/>
   <operation name=″getAccountsByUser″>
       <soap:operation soapAction=″http://www.openuri.org/getAccountsByUser″
          style=″document″/>
       <input>
          <soap:body use=″literal″/>
       </input>
       <output>
          <soap:body use=″literal″/>
       </output>
   </operation>
</binding>
<service name=″CRM″>
   <port name=″CRMSoap″binding=″s0:CRMSoap″>
       <soap:address location=″http://BISHAMON:7001/CRMWeb/CRM.jws″/>
   </port>
</service>
SalesForce管道定义
下面的管道文件实现与SalesForce.com Web服务相连的管道的部分。
/**
 *mas:stateful shared=″false″
 *common:xmlns namespace=″http://schemas.xmlsoap.org/soap/envelope/
prefix=″soap″
 *common:xmlns namespace=″urn:partner.soap.sforce.com″prefix=″sfdc′
 *common:xmlns namespace=″http://example.com/″prefix=″app″
 */
/**
 *common:control
 *jc:location http-url=″http://enterprise.soap.sforce.com/″
 */
ws=new WebServiceControl();
//session object returned from web service
var sessionId=null;
//create and send login message and process results
function login(){
   var body=
       <login>
           <username>{$user.username}</username>
           <password>{$user.password}</password>
       </login>;
   var response=ws.invoke(body);
   //set session id
   sessionId=string(response.body.sfdc:result.sfdc:sessionId);
   //set URL for subsequent calls(from this conduit)
   ws.endPoint=string(response.body.sfdc:result.sfdc:serverUrl);
}
//create conversational header
function createHeader(){
   if(sessionId==null){
     login();
   }
   return
      <SessionHeader>
          <sessiondId>{sessionId}</sessiondId>
      </SessionHeader>;
}
/**
 *select contacts for an account:$account.contacts.*
 *mas:operation type=″select″keyref=″app:contactAccountRef″inverse=″tru
 *mas:transform type=″request″function=″selectContacts_request″
 *mas:transform type=″response″function=″selectContacts_response″
 */
function selectContacts($msg,$source){
   $msg.header+=createHeader();
   return ws.invoke($msg);
}
/**
 *mas:namespace target=″sfdc″
 *mas:field xpath=″id″
 *language:body type=″xquery″
 */
function selectContacts_request($source){
   <query>
       <queryString>
           SELECT*FROM Contact
           WHERE AccountId=″{string($source/id)}″
       </queryString>
   </query>
}
/**
 *mas:namespace target=″app″
 *language:body type=″xquery″
 */
function selectContacts_response($response){
   for $i in$response/sfdc:queryResponse/sfdc:result/sfdc:records
   return
       <contact id=″{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>
}
/**
 *insert contact:$root.create(<contact>...</contact>);
 *mas:operation type=″insert″node=″app:contact″
 *mas:transform type=″request″function=″insertContact_request″
 *mas:transform type=″response″function=″insertContact_response″
 */
function insertcontact($msg,$node){
   $msg.header+=createHeader();
   var response=ws.invoke($msg);
   var id=response.sfdc:createResponse.sfdc:result.sfdc:Id;
   //retrieve sequence number
   var $msg2=createMessage(
       <query>
           <queryString>
               SELECT SystemModstamp FROM Contact
               WHERE Id=″{id}″
           </queryString>
       </query>
   );
   $msg2.header+=createHeader();
   var response2=ws.invoke($msg2);
   //return both responses
   response.body+=response2.body.sfdc:queryResponse;
   return response;
}
/**
 *mas:namespace target=″sfdc″
 *language:body type=″xquery″
 */
function insertContact_request($node){
   <create>
       <sObjects xsi: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:namespace target=″app″
 *language:body type=″xquery″
 */
function insertContact_response($response){
   <contact id=″{string($response/sfdc:createResponse/sfdc:result/sfdc:Id)}″>
       <modified>
   {string($response/sfdc:queryResponse/sfdc:records/sfdc:SystemModstamp)}
       </modified>
   </contact>
}
在一个实施例中,偶尔链接的应用服务器可以与服务总线(service bus)交互。在一个实施例中,服务总线像web服务器一样工作。
服务总线可以是从多个位置获得信息的代理。服务器总线可以:
●在封装协议、传输协议、安全方案、负载内容、单向和请求/响应范例、同步和异步通信以及点到点和pub/sub的领域,消除(bridge)发送者发送和接收者期望的消息之间的差距。
●在完成像多目的地发布、基于内容的路由、鉴别和授权以及资格映射这样的任务的中间提供额外的计算能力。
●在度量收集和显示、警报显示、跟踪事件收集和使用、消息存档和SLA管理的中间提供监视能力。
服务总线可以是中间人。到服务总线的消息可以通过传输进入,它被处理来确定要将其路由到哪儿并且被变换以便消息浓缩。然后它再次通过传输出去。响应可以沿着相反路径。当消息经过时可以向感兴趣的接听者发布消息的副本。中间人的消息处理可以通过控制台指定的元数据驱动。
服务总线可以支持WebLogic管理的服务器的分簇(clustering)。配置和元数据被自动传播到管理的服务器供快速本地检索。可以从所有管理的服务器自动收集监视的度量,以便集中并显示在控制台上。
中间人调用的中间人(代理服务)和外部服务都可以模型化为服务。
服务可以具有:
●称为端口(也称为端点)的具体接口集,每个具有传输地址和相关配置。端口集组成服务的负载平衡和失败转移备选并且特征相同。
●单个可选的抽象接口(类比物是java接口),它是操作可能破坏的接口中的消息部分的结构的定义(类比物是与参数的java接口的方法),
●单个绑定,定义抽象接口中的消息部分到具体消息的封装和该消息到传输的绑定。
●关于WS安全性(WSS)和WS可靠消息收发(WS-RM)的策略、
授权策略和需要绑定层透明执行的动作(如登录)。
在基于HTTP(S)或JMS传输的标准SOAP web服务的情况下,抽象接口、具体接口和绑定的WSDL表示是可能的。WSDL资源或现有的服务可以用于跳跃开始(jumpstart)新服务的接口的定义。
服务总线可以支持JMS(对BEA和外部JMS提供商)、HTTP(S)、电子邮件、文件、WS-RM和FTP作为服务传输。服务总线可以支持HTTP和JMS异步传输的请求/响应和单向范例。它可选地支持有序的消息传送(如果底层的传输支持它)。服务总线可以支持XML、非XML(用MFL描述的结构)、二进制、具有附件的MIME(电子邮件)以及SOAP 1.1和1.2(具有或没有RPC风格和文档风格的附件)封装。
服务对同一绑定可以具有多个端口。这些端口可以用作负载平衡和失败转移备选。服务可以定义对其断开使用的负载平衡策略。支持的策略是循环复用和随机(加权或未加权)。端口不仅用作负载平衡目的地,在失败时还用作失败转移备用。对于HA负载平衡方案来说这两个概念是连在一起的。
服务还可以定义失败时的重试策略和(对于请求/响应的)超时策略。
服务可以定义应用到其接口中的消息的安全策略。这可以在服务级(应用到所有消息)或对服务操作的各个消息指定。
服务可以被分类。可以定义类别方案。类别本质上是关键字名,并且类别值是关键字名的值。服务可以具有多个类别名的多个值。类别对于发现目的非常有用。存在多个定义关键字名和允许的值分层的标准本体论(ontology)(或类别方案)。服务总线只允许使用分层中的叶值分类服务。
服务集合可以由称为服务提供商的组织或应用来提供。定义服务的提供商是可选的,并且你可以具有单独的服务。这些既可以是企业内部的子组织,也可以是外部的合作组织,甚至单独的应用(句法取决于用户)。此外,服务提供商可以被分类,如搜索服务。服务提供商与资格相关联,并且可以依赖于用户,从而它可以属于授权角色。服务提供商可以发送和接收消息。
服务消费者可以是组织或应用,并且只能发送消息(或接收同步响应)。此外,服务提供商可以被分类,如搜索服务。服务消费者与资格相关联,并且依赖于用户,从而它可以属于授权角色。
代理服务的实现可以由流水线定义指定。它包括请求流水线定义和响应流水线定义。流水线指定在调用外部(或其他代理)服务之前对于对代理服务的请求消息执行什么动作,并且在代理返回响应之前对来自代理调用的服务的响应执行什么处理。
每个流水线可以是阶段的序列。送入流水线的消息可以伴有可由流水线阶段访问或修改的消息上下文变量的集合(包括具有消息内容的变量)。
流水线中的主要阶段如下。
●变换阶段,允许是否嵌套结构来选择要执行的影响上下文的变换。web服务呼出或DB查找可以是用来设置输出上下文变量的Xquery或XSLT变换的替代。
●路由阶段(仅在请求流水线中允许),允许是否合并(和嵌套)结构和范例结构来定义消息要路由到的单个端点和操作。可以在消息被发布到每个端点之前定义影响上下文变量的变换集合。web服务呼出或DB查找可以是用来设置上下文变量的Xquery或XSLT变换的替代。
●发布阶段,允许是否合并(和嵌套)结构和范例结构来定义消息要发布到的端点和操作集合。可以在消息被发布到每个端点之前定义影响上下文变量的变换集合。web服务呼出或DB查找可以是用来设置上下文变量的Xquery或XSLT变换的替代。上下文的改变与每个发布的端点是孤立的,并且不影响流水线的随后处理。
●WS-安全处理以及授权在绑定层中透明地执行。
●跟踪阶段,允许用用户定义的信息写跟踪记录,从而可以使用跟踪系统按照用户定义的准则来搜索。
●归档阶段,为了历史和保持记录的目的将消息写到存档。
●日志阶段,允许将所选的上下文记录到系统日志以便进行调试。
●验证阶段,按照MFL模式的XML验证文档。
●自定义阶段,允许用户使用阶段SDK实现的阶段定义它们自己的动作。
每个流水线可以包括阶段的序列。然而,单个服务级请求流水线可以可选地分支出操作流水线(每个操作最多一个,并且可选地为缺省操作流水线)。因此,没有从消息内容确定操作的标准方法,操作的确定是通过用户所选的准则进行的。响应处理以相关操作流水线开始,然后加入单个服务级响应流水线。
上下文可以在请求流水线和响应流水线中共享,并且其值与各个请求/响应消息相关联。上下文可以是预定义的XML变量集合。可以动态地向上下文添加或删除新变量。预定义的上下文变量具有关于消息、传输头、安全原理、当前代理服务的元数据、主路由的元数据和代理服务调用的订阅服务的信息。上下文可以由阶段用Xquery/Xupdate表达式读取和修改。
上下文的核心是变量$header、$body和$attachments。这些分别是包含SOAP头、SOAP主体内容和MIME附件的包装变量。上下文给出这样的印象,即,所有消息都是soap消息,而非soap消息被映射到该范例中。在二进制或MFL数据的情况下,表示$attachments或$body中的文档的XML元素是指具有唯一标识符的文档。在SOAP RPC的情况下,主体内容自身是包含分类的RPC参数的包装元素。
服务总线可以具有如果在设计时期望的话可以使用的内置型系统。当在设计时创建条件或变换的Xquery表达式时,可以声明变量为编辑器中的一个或多个类型以帮助容易地创建Xquery。类型在XML模式、MFL或WSDL资源中。该类型声明处理知道要分类的变量的本质(是类型的元素或类型自身的包装)。它还提供帮助来容易地访问$body中的SOAP RPC参数或文档。
每个阶段可以具有在该阶段中出现错误时执行的步骤序列。该步骤序列组成该阶段的出错流水线。此外,可以为整个流水线或整个代理服务定义出错流水线。在出错时调用存在的最低范围的出错流水线。该出错流水线允许消息发布到端点,制订返回到代理的调用者的出错响应消息,记录该消息,在修改上下文后继续,或者产生异常。产生异常将控制转交给下一较高范围的出错流水线。
请求流水线的处理可以包括进入传输处理、进入绑定层、流水线执行、输出绑定层和输出传输处理步骤。绑定层自动进行要执行的一些处理,像将消息映射到/从上下文变量,封装和解封装消息以及进行WSS安全和授权。主路由目的地和发布目的地都遵从该范例。
在主路由端点被调用时,响应流水线处理遵从类似的模型。
来自阶段的web服务呼出通过传输层前面的绑定层。呼出响应沿着反向路径。
用户是安全负责人,可以是人、组织或应用。用户可以调用UI接口(控制台用户)或消息接口(模型化为服务消费者或提供商的用户)。
服务总线资源可以是可再用的共同的实体定义或描述,并且典型地是该实体的元数据。资源可以由多个服务使用,并且是企业或部分中的标准化定义或描述。资源的例子有类别方案、MFL模式、XSD模式、Xquery图、XSLT图、WSDL接口和WS-策略文件。
类别方案可以定义单个类别名和类别名值的分层集合。可以使用登记的方案分类服务提供商和消费者。它们可以以一个类别方案的多个叶值或者来自多个类别方案的叶值分类。
模式可以描述本原或结构数据的类型。MFL模式描述非XML数据的类型。XML模式描述XML的类型。XML模式类型可以导入或包括其他模式文件。
变换图可以描述两种类型之间的映射。XSLT图描述使用XLST标准的XML数据的映射。Xquery图描述使用Xquery标准的XML和非XML(MFL)数据的映射。
WSDL接口可以是服务接口的模板并且描述包括该接口中的操作的服务的出现接口,以及操作签名中的消息部分的类型。它还可选地描述消息部分到消息的绑定(封装)和消息到传输的绑定。它还可选地描述服务的具体接口。
WS-策略可以描述安全和可靠消息传输策略。它描述应当使用什么算法签名或加密消息中的什么。它可以描述对于接收到的消息应当使用什么鉴别机制。
在一个实施例中,偶尔连接的应用服务器平台提供一个框架用来使用与现有企业组件集成的类似Web的编程模型开发、部署和管理复杂移动解决方案。
移动应用可以包括数据模型定义、用户接口模板、包括定义动作的脚本的客户端控制器、以及在服务器侧的用于描述如何在数据模型和企业之间仲裁的一组管道。偶尔连接的应用服务器可以假设移动应用使用的所有数据由外部系统永久地存储和管理。数据模型可以是移动应用对该数据的预期用途的元数据描述,并且被优化来允许在偶尔连接设备和外部系统之间有效遍历和同步该数据。
偶尔链接的数据模型可以描述永久性应用数据的结构(和其他特性)。模型自身可以与移动浏览器同步,从而客户端能够智能地遍历数据并且与服务器同步数据。
本发明的其他特征、方面和目的可以通过回顾附图和权利要求书获得。应当理解,可以开发本发明的其他实施例并使其落入本发明和权利要求书的宗旨和范围内。
为了说明和描述的目的提供对本发明的前述优选实施例的描述。它并不意图穷举或将本发明限制在所披露的具体形式。显然,对本领域技术人员来说许多修改和变型将是明显的。选择和描述实施例以便最好地说明本发明原理及其实际应用,从而允许本领域技术人员明白本发明各个实施例以及适合特定用途的各种修改。本发明的范围意图由权利要求书及其等效物限定。
除了包括专门设计的集成电路或其他电子电路的实施例外,本发明还可以使用根据本发明公开的教学编程的常规通用或专用数字计算机或微处理器来方便地实现,这对于计算机领域的技术人员是清楚的。
熟练程序员基于本公开的教学可以容易地准备适当的软件编码。本方面还可以通过专用集成电路的准备或通过互连常规组件电路的适当网络来实现,这对于本领域技术人员是容易理解的。
本发明包括计算机程序产品,它是其上存储有指令的存储介质,指令可以用于编程计算机来执行本发明的任何处理。存储介质可以包括但不限于,包括软盘、光盘、DVD、CD-ROM、微型驱动器和磁光盘在内的任何类型的盘、ROM、RAM、EPROM、EEPROM、DRAM、VRAM、闪存器件、磁或光卡、毫微系统(包括分组存储IC)或适于存储指令和/或数据的任何类型的介质或器件。
存储在任何一种计算机可读介质上,本发明包括用于控制通用/专用计算机或微处理器的硬件和用于允许计算机或微处理器与人类用户或其他利用本发明结果的机构交互的软件。该软件可以包括,但不限于,设备驱动器、操作系统和用户应用。
通用/专用计算机或微处理器的编程(软件)中包括用于实现本发明的教学软件模块,包括但不限于用于偶尔连接的应用服务器的系统和方法。

Claims (21)

1.一种偶尔连接的应用服务器,包括:
同步单元,其被配置成后台地在该应用服务器和应用的移动客户端之间同步数据节点,该应用包括偶尔连接的数据模型,用以指示该移动客户端对外部数据的预期用途;和
管道管理器,其被配置成使用管道,该管道定义在偶尔连接的数据模型所定义的数据节点与来自外部系统的数据之间的转换,
其中,数据节点与同步状态相关联,其中该应用服务器通过使用该同步单元与移动客户端来回传递数据节点的同步状态,以同步该应用服务器上的数据节点与移动客户端上的数据节点,使得当通过使用与数据节点相关联的同步状态重建连接时,在该应用服务器上反映在移动客户端与该应用服务器断开的时段期间对数据节点执行的更新操作。
2.如权利要求1所述的偶尔连接的应用服务器,其中,该数据节点按照偶尔连接的数据模型中的元数据所指示的那样被高速缓存在高速缓存中。
3.如权利要求1所述的偶尔连接的应用服务器,其中,来自外部系统的数据为对特定网页服务的请求和响应。
4.如权利要求1所述的偶尔连接的应用服务器,还包括自适应用户接口服务器,其中,移动客户端从偶尔连接的应用服务器接收HTML页面,所述HTML页面是由自适应用户接口服务器使用数据节点和偶尔连接的数据模型构造的。
5.如权利要求1所述的偶尔连接的应用服务器,其中,该同步单元向移动客户端传送数据节点和偶尔连接的数据模型来在移动客户端产生显示。
6.如权利要求5所述的偶尔连接的应用服务器,其中,所述移动客户端能在不与偶尔连接的应用服务器联系的情况下使用数据节点和偶尔连接的数据模型运行应用。
7.如权利要求1或2所述的偶尔连接的应用服务器,其中,该偶尔连接的数据模型被存储在存储器中。
8.如权利要求7所述的偶尔连接的应用服务器,其中,偶尔连接的应用服务器被配置成利用该管道管理器在来自外部系统的数据和由偶尔连接的数据模型所定义的数据节点之间进行转换。 
9.如权利要求7所述的偶尔连接的应用服务器,其中,数据节点包括XML。
10.如权利要求7所述的偶尔连接的应用服务器,其中,来自外部系统的数据为对特定网页服务的请求和响应。
11.如权利要求7所述的偶尔连接的应用服务器,还包括自适应用户接口服务器,用于使用数据节点和偶尔连接的数据模型构造至少一个客户端要从偶尔连接的应用服务器接收的HTML页面。
12.如权利要求7所述的偶尔连接的应用服务器,其中,该同步单元向至少一个客户端传送数据节点和偶尔连接的数据模型来在客户端产生显示。
13.如权利要求12所述的偶尔连接的应用服务器,其中,所述至少一个客户端能在不与偶尔连接的应用服务器联系的情况下使用数据节点和偶尔连接的数据模型运行应用。
14.一种用于偶尔连接应用服务器的方法,包括:
在应用服务器中,后台地在偶尔连接的应用服务器和包括偶尔连接的数据模型的应用的移动客户端之间的同步数据节点,该偶尔连接的数据模型指示移动客户端对外部数据的预期用途;和
在该应用服务器中,在偶尔连接的数据模型所定义的数据节点与来自外部系统的数据之间进行转换,
其中,数据节点与同步状态相关联,其中该应用服务器通过使用后台进程与移动客户端来回传递数据节点的同步状态,以同步该应用服务器上的数据节点与移动客户端上的数据节点,使得当通过使用与数据节点相关联的同步状态重建连接时,在该应用服务器上反映在移动客户端与该应用服务器断开的时段期间对数据节点执行的更新操作。
15.如权利要求14所述的方法,其中,偶尔连接的应用服务器按照偶尔连接的数据模型中的元数据所指示的那样在高速缓存中高速缓存数据节点。
16.如权利要求14所述的方法,其中,来自外部系统的数据为对特定网页服务的请求和响应。
17.如权利要求14所述的方法,其中,向客户端传送数据节点和偶尔连接的数据模型来在移动客户端产生显示。
18.一种偶尔连接的应用服务器,包括:
第一组件,其被配置成后台地在该应用服务器和应用的移动客户端之间 同步的数据节点,该应用包括偶尔连接的数据模型,用以指示该移动客户端对外部数据的预期用途;和
第二组件,其被配置成在偶尔连接的数据模型所定义的数据节点与来自外部系统的数据之间进行转换,
其中,数据节点与同步状态相关联,其中该应用服务器通过使用该第一组件与移动客户端来回传递数据节点的同步状态,以同步该应用服务器上的数据节点与移动客户端上的数据节点,使得当通过使用与数据节点相关联的同步状态重建连接时,在该应用服务器上反映在移动客户端与该应用服务器断开的时段期间对数据节点执行的更新操作。
19.一种用于偶尔连接应用的系统,包括:
偶尔连接的应用服务器,配置成从外部系统获得要发送到移动客户端的应用数据并将该应用数据转换成数据节点发送到移动客户端,其中该应用允许该移动客户端读取和更新应用数据,而不需要对偶尔连接的应用服务器的当前访问,该偶尔连接的应用服务器包括
同步单元,其被配置成后台地在该应用服务器和应用的移动客户端
之间同步的数据节点,该应用包括偶尔连接的数据模型,用以指示该移动客户端对外部数据的预期用途;和
管道管理器,其被配置成使用管道,该管道定义在偶尔连接的数据模型所定义的数据节点与来自外部系统的数据之间的转换,
其中,数据节点与同步状态相关联,其中该应用服务器通过使用该同步单元与移动客户端来回传递数据节点的同步状态,以同步该应用服务器上的数据节点与移动客户端上的数据节点,使得当通过使用与数据节点相关联的同步状态重建连接时,在该应用服务器上反映在移动客户端与该应用服务器断开的时段期间对数据节点执行的更新操作。
20.如权利要求19所述的系统,其中,外部系统是服务总线。
21.如权利要求19所述的系统,其中,外部系统是网页服务系统。 
CN2005800016028A 2004-05-20 2005-05-20 偶尔连接的应用服务器 Active CN101421726B (zh)

Applications Claiming Priority (5)

Application Number Priority Date Filing Date Title
US57307704P 2004-05-20 2004-05-20
US60/573,077 2004-05-20
US11/122,294 2005-05-04
US11/122,294 US7650432B2 (en) 2004-05-20 2005-05-04 Occasionally-connected application server
PCT/US2005/017822 WO2005114489A2 (en) 2004-05-20 2005-05-20 Occasionally-connected application server

Publications (2)

Publication Number Publication Date
CN101421726A CN101421726A (zh) 2009-04-29
CN101421726B true CN101421726B (zh) 2012-08-22

Family

ID=40631503

Family Applications (1)

Application Number Title Priority Date Filing Date
CN2005800016028A Active CN101421726B (zh) 2004-05-20 2005-05-20 偶尔连接的应用服务器

Country Status (2)

Country Link
US (6) US20060030292A1 (zh)
CN (1) CN101421726B (zh)

Families Citing this family (152)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
EP1574014B1 (en) * 2002-12-13 2006-11-08 Telefonaktiebolaget LM Ericsson (publ) Error messaging method in http based communication systems
US20070180127A1 (en) 2003-11-11 2007-08-02 Nokia Corporation Preconfigured syncml profile categories
US20050157746A1 (en) * 2004-01-16 2005-07-21 Celljump Ltd. Portable apparatus for providing a computer data and/or computer data program to a mobile computerized electronic device, and associated method
US8566732B2 (en) * 2004-06-25 2013-10-22 Apple Inc. Synchronization of widgets and dashboards
US8302020B2 (en) 2004-06-25 2012-10-30 Apple Inc. Widget authoring and editing environment
US7490295B2 (en) * 2004-06-25 2009-02-10 Apple Inc. Layer for accessing user interface elements
US8453065B2 (en) * 2004-06-25 2013-05-28 Apple Inc. Preview and installation of user interface elements in a display environment
US7603466B2 (en) * 2004-07-19 2009-10-13 Sap (Ag) Mobile collaborative peer-to-peer business applications
JP4487725B2 (ja) * 2004-10-25 2010-06-23 株式会社島津製作所 分析データ処理システム及び分析装置
US7908286B2 (en) * 2004-12-08 2011-03-15 Oracle International Corporation Techniques for providing XQuery access using web services
US7546526B2 (en) * 2004-12-20 2009-06-09 Microsoft Corporation Efficient extensible markup language namespace parsing for editing
WO2006071062A1 (en) * 2004-12-30 2006-07-06 Samsung Electronics Co., Ltd. A terminal data format and a communication control system and method using the terminal data format
US20060242302A1 (en) * 2005-04-22 2006-10-26 Walker Arthur P Proof-of-service (POS) workflow customization via task extension
US7370060B2 (en) * 2005-05-24 2008-05-06 Microsoft Corporation System and method for user edit merging with preservation of unrepresented data
US7970386B2 (en) * 2005-06-03 2011-06-28 Good Technology, Inc. System and method for monitoring and maintaining a wireless device
US8543931B2 (en) 2005-06-07 2013-09-24 Apple Inc. Preview including theme based installation of user interface elements in a display environment
US7774546B1 (en) * 2005-06-17 2010-08-10 Oracle America, Inc. Method and apparatus for facilitating in-cache reference counting
US7979417B1 (en) * 2005-06-30 2011-07-12 Google Inc. Embedded communication of link information
US8745485B2 (en) * 2005-08-18 2014-06-03 Oracle International Corporation Extensible remote tag markup system and method
US8015270B2 (en) * 2005-09-06 2011-09-06 Reldata, Inc. Redundant appliance configuration repository in standard hierarchical format
US8972423B2 (en) * 2006-09-26 2015-03-03 Siemens Product Lifecycle Management Software Inc. Opaque mechanism for web service interoperability
US7702341B2 (en) * 2005-10-03 2010-04-20 Yahoo! Inc. Shortcut for establishing a communication channel with a remote device over a network
US8543824B2 (en) * 2005-10-27 2013-09-24 Apple Inc. Safe distribution and use of content
US7954064B2 (en) * 2005-10-27 2011-05-31 Apple Inc. Multiple dashboards
US20070101279A1 (en) * 2005-10-27 2007-05-03 Chaudhri Imran A Selection of user interface elements for unified display in a display environment
US7743336B2 (en) * 2005-10-27 2010-06-22 Apple Inc. Widget security
US7752556B2 (en) * 2005-10-27 2010-07-06 Apple Inc. Workflow widgets
US9104294B2 (en) * 2005-10-27 2015-08-11 Apple Inc. Linked widgets
US7707514B2 (en) 2005-11-18 2010-04-27 Apple Inc. Management of user interface elements in a display environment
US7809838B2 (en) * 2005-12-08 2010-10-05 International Business Machines Corporation Managing concurrent data updates in a composite services delivery system
US7529780B1 (en) * 2005-12-30 2009-05-05 Google Inc. Conflict management during data object synchronization between client and server
US8725683B2 (en) 2006-01-13 2014-05-13 Microsoft Corporation RSS feed generation using objects
US8239754B1 (en) * 2006-04-07 2012-08-07 Adobe Systems Incorporated System and method for annotating data through a document metaphor
KR100823265B1 (ko) * 2006-04-13 2008-04-17 삼성전자주식회사 모바일 디바이스에서 XHTML-Print 문서를전송하는 방법 및 장치
US20070265855A1 (en) * 2006-05-09 2007-11-15 Nokia Corporation mCARD USED FOR SHARING MEDIA-RELATED INFORMATION
US20070288853A1 (en) * 2006-06-09 2007-12-13 Nextair Corporation Software, methods and apparatus facilitating presentation of a wireless communication device user interface with multi-language support
US7697472B2 (en) * 2006-06-13 2010-04-13 Vladimir Sadovsky Reporting portable device statistics
US8782542B2 (en) 2006-07-19 2014-07-15 Red Hat, Inc. Display and management of a service composition candidate inventory
US9841951B2 (en) 2006-07-19 2017-12-12 Red Hat, Inc. Management of SOA service model
US8850384B2 (en) * 2006-07-19 2014-09-30 Red Hat, Inc. Creation and management of service candidates for a service model
US20080027996A1 (en) * 2006-07-31 2008-01-31 Morris Robert P Method and system for synchronizing data using a presence service
US20080034309A1 (en) * 2006-08-01 2008-02-07 Louch John O Multimedia center including widgets
US8869027B2 (en) * 2006-08-04 2014-10-21 Apple Inc. Management and generation of dashboards
CA2568465A1 (en) * 2006-11-17 2008-05-17 Cognos Incorporated System and method of web service description language transformation
KR101221672B1 (ko) * 2006-11-30 2013-01-14 재단법인서울대학교산학협력재단 데이터 동기화 시스템
US8499044B2 (en) * 2006-12-07 2013-07-30 Microsoft Corporation Formatted message processing utilizing a message map
US20080162728A1 (en) * 2007-01-03 2008-07-03 Microsoft Corporation Synchronization protocol for loosely coupled devices
US7613828B2 (en) * 2007-01-12 2009-11-03 Microsoft Corporation Store-and-forward messaging channel for occasionally connected mobile applications
US7983249B2 (en) * 2007-01-23 2011-07-19 Oracle America, Inc. Enterprise web service data to mobile device synchronization
US8190661B2 (en) * 2007-01-24 2012-05-29 Microsoft Corporation Using virtual repository items for customized display
US20080183822A1 (en) * 2007-01-25 2008-07-31 Yigang Cai Excluding a group member from receiving an electronic message addressed to a group alias address
US7899917B2 (en) * 2007-02-01 2011-03-01 Microsoft Corporation Synchronization framework for occasionally connected applications
US8145673B2 (en) * 2007-02-16 2012-03-27 Microsoft Corporation Easily queriable software repositories
US20080201330A1 (en) * 2007-02-16 2008-08-21 Microsoft Corporation Software repositories
US9729843B1 (en) 2007-03-16 2017-08-08 The Mathworks, Inc. Enriched video for a technical computing environment
US8005812B1 (en) 2007-03-16 2011-08-23 The Mathworks, Inc. Collaborative modeling environment
US7831625B2 (en) * 2007-05-16 2010-11-09 Microsoft Corporation Data model for a common language
US20080307071A1 (en) * 2007-06-05 2008-12-11 Oracle International Corporation Retrieving specific hierarchical information using web services
US20090005071A1 (en) * 2007-06-28 2009-01-01 Apple Inc. Event Triggered Content Presentation
US8683446B2 (en) * 2007-07-09 2014-03-25 International Business Machines Corporation Generation of test cases for functional testing of applications
US8954871B2 (en) 2007-07-18 2015-02-10 Apple Inc. User-centric widgets and dashboards
US20090024671A1 (en) * 2007-07-19 2009-01-22 Microsoft Corporation Content management system and external data storage system data synchronization
US9009292B2 (en) * 2007-07-30 2015-04-14 Sybase, Inc. Context-based data pre-fetching and notification for mobile applications
US20090259744A1 (en) * 2008-04-14 2009-10-15 Kolke Daniel J System and Method for Running a Web-Based Application while Offline
US8204870B2 (en) * 2007-08-03 2012-06-19 Sybase, Inc. Unwired enterprise platform
US8667415B2 (en) * 2007-08-06 2014-03-04 Apple Inc. Web widgets
US9009181B2 (en) * 2007-08-23 2015-04-14 International Business Machines Corporation Accessing objects in a service registry and repository
US20090063590A1 (en) * 2007-08-30 2009-03-05 Microsoft Corporation Operating System Support of Graceful Degradation for Web Applications
US8185494B2 (en) * 2007-09-14 2012-05-22 Microsoft Corporation Data-driven synchronization
US20090083441A1 (en) * 2007-09-24 2009-03-26 Microsoft Corporation Synchronization of web service endpoints in a multi-master synchronization environment
EP2206049A4 (en) * 2007-09-28 2013-11-13 Xcerion Ab NETWORK EXHIBIT SYSTEM
US7941399B2 (en) 2007-11-09 2011-05-10 Microsoft Corporation Collaborative authoring
US20090125526A1 (en) * 2007-11-13 2009-05-14 Brent Neufeld System and method for providing automated non-volatile offline access to relational data
US8825758B2 (en) 2007-12-14 2014-09-02 Microsoft Corporation Collaborative authoring modes
US20090196311A1 (en) * 2008-01-31 2009-08-06 Microsoft Corporation Initiation and expiration of objects in a knowledge based framework for a multi-master synchronization environment
US8626720B2 (en) 2008-02-11 2014-01-07 International Business Machines Corporation System and method of reconstructing complex custom objects
US20090204590A1 (en) * 2008-02-11 2009-08-13 Queplix Corp. System and method for an integrated enterprise search
US8966465B2 (en) * 2008-02-12 2015-02-24 Oracle International Corporation Customization creation and update for multi-layer XML customization
US8875306B2 (en) * 2008-02-12 2014-10-28 Oracle International Corporation Customization restrictions for multi-layer XML customization
US8788542B2 (en) * 2008-02-12 2014-07-22 Oracle International Corporation Customization syntax for multi-layer XML customization
US7996444B2 (en) * 2008-02-18 2011-08-09 International Business Machines Corporation Creation of pre-filters for more efficient X-path processing
US7831608B2 (en) * 2008-02-28 2010-11-09 International Business Machines Corporation Service identification in legacy source code using structured and unstructured analyses
US8301588B2 (en) 2008-03-07 2012-10-30 Microsoft Corporation Data storage for file updates
US8352870B2 (en) 2008-04-28 2013-01-08 Microsoft Corporation Conflict resolution
US8095963B2 (en) 2008-04-30 2012-01-10 Microsoft Corporation Securing resource stores with claims-based security
US8825594B2 (en) * 2008-05-08 2014-09-02 Microsoft Corporation Caching infrastructure
US8429753B2 (en) * 2008-05-08 2013-04-23 Microsoft Corporation Controlling access to documents using file locks
US20090291680A1 (en) * 2008-05-23 2009-11-26 Mort Deborah K Wireless communication network and wireless control or monitoring device employing an xml schema
US8417666B2 (en) * 2008-06-25 2013-04-09 Microsoft Corporation Structured coauthoring
US8560563B2 (en) * 2008-07-09 2013-10-15 International Business Machines Corporation Apparatus and method of semantic service correlation system
US8996658B2 (en) * 2008-09-03 2015-03-31 Oracle International Corporation System and method for integration of browser-based thin client applications within desktop rich client architecture
US8799319B2 (en) * 2008-09-19 2014-08-05 Oracle International Corporation System and method for meta-data driven, semi-automated generation of web services based on existing applications
US9122520B2 (en) * 2008-09-17 2015-09-01 Oracle International Corporation Generic wait service: pausing a BPEL process
US8620861B1 (en) 2008-09-30 2013-12-31 Google Inc. Preserving file metadata during atomic save operations
EP2337330B1 (en) * 2008-09-30 2019-09-18 Brother Kogyo Kabushiki Kaisha Printer having web server function
US9934240B2 (en) 2008-09-30 2018-04-03 Google Llc On demand access to client cached files
US7870482B2 (en) * 2009-01-30 2011-01-11 International Business Machines Corporation Web browser extension for simplified utilization of web services
US8812451B2 (en) 2009-03-11 2014-08-19 Microsoft Corporation Programming model for synchronizing browser caches across devices and web services
US8413139B2 (en) * 2009-03-11 2013-04-02 Microsoft Corporation Programming model for application and data access and synchronization within virtual environments
US9680964B2 (en) * 2009-03-11 2017-06-13 Microsoft Technology Licensing, Llc Programming model for installing and distributing occasionally connected applications
US8346768B2 (en) * 2009-04-30 2013-01-01 Microsoft Corporation Fast merge support for legacy documents
US8176071B2 (en) * 2009-05-22 2012-05-08 Microsoft Corporation Selection and sorting protocol extensions to the WS-enumeration protocol
US8095571B2 (en) 2009-06-22 2012-01-10 Microsoft Corporation Partitioning modeling platform data
KR101606373B1 (ko) * 2009-08-31 2016-03-28 삼성전자주식회사 데이터 운용 방법과, 이를 지원하는 단말기 및 시스템
US8793571B1 (en) * 2010-01-11 2014-07-29 Documensions, Inc. System and method for repeat viewing components of digital documents and determining viewer context
US8290900B2 (en) * 2010-04-24 2012-10-16 Research In Motion Limited Apparatus, and associated method, for synchronizing directory services
CN102238002A (zh) * 2010-04-30 2011-11-09 国际商业机器公司 用于网络通信的动态加密和解密的方法和设备
AU2011289732B2 (en) * 2010-08-12 2015-11-05 Unisys Corporation Moving enterprise software applications to a cloud domain
KR101824647B1 (ko) * 2010-10-12 2018-02-02 삼성전자주식회사 디바이스간 동기화 방법, 유저 디바이스, 및 컴퓨터로 읽을 수 있는 저장 매체
KR101755421B1 (ko) * 2011-01-10 2017-07-10 삼성전자주식회사 클라이언트 장치를 이용한 호스트 장치의 파일 정보 시스템 편집 방법 및 시스템
US8615712B2 (en) 2011-03-01 2013-12-24 Weever Apps Inc. Executing a populated code template to generate a browser-executable software program to present a web page as a mobile application
US10048992B2 (en) * 2011-04-13 2018-08-14 Microsoft Technology Licensing, Llc Extension of schematized XML protocols
CN102810090B (zh) * 2011-05-30 2017-06-09 Sap欧洲公司 网关数据分布引擎
US8943150B2 (en) 2011-09-12 2015-01-27 Fiserv, Inc. Systems and methods for customizing mobile applications based upon user associations with one or more entities
US9542432B2 (en) 2011-09-30 2017-01-10 Oracle International Corporation Systems and methods for multitenancy data
US8954942B2 (en) * 2011-09-30 2015-02-10 Oracle International Corporation Optimizations using a BPEL compiler
US9529576B2 (en) * 2011-09-30 2016-12-27 Oracle International Corporation Systems and methods for object to XML mappings
US9100685B2 (en) 2011-12-09 2015-08-04 Microsoft Technology Licensing, Llc Determining audience state or interest using passive sensor data
US8918712B2 (en) * 2011-12-13 2014-12-23 Fmr Llc Dynamically generating a mobile application
US20130159555A1 (en) * 2011-12-20 2013-06-20 Microsoft Corporation Input commands
US9406044B2 (en) * 2011-12-22 2016-08-02 Sap Se Rule-based determination and validation in business object processing
US8732201B2 (en) * 2012-02-28 2014-05-20 Software Ag Systems and/or methods for automatically deriving web service permissions based on XML structure permissions
CN102662993A (zh) * 2012-03-14 2012-09-12 北京神州数码思特奇信息技术股份有限公司 一种页面数据提供方法
US9075889B2 (en) 2012-04-09 2015-07-07 Salesforce.Com, Inc. Mechanism for facilitating user-controlled management of site network mapping and synchronization
US9244934B2 (en) 2012-04-23 2016-01-26 Google Inc. Sharing and synchronizing electronically stored files
US9239846B2 (en) 2012-04-23 2016-01-19 Google Inc. Sharing and synchronizing electronically stored files
US8949179B2 (en) 2012-04-23 2015-02-03 Google, Inc. Sharing and synchronizing electronically stored files
US9529818B2 (en) 2012-04-23 2016-12-27 Google Inc. Sharing and synchronizing electronically stored files
CA2775700C (en) 2012-05-04 2013-07-23 Microsoft Corporation Determining a future portion of a currently presented media program
US9424243B1 (en) * 2012-12-21 2016-08-23 Emc Corporation Mechanism to support composite data models in HTML form
US9614932B2 (en) 2013-03-14 2017-04-04 Microsoft Technology Licensing, Llc Managing and implementing web application data snapshots
CN104376025B (zh) * 2013-08-16 2017-10-10 华为技术有限公司 分布式数据库的数据存储方法和装置
CN103607434A (zh) * 2013-11-04 2014-02-26 四川长虹电器股份有限公司 网络通信数据的交互方法
DE102013225058A1 (de) * 2013-12-05 2015-06-11 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. Vorrichtung, system und verfahren zur effizienten und verzögerungsarmen synchronisation graphenförmiger datenstrukturen
WO2015085485A1 (zh) * 2013-12-10 2015-06-18 华为终端有限公司 一种同步方法及终端、服务器
US9734044B2 (en) * 2014-03-05 2017-08-15 International Business Machines Corporation Automatic test case generation
CN104915288A (zh) * 2014-03-13 2015-09-16 阿里巴巴集团控股有限公司 测试方法及装置
JP5783301B1 (ja) * 2014-06-11 2015-09-24 富士ゼロックス株式会社 通信端末、通信システム及びプログラム
AU2016217500A1 (en) * 2015-02-13 2017-10-05 Eutech Cybernetic Integration platform to enable operational intelligence and user journeys for smart cities and the internet of things
US11226940B2 (en) * 2015-03-16 2022-01-18 Oracle International Corporation Adapting data for changes to data attributes
CN106921734B (zh) * 2017-02-13 2020-04-03 上海大学 一种基于选择性缓存与同步的客户端与服务器数据交互方法
US11138236B1 (en) * 2017-05-17 2021-10-05 Palantir Technologies Inc. Systems and methods for packaging information into data objects
CA3008302A1 (en) * 2017-06-13 2018-12-13 Radicalogic Technologies, Inc. Platform for context based syndromic surveillance
EP3444719B1 (en) 2017-08-14 2021-07-21 Unify Patente GmbH & Co. KG Method and system for a client to server deployment via an online distribution platform
US11714811B2 (en) 2017-09-27 2023-08-01 Salesforce, Inc. Run-time querying of multi-tenant non-relational platform objects
US10579692B2 (en) * 2017-09-27 2020-03-03 Salesforce.Com, Inc. Composite keys for multi-tenant non-relational platform objects
US10579691B2 (en) 2017-09-27 2020-03-03 Salesforce.Com, Inc. Application programming interface representation of multi-tenant non-relational platform objects
US10678528B1 (en) * 2017-11-21 2020-06-09 Amazon Technologies, Inc. Directory schema deployment with pipelines
US20220200394A1 (en) * 2019-07-12 2022-06-23 Weg Equipamentos Elétricos S.a. Rotary electric machine and oil tank for a rotary electric machine
US11108862B2 (en) * 2019-10-14 2021-08-31 Journey Mobile, Inc. Bi-directional data sync between a client device and an application server
CN111638923B (zh) * 2020-06-04 2023-03-24 北京思特奇信息技术股份有限公司 一种基于Java注解进行数据路由的方法和装置
US11500834B2 (en) * 2020-09-18 2022-11-15 Atlassian Pty Ltd. Systems and methods for migrating data

Citations (1)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN1346464A (zh) * 1998-12-31 2002-04-24 联合想象计算机公司 动态过滤和路由事件的方法和装置

Family Cites Families (113)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US520789A (en) * 1894-06-05 Voltmeter
US5159592A (en) * 1990-10-29 1992-10-27 International Business Machines Corporation Network address management for a wired network supporting wireless communication to a plurality of mobile users
US5250789A (en) * 1991-10-31 1993-10-05 Johnsen Edward L Shopping cart
US5546549A (en) * 1994-06-01 1996-08-13 International Business Machines Corporation Multi-path channel (MPC) interface with user transparent, unbalanced, dynamically alterable computer input/output channels
US5566225A (en) * 1994-11-21 1996-10-15 Lucent Technologies Inc. Wireless data communications system for detecting a disabled condition and simulating a functioning mode in response to detection
US5758257A (en) * 1994-11-29 1998-05-26 Herz; Frederick System and method for scheduling broadcast of and access to video programs and other data using customer profiles
US6571279B1 (en) * 1997-12-05 2003-05-27 Pinpoint Incorporated Location enhanced information delivery system
US5664110A (en) * 1994-12-08 1997-09-02 Highpoint Systems, Inc. Remote ordering system
US5812819A (en) * 1995-06-05 1998-09-22 Shiva Corporation Remote access apparatus and method which allow dynamic internet protocol (IP) address management
US5727159A (en) * 1996-04-10 1998-03-10 Kikinis; Dan System in which a Proxy-Server translates information received from the Internet into a form/format readily usable by low power portable computers
US6314406B1 (en) * 1996-06-26 2001-11-06 Telxon Corporation Customer information network
US5828832A (en) * 1996-07-30 1998-10-27 Itt Industries, Inc. Mixed enclave operation in a computer network with multi-level network security
US5931917A (en) * 1996-09-26 1999-08-03 Verifone, Inc. System, method and article of manufacture for a gateway system architecture with system administration information accessible from a browser
US6096096A (en) * 1996-12-13 2000-08-01 Silicon Graphics, Inc. Web-site delivery
US6477527B2 (en) * 1997-05-09 2002-11-05 International Business Machines Corporation System, method, and program for object building in queries over object views
US6314408B1 (en) * 1997-07-15 2001-11-06 Eroom Technology, Inc. Method and apparatus for controlling access to a product
US6112212A (en) * 1997-09-15 2000-08-29 The Pangea Project Llc Systems and methods for organizing and analyzing information stored on a computer network
US6236768B1 (en) * 1997-10-14 2001-05-22 Massachusetts Institute Of Technology Method and apparatus for automated, context-dependent retrieval of information
US6009410A (en) * 1997-10-16 1999-12-28 At&T Corporation Method and system for presenting customized advertising to a user on the world wide web
US6128661A (en) * 1997-10-24 2000-10-03 Microsoft Corporation Integrated communications architecture on a mobile device
US6594682B2 (en) * 1997-10-28 2003-07-15 Microsoft Corporation Client-side system for scheduling delivery of web content and locally managing the web content
US6065120A (en) * 1997-12-09 2000-05-16 Phone.Com, Inc. Method and system for self-provisioning a rendezvous to ensure secure access to information in a database from multiple devices
US6058391A (en) * 1997-12-17 2000-05-02 Mci Communications Corporation Enhanced user view/update capability for managing data from relational tables
US6801916B2 (en) * 1998-04-01 2004-10-05 Cyberpulse, L.L.C. Method and system for generation of medical reports from data in a hierarchically-organized database
US6101483A (en) * 1998-05-29 2000-08-08 Symbol Technologies, Inc. Personal shopping system portable terminal
US6151675A (en) * 1998-07-23 2000-11-21 Tumbleweed Software Corporation Method and apparatus for effecting secure document format conversion
US6925595B1 (en) * 1998-08-05 2005-08-02 Spyglass, Inc. Method and system for content conversion of hypertext data using data mining
US7778260B2 (en) * 1998-10-09 2010-08-17 Netmotion Wireless, Inc. Method and apparatus for providing mobile and other intermittent connectivity in a computing environment
CN1352776A (zh) * 1998-11-30 2002-06-05 英戴克系统公司 基于习惯、统计推导和心理学-人口统计简档的智能工具
US6177905B1 (en) * 1998-12-08 2001-01-23 Avaya Technology Corp. Location-triggered reminder for mobile user devices
JP4014326B2 (ja) * 1999-02-18 2007-11-28 本田技研工業株式会社 静電容量式傾斜センサ
US6212640B1 (en) * 1999-03-25 2001-04-03 Sun Microsystems, Inc. Resources sharing on the internet via the HTTP
US6226752B1 (en) * 1999-05-11 2001-05-01 Sun Microsystems, Inc. Method and apparatus for authenticating users
US6681220B1 (en) * 1999-05-28 2004-01-20 International Business Machines Corporation Reduction and optimization of information processing systems
US20030191832A1 (en) * 1999-06-01 2003-10-09 Ramakrishna Satyavolu Method and apparatus for controlled establishment of a turnkey system providing a centralized data aggregation and summary capability to third party entities
US6477373B1 (en) * 1999-08-10 2002-11-05 Research Foundation Of State University Of New York Method and apparatus to maintain connectivity for mobile terminals in wireless and cellular communications systems
US6760758B1 (en) * 1999-08-31 2004-07-06 Qwest Communications International, Inc. System and method for coordinating network access
US7392308B2 (en) * 1999-09-10 2008-06-24 Ianywhere Solutions, Inc. System, method, and computer program product for placement of channels on a mobile device
US6725022B1 (en) * 1999-09-22 2004-04-20 Motorola, Inc. Method and apparatus for enabling the selection of content on a wireless communication device
US7020697B1 (en) * 1999-10-01 2006-03-28 Accenture Llp Architectures for netcentric computing systems
US6578054B1 (en) * 1999-10-04 2003-06-10 Microsoft Corporation Method and system for supporting off-line mode of operation and synchronization using resource state information
US6430624B1 (en) * 1999-10-21 2002-08-06 Air2Web, Inc. Intelligent harvesting and navigation system and method
US6353398B1 (en) * 1999-10-22 2002-03-05 Himanshu S. Amin System for dynamically pushing information to a user utilizing global positioning system
US6647001B1 (en) * 1999-12-06 2003-11-11 At&T Corp. Persistent communication with changing environment
US7047305B1 (en) * 1999-12-09 2006-05-16 Vidiator Enterprises Inc. Personal broadcasting system for audio and video data using a wide area network
WO2001067309A2 (en) * 2000-03-03 2001-09-13 Radiant Logic, Inc. System and method for providing access to databases via directories and other hierarchical structures and interfaces
GB2360173B (en) * 2000-03-07 2004-04-07 Hewlett Packard Co Distributed telemetry method and system
US6618737B2 (en) * 2000-03-09 2003-09-09 International Business Machines Corporation Speculative caching of individual fields in a distributed object system
US6845091B2 (en) * 2000-03-16 2005-01-18 Sri International Mobile ad hoc extensions for the internet
US6701522B1 (en) * 2000-04-07 2004-03-02 Danger, Inc. Apparatus and method for portal device authentication
WO2001080093A2 (en) * 2000-04-17 2001-10-25 Circadence Corporation System and method for reformatting data traffic
AU2001251634A1 (en) * 2000-04-17 2001-10-30 Emtera Corporation System and method for wireless purchases of goods and services
US20020057803A1 (en) * 2000-05-05 2002-05-16 Loos Michael T. System and method for communicating in a mobile domain across non-persistent data links
GB0011426D0 (en) * 2000-05-11 2000-06-28 Charteris Limited A method for transforming documents written in different XML-based languages
US6922685B2 (en) * 2000-05-22 2005-07-26 Mci, Inc. Method and system for managing partitioned data resources
US6438575B1 (en) * 2000-06-07 2002-08-20 Clickmarks, Inc. System, method, and article of manufacture for wireless enablement of the world wide web using a wireless gateway
CN1300677C (zh) * 2000-06-22 2007-02-14 微软公司 分布式计算服务平台
US6615216B1 (en) * 2000-06-29 2003-09-02 Microsoft Corporation Lock free data structure maintenance
AU2001276992A1 (en) * 2000-07-20 2002-02-05 Aeptec Microsystems, Inc. Method, system, and protocol for location-aware mobile devices
KR100425494B1 (ko) * 2000-08-21 2004-03-30 엘지전자 주식회사 웹 기반 전송장비의 관리 데이터 동기 방법
EP1366435A2 (en) * 2000-08-22 2003-12-03 Symbian Limited Database for use with a wireless information device
US20020059345A1 (en) * 2000-09-12 2002-05-16 Wang Wayne W. Method for generating transform rules for web-based markup languages
US20030021417A1 (en) * 2000-10-20 2003-01-30 Ognjen Vasic Hidden link dynamic key manager for use in computer systems with database structure for storage of encrypted data and method for storage and retrieval of encrypted data
US7362868B2 (en) * 2000-10-20 2008-04-22 Eruces, Inc. Hidden link dynamic key manager for use in computer systems with database structure for storage of encrypted data and method for storage and retrieval of encrypted data
US6542740B1 (en) * 2000-10-24 2003-04-01 Litepoint, Corp. System, method and article of manufacture for utilizing a wireless link in an interface roaming network framework
US6865680B1 (en) * 2000-10-31 2005-03-08 Yodlee.Com, Inc. Method and apparatus enabling automatic login for wireless internet-capable devices
US7600014B2 (en) * 2000-11-16 2009-10-06 Symantec Corporation Method and system for monitoring the performance of a distributed application
US20020099829A1 (en) * 2000-11-27 2002-07-25 Richards Kenneth W. Filter proxy system and method
JP3768406B2 (ja) * 2001-01-15 2006-04-19 株式会社エヌ・ティ・ティ・ドコモ 移動通信網における情報配信制御方法及びシステム、及び移動通信網における通信ノードでの情報蓄積方法
US7017175B2 (en) * 2001-02-02 2006-03-21 Opentv, Inc. Digital television application protocol for interactive television
US6714791B2 (en) * 2001-02-23 2004-03-30 Danger, Inc. System, apparatus and method for location-based instant messaging
US6668177B2 (en) * 2001-04-26 2003-12-23 Nokia Corporation Method and apparatus for displaying prioritized icons in a mobile terminal
US20030177175A1 (en) * 2001-04-26 2003-09-18 Worley Dale R. Method and system for display of web pages
US7190956B2 (en) * 2001-05-15 2007-03-13 Motorola Inc. Instant message proxy for circuit switched mobile environment
US7003566B2 (en) * 2001-06-29 2006-02-21 International Business Machines Corporation Method and system for predictive directional data caching
US6813641B2 (en) * 2001-07-05 2004-11-02 Sun Microsystems, Inc. Teamware server working over HTTP/HTTPS connections
US7117225B2 (en) * 2001-08-13 2006-10-03 Jasmin Cosic Universal data management interface
US20030039362A1 (en) * 2001-08-24 2003-02-27 Andrea Califano Methods for indexing and storing genetic data
GB2379296B (en) * 2001-09-01 2005-05-25 Ibm A data storage system having a unified container layer for an active data store
US7257649B2 (en) * 2001-09-28 2007-08-14 Siebel Systems, Inc. Method and system for transferring information during server synchronization with a computing device
US7062756B2 (en) * 2001-11-30 2006-06-13 Sun Microsystems, Inc. Dynamic object usage pattern learning and efficient caching
US7032033B1 (en) * 2001-11-30 2006-04-18 Microsoft Corporation Handling collisions during synchronization of data between client and server computers
US20030135556A1 (en) * 2001-12-14 2003-07-17 International Business Machines Corporation Selection of communication strategies for message brokers or publish/subscribe communications
US6826568B2 (en) * 2001-12-20 2004-11-30 Microsoft Corporation Methods and system for model matching
US7062515B1 (en) * 2001-12-28 2006-06-13 Vignette Corporation System and method for the synchronization of a file in a cache
US7275105B2 (en) * 2002-01-16 2007-09-25 Laszlo Systems, Inc. Enabling online and offline operation
JP3967141B2 (ja) * 2002-01-28 2007-08-29 富士通株式会社 フレーム中継システムおよびフレーム中継装置
US9087319B2 (en) * 2002-03-11 2015-07-21 Oracle America, Inc. System and method for designing, developing and implementing internet service provider architectures
US7089491B2 (en) * 2002-05-03 2006-08-08 Microsoft Corporation System and method for enhancing XML schemas
US8255548B2 (en) * 2002-06-13 2012-08-28 Salesforce.Com, Inc. Offline web services API to mirror online web services API
US20040001476A1 (en) * 2002-06-24 2004-01-01 Nayeem Islam Mobile application environment
US7076508B2 (en) * 2002-08-12 2006-07-11 International Business Machines Corporation Method, system, and program for merging log entries from multiple recovery log files
TWI231669B (en) * 2002-11-02 2005-04-21 Ibm System and method for using portals by mobile devices in a disconnected mode
US20040098463A1 (en) * 2002-11-19 2004-05-20 Bo Shen Transcoding-enabled caching proxy and method thereof
US6973460B1 (en) * 2002-11-26 2005-12-06 Microsoft Corporation Framework for applying operations to nodes of an object model
WO2004051453A1 (en) * 2002-12-04 2004-06-17 Entriq Inc. Multiple content provider user interface
AU2003296975A1 (en) * 2002-12-13 2004-07-09 Bea Systems, Inc. System and method for mobile communication
US7644361B2 (en) * 2002-12-23 2010-01-05 Canon Kabushiki Kaisha Method of using recommendations to visually create new views of data across heterogeneous sources
US20040128345A1 (en) * 2002-12-27 2004-07-01 Robinson Scott H. Dynamic service registry
WO2004064481A2 (en) * 2003-01-23 2004-08-05 Dexterra, Inc. System and method for mobile data update
US7966418B2 (en) * 2003-02-21 2011-06-21 Axeda Corporation Establishing a virtual tunnel between two computer programs
US7516157B2 (en) * 2003-05-08 2009-04-07 Microsoft Corporation Relational directory
GB0311564D0 (en) * 2003-05-20 2003-06-25 Ibm Monitoring operational data in data processing systems
US20050033767A1 (en) * 2003-08-04 2005-02-10 Kamentz Joel D. Computer-implemented system and method for resource caching and execution
US20050234969A1 (en) * 2003-08-27 2005-10-20 Ascential Software Corporation Services oriented architecture for handling metadata in a data integration platform
US7290034B2 (en) * 2003-09-18 2007-10-30 Vulcan Portals Inc. Method and system for polling a server for new emails, downloading the new emails in a background process, and caching the downloaded emails for access by an email application of an electronic device, such as a portable computer
US20050138143A1 (en) * 2003-12-23 2005-06-23 Thompson Blake A. Pre-fetching linked content
WO2005079349A2 (en) * 2004-02-12 2005-09-01 Mobileframe Llc Integrated deployment of software projects
US7228312B2 (en) * 2004-03-09 2007-06-05 Microsoft Corporation Transformation tool for mapping XML to relational database
US20060155759A1 (en) * 2004-12-29 2006-07-13 Yahoo! Inc. Scalable cache layer for accessing blog content
US8175233B2 (en) * 2005-02-07 2012-05-08 Avaya Inc. Distributed cache system
US7548915B2 (en) * 2005-09-14 2009-06-16 Jorey Ramer Contextual mobile content placement on a mobile communication facility
US7702318B2 (en) * 2005-09-14 2010-04-20 Jumptap, Inc. Presentation of sponsored content based on mobile transaction event

Patent Citations (1)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN1346464A (zh) * 1998-12-31 2002-04-24 联合想象计算机公司 动态过滤和路由事件的方法和装置

Also Published As

Publication number Publication date
US20060031256A1 (en) 2006-02-09
US20060030292A1 (en) 2006-02-09
US20060031228A1 (en) 2006-02-09
US20060026168A1 (en) 2006-02-02
CN101421726A (zh) 2009-04-29
US20060031264A1 (en) 2006-02-09
US20060053368A1 (en) 2006-03-09

Similar Documents

Publication Publication Date Title
CN101421726B (zh) 偶尔连接的应用服务器
JP4551899B2 (ja) 随時接続アプリケーションサーバー
US8645973B2 (en) Mobile applications
AU2006200230B2 (en) Platform for data services across disparate application frameworks
JP5065056B2 (ja) ワークフローを処理するための方法、コンピュータ・プログラム、およびシステム(ワークフロー・システムへのデータ管理動作の統合)
US7543000B2 (en) Method and system combining state replication and operational-replay synchronization
US20100082538A1 (en) Isolated replication of shared objects
US20070219976A1 (en) Extensible query language with support for rich data types
US20020032775A1 (en) System and method for transmitting and retrieving data via a distributed persistence framework
US20080016516A1 (en) Systems and methods for using application services
JP2004500619A (ja) サービスを作成するための方法および装置
US8626716B1 (en) Service broker enhancements
Palmer et al. Towards collaborative editing of structured data on mobile devices
US20030149957A1 (en) Development and generation of enterprise applications using a high-level specification
US20030188034A1 (en) Method and apparatus for enabling retargetable application architectures
Betzing Design and Development of an Event-driven In-memory Business Process Engine
Blackham et al. Supporting Pervasive Business via Virtual Database Aggregation
Lins Event-based information sharing
Leff et al. Programming models and synchronization techniques for disconnected business applications
Mahjourian An architectural style for data-driven systems
Sipos Synchronization with SyncML

Legal Events

Date Code Title Description
C06 Publication
PB01 Publication
C10 Entry into substantive examination
SE01 Entry into force of request for substantive examination
ASS Succession or assignment of patent right

Owner name: ORACLE INT CORP

Free format text: FORMER OWNER: BEA SYSTEMS CORP.

Effective date: 20110415

C41 Transfer of patent application or patent right or utility model
TA01 Transfer of patent application right

Effective date of registration: 20110415

Address after: American California

Applicant after: Oracle Int Corp

Address before: American California

Applicant before: Bea Systems Corp.

C14 Grant of patent or utility model
GR01 Patent grant