← Prev in month ← Prev in thread
Next in thread → Next in month →

AW: [sdo] ISSUE 44: ChangeSummary semantics

From
Barack, Ron <>
Date
2009-09-07T14:56:11+00:00
ID
Thread
AW: [sdo] ISSUE 44: ChangeSummary semantics
Title: ISSUE 44: ChangeSummary semantics

Hi Everyone,

 

After some discussion on recent calls, I decided to look at 
the specification for what would actually have to be changed here.  I 
actually think my reworking of the text on change summary, specifically 4.2.3, 
unintentially decided this issue.  If we accept the text as is, then I 
believe we can close ISSUE 44 as a duplicate.

 

To save everyone opening the document, here is the relevant 
text:

 

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 appear in the 
ChangeSummary.changedObjects list, and passing the DataObject to 
ChangeSummary.isDeleted MUST return true [COR04020301] 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.changedObjects list, 
and passing the DataObject to ChangeSummary.isCreated MUST return 
true.[COR04020302] DataObjects that remained 
in the ChangeSummary scope and whose property values changed during the time 
that logging was activated MUST appear in the ChangeSummary.changedObjects list, 
and passing the DataObject to ChangeSummary.isModified MUST return true. 
[COR04020303].  The 
changeObject MUST NOT contain any objects other than those meeting the defined 
criteria. [COR04020304].  

So, in other words, to be deleted, an object has to have 
been removed from the scope, a created object must be new in the scope.  We 
are talking here about instances of DataObjects, not about objects that have 
identical XML serializations.

 

One of the things I've at least tried to clean up is 
for chapter 10, Change Summary XML Format, to focus on...ummm...the XML format 
only, not on defining, or redefining the contents of the change summary.  
After all, the goal is for the ChangeSummary to have the same values before 
serialization and after deserialization, for the change summary to survive 
unaltered the roundtrip, therefore the XML serialization shouldn't go about 
changing the definition of these values.

 

The only place I expect that the described behavior 
will be surprising to users is when DataObject.delete() is called.  A 
"deleted" object that is returned to the graph is also shown as a move...which 
is surprising, to say the least.  Also, although a deleted object is 
implicitly detached, it is may still be a referenced orphan.  Then the 
resulting graph still contains the deleted object, just with all its properties 
unset.  Ugly.

 

The most direct solution is to simply deprecate the 
delete method.  Do we really expect application to implement the kind of 
DataObject pooling that delete seems to imply?  

 

An alternative approach is for objects on which 
"delete" was called to always be renedered as deleted.  If we ignore the 
pooling of DataObjects use-case, we could also add a restriction that deleted 
DataObjects not be re-used.

 

Comments?

 

Ron

Von: Barack, Ron [mailto:] 

Gesendet: Montag, 18. Mai 2009 15:41
An: 

Betreff: [sdo] ISSUE 44: ChangeSummary 
semantics

Hi Everyone, 

I realize that I may getting too far ahead of the 
group here, but I want to write down my thoughts on this issue:  sooner or 
later we must address it in the TC.

When an object is moved from one container to 
another, so long as both are within the scope of the same ChangeSummary, the 2.1 
spec allows for 2 possible interpretations, as far as the ChangeSummary is 
concerned.  The object may simply be moved (that is, the object itself is 
not changed, but the old container loses a reference to it), or the object may 
be deleted from the old container, and created in the new container.

I realize this will be a very sensitive issue: as 
soon as we decide one way or the other, we are breaking someone's backwards 
compatibility.  The trouble is, this is a pretty large whole to have been 
left open.  It makes it very hard to write a DAS that is independent of the 
SDO client, the DAS has to be programmed for different interpretations of the 
CS, and users that access the CS themselves never know what to 
expect.

To make things concrete, let's start with a code 
sample: 

        DataObject 
root = DataFactory.INSTANCE.create("commonj.sdo","DataGraph"); 
            
DataObject company = DataFactory.INSTANCE.create("example","Company"); 

        DataObject dept1 = company.createDataObject("department"); 

            
DataObject dept2 = company.createDataObject("department"); 
            
DataObject child = dept1.createDataObject("employee"); 

        root.getChangeSummary().beginLogging(); 

        dept2.getList("employee").add(child); 

        root.getChangeSummary().endLoggin(); 

