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所包含的属性。
在日志开始时,获取DataObject的Sequence。
获取一个特殊的旧值。
获取一个旧值列表。
启动或停止一个更改日志
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接口提供了下列方法:
· 检查日志的状态,或者开关日志;
当日志开始时,重做日志里的所有变化;
返回根DataObject和DataGraph;
返回已经被修改、创建或删除的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属性。
字符串annotation text被添加到顺序中。
值A被添加到letters属性。
值2被加入到numbers属性。
值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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值