| Summary: | getOldValue call on Notification from CDO returns null as opposed to old value | ||
|---|---|---|---|
| Product: | [Modeling] EMF | Reporter: | Dan Pollitt <dan.s.pollitt> |
| Component: | cdo.core | Assignee: | Eike Stepper <stepper> |
| Status: | CLOSED DUPLICATE | QA Contact: | |
| Severity: | normal | ||
| Priority: | P3 | CC: | chewbizz, christian.mohr, dan.s.pollitt, esteban.dugueperoux, stepper |
| Version: | 4.6 | ||
| Target Milestone: | --- | ||
| Hardware: | PC | ||
| OS: | Windows 7 | ||
| Whiteboard: | |||
|
Description
Dan Pollitt
Just to include other comments from newsgroup discussion: I am setting the reference in a CDOTransaction in the same VM. The adapters view has already loaded the object being adapted as well as the old and new reference objects. .. I need the old value in order to perform some fine-grained updates on a JFace Viewer. Also setting: CDOView.Options.setInvalidationPolicy(CDOInvalidationPolicy.RELAXED) didn't seem to alter the behaviour. Moving all open issues to 4.2. Open bugs can be ported to 4.1 maintenance after they've been fixed in master. No activity or ping here for almost a year. And not test case. Please reopen this bug if you feel a need. From the newsgroup: having classes 'A' and 'B', with 'A.b' referencing/containing instances of 'B', I stumbled over the following oddity when setting 'A.b' to null: Other "local" views and transactions [from same CDOSession] do *not* get notified when 'A.b' is set to 'null', but they get notified when the reference is changed to another instance of 'B'. In other clients ["remote"], changes are visible immediately -- regardless if 'A.b' is set to 'null' or another instance of 'B'. (So the client which sets to 'null' does NOT reflect the changes, but all other clients do so) On the one hand I might have overseen something obvious to those who know what they're doing, on the other hand I'm a bit confused why things work for "remote" clients as expectedly. In short: EMFObservables.observeValue((A) instance, (EReference) bReference); (Value)ChangeListeners fire for local modifications != 'null', and all remote modifications regardless of value. ===== Looking deeper into the matter, something seems to be wrong with 'oldValue's of Notifications. Btw, this is Eclipse 4.3.1 with CDO 4.2 20130918 on Linux. As mentioned, my application (= e.g. bound Viewers..) does not react on the "local" change of a reference to value 'null'. Viewers and listeners react on changing references to *other* (non-null) values, and they react on changes to value 'null' when the change was committed from another session(sic). Bug 367738, result of ~2 years old thread "[CDO] Notification#getOldValue always null?", was apparently closed to sudden lack of any interest. [ https://bugs.eclipse.org/bugs/show_bug.cgi?id=367738 ] According to that thread, the original poster encountered unexpected 'oldValue's valued 'null'. My problem also seems to be related to getting unexpected 'oldValue's of value 'null'". My (local) Viewers do not react, because method "isTouch", in class org.eclipse.emf.common.notify.impl.NotificationImpl for event-types (non-primitive-)SET and UNSET returns: oldValue == null ? newValue == null : oldValue.equals(newValue) In my case (local change), and --probably same issue as for the creator of bug 367738--, 'oldValue' is (incorrectly? but always) null, so when newValue [UNSET/SET value 'null'] is 'null', too - local Viewers will not update. -- For me personally I hacked kindof if type==UNSET then oldValue=new Object() into org.eclipse.emf.internal.cdo.object.CDONotificationBuilder to fool this rule, and .. I do get my updates. -- I personally am too new to all this to dare to call this a bug, but when changing a reference from "anything non-null" to "null", or when unsetting a reference, oldValue should not be null. I've added a test case:
public class Bugzilla_367738_Test extends AbstractCDOTest
{
public void testNotificationOldValue() throws Exception
{
Company company = getModel1Factory().createCompany();
company.setName("ESC");
CDOSession session = openSession();
CDOTransaction transaction = session.openTransaction();
CDOResource resource = transaction.createResource(getResourcePath("/test1"));
resource.getContents().add(company);
transaction.commit();
TestAdapter adapter = new TestAdapter();
company.eAdapters().add(adapter);
company.setName(null);
Notification[] notifications = adapter.getNotifications();
assertEquals("ESC", notifications[0].getOldValue());
}
}
It does not fail. It could be that I don't test for the right thing but I also vaguely remember that we did something with respect to oldValues in this current stream. Have you already tried your scenario with the latest CDO 4.3 builds?
Hi, we're having this problem too, and i tried to debug it. I'll try to describe the things i noticed. I hope they help.
1. In the CDONotificationBuilder.visit(CDOSetFeatureDelta delta) you are calling getOldValue(feature). There the oldRevision is null and null is returned. Next there is only a check if oldValue is a CDOID, but not if it is an attribute (e.g String). So the oldValue stays null. For our configuration, we have auditing/branching off and i used h2 for the tests.
A modified Version of your Test:
public void testOldValue_Attribute() throws Exception
{
CDOID id;
Company company = getModel1Factory().createCompany();
company.setName("ESC");
CDOSession session = openSession();
CDOTransaction transaction = session.openTransaction();
CDOResource resource = transaction.createResource(getResourcePath("/test1"));
resource.getContents().add(company);
transaction.commit();
id = CDOUtil.getCDOObject(company).cdoID();
CDOView view = session.openView();
Company companyView = (Company)view.getObject(id);
TestAdapter adapter = new TestAdapter();
companyView.eAdapters().add(adapter);
company.setName(null);
transaction.commit();
sleep(10000);
Notification[] notifications = adapter.getNotifications();
Object oldValue = notifications[0].getOldValue();
assertEquals("ESC", oldValue);
}
2. Maybe the same problem is with CDONotificationBuilder.visit(CDORemoveFeatureDelta delta). Here its not the old value, but the detachedObjects (it contains references to "invalid" objects). Frameworks like Incquery expect a reference to the "invalid" removed Object, to determine which element was removed. If there is just one detachedObject it is possible to send it as oldValue, but with more than one there will have to be more than one notification. What do you think about that?
I hope you can use this information.
I have executed the test of https://bugs.eclipse.org/bugs/show_bug.cgi?id=367738#c6 and indeed it fails with non auditing because when adding the new CDORevision of Company in CDORevisionCacheNonAuditing the addRevision() method call has the effect to remove the old CDORevision. Consequently in invalidation, i.e. CDOSessionImpl$Invalidation.reviseRevisions(), we cannot retreive the old CDORevision to get the old value. This issue doesn't occurs between 2 differents CDOSession because the old CDORevision has not yet been removed on the remote CDOSession. I have submit a Gerrit change-set with the test of previous comment : https://git.eclipse.org/r/#/c/29890/. The fix needs to refactor the CDORevisionManager/CDORevisionCache to remove old CDORevision later. The Gerrit job which launch the tests suites is executed with auditing enabled, then the test does not failed. I have updated the change-set to add scenario with auditing disabled. Moving all open bugzillas to 4.5. Moving all unaddressed bugzillas to 4.6. I think I fixed this in the context of bug 395685. *** This bug has been marked as a duplicate of bug 395685 *** Closing. Closing. |