If we want to depict this as a "move", the following 
unit test would look like this: 

        assertFalse(root.getChangeSummary().isModified(child)); 

        assertFalse(root.getChangeSummary().isCreated(child));  

        assertFalse(root.getChangeSummary().isDeleted(child));  

        assertTrue(root.getChangeSummary().isModified(dept1)); 

        assertTrue(root.getChangeSummary().isModified(dept2)); 

The XML looks like this 

<DataGraph> 

        <ChangeSummary> 

        
        <Department ref="Company/Department[1]"> 

        
        
        <Employee 
ref="Company/Department[2]/Employee[1]/> 

        
        </Department> 
        
        <Department ref="Company/Department[2]" 
sdox:unset="Employee"/> 
        
</ChangeSummary> 

        <Company> 
           
             
<Department> 
        
        </Department> 
        
        <Department> 
        
        
        <Employee/> 
        
        </Department> 
        
</Company> 
</DataGraph> 

By contrast, if we we wanted to use create/delete, 
then the test would be something like this: 

        assertFalse(root.getChangeSummary().isModified(child)); 

        assertTrue(root.getChangeSummary().isCreated(child));   // Is 
this correct? 
        assertTrue(root.getChangeSummary().isDeleted(child));   // Is 
this correct? 
        assertTrue(root.getChangeSummary().isModified(dept1)); 

        assertTrue(root.getChangeSummary().isModified(dept2)); 

And the XML would look like: 

<DataGraph> 

        <ChangeSummary deleted="ChangeSummary/Department[1]/Employee[1]" 
created="Company/Department[2]/Employee[1]"> 

        
        <Department ref="Company/Department[1]"> 

        
        
        <Employee/> 
        
        </Department> 
        
        <Department ref="Company/Department[2]" 
sdox:unset="Employee"/> 
        
</ChangeSummary> 

        <Company> 
           
             
<Department> 
        
        </Department> 
        
        <Department> 
        
        
        <Employee/> 
        
        </Department> 
        
</Company> 
</DataGraph> 

The result coming from deserializing the XML gives a 
different ChangeSummary than the one we had before serialization.  Namely, 
the following:

        DataObject 
root = XMLHelper.INSTANCE.load(…).getRootObject(); 

        DataObject company = root.getDataObject(0); 

        DataObject dept1 = company.getList("department").get(0); 

        DataObject dept2 = company.getList("department").get(1); 

        DataObject child = dept2.getList("employee").get(0); 

        assertFalse(root.getChangeSummary().isModified(child)); 

        assertTrue(root.getChangeSummary().isCreated(child));   

        assertFalse(root.getChangeSummary().isDeleted(child));  

        assertTrue(root.getChangeSummary().isModified(dept1)); 

        assertTrue(root.getChangeSummary().isModified(dept2)); 

        DataObject 
deleted = root.getChangeSummary().getChangedObjects()… 

        assertFalse(root.getChangeSummary().isCreated(child));  

        assertTrue(root.getChangeSummary().isDeleted(child));   

I think these two behaviours are too diverent, we 
should really try to reconcile them. 

Our implementation takes the "move" approach.  I 
would argue that this is the approach that obeys the "priciple of least 
surprise".  Being able to roundtrip to XML is also a major 
advantage.

I've heard two arguments for the create/delete 
approach: 

1)  That containment "means" aggregation, and 
therefore that "moving" things between containers is nonsence.  What looks 
like a move is actually a delete/create.  The problem with this argument is 
that there is absolutely nothing else in the spec or the API that supports 
it.  For instance, if moving an object between two containers is 
impossible, then we should not allow it.  That is, the statement 
"dept2.getList("employee").add(child)" in the above code sample should throw an 
exception.  Actually, I'd be really happy to discuss this approach, and it 
certainly would clear up problems like "isCreated" and "isDeleted" both 
returning true.  On the other hand, this is a breaking change.

2)  That we should be able to calculate the 
change summary based on diff'ing the XML generated "before" and "after" the 
changes.  If we follow this argument to ist logical consequences, don't we 
also run into a bunch of other nasty problems.  Isn't it true that, from 
looking at the XML, you cannot distinguish any modification from a delete 
followed by a create?   And I never understood the role of XML is the 
calculation.  That's not to say that the CS cannot be calculated by 
diff'ing two graphs, but I am saying that the CS cannot necessarily be 
calculated by diff'ing the XML representation of the graphs.

Looking forward to an intersting discussion on this 
one! 

Best Regards, 
Ron
← Prev in month ← Prev in thread
Next in thread → Next in month →