[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Newsgroup Home]
[news.eclipse.tools.emf] Re: ChangeRecorder issue ?

Ed,

Answers below.

I found the issue : my mistake. The change recorder is started at a moment, where the EReference is still not loaded (i.e the list is null).
When my wizard is displayed, depending on the pages, data are lazy loaded (i'm not using the EMF serialization). Hence, the change recorder detects the EReference is loaded and then depending on end-user actions, the EReference can be cleared. At the end, in the case where the EReference were cleared, the state for the EReference does not change : stay empty.


It is too complex and risky to change the way data are loaded in my application. Thus I create my own ChangeRecorder that extends the one provided by EMF and I override the eliminateEmptyChanges method.

Thank you for your answers, it helps me to come up with ideas to figure out my issue.

Ed Merks wrote:

Stephane,

Comments below.

Stephane wrote:
Hi,

I'm using the ChangeRecorder API and I have got a weird problem.
As opposed to those non-wierd problems. :-P

I monitor an EMF object "Canvas" that has a containment reference named "figures" of type Figure .


Let's imagine, one instance of this "Canvas" named canvas1 has 2 objects contained in the "figures" feature.

a) I start a change recorder for canvas1.
b) I unset the "figures" containment feature.
c) I end the change recorder and get the change description.

Result : no change happens for canvas1 : ChangeDescription#getObjectChanges(), ChangeDescription#getObjectsToAttach or ChangeDescription#getObjectsToDetach are empty collections !! Weird isn'it ?
Hmm. Is it an unsettable multi-valued containment? Do you need that?


The "figures" EReference is not unsettable. When I called eUnset(EReference), it does the same thing as the method clear on the list.



When ending the change recorder, the BasicChangeRecorder#eliminateEmptyChanges() is called.
I debug the code, and the featureChange is retrieved according the unset on the "figures" feature. Nevertheless, It compares the value registered into the featureChange with the current value of the related feature on canvas1. Both lists are empty ones and hence equals, the featureChange is removed... What's a pitty !!


Is it a bug or normal behavior ? How can i figure out that issue ?
It doesn't sound good. I would expect the unset to fire a REMOVE_MANY and for this code in the ChangeRecorder to kick in to record the old value of the list.

The notification with the eUnset or clear() does not trigger a REMOVE_MANY event but a REMOVE one. (I'm using EMF 2.3.1) The ChangeRecorder#notifyChanged delegates to handleFeature in case of EObject && EReference.



case Notification.REMOVE_MANY:
{
if (change == null && changes != null)
{
@SuppressWarnings("unchecked") List<Object> removedValues = (List<Object>)notification.getOldValue();
List<Object> oldValue = new BasicEList<Object>((Collection<?>)eObject.eGet(feature));
int[] positions = (int[])notification.getNewValue();
if (positions == null)
{
oldValue.addAll(removedValues);
}
else
{
for (int i = 0; i < positions.length; ++i)
{
oldValue.add(positions[i], removedValues.get(i));
}
}
change = createFeatureChange(eObject, feature, oldValue, notification.wasSet());
((InternalEList<FeatureChange>)changes).addUnique(change);
}
break;
}

Does a clear cause the same problems as an unset? Does the unset case kick in?


A clear does the same problem. The clear or unset does not kick in the following case.


          case Notification.UNSET:
          {
            if (change == null && changes != null)
            {
              if (feature.isMany())
              {
                List<Object> oldValue = new
    BasicEList<Object>((Collection<?>)eObject.eGet(feature));
                int index = notification.getPosition();
                if (index != Notification.NO_INDEX)
                {
                  oldValue.set(index, notification.getOldValue());
                }
                change = createFeatureChange(eObject, feature, oldValue,
    notification.wasSet());
              }
              else
              {
                Object oldValue = notification.getOldValue();
                change = createFeatureChange(eObject, feature, oldValue,
    notification.wasSet());
              }
              ((InternalEList<FeatureChange>)changes).addUnique(change);
            }
            if (containment != null)
            {
              Object newValue = notification.getNewValue();
              if (newValue != null && newValue != Boolean.TRUE &&
    newValue != Boolean.FALSE)
              {
                addAdapter((Notifier)newValue);
              }
            }
            break;
          }


Stephane.