SDO/DAS研究(1): SDO规范

          数据对象是 SDO 框架的核心。数据对象是一个业务对象的一般表达,并且没有和特殊的持久化存储机制绑定。
数据图是一个相关数据对象的集合。在 SDO1.0 里,一个数据图总是被一个 DataGraph 信封对象所包装,而在 SDO.0 里,数据对象图可以存在于 DataGraph 之外。(数据图) Data graph 作为两个单词分开使用时,指任何一个数据对象集合;(数据图) DataGraph 作为一个单一单词使用时,特指一个 DataGraph 信封对象。
所有数据图都有一个单一的根数据对象,它直接或间接的包含图里的所有其它数据对象。当的数据图里的所有数据对象仅仅引用自身的数据对象时,我们称该数据图是封闭的。封闭是一个数据图的标准状态。
一个数据图由以下组成:
·           一个单一的根数据对象。
·           通过对根数据对象属性的递归检索到的所有可达的数据对象。
一个封闭的数据图形成了一个数据对象的树形结构。数据图能够记录跟踪描述数据对象的模式。数据图同样也可以维护一个更改概要( ChangeSummary ), ChangeSummary 表达了施加于该图数据对象之上的更改。
1 ,数据图包含数据对象
对于终端用户而言,访问数据图的标准方式是通过数据访问服务( DAS )。 DAS 提供了从库中加载数据图和将数据图保存回库中的方法。例如,一个 XML 文件 DAS 将加载和保存一个数据图为 XML 文件,一个 JDBC DAS 将使用一个关系数据库加载和保存一个数据图。针对其它特殊的 DAS 的规范超出了本规范的范围。
经典的 DAS 使用了一个非连接的数据架构,客户端除了在读写数据图时,均和 DAS 保持一个非连接的状态。因而,一个使用数据图的典型场景涉及以下步骤:
·             终端用户发送一个加载数据图的请求给 DAS
·             DAS 启动一个持久库上的事务去接收数据,创建一个表达该数据的数据图,并且结束这个事务。
·             DAS 返回一个数据图给一个终端用户应用。
·             终端用户应用处理数据图。
·             终端用户应用使用修改后的数据图调用 DAS
·             DAS 基于终端用户对数据的修改,启动一个新的事务更新持久库中的数据。
2 SDO 的非连接数据结构
注意有两个特别的角色能够用来区分数据对象用户:客户和 DAS writer
客户需要能够纵览整个数据图去访问每一个数据对象并且能够获取和设置每一个数据对象域的能力。客户也需要序列化和反序列化一个数据图。如使用 XML DAS 时,数据图能够被序列化一个 XML
DAS writer 必须能够为数据图定义一个模型,创建一个新的数据图,产生更改历史信息,并且能够访问更改历史信息。
一个数据图包含一个(更改概要) ChangeSummary ,通过 ChangeSummary ,能够访问数据图中任何一个数据对象的更改历史。当 DAS 返回一个数据图时, ChangeSummary 应该是空的。如果 DAS 的客户修改了数据对象的状态,例如创建或者删除,这些更改的概要将被记录在 ChangeSummary 中。
如果一个客户端将一个修改后的数据图发送给 DAS DAS 将会进行数据图的错误性检查,这些错误主要包括数据图是否缺少封闭,属性值是否越界,由树形子图生成的属性或数据对象的选择,不同的约束或者任何针对 DAS 的特殊限制(如 XML 模式的特殊校验)。这里,封闭( Closure )指任何一个该数据图的数据对象的引用均指向自身内部的一个对象。通常, DAS 使用异常报告更新的问题。
一个数据图可能没有封闭,此时,终端用户可以临时通过数据对象接口修改该数据图所包含的数据对象。然而在所有的用户操作完成后,数据图将重建一个封闭。 DAS 只能操作带有封闭的数据图。
SDO API 由下列与实例数据相关的接口组成:
·             DataObject :业务数据对象;
·             DataGraph :数据对象图的信封;
·             ChangeSummary :数据图中所包含的数据对象的更改摘要;
·             Sequence :设置的顺序;
SDO 也包含一个用来内省数据对象模型的小型元数据 API
·             Type :数据对象或属性的类型;
·             Property :数据对象所拥有的属性;
最后, SDO 还有一些帮助接口和帮助类:
·             DataFactory :用于数据对象的创建;
·             CopyHelper :浅拷贝和深拷贝;
·             EqualityHelper :浅相等和深相等;
·             XMLHelper :序列化为 XML
·             XMLDocument :序列化为 XML
·             XSDHelper :加载 XSDs
·             DataHelper
·             HelperProvider
APIs 如图 3 所示。
数据对象用于描述业务数据,数据对象利用属性保存数据。
数据对象接口的设计原则是:使编程更为简单,因为它提供了对所有普通类型的业务数据的访问以及各种访问模式的支持,如基于名字、索引和路径进行访问。
数据对象接口包含以下方法:
·             获取和设置数据对象的属性;
·             查询一个属性是否是集合;
·             创建一个新的被包含的子数据对象实例;
·             从数据对象的容器删除该数据对象;
·             从数据对象的容器分派该数据对象;
·             获取数据对象的容器及其包含的属性;
·             获取根数据对象;
·             获取数据对象所属的数据图;
·             获取数据对象的类型;
·             获取数据对象的顺序(如果存在的话);
·             获取数据对象的额外属性(如果存在的话);
对于许多不使用生成代码的应用而言,数据对生成象接口是唯一用来编写应用的 SDO 部件。对于那些使用生成代码的应用来说,将直接使用生成的接口。 SDO 的其它部件主要根据用户需要加以使用。
数据对象概念
数据对象可以分为以下几类。在分类过程中,开放( open )或顺序( sequenced )概念能够独自或一起使用。
1.        Basic 。数据对象和一个每个属性都有一个赋值域的 JavaBean 类似。所有允许的属性集合可以通过 getType().getProperties() 方法获得。通过 get(property) 方法可以访问属性的值。属性内部的顺序是可以维护的,但是跨越多个属性之间的顺序是不可维护的。
2.        Open 。数据对象和一个容许有额外属性的 JavaBean 类似。在 XML 中,这等同于开放(通配符)内容。它类似于一个和新属性拥有额外映射的 JavaBean 。额外属性不是由 getType().getProperties() 方法返回属性的一部分。通过使用 getInstanceProperties() 方法,能够获得一个特殊数据对象的实际拥有的属性。属性值可以使用 get(property) 方法访问。属性内部的顺序是可以维护的,但是跨越多个属性之间的顺序是不可维护的。
3.        Sequenced 。数据对象和一个能够同时维护属性内部和属性之间顺序的 JavaBean 类似。在 XML 中,这等同于一个 DOM 。在使用 XML 时, Sequence 表示了数据对象内部所有 XML 元素的顺序。使用 get(property) 方法可以获得属性值,但是维护跨越多个属性之间的顺序,则需要通过顺序 interface. getSequence() 方法返回 XML 实例的所有 XML 元素的 Sequence 进行。 XML 属性没有顺序的概念并且可以通过 get(property) 方法进行访问。
数据对象的值和属性
数据对象拥有给其属性所赋的数据值。例如,一个采购订单数据对象的 orderDate 属性有一个值为:2005-6-30。通过使用数据对象的 get("orderDate") set("orderDate") 方法,可以获取或修改其 orderDate 属性的值。当使用生成的代码时,也可以通过使用 PurchaseOder 接口上的 getOrderDate() setOrderDate() 方法访问属性的值。
在数据对象接口上,可以基于属性的名字通过使用 get(String path) 方法访问属性值,也可以利用属性的索引或者直接利用属性对象访问属性值。数据对象的 get(String path) 方法可以使用别名,也可以使用路径里的属性名。在这里,路径可能仅仅是一个属性的名字,也有可能是一个基于 XPath 子集的路径表达。
类型转换
有时属性的类型会和应用程序中习惯使用的类型不同。例如,当在用户界面中显示一个整型数量时,字符串型可能比整型表达更有效。可以方便的访问整型数量属性的 getString(“quantity”) 方法将会返回一个字符串类型的值。在许多应用中,这使一个常用的任务得以简化。
在调用一个数据对象的类型访问器( accessor get set 时,如果值不是请求所需要的类型 T 的实例,则必须进行类型转换。类型转换由数据对象的实现自动完成。 SDO 实现被期望能够实现任何数据类型与数据对象内定义的类型之间的转换,并且在转换过程中尽可能不丢失信息。所支持的数据类型在 SDO DataTypes 片段中定义。这些类型包括:
·             Java 基本类型;
·             Java 基本类型的对象包装;
·             String
·             Date 和时间类型;
·             URI
·             Byte[]
·             BigDecimal
·             BigInteger
Java DataHelper 描述了类型转换。本规范 145 页“ DataType Conversions ”中说明了所支持的类型转换。
多值( Many-Valued )数据对象属性
属性可能有一个或多个值。如果一个属性是多值的,那么 property.many 返回 true get(property) 方法将返回一个列表( List )。
在数据接口或自动生成的代码上,当属性没有值时,返回值为 List 的数据对象方法将返回一个空列表而不是返回一个 null 。返回的列表可以描述数据对象的值的任何变化。
对于访问多值属性来说, getList(property) 访问器是极其方便的。如果 property.many true ,那么 set(property, value) setList(property, value) 方法需要 “value” 分别为 java.util.Collection List 对象。这些方法和在使用完 getList(property).clear() 之后紧接着使用 getList(property).addAll(value) 方法效果一样。
对于多值属性, get() getList() 方法将返回一个包含当前值的列表 List 。通过 List 接口立即可以对数据对象的当前值进行更新操作。每次使用 get() getList() 方法访问时,都将返回同一个 List 对象。
判断一个属性是否是集合
对于一个多值属性, isSet(property) 方法将返回:
·             True ,如果 List 不为空;
·             False ,如果 List 为空;
对于一个单值属性, isSet(property) 方法将返回:
·             False ,如果 Property 还没有被 set() 或者已经被 unset() 了;
·             True ,如果当前值不是 Property 的缺省值;
·             对于某些实例,实现基于下列策略决定 isSet(property) 的值:
·             调用 set() 之后而没有调用 unset() isSet() 返回 True 。在 set(property, property.getDefault()) 之后, isSet(property) 返回 True
·             当前值不等于缺省值时, isSet() 返回 true ;在 set(property, property.getDefault()) 之后, isSet(property) 返回 false
unset(property) 访问器可以用来清空一个简单属性,因此在 unset(property) 之后, isSet(property) 返回 false get(property) 返回缺省值。 delete() 方法将取消数据对象的所有属性的值,除非该属性为只读属性。在 unset() 之后, get(property) 将返回缺省值,对于多值属性,则返回一个空列表。
注意:试图使用 set unset 或者 delete 修改一个只读属性将会引发一个异常。
包含内容( Containment
数据图内的数据对象被组织成一个树型结构。有一个数据对象作为树的根节点,而其它数据对象则组成这个树的其它叶子节点。
通过使用由根数据对象开始的包含内容引用( containment references )就可以创建一个树型结构。根数据对象引用其它数据对象,而这些数据对象则可以进一步引用更深一层的数据对象。除了根数据对象,数据图内的每一个数据对象必定有一个从树内其它节点而来的包含内容引用。图内的每一个数据对象可以跟踪它的包含内容引用的位置。
对于一个数据图来说,拥有一个非包含内容引用( containment references )是可能的。这些引用所指向的数据对象是同一个数据图的一部分(引用的数据对象必定是同一个树的一部分),但是这些引用对该数据图的树型结构没有影响。
包含内容和非包含内容都是数据对象的属性。该属性的类型可以是任何一种数据对象类型。
一个特殊的数据对象引用属性是否是一个包含内容引用或非包含内容引用由该数据图的数据模型定义,例如定义一个 XML 文档数据类型的 XSD 。一旦数据模型被定义好后,将不能被修改。可以通过访问 property.containment 来查询一个特殊的引用是否是一个包含内容引用。
容器型数据对象包含其它数据对象。数据对象能够拥有一个容器数据对象的最大数目。如果一个数据对象没有容器,那么它就是一个根数据对象。
getContainer() getContainmentProperty() 方法提供了自上而下的简单浏览数据对象所包含的内容的方法。 getContainer() 方法返回一个父数据对象, getContainmentProperty() 方法返回包含该对象的容器属性。使用 detach() 方法,在不做任何改变的情况下,可以将一个数据对象能够从它的容器中移出。
包含内容可以被管理。当一个数据对象作为一个包含内容属性的值被设置或添加时,它将被从先前的任何一个包含内容属性中移出。包含内容不可能有循环。如果设置或添加将生成一个循环,一个异常将会抛出。
创建和删除数据对象
创建方法可以创建一个该属性所属类型的数据对象,或者创建一个在参数中说明的类型的数据对象,并且能够将一个创建好的数据对象添加到指定的属性。如果数据对象的类型是一个顺序型( getType().isSequenced() 方法返回 true ),新创建的数据对象将被添加在顺序的末尾。如果属性是单值的,属性的值将被设置为该新创建的对象。如果属性是多值的,新创建的对象将被作为最后一个对象而添加。只有包含内容属性能够被用来创建对象。一个新创建的对象的所有属性都被取消(未赋值或仅是缺省值)。
delete() 方法取消了数据对象的所有非只读属性。如果包含内容属性不是只读的, delete() 方法也将把该数据对象从包含其的数据对象中移出。包含内容属性所包含的递归的子数据对象也将被删除。
如果其它数据对象有一个单步的或非包含内容属性指向已删除的数据对象,那么这些引用将不会被修改。然而为了满足数据图的封闭特性,上述属性的值需要改变。一个被删除的数据对象能够被再次使用,并且能够被再次添加到数据图中。
顺序型数据对象
数据对象可能是顺序型的或非顺序型的。 getType().isSequenced() 方法可以告诉你该数据对象的类型是否是顺序型的。
如果数据对象的类型是顺序型的,那么 getSequence() 方法将会返回一个顺序( Sequence ),否则 getSequence() 方法返回 null
数据对象的顺序和表达其属性值的 XML 元素一致。如果更新一个数据对象的话,那么从该数据对象返回的列表或顺序,也进行同样的数据操作。
返回的顺序可以有效的描述数据对象值的任何变化。
开放内容的数据对象属性
数据对象有两种类型的属性:
·             由类型( Type )说明的属性;
·             不是由类型( Type )说明的属性,这样的属性叫做开放内容( open content );
与数据对象类型相关的属性可以通过 getType().getProperties() 方法获得,该方法将返回一个列表。
除了拥有由类型描述的属性之外,数据对象还能够拥有其它属性:
·             处理开放的或者混合的 XML 内容。
·             动态的遭遇新的属性。
Type.open true 时,允许拥有开放内容属性。一些类型将开放( open )设置为 false ,因为它们不能接受附加的属性。
一个属性如果出现在 getInstanceProperties() 方法返回值中而不是出现在 getType().getProperties() 方法的返回值中,那么该属性来源于开放内容。如果一个属性来源于开放内容,那么 isSet(property) 方法必定返回 true
如果 equals() 方法为 true 的话,由 DataType Types 说明的属性可以返回不同的对象。对于多变的数据值(例如,日期型或字符串列表),对这些值进行修改直接由实现决定。
当你使用 getInstanceProperties() 方法时,将返回一个只读的列表,里面包含一个数据对象当前所使用的所有属性。这包括开放内容的属性。属性的顺序由所有 getType().getProperties() 方法返回值开始;其它属性的顺序由实现决定。每一次对 getInstanceProperties() 方法的调用将返回同一个列表对象,除非该数据对象已经更新,从而导致列表内容改变。
在一个实例属性中,通过调用 getProperty() 方法并基于属性名就能够有效的查找数据对象上对应的属性。
为了设置一个该属性尚未设置(其并未出现在 getInstanceProperties() 方法返回值中)的开放内容值,一个数据对象的设置或创建访问器,或者在列表或顺序中添加,一个属性的参数将要被使用,该参数可以通过访问 TypeHelper 或者 XSDHelper 查找到。创建一个开放内容的例子可以在 135 “Creating open content XML documents” 中找到。
对于所有通过 getInstanceProperties() 方法获得的开放内容属性,其 isSet(property) 方法将返回真。
属性索引
当一个数据对象拥有多个属性时,每一个属性都能够被一个数字索引所引用,其中第一个属性的数字索引从 0 开始。
get(int property) 方法中使用的属性索引是该属性在 getInstanceProperties() 方法返回的列表中的位置。
如果数据正在修改之中,不推荐对开放内容使用索引参数访问器;除非该索引被用在 getInstanceProperties() 方法获得的属性中,因为在 getInstanceProperties() 方法中,开放内容的属性索引能够改变,如果几个开放内容属性的值能够被重复的设置和取消设置。
下面的例子是正确的,因为索引和 getInstanceProperties() 方法一起使用。注意由于数据对象不是同步的,因此用户不应该在读的同时对其进行更新操作。该实例显示了一个普通的模式,在所有实例属性中循环并且打印属性名和值:
for (int i=0; i
{
Property p = (Property) myDo.getInstanceProperties().get(i);
System.out.println(p.getName()+"="+myDo.getString(i));
}
getInstanceProperties() 方法获得的属性的名称和别名与那些拥有较高的索引的属性相比,具有一个较高的优先级,因此开放内容属性可以通过使用类型属性中定义的名称隐藏其真实名称,因为这些属性在列表的开始。优先级的顺序就是 getInstanceProperties() 方法返回值中的顺序。
在一个复制名称的事件中,开放内容属性可以通过它的别名访问,前提条件是该别名和已有其它属性的名称、别名不冲突。
数据对象的当前状态( current state
数据对象的 current state 包含所有用来区分其与由 DataFactory 创建的新对象的值,因为由 DataFactory 新创建的对象还没有属性集合和容器。数据对象的当前状态是 getInstanceProperties() 方法返回值中所有 isSet() 为真的属性。容器和包含内容属性是包含该数据对象的数据对象的状态的一部分。下列程序将打印出数据对象 myDO 的当前状态:
for (int i=0; i
{
Property p = (Property) myDo.getInstanceProperties().get(i);
if (myDo.isSet(p))
{
System.out.println(p.getName()+"="+myDo.getString(i));
}
}
数据对象接口
public interface DataObject extends Serializable
{
Object get(String path);
void set(String path, Object value);
boolean isSet(String path);
void unset(String path);
数据图( DataGraph )是拥有一个更改摘要( ChangeSummary )的数据对象图的可选信封。
为了获取仅包含数据对象的数据图的同样的功能,数据对象可以使用 SDO 数据图 XSD 进行定义。
如更改摘要章节所述,一个更改摘要可以直接使用在数据对象身上。
数据图包含以下方法:
·             返回一个根数据对象;
·             如果数据图内没有根数据对象,创建一个根数据对象;
·             返回更改摘要;
·             基于 uri 和类似于 TypeHelper 的名字查找类型;
数据图接口
public interface DataGraph extends Serializable
{
DataObject getRootObject();
DataObject createRootObject(String namespaceURI, String typeName);
DataObject createRootObject(Type type);
ChangeSummary getChangeSummary();
Type getType(String uri, String typeName);
}
创建数据图
数据图由 DAS 创建, DAS 或者返回一个空数据图,或者返回一个包含数据对象的数据图。空数据图能够使用 createRootObject() 方法创建该数据图的根对象。如果在创建根数据对象时,数据图已经存在一个根数据对象,将会抛出一个 IllegalStateException 异常。
DAS 也负责创建供数据对象和数据图使用的元数据(数据模型)。例如,一个面向 XML 数据的 DAS 能够基于 XSD 建立该 XML 文件的模型。
修改数据图
为了修改一个数据图,程序需要使用 getRootObject() 方法访问根数据对象。基于对根数据对象的包含内容引用的递归遍历,该树形结构内的其它数据对象都能够被访问到。
访问类型
使用 getType(String uri, String typeName) 方法或通过 TypeHelper 可以访问类型( Type )。这将返回一个含有恰当的 URI 和名字的类型( Type )。对于 getType() 方法或者所有拥有 URI 参数的方法而言, URI 是一个如同 targetNamespace 这样的逻辑名。
DataGraph TypeHelper DataObject 的实现负责访问包含所请求的元数据的物理资源。物理资源可能是一个本地拷贝或者是一个网络资源。
基于实现所独有的配置文件,可以提供从逻辑到物理映射的必须配置信息。
如果元数据不可用,那么将会产生一个实现所独有的异常。
ChangeSummary 提供了访问数据图中数据对象的更改历史信息的机制。
更改历史覆盖了一个数据图自日志被激活开始的所有修改情况。如果日志不再处于激活状态,那么日志仅仅包括日志被冻结前的变更。否则它仅仅包括 ChangeSummary 被查询以来的变更情况。尽管只有在日志激活时,变更信息才开始被采集,但是无论无论日志被激活还是被关闭,你都可以查询变更信息。所有查询返回的信息都是只读的。
该接口具有下列方法:
·           激活或冻结日志。
  • 当日志开始时,重建一个DataObjects树,并且清除日志。
  • 查询日志状态。
  • 获取ChangeSummary所属的DataGraph
  • 获取ChangeSummary的根DataObject
  • 获取修改过的DataObject
  • 指出是否一个数据对象已经被创建、删除或被修改。
  • 在日志开始时,获取容器类型的DataObject
  • 在日志开始时,获取DataObject所包含的属性。
  • 在日志开始时,获取DataObjectSequence
  • 获取一个特殊的旧值。
  • 获取一个旧值列表。
启动或停止一个更改日志
beginLogging() 方法清除 ChangeSummary 中变更 DataObject 的列表并且启动一个更改日志。 endLogging() 方法停止更改日志。 undoChanges() 方法在日志开始时重建 DataObject 树, undoChanges() 方法同时也清除日志,但是对 isLogging() 方法没有任何影响。
注意: beginLogging(), endLogging() 以及 undoChanges() 方法基本上是给服务实现使用的,这是由于服务定义了如何将 ChangeSummary 的处理与外部资源进行关联。 ChangeSummary 如果不能捕获产生的变更,这将可能会引起服务基于 ChangeSummary 的不完整信息去执行数据源的更新。
作用范围( Scope
ChangeSummary 的作用范围被定义为自 ChangeSummary 根开始的 DataObject 树所包含的所有数据对象。 ChangeSummary 根对象是所有变更被跟踪的源 DataObject 。可以通过 getRootObject() 方法获取 ChangeSummary 根对象。该对象是下列之一:
·           ChangeSummary 作为其属性的一个值的数据对象。
·           数据图的根数据对象
旧值( Old Values
使用 getOldValues(DataObject dataObject) 方法可以取得一个旧值列表。旧值的返回顺序由实现具体决定。对于一个被删除的 DataObject ,旧值列表包含了该 DataObject 的所有属性。对于一个已经被修改过的 DataObject 来说,旧值列表仅仅包含被修改的属性。对于那些没有被删除和修改的 DataObject 来说,旧值列表为空。
旧值被描述为 ChangeSummary.Setting 对象( ChangeSummary.Setting ChangeSummary 的一个内部接口)。每一个 ChangeSummary.Setting 都有一个属性和一个值,同时还有一个用于指明属性是否为集合的标记。
如果一个 DataObject 被删除或修改,那么 getOldValue(DataObject dataObject, Property property) 方法将返回一个用于描述指定属性的 ChangeSummary.Setting ,否则,它将返回 null 。如果旧值的 setting.isSet() 方法返回 false ,则该旧值没有任何意义。
顺序数据对象( Sequenced DataObject
在日志开始时, getOldSequence(DataObject dataObject) 方法将返回一个数据对象顺序的全部值。返回值可能为 null 。如果 DataObject.getSequence() 方法返回 null ,那么 getOldSequence(DataObject dataObject) 方法将返回 null
序列化与反序列化
ChangeSummary 被反序列化时,如果 XML 文件中有 <changeSummary> 元素,那么其日志状态将为 on ,除非 changeSummary 标记日志为 off 。在下列条件下,一个序列化器必须在 XML 文件中生成一个 <changeSummary> 元素:
·           变更已经被日志记录( getChangedDataObjects().size() > 0 )。
  • 没有变更被日志记录,但是在序列化时,isLogging()方法为true。在该情况下,一个空<changeSummary/>或者 <changeSummary logging="true"/>元素被建立。
日志的状态被记录进 changeSummary 元素的 logging 属性。
ChangeSummary 的序列化在日志启动时,包含了足够多的用来重构 DataObject 初始信息的信息。当日志启动时,新创建的数据图中的属性标签 DataObject 将不会被显示出来,删除的包含在 ChangeSummary 中的属性标签对象将不再包含在数据图中。标签可以是 IDs ,如果可用的话,也可以是 sdo 路径表达式。
ChangeSummary 元素的内容可以是一个被删除的数据对象的深拷贝,也有可能是一个数据对象的原型,该原型仅仅拥有数据类型的变更以及已经改变过的属性的值。
关联更改摘要与数据对象
有两种可能的方式用于关联 DataObject ChangeSummary
1 1 DataGraph 使用 getChangeSummary() 方法获取一个 ChangeSummary
该方法通常在对于 DataObject 树而言 ChangeSummary 为外部的情况下采用。 ChangeSummary 从根数据对象开始跟踪数据对象树的变化,根数据对象可以通过 DataGraph getRootObject() 方法获得。
2 DataObject 的类型能够包括一个用于包含 ChangeSummary 的属性。
该方法常被用在 ChangeSummary DataObject 树的一部分的情形下,例如当一个根 DataObject 是一个消息头,该消息头同时包含 DataObject 以及 ChangeSummary 这二者的消息体。 ChangeSummary 从包含该 ChangeSummary DataObject 开始跟踪 DataObject 树的变化。
更改摘要接口
ChangeSummary 接口提供了下列方法:
·           检查日志的状态,或者开关日志;
  • 当日志开始时,重做日志里的所有变化;
  • 返回根DataObjectDataGraph
  • 返回已经被修改、创建或删除的DataObject
  • 识别出已经发生的改变类型(修改、创建、删除);
  • 返回已经被更改或删除掉的数据对象的旧值;
public interface ChangeSummary
{
void beginLogging();
void endLogging();
boolean isLogging();
void undoChanges();
DataGraph getDataGraph();
DataObject getRootObject();
List /*DataObject*/ getChangedDataObjects();
boolean isCreated(DataObject dataObject);
boolean isDeleted(DataObject dataObject);
boolean isModified(DataObject dataObject);
DataObject getOldContainer(DataObject dataObject);
Property getOldContainmentProperty(DataObject dataObject);
Sequence getOldSequence(DataObject dataObject);
public interface Setting
{
Object getValue();
Property getProperty();
boolean isSet();
}
Setting getOldValue(DataObject DataObject, Property property);
List /*Setting*/ getOldValues(DataObject dataObject);
}
顺序是一个设置( settings )的有序集合。顺序的每一个入口都有一个索引。
顺序的关键点是设置的顺序可以被保存,跨越多个不同属性之间的设置也可以被保存。因此,如果属性 A 被更新了,接着属性 B 被更新,最后属性 A 又被更新,则一个顺序可以反映这个过程。
每一个设置都是一个属性和值对。SDO文本属性,具有一个使用文本的快捷方式。
非结构化的文本
使用SDO文本属性,非结构化的文本可以被添加入顺序。 add(String text) 方法使用SDO文本属性添加一个新的入口到顺序的末尾。 add(int index, String text) 方法使用SDO文本属性将一个新的入口添加到顺序中指定索引的位置。
使用顺序
顺序经常用在处理半结构化业务数据时,例如混有文本的 XML 元素。假定一个顺序有两个多值属性,分别为 numbers (整型属性)和 letters (字符串型属性)。同时,假定顺序被如下初始化:
1.        1 被加入到 numbers 属性。
  1. 字符串annotation text被添加到顺序中。
  2. A被添加到letters属性。
  3. 2被加入到numbers属性。
  4. B被添加到letters属性。
则初始化结束后,顺序包含如下设置:
{<numbers, 1>, <text, ”annotation text”>, <letters, ”A”>, <numbers, 2>, <letters, ”B”>}
numbers 属性被设置为 {1, 2} letters 属性将被设置为 {“A”, ”B”}, ,但是如果只是使用访问器( accessors )而不使用顺序的话,则将无法获得跨越 numbers 属性和 letters 属性的设置顺序。
顺序和数据对象的比较
数据对象跟踪属性和值的顺序的方式与顺序( Sequence )使用的跟踪方式很不同。
数据对象是不保存添加到其之中的不同属性之间的顺序的。在一个多值属性的情况下,添加到该属性的不同值之间的顺序是可以保存的,但是当值被加入到两个不同的属性时,就没有办法知道哪一个属性被先设置了。在一个顺序内,对于多个属性的设置顺序是可以被保存的。
顺序( Sequence )内出现的相同属性同样可以通过数据对象获得,但是数据对象没有保存多个属性设置的顺序( order )。
注意如果数据对象的类型是一个顺序类型(即 getType().isSequenced() 返回值为 true ),那么该数据对象将有一个顺序( Sequence )。
顺序的方法:
·             size() 方法返回顺序上的入口的数目。
  • getProperty(int index) 访问器返回指定索引位置的属性。
  • getValue(int index)访问器返回指定索引位置的值。
  • setValue(int index, Object value) 访问器更新指定索引位置的值并且维护顺序的位置。
  • 布尔型add()访问器添加到顺序的末尾。
  • add(int index, String text) 访问器在指定的索引位置添加非结构化的文本。
  • add(String text)访问器将非结构化文本添加到顺序的末尾。
  • 其它add(int index)访问器将一个特定的位置添加到顺序中,如同java.util.List,将其后位置的接口依次加一。
  • remove()方法移走指定索引位置的入口并且将其之后位置的索引依次减一。
·             move() 方法移走从 fromIndex toIndex 之间的入口。
为了在顺序的末尾创建数据对象,可以使用数据对象的 create() 方法。
顺序接口
public interface Sequence
{
int size();
Property getProperty(int index);
Object getValue(int index);
Object setValue(int index, Object value);
boolean add(String propertyName, Object value);
boolean add(int propertyIndex, Object value);
boolean add(Property property, Object value);
void add(int index, String propertyName, Object value);
void add(int index, int propertyIndex, Object value);
void add(int index, Property property, Object value);
void add(int index, String text);
void add(String text);
void remove(int index);
void move(int toIndex, int fromIndex);
}

类型接口表达了一个数据对象模型或者数据类型的普通视图。
大多数编程语言或者数据建模语言都有数据类型概念; SDO 类型与其它数据类型类似。除非该类型为一个简单数据类型,否则一个SDO类型均有一个属性对象集合。
SDO 类型到编程语言和数据建模语言类型的映射
Java, C++, UML 或者 EMOF
·             可以使用SDO类型表达类。
·             类的每一个属性可以表达为一个SDO属性。
XML Schema
·             可以使用SDO类型表达复杂或简单类型。
·             元素和属性可以使用SDO属性表达。
C 结构体
·             可以使用SDO类型表达 C 结构体。
·             结构体的每一个域可以使用SDO属性表达。
关系数据库
·             表可以表达为一个SDO类型。
·             列可以表达为一个SDO属性。
上述领域均共享某些概念,SDO类型和属性接口表达了上述概念的一个小子集。这些接口对于数据对象编程者来说是有用的,因为其需要内省运行期的数据形状和本质。
表达所有特定领域信息的比较完整的元模型 API (例如, XML Schema 或者 EMOF )超出了本规范的范围。
类型内容
一个类型总是有:
·             名字——同一个 URI 内类型之间的一个唯一的字符串。
·             URI ——一个包的逻辑 URI 或者是一个目标命名空间,这取决于你的观点。
·             用于指明该类型为开放的、抽象的、顺序的、还是一个数据类型的布尔型域。
一个类型可能拥有:
  • 属性——由该类型定义的属性对象列表。与简单数据类型一致的类型则没有定义属性。
  • 实例类——用来实现SDO类型的java.lang.Class
如果 DataType 为真,那么一个类型必须拥有一个实例类。例如象 java.lang.Integer java.lang.String 这样的类。
如果 DataType 为假,并且使用了由代码生成器生成的代码,那么一个实例类是可选的。例如象 PurchaseOrder Customer 这样的类。
  • 别名——包含额外名字的字符串。在同一个URI内,别名必须是唯一的。
类型上所有基于名字进行操作的方法也可以使用别名进行操作。例如,一个类型可以被赋予一个该领域的别名:一个名为 PurchaseOrderType XML Schema ,一个 Java PurchaseOrder 和一个数据库表名 PRCHORDR
名字的唯一性
在一个 URI 内,类型名字和类型别名都是唯一的。在一个类型和任何一个基础类型内,属性名和属性别名都是唯一的。
SDO 数据类型
SDO 为其所支持的普通数据类型定义了类型( Type ),以便于在定义服务使用的类型和属性时保持一致。详细内容参见 “Standard SDO Types” 章节。
多重继承
通过允许多个基础类型,类型( Type )支持多重继承。使用多重继承时,使用 getProperties() 方法获得的属性顺序可以不同于一个类型和基础类型的顺序。
类型方法
  • getName()方法返回一个类型名字。
  • getURI方法返回该类型的URI
  • getInstanceClass()方法返回实现SDO类型的类。
  • 如果指定的对象是该类型的实例,isInstance(Object object)方法将返回真。
  • 如果该类型用于描述DataType,那么isDataType()方法返回真,如果其用于描述DataObject,则返回假。
  • 如果该类型描述了顺序型数据对象,那么isSequenced()方法返回真,当其为真时,数据对象能够返回一个顺序(Sequence)。
  • 如果该类型允许开放内容,那么isOpen()方法返回真。如果返回值为假,那么dataObject.getInstanceProperties()返回值必定与该类型的任何一个数据对象的dataObject.getType().getProperties()方法返回值相同。
  • 如果类型是抽象的,那么isAbstract()方法返回真,并且该类型不能被实例化。抽象类型不能够用在数据对象或数据工厂(DataFactory)的创建方法中。抽象类型常被用作实例化类型的基础类型。
  • getBaseTypes()方法将返回该类型的基础类型列表。如果没有基础类型,该列表为空。XSD <extension>, <restriction>Java“extends”关键字被映射到基础类型列表。
  • getAliasNames()返回该类型的别名列表。如果没有别名,则该列表为空。
  • getProperties()方法返回该类型的所有属性,包括那些在基础类型中声明的属性。
  • getDeclaredProperties()方法用于获取该类型中声明的属性,对基础类型中声明的属性无效。
  • getProperty(String propertyName)方法返回一个特殊的属性,在没有指定名称的属性时返回null
类型接口
public interface Type
{
String getName();
String getURI();
Class getInstanceClass();
boolean isInstance(Object object);
boolean isDataType();
boolean isSequenced();
boolean isOpen();
boolean isAbstract();
List /*Type*/ getBaseTypes();
List /*String*/ getAliasNames();
List /*Property*/ getProperties();
List /*Property*/ getDeclaredProperties();
Property getProperty(String propertyName);
}
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值