7C3EF93EEBC6EB4A8B4470853DE86566DEEDF2@dewdfe18.wdf.sap.corp
type="cite">
4.3 ChangeSummary
A ChangeSummary provides access to the changes
made to the DataObjects in a data graph, comparing the data graph’s “before”
state to its “after” state. The “before” state is the state of the
data graph at the time when logging was activated. If logging is no longer
active, the “after” state is the state of the graph when logging was
deactivated. This means that only changes that were made up to the point
when logging was deactivated are included in the ChangeSummary. Otherwise, the
ChangeSummary includes all changes up to the point at which the it is
interrogated. The ChangeSummary contains only net changes, transient
values that are assigned to properties after logging begins, but which are
overwritten before logging is deactivated are not visible throught the change
summary. Although change information is only gathered when logging is
on, the ChangeSummary can be queried whether logging is on or off. All of the
information returned is read-only.
The ChangeSummary interface has
methods that:
- Activate and deactivate
logging.
- Restore a tree of DataObjects to
the state it was in when logging began and clear the log.
- Query the logging
status.
- Get the ChangeSummary’s root
DataObject.
- Get the list of changed
DataObjects.
- Indicate whether a DataObject in
the list of changed DataObjects has been created, deleted or
modified.
- Get a DataObject’s container
DataObject at the point when logging began.
- Get a DataObject’s containment
property at the point when logging began.
- Get a DataObject’s Sequence at
the point when logging began.
- Get a specific old
value.
- Get a list of old values.
4.3.1 Starting and Stopping Change Logging
ChangeSummary.beginLogging() clears
the ChangeSummary’s list of changed DataObjects and starts change logging.
ChangeSummary.endLogging() stops change logging. ChangeSummary.undoChanges()
restores the data graph to its state when logging began.
ChangeSummary.undoChanges() also clears the log, but does not affect
isLogging().
NOTE: The beginLogging(), endLogging() and undoChanges() methods are
intended primarily for the use of service implementations since services
define how the processing of a ChangeSummary relates to external resources.
Making changes that are not captured in the ChangeSummary may cause services
that drive updates from a ChangeSummary to act on incomplete
information.
4.3.2 ChangeSummary Root
ChangeSummaries become associated with
DataObjects when the DataObject includes a Property with type
ChangeSummaryType. The ChangeSummary root is the DataObject having the
ChangeSummary property. ChangeSummary.getRootObject() MUST return the
ChangeSummary root. Calling DataObject.getChangeSummary() on the
ChangeSummary root, or on any DataObject contained, directly or indirectly, by
the ChangeSummary root, MUST return the same ChangeSummary object. It
MUST also be possible to retrieve this object using
DataObject.get(“changeSummaryProperty”) where “changeSummaryProperty” is the
name of a property whose Type is ChangeSummaryType. The following rules
and restrictions apply to ChangeSummary properties:
- Types are allowed to contain at
most one property with type ChangeSummaryType.
- A property with type
ChangeSummaryType must have many=false and readOnly=true.
- The scope of ChangeSummaries may
never overlap. If a DataObject has a property of type ChangeSummary, it
cannot be directly or indirectly contained or otherwised referenced by any
other DataObjects that have a property of type ChangeSummay.
- When the DataObject containing
the ChangeSummary is created, logging is by default off. Before any
changes will be logged, ChangeSummary.beginLogging() must be
called.
- The ChangeSummary will not
contain the creation or deletion of its containing
DataObject.
- The ChangeSummaryType MAY NOT be
used to define OpenContent properties.
4.3.3 ChangeSummary Scope
The scope of a ChangeSummary is defined as the
set of DataObjects reachable from the ChangeSummary root either through
containment or over any orphanHolder properties. In other words the
scope of the change summary is the same set of DataObjects that would be in
the sub-tree whose root node is ChangeSummary root, if the graph were
serialized to XML
DataObjects that were in the
ChangeSummary scope when logging was activated but are not in the scope when
logging was deactivated (or when ChangeSummary.getChangedObjects() was called,
if logging is still active) and which are not themselves contained by a
deleted DataObject MUST be appear in the ChangeSummary as deleted.
DataObjects that were not in the ChangeSummary scope when logging was
activated , but are in scope when logging was deactivated (or when
ChangeSummary.getChangedObjects() was called, if logging is still active) and
which are not themselves contained by a created DataObject MUST be appear in
the ChangeSummary as created. Other DataObjects within the ChangeSummary
scope whose property values changed during the time that logging was activated
MUST appear in the ChangeSummary as modified.
4.3.4 OrphanHolder Properties
Although orphanHolder properties play a role
in determining the scope of the ChangeSummary, changes to the orphanHolder
properties themselves are not tracked. If the only change to the
ChangeSummary root is to the contents of its orphanHolder properties, the
object itself MUST NOT be contained in the ChangeSummary as a modified.
OrphanHolder properties MUST NOT
appear in the getOldValues, getOldSequence lists.
The following restrictions apply to the use of
orphanHolder properties together with ChangeSummaries.
1. If an orphan DataObject is referenced from within the
scope of a ChangeSummary, and if an object with a matching orphanHolder
property is contained, either directly then the object is in scope of the
ChangeSummary. When the change summary root is serialized using
XMLHelper.save, then the orphan DataObject must be serialized as being
“contained” by the ChangeSummary root’s orphanHolder
property.
2. All orphanHolders associated with the
ChangeSummary root or any DataObjects contained, directly or indirectly by
the ChangeSummary root MUST be considered in determining the scope.
3. Implementations MAY ignore orphanHolder properties on
DataObjects that themselves are orphans.
4.3.5 Old Values
A List of old values can be retrieved using the
getOldValues(DataObject dataObject) method. The order of old values returned
is implementation dependent. For a deleted DataObject, the old values
List contains all the properties of the DataObject. For a DataObject that has
been modified, the old values List consists of the modified properties only.
For a DataObject that has not been deleted or modified, the List of old values
is empty.
Individual languages MAY return a
list of changed properties or a list of objects which contain the old value,
the property, and other information if desired. If a list of objects is
returned, then getOldValue and isOldSet are methods on the returned
objects.
4.3.6 Sequenced DataObject
getOldSequence(DataObject dataObject) returns
the entire value of a DataObject’s Sequence, at the point when logging began.
This return value can be null. If DataObject.getSequence() returns null then
getOldSequence(DataObject dataObject) will return null.
4.3.7 Serialization and Deserialization
When a ChangeSummary is
deserialized, the logging state will be on if a <changeSummary> element
is present in the XML unless the changeSummary marks logging as off. A
serializer must produce a <changeSummary> element in the XML if either
of the following conditions applies:
- Changes have been logged
(getChangedDataObjects().size() > 0).
- No changes have been
logged but isLogging() is true at the time of serialization. In this case, an
empty <changeSummary/> or <changeSummary logging="true"/>
element must be produced.
The state of logging is recorded in
the logging attribute of the changeSummary element.
The serialization of a ChangeSummary
includes enough information to reconstruct the original state of all
DataObjects in its scope, at the point when logging was turned on. Each
individual object removed from the data graph must be recorded in the
ChangeSummary serialization in order to perform this reconstruction. The
create attribute labels DataObjects currently in the data graph that were not
present when logging started, and the delete attribute labels objects
contained in the change summary that are no longer in the data graph. Labels
are space-separated lists of either IDs, if available, or XPath expressions.
The contents of a ChangeSummary
element are either deep copies of the objects at the point they were deleted,
or a prototype of an object that has had only data type changes, with values
for the properties that have changed value.
4.3.8 ChangeSummary Interface
The type returned by getOldValue, and
the types in the List returned by getOldValues is implementation language
dependent.
_______________________________________________________________________________________________________________
6.4 SDO Type and Property
constraints
There
are several restrictions on SDO Types and Properties. These restrictions
ensure Types and Properties for DataObjects are consistent with their API
behavior. Behavior of ChangeSummaryType Properties is
defined.
Instances of Types with
dataType=false must implement the DataObject interface.
Values of
bidirectional Properties with type.dataType=false and many=true must be unique
objects within the same list.
Values of Properties with type.dataType=false and many=true cannot
contain null.
Property.containment has no effect unless
type.dataType=false.
Property.default!=null requires type.dataType=true and
many=false
Types with
dataType=true cannot contain properties, and must have open=false and
sequenced=false.
Type.dataType and sequenced must have the same value as their base
Types' dataType and sequenced.
Type.open may only be false when the base Types' open are
also false.
An
implementation is not required to modify pre-existing types when derived types
are defined.
Properties that are bidirectional require
type.dataType=false
Properties that are bidirectional require that no more than one end has
containment=true
Properties that are bidirectional require that both ends have the same
value for readOnly
Properties that are bidirectional with containment require that the
non-containment Property has many=false.
Names and aliasNames must all be unique within
Type.getProperties()
_______________________________________________________________________________________________________________
11.2
Inclusion of Orphaned Objects
As discussed in section 4.3.3, if the ChangeSummary root
contains orphanHolder properties, the orphaned objects that are associated
with these holders are also in the scope of the
ChangeSummary.
As discussed in section 4.3.4,
changes to the orphanHolder properties themselves are not tracked as
modifications.
This has the consequence that modified and deleted orphans always
appear as top level elements in the changeSummary XML. Other than this,
there are no special rules for the serialization the changes associated with
orphaned DataObjects.
11.3 Example Use of ChangeSummary on a
DataObject
We
begin with a model that is specified without a containment structure. In
this example, we use a simple model of an organization, with types
representing the company, its departments and their employees. For
clarity, we specify the model using XSD:
<?xml version="1.0"
encoding="UTF-8"?>
<schema
xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://sdo.example"
xmlns:tns="http://sdo.example" xmlns:sdox="commonj.sdo/xml">
<element name="Company" type="tns:Company" />
<complexType name="Company">
<sequence>
<element name="department" type="string" sdox:propertyType="tns:Department"
minOccurs="0" maxOccurs="unbounded"
/>
</sequence>
<attribute name="name" type="string" sdox:key="true"
/>
</complexType>
<complexType name="Department">
<sequence>
<element name="employee" type="string" sdox:propertyType="tns:Employee"
minOccurs="0" maxOccurs="unbounded"
/>
</sequence>
<attribute name="name" type="string" sdox:key="true"
/>
</complexType>
<complexType name="Employee">
<attribute name="name" type="string" sdox:key="true"
/>
<attribute name="salary" type="int" />
</complexType>
</schema>
Let us suppose that the client
receives the following document from the server.
<?xml version="1.0"
encoding="UTF-8"?>
<sdo:datagraph
xmlns:sdo="commonj.sdo" xmlns:ex="http://sdo.example" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<changeSummary logging="true"/>
<ex:Company name="Acme">
<department>Sales</department>
<department>Manufacturing</department>
</ex:Company>
<orphanHolder xsi:type="ex:Department" name="Sales">
<employee>Ron</employee>
<employee>Stefan</employee>
</orphanHolder>
<orphanHolder xsi:type="ex:Department" name="Manufacturing">
<employee>Stefan</employee>
<employee>Ulf</employee>
</orphanHolder>
<orphanHolder xsi:type="ex:Employee" name="Ron" salary="2"/>
<orphanHolder xsi:type="ex:Employee" name="Ulf" salary="2"/>
<orphanHolder xsi:type="ex:Employee" name="Stefan" salary="2"/>
</sdo:datagraph>
After deleting the "Sales"
department, changing a salary and adding a new employee to Manufacturing,
calling XMLHelper.save returns the following document:
<?xml version="1.0"
encoding="UTF-8"?>
<sdo:datagraph
xmlns:sdo="commonj.sdo" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ex="http://sdo.example">
<changeSummary create="#/orphanHolder.3"
delete="#/changeSummary/orphanHolder.2
#/changeSummary/orphanHolder.3">
<ex:Company
xsi:type="ex:Company"
sdo:ref="Acme">
<department
sdo:ref="Sales"></department>
<department
sdo:ref="Manufacturing"></department>
</ex:Company>
<orphanHolder xsi:type="ex:Department" sdo:ref="Manufacturing">
<employee
sdo:ref="Stefan"></employee>
<employee
sdo:ref="Ulf"></employee>
</orphanHolder>
<orphanHolder xsi:type="ex:Employee" sdo:ref="Stefan" salary="2"></orphanHolder>
<orphanHolder xsi:type="ex:Employee" name="Ron" salary="2"></orphanHolder>
<orphanHolder xsi:type="ex:Department" name="Sales">
<employee>Ron</employee>
<employee>Stefan</employee>
</orphanHolder>
</changeSummary>
<orphanHolder xsi:type="ex:Department" name="Manufacturing">
<employee>Stefan</employee>
<employee>Ulf</employee>
<employee>Frank</employee>
</orphanHolder>
<orphanHolder xsi:type="ex:Employee" name="Stefan" salary="3"></orphanHolder>
<orphanHolder xsi:type="ex:Employee" name="Ulf" salary="2"></orphanHolder>
<orphanHolder xsi:type="ex:Employee" name="Frank" salary="2"></orphanHolder>
<ex:Company name="Acme">
<department>Manufacturing</department>
</ex:Company>
</sdo:datagraph>