Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF » Forward (redo) change description without using applyAndReverse
Forward (redo) change description without using applyAndReverse [message #654230] Mon, 14 February 2011 16:46 Go to next message
Marek V is currently offline Marek VFriend
Messages: 3
Registered: February 2011
Junior Member
Hi all,

Can anyone suggest a better approach then the one below to getting a "forward" (redo) change description rather than a reverse (undo) change description without running reverseAndApply against actual eobjects?

Brief context: An RCP client using EMF. Data is loaded as required from an app server (from a DB) and cached during an "editing session". A series of changes can be made to the cached data client side. A "Persist changes" button sends change description to app server. The app server loads current persisted versions of the objects from the DB, applies the same changes as were made on the client and commits the changes.

A change recorder seems almost ideal for this, but is there a good way to get a forward (redo) version of a change description without having to run applyAndReverse which actually makes changes to the original objects?

The option to clone the objects, "attach" the change description to the clones and run applyAndReverse seems very messy (even more so as it seems to require the change description is marshalled and then unmarshalled so it now holds proxies which can then be set to resolve to the clones and not the originals).

This recent post http://www.eclipse.org/forums/index.php?t=msg&th=204437& amp;start=0&S=0b602a970a8dc06b5267d96a3ca76d89 seems to imply there isn't a better way, but any additional ideas would be very welcome!

Should we consider enhancing the change recorder to support this or is this likely to be very difficult?

NOTE: our project has looked at CDO briefly and currently discounted it.

Many thanks,

Marek
Re: Forward (redo) change description without using applyAndReverse [message #654298 is a reply to message #654230] Tue, 15 February 2011 00:14 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 26287
Registered: July 2009
Senior Member
Marek,

Comments below.

Marek V wrote:
> Hi all,
>
> Can anyone suggest a better approach then the one below to getting a
> "forward" (redo) change description rather than a reverse (undo)
> change description without running reverseAndApply against actual
> eobjects?

I'm working on a solution and the preliminary patches are part of
https://bugs.eclipse.org/bugs/show_bug.cgi?id=308136
>
> Brief context: An RCP client using EMF. Data is loaded as required
> from an app server (from a DB) and cached during an "editing session".
> A series of changes can be made to the cached data client side. A
> "Persist changes" button sends change description to app server. The
> app server loads current persisted versions of the objects from the
> DB, applies the same changes as were made on the client and commits
> the changes.
>
> A change recorder seems almost ideal for this, but is there a good way
> to get a forward (redo) version of a change description without having
> to run applyAndReverse which actually makes changes to the original
> objects?
It's a tricky problem. You can see in the patches that the approach I'm
taking is to create a copy of just the objects being changed and to
record the original proxy URIs of the objects (since those URIs can
change as a result of changes to the objects and the server will need
the original URI to locate the original object).
>
> The option to clone the objects, "attach" the change description to
> the clones and run applyAndReverse seems very messy (even more so as
> it seems to require the change description is marshalled and then
> unmarshalled so it now holds proxies which can then be set to resolve
> to the clones and not the originals).
You should be able to copy the change description as you copy the
changed objects using a single copyAll...
>
> This recent post
> http://www.eclipse.org/forums/index.php?t=msg&th=204437& amp;start=0&S=0b602a970a8dc06b5267d96a3ca76d89
> seems to imply there isn't a better way, but any additional ideas
> would be very welcome!
>
> Should we consider enhancing the change recorder to support this or is
> this likely to be very difficult?
It is very difficult in the general case.
>
> NOTE: our project has looked at CDO briefly and currently discounted it.
I'm sure Eike will be curious about the reasons.... CDO does support an
offline mode for example. I'm not sure how much copying is involved in
that. It may not always be feasible to clone an entire repository...
>
> Many thanks,
>
> Marek
>
Re: Forward (redo) change description without using applyAndReverse [message #654333 is a reply to message #654298] Tue, 15 February 2011 08:26 Go to previous messageGo to next message
Maximilian Koegel is currently offline Maximilian KoegelFriend
Messages: 225
Registered: July 2009
Senior Member
Marek,

While implementing EMFStore I have tried the approach of recording
change descriptions, serialize them, send them to a server and
deserialize. In general it worked but there where a couple of corner
cases which made it quite fragile.
BTW ;): Did you look at EMFStore (http://emfstore.org). EMFStore is a
model repository for EMF models and would solve your problem. It would
also help you if you were going to have multiple RCP clients connecting
to the same app server.

Cheers,
Maximilian

Am 15.02.2011 01:14, schrieb Ed Merks:
> Marek,
>
> Comments below.
>
> Marek V wrote:
>> Hi all,
>>
>> Can anyone suggest a better approach then the one below to getting a
>> "forward" (redo) change description rather than a reverse (undo)
>> change description without running reverseAndApply against actual
>> eobjects?
>
> I'm working on a solution and the preliminary patches are part of
> https://bugs.eclipse.org/bugs/show_bug.cgi?id=308136
>>
>> Brief context: An RCP client using EMF. Data is loaded as required
>> from an app server (from a DB) and cached during an "editing session".
>> A series of changes can be made to the cached data client side. A
>> "Persist changes" button sends change description to app server. The
>> app server loads current persisted versions of the objects from the
>> DB, applies the same changes as were made on the client and commits
>> the changes.
>>
>> A change recorder seems almost ideal for this, but is there a good way
>> to get a forward (redo) version of a change description without having
>> to run applyAndReverse which actually makes changes to the original
>> objects?
> It's a tricky problem. You can see in the patches that the approach I'm
> taking is to create a copy of just the objects being changed and to
> record the original proxy URIs of the objects (since those URIs can
> change as a result of changes to the objects and the server will need
> the original URI to locate the original object).
>>
>> The option to clone the objects, "attach" the change description to
>> the clones and run applyAndReverse seems very messy (even more so as
>> it seems to require the change description is marshalled and then
>> unmarshalled so it now holds proxies which can then be set to resolve
>> to the clones and not the originals).
> You should be able to copy the change description as you copy the
> changed objects using a single copyAll...
>>
>> This recent post
>> http://www.eclipse.org/forums/index.php?t=msg&th=204437& amp;start=0&S=0b602a970a8dc06b5267d96a3ca76d89
>> seems to imply there isn't a better way, but any additional ideas
>> would be very welcome!
>>
>> Should we consider enhancing the change recorder to support this or is
>> this likely to be very difficult?
> It is very difficult in the general case.
>>
>> NOTE: our project has looked at CDO briefly and currently discounted it.
> I'm sure Eike will be curious about the reasons.... CDO does support an
> offline mode for example. I'm not sure how much copying is involved in
> that. It may not always be feasible to clone an entire repository...
>>
>> Many thanks,
>>
>> Marek
>>
Re: Forward (redo) change description without using applyAndReverse [message #654761 is a reply to message #654333] Thu, 17 February 2011 01:22 Go to previous messageGo to next message
Marek V is currently offline Marek VFriend
Messages: 3
Registered: February 2011
Junior Member
Hi,

Thanks for the replies.

Ed:

"I'm working on a solution and the preliminary patches are part of
https://bugs.eclipse.org/bugs/show_bug.cgi?id=308136"
- thanks, have been looking at the patch. Haven't managed to successfully run the test case yet but I'm sure that is something with my set up.

It looks more complicated than I expected, also it appears similar to the idea of applyAndReverse to a copy of the objects except it does it for you, i.e. it isn't a recording of a forward change description (no reverse required) - would this be too difficult?

"You should be able to copy the change description as you copy the
changed objects using a single copyAll..."
- I don't quite follow this, are you saying if I copyAll the change description itself plus all changed/added/removed objects I should end up with a copy of the change description linked to copies of the original model objects?

Maximilian:

"I have tried the approach of recording
change descriptions, serialize them, send them to a server and
deserialize. In general it worked but there where a couple of corner
cases which made it quite fragile."
- how did you reverse the change description or what approach did you use? Do you have details of the corner cases you found?

Many thanks,

Marek
Re: Forward (redo) change description without using applyAndReverse [message #654766 is a reply to message #654761] Thu, 17 February 2011 02:10 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 26287
Registered: July 2009
Senior Member
Marek,

Comments below.


Marek V wrote:
> Hi,
>
> Thanks for the replies.
>
> Ed:
>
> "I'm working on a solution and the preliminary patches are part of
> https://bugs.eclipse.org/bugs/show_bug.cgi?id=308136" - thanks, have
> been looking at the patch. Haven't managed to successfully run the
> test case yet but I'm sure that is something with my set up.
>
> It looks more complicated than I expected,
It's a deceptively difficult problem.
> also it appears similar to the idea of applyAndReverse to a copy of
> the objects except it does it for you,
Yes, though not the entire resource set nor the change description itself.
> i.e. it isn't a recording of a forward change description (no reverse
> required)
The recording process (ChangeRecorder) effectively just records the
original value before any changes. The ChangeDescription's contents
itself is computed from that
> - would this be too difficult?
The problem comes down to the fact that a contained object can only be
contained in one place. A new object added to a containment reference
needs to be contained by the ChangeDescription so it can be sent to the
server...
>
> "You should be able to copy the change description as you copy the
> changed objects using a single copyAll..." - I don't quite follow
> this, are you saying if I copyAll the change description itself plus
> all changed/added/removed objects
No, the whole resource set of all objects involved along with the change
description.
> I should end up with a copy of the change description linked to copies
> of the original model objects?
No, linked to copies of the model objects. You can copy just to change
description to end up with a copy linked to originals.
>
> Maximilian:
>
> "I have tried the approach of recording
> change descriptions, serialize them, send them to a server and
> deserialize. In general it worked but there where a couple of corner
> cases which made it quite fragile." - how did you reverse the change
> description or what approach did you use? Do you have details of the
> corner cases you found?
>
> Many thanks,
>
> Marek
Re: Forward (redo) change description without using applyAndReverse [message #1004719 is a reply to message #654230] Wed, 23 January 2013 18:30 Go to previous messageGo to next message
Silvestre Martins is currently offline Silvestre MartinsFriend
Messages: 43
Registered: July 2009
Member
Can anyone post some update about this? Is there any news?
I'm also interested in this approach, of using the change description as some kind of change log, so I could reapply changes starting from a previous model state, which means, be able to perform a redo, without ever had performed the undo.

I can see that since version 2.7 there is this new method:
ChangeDescription.copyAndReverse(Map<EObject, URI>)


But it doesn't come with any javadoc, so I'm not sure of what is supposed to do. My expectation was that it does what I want, by copying (cloning) internally the objects so it can determine the reverse changes, without actually making any change on the original model.
The problem is that the cloned objects referred by the change description are then not contained, and therefore, when serializing the change description, it fails to resolve the href.

So I'm not sure if this is supposed to do what I expect and/or if I'm not using in the correct way. For instance, what is supposed to pass as argument to this method?

Answers are welcome!
Thanks in advance.

--
Silvestre
Re: Forward (redo) change description without using applyAndReverse [message #1004904 is a reply to message #1004719] Thu, 24 January 2013 05:05 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 26287
Registered: July 2009
Senior Member
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
</head>
<body text="#000000" bgcolor="#FFFFFF">
Silvestre,<br>
<br>
You can have a look at how it's used in the tests<br>
<blockquote><a class="moz-txt-link-freetext" href="http://git.eclipse.org/c/emf/org.eclipse.emf.git/tree/tests/org.eclipse.emf.test.core/src/org/eclipse/emf/test/core/change/ChangeDescriptionReverseTest.java">http://git.eclipse.org/c/emf/org.eclipse.emf.git/tree/tests/org.eclipse.emf.test.core/src/org/eclipse/emf/test/core/change/ChangeDescriptionReverseTest.java</a><br>
</blockquote>
This method in particular shows the usage pattern:<br>
<br>
    void doit() throws Exception<br>
    {<br>
      ResourceSet originalResourceSet = new ResourceSetImpl();<br>
<br>
      loadResources(originalResourceSet);<br>
<br>
      Map&lt;EObject, URI&gt; eObjectToProxyURIMap = new
HashMap&lt;EObject, URI&gt;();<br>
      ChangeRecorder changeRecorder = new ChangeRecorder();<br>
      changeRecorder.setRecordingTransientFeatures(false);<br>
      changeRecorder.setEObjectToProxyURIMap(eObjectToProxyURIMap);<br>
     
changeRecorder.beginRecording(Collections.singleton(originalResourceSet));<br>
      <br>
      makeChanges();<br>
        <br>
      ChangeDescription changeDescription =
changeRecorder.endRecording();<br>
      changeDescription.copyAndReverse(eObjectToProxyURIMap);<br>
      <br>
      ResourceSet finalResourceSet = new ResourceSetImpl();<br>
      Resource changeDescriptionResource =
finalResourceSet.createResource(URI.createURI("changes.change"));<br>
     
changeDescriptionResource.getContents().add(changeDescription);<br>
      ByteArrayOutputStream out = new ByteArrayOutputStream();<br>
      changeDescriptionResource.save(out, null);<br>
      changeDescriptionResource.getContents().clear();<br>
      changeDescriptionResource.unload();<br>
      changeDescriptionResource.load(new
ByteArrayInputStream(out.toByteArray()), null);<br>
      <br>
      ChangeDescription finalChangeDescription =
(ChangeDescription)changeDescriptionResource.getContents().get(0);<br>
      finalChangeDescription.apply();<br>
      <br>
      finalResourceSet.getResources().remove(0);<br>
      <br>
      assertEquals(originalResourceSet, finalResourceSet);<br>
    }<br>
<br>
It shows the change description being serialized as well, and
simulates it being loaded and applied.<br>
<br>
<div class="moz-cite-prefix">On 23/01/2013 7:30 PM, Silvestre
Martins wrote:<br>
</div>
<blockquote cite="mid:kdpa7i$vli$1@xxxxxxxxe.org" type="cite">Can
anyone post some update about this? Is there any news?
<br>
I'm also interested in this approach, of using the change
description as some kind of change log, so I could reapply changes
starting from a previous model state, which means, be able to
perform a redo, without ever had performed the undo.
<br>
<br>
I can see that since version 2.7 there is this new method:
<br>
ChangeDescription.copyAndReverse(Map&lt;EObject, URI&gt;)
<br>
<br>
But it doesn't come with any javadoc, so I'm not sure of what is
supposed to do. My expectation was that it does what I want, by
copying (cloning) internally the objects so it can determine the
reverse changes, without actually making any change on the
original model.
<br>
The problem is that the cloned objects referred by the change
description are then not contained, and therefore, when
serializing the change description, it fails to resolve the href.
<br>
<br>
So I'm not sure if this is supposed to do what I expect and/or if
I'm not using in the correct way. For instance, what is supposed
to pass as argument to this method?
<br>
<br>
Answers are welcome!
<br>
Thanks in advance.
<br>
<br>
--
<br>
Silvestre
<br>
<br>
</blockquote>
<br>
</body>
</html>
Re: Forward (redo) change description without using applyAndReverse [message #1005045 is a reply to message #1004904] Thu, 24 January 2013 11:25 Go to previous messageGo to next message
Silvestre Martins is currently offline Silvestre MartinsFriend
Messages: 43
Registered: July 2009
Member
Thanks Ed.

After looking to the examples, I have one question: how is this testing working ok, if it is applying the reverse changes (the ones serialized after calling copyAndReverse) to the model that contains already these changes? I was expecting that before calling apply(), it would load again the original state, by using loadResources(). Did I miss something?

Anyway, I tried to use the same code for my test, and I ended up with same result as before (without using the copyAndReverse, but performing a real rollback using applyAndReverse, and then serializing it): after applying the changes, there are duplicated on list features.

See the example:

Model initial state (before any change):
<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:org.eclipse.example.changerecorder.library="http:///org/eclipse/example/changerecorder/library.ecore">
  <org.eclipse.example.changerecorder.library:Library location="Lisbon">
    <writers name="Writer 1" books="#/0/@books.0">
      <test/>
    </writers>
    <books title="Book 1" author="#/0/@writers.0"/>
  </org.eclipse.example.changerecorder.library:Library>
  <org.eclipse.example.changerecorder.library:Library location="Aveiro"/>
</xmi:XMI>


Model after changes:
<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:org.eclipse.example.changerecorder.library="http:///org/eclipse/example/changerecorder/library.ecore">
  <org.eclipse.example.changerecorder.library:Library location="Lisbon -changed">
    <writers name="Writer 1">
      <test/>
    </writers>
  </org.eclipse.example.changerecorder.library:Library>
  <org.eclipse.example.changerecorder.library:Library location="Aveiro">
    <writers name="Writer 2" books="#/1/@books.0"/>
    <books title="Book 1 -changed" author="#/1/@writers.0"/>
  </org.eclipse.example.changerecorder.library:Library>
</xmi:XMI>


Model after changes using serialized change description from copyAndReverse:
<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:org.eclipse.example.changerecorder.library="http:///org/eclipse/example/changerecorder/library.ecore">
  <org.eclipse.example.changerecorder.library:Library location="Lisbon -changed">
    <writers name="Writer 1">
      <test/>
    </writers>
  </org.eclipse.example.changerecorder.library:Library>
  <org.eclipse.example.changerecorder.library:Library location="Aveiro">
    <writers name="Writer 2" books="#/1/@books.0 #/1/@books.0"/>
    <books title="Book 1 -changed" author="#/1/@writers.0"/>
  </org.eclipse.example.changerecorder.library:Library>
</xmi:XMI>


As you can see the list of books in Library got duplicated:
<writers name="Writer 2" books="#/1/@books.0 #/1/@books.0"/>

These are the changes that I'm applying, in case it helps:
Library library1 = (Library) resource.getContents().get(0);
Library library2 = (Library) resource.getContents().get(1);
Book book = library1.getBooks().get(0);
library1.setLocation("Lisbon -changed");
book.setTitle("Book 1 -changed2");
book.setTitle("Book 1 -changed1");
book.setTitle("Book 1 -changed");
Writer newWriter = LibraryFactory.eINSTANCE.createWriter();
newWriter.setName("Writer 2");
library2.getWriters().add(newWriter);
book.setAuthor(newWriter);
library2.getBooks().add(book);


If I apply the changes before serializing them, then it's ok.

Any clue of what it's causing this?

Thanks.
Silvestre

[Updated on: Thu, 24 January 2013 11:27]

Report message to a moderator

Re: Forward (redo) change description without using applyAndReverse [message #1005053 is a reply to message #1005045] Thu, 24 January 2013 11:41 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 26287
Registered: July 2009
Senior Member
Silvestre,

Comments below.

On 24/01/2013 12:25 PM, Silvestre Martins wrote:
> Thanks Ed.
>
> After looking to the examples, I have one question: how is this
> testing working ok, if it is applying the reverse changes (the ones
> serialized after calling copyAndReverse) to the model that contains
> already these changes?
It's not doing that. Note how it's putting the change description in a
new resource in a new resource set. Then it discarding that resource's
contents and loading it again from the serialized bytes. All references
to the model are proxies after loading those bytes. Resolving those
proxy will load their corresponding resources into this new resource set
and of course those newly loaded versions are the original unchanged
versions. The changes are applied to those...
> I was expecting that before calling apply(), it would load again the
> original state, by using loadResources().
Resolving of the proxies in the change description does that on demand.
> Did I miss something?
I guess so. :-P
>
> Anyway, I tried to use the same code for my test, and I ended up with
> same result as before (without using the copyAndReverse, but
> performing a real rollback using applyAndReverse): after applying the
> changes, there are duplicated on list features.
>
> See the example:
>
> Model initial state (before any change):
> <?xml version="1.0" encoding="UTF-8"?>
> <xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
> xmlns:org.eclipse.example.changerecorder.library="http:///org/eclipse/example/changerecorder/library.ecore">
> <org.eclipse.example.changerecorder.library:Library location="Lisbon">
> <writers name="Writer 1" books="#/0/@books.0">
> <test/>
> </writers>
> <books title="Book 1" author="#/0/@writers.0"/>
> </org.eclipse.example.changerecorder.library:Library>
> <org.eclipse.example.changerecorder.library:Library location="Aveiro"/>
> </xmi:XMI>
>
> Model after changes:
> <?xml version="1.0" encoding="UTF-8"?>
> <xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
> xmlns:org.eclipse.example.changerecorder.library="http:///org/eclipse/example/changerecorder/library.ecore">
> <org.eclipse.example.changerecorder.library:Library location="Lisbon
> -changed">
> <writers name="Writer 1">
> <test/>
> </writers>
> </org.eclipse.example.changerecorder.library:Library>
> <org.eclipse.example.changerecorder.library:Library location="Aveiro">
> <writers name="Writer 2" books="#/1/@books.0"/>
> <books title="Book 1 -changed" author="#/1/@writers.0"/>
> </org.eclipse.example.changerecorder.library:Library>
> </xmi:XMI>
>
> Model after changes using serialized change description from
> copyAndReverse:
> <?xml version="1.0" encoding="UTF-8"?>
> <xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
> xmlns:org.eclipse.example.changerecorder.library="http:///org/eclipse/example/changerecorder/library.ecore">
> <org.eclipse.example.changerecorder.library:Library location="Lisbon
> -changed">
> <writers name="Writer 1">
> <test/>
> </writers>
> </org.eclipse.example.changerecorder.library:Library>
> <org.eclipse.example.changerecorder.library:Library location="Aveiro">
> <writers name="Writer 2" books="#/1/@books.0 #/1/@books.0"/>
> <books title="Book 1 -changed" author="#/1/@writers.0"/>
> </org.eclipse.example.changerecorder.library:Library>
> </xmi:XMI>
>
> As you can see the list of books in Library got duplicated:
> <writers name="Writer 2" books="#/1/@books.0 #/1/@books.0"/>
>
> These are the changes that I'm applying, in case it helps:
> Library library1 = (Library) resource.getContents().get(0);
> Library library2 = (Library) resource.getContents().get(1);
> Book book = library1.getBooks().get(0);
> library1.setLocation("Lisbon -changed");
> book.setTitle("Book 1 -changed2");
> book.setTitle("Book 1 -changed1");
> book.setTitle("Book 1 -changed");
> Writer newWriter = LibraryFactory.eINSTANCE.createWriter();
> newWriter.setName("Writer 2");
> library2.getWriters().add(newWriter);
> book.setAuthor(newWriter);
> library2.getBooks().add(book);
>
> If I apply the changes before serializing them, then it's ok.
>
> Any clue of what it's causing this?
There's no code here showing me what you've done with the change
recorder or what resource sets are involved so it's impossible to
comment on this. Given your misinterpretation of the test case, it
seems likely that you might have made a mistake applying the pattern...
>
> Thanks.
> Silvestre
>
Re: Forward (redo) change description without using applyAndReverse [message #1005113 is a reply to message #1005053] Thu, 24 January 2013 13:52 Go to previous messageGo to next message
Silvestre Martins is currently offline Silvestre MartinsFriend
Messages: 43
Registered: July 2009
Member
Ok, I got it. However, if I understand it correctly, if I decide to reload the initial model between lines 89 and 90, it should work in the same way, right?
This is the case where we want to simulate a failure on the system, and use the stored changes to apply on a previous stored state, to restore to the final model state.

Nevertheless, I changed my test to be as the one from the example, by not reloading the initial model, just to make sure it works.

Now I get this exception:

java.lang.ArrayStoreException: org.eclipse.emf.ecore.impl.EObjectImpl
	at org.eclipse.emf.common.util.BasicEList.assign(BasicEList.java:118)
	at org.eclipse.emf.common.util.BasicEList.addUnique(BasicEList.java:442)
	at org.eclipse.emf.common.notify.impl.NotifyingListImpl.doAddUnique(NotifyingListImpl.java:387)
	at org.eclipse.emf.common.notify.impl.NotifyingListImpl.addUnique(NotifyingListImpl.java:371)
	at org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:339)
	at org.eclipse.emf.common.util.ECollections.setEList(ECollections.java:225)
	at org.eclipse.emf.ecore.change.impl.FeatureChangeImpl.process(FeatureChangeImpl.java:593)
	at org.eclipse.emf.ecore.change.impl.FeatureChangeImpl.apply(FeatureChangeImpl.java:518)
	at org.eclipse.emf.ecore.change.impl.FeatureChangeImpl.apply(FeatureChangeImpl.java:493)
	at org.eclipse.emf.ecore.change.impl.ChangeDescriptionImpl.apply(ChangeDescriptionImpl.java:298)
	at changerecorder.library.tests.TestChangeRecorder.testChangeRecorderReverse(TestChangeRecorder.java:199)
	...


I attached the test file in case you want to take a look.
Thanks.


--
Silvestre

[Updated on: Thu, 24 January 2013 13:55]

Report message to a moderator

Re: Forward (redo) change description without using applyAndReverse [message #1005134 is a reply to message #1005113] Thu, 24 January 2013 14:38 Go to previous messageGo to next message
Silvestre Martins is currently offline Silvestre MartinsFriend
Messages: 43
Registered: July 2009
Member
Please disregard the previous post, I already found the problem, it was an error in my test.

Nevertheless, I'm still not sure if this is exactly what I want. In fact, I want that the serialized+loaded changes are applied to the original model that is memory after the application finishes the startup process, I don't want that the apply() causes the load of new objects from the original resource to a new ResourceSet.



Silvestre Martins wrote on Thu, 24 January 2013 08:52
Ok, I got it. However, if I understand it correctly, if I decide to reload the initial model between lines 89 and 90, it should work in the same way, right?
This is the case where we want to simulate a failure on the system, and use the stored changes to apply on a previous stored state, to restore to the final model state.

Nevertheless, I changed my test to be as the one from the example, by not reloading the initial model, just to make sure it works.

Now I get this exception:

java.lang.ArrayStoreException: org.eclipse.emf.ecore.impl.EObjectImpl
	at org.eclipse.emf.common.util.BasicEList.assign(BasicEList.java:118)
	at org.eclipse.emf.common.util.BasicEList.addUnique(BasicEList.java:442)
	at org.eclipse.emf.common.notify.impl.NotifyingListImpl.doAddUnique(NotifyingListImpl.java:387)
	at org.eclipse.emf.common.notify.impl.NotifyingListImpl.addUnique(NotifyingListImpl.java:371)
	at org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:339)
	at org.eclipse.emf.common.util.ECollections.setEList(ECollections.java:225)
	at org.eclipse.emf.ecore.change.impl.FeatureChangeImpl.process(FeatureChangeImpl.java:593)
	at org.eclipse.emf.ecore.change.impl.FeatureChangeImpl.apply(FeatureChangeImpl.java:518)
	at org.eclipse.emf.ecore.change.impl.FeatureChangeImpl.apply(FeatureChangeImpl.java:493)
	at org.eclipse.emf.ecore.change.impl.ChangeDescriptionImpl.apply(ChangeDescriptionImpl.java:298)
	at changerecorder.library.tests.TestChangeRecorder.testChangeRecorderReverse(TestChangeRecorder.java:199)
	...


I attached the test file in case you want to take a look.
Thanks.


--
Silvestre

Re: Forward (redo) change description without using applyAndReverse [message #1005190 is a reply to message #1005134] Thu, 24 January 2013 15:56 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 26287
Registered: July 2009
Senior Member
Silvestre,

Comments below.

On 24/01/2013 3:38 PM, Silvestre Martins wrote:
> Please disregard the previous post, I already found the problem, it
> was an error in my test.
Consider it ignored. :-P
>
> Nevertheless, I'm still not sure if this is exactly what I want. In
> fact, I want that the serialized+loaded changes are applied to the
> original model that is memory after the application finishes the
> startup process, I don't want that the apply() causes the load of new
> objects from the original resource to a new ResourceSet.
If you load the change description's resource into a resource set
containing resources with the target object in their original state, the
proxies will resolve to those resources already in the resource set. It
sounds like that's what you want. The test is just written the way it
is so that it can test that applying the changes to the objects in their
original state produces a final state structurally equal to the "real"
final state we're expecting it to achieve...
>
>
>
> Silvestre Martins wrote on Thu, 24 January 2013 08:52
>> Ok, I got it. However, if I understand it correctly, if I decide to
>> reload the initial model between lines 89 and 90, it should work in
>> the same way, right?
>> This is the case where we want to simulate a failure on the system,
>> and use the stored changes to apply on a previous stored state, to
>> restore to the final model state.
>>
>> Nevertheless, I changed my test to be as the one from the example, by
>> not reloading the initial model, just to make sure it works.
>>
>> Now I get this exception:
>>
>> java.lang.ArrayStoreException: org.eclipse.emf.ecore.impl.EObjectImpl
>> at
>> org.eclipse.emf.common.util.BasicEList.assign(BasicEList.java:118)
>> at
>> org.eclipse.emf.common.util.BasicEList.addUnique(BasicEList.java:442)
>> at
>> org.eclipse.emf.common.notify.impl.NotifyingListImpl.doAddUnique(NotifyingListImpl.java:387)
>> at
>> org.eclipse.emf.common.notify.impl.NotifyingListImpl.addUnique(NotifyingListImpl.java:371)
>> at
>> org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:339)
>> at
>> org.eclipse.emf.common.util.ECollections.setEList(ECollections.java:225)
>> at
>> org.eclipse.emf.ecore.change.impl.FeatureChangeImpl.process(FeatureChangeImpl.java:593)
>> at
>> org.eclipse.emf.ecore.change.impl.FeatureChangeImpl.apply(FeatureChangeImpl.java:518)
>> at
>> org.eclipse.emf.ecore.change.impl.FeatureChangeImpl.apply(FeatureChangeImpl.java:493)
>> at
>> org.eclipse.emf.ecore.change.impl.ChangeDescriptionImpl.apply(ChangeDescriptionImpl.java:298)
>> at
>> changerecorder.library.tests.TestChangeRecorder.testChangeRecorderReverse(TestChangeRecorder.java:199)
>> ...
>>
>>
>> I attached the test file in case you want to take a look.
>> Thanks.
>>
>>
>> --
>> Silvestre
>
>
Re: Forward (redo) change description without using applyAndReverse [message #1005257 is a reply to message #1005190] Thu, 24 January 2013 18:21 Go to previous messageGo to next message
Silvestre Martins is currently offline Silvestre MartinsFriend
Messages: 43
Registered: July 2009
Member
Yes, that's what I want.
Just to add some info about this scenario - the expected usage of this for a recovery mechanism in case of failure, from my point of view, would be:

1. Read an initial model - process not controlled by me, but by the application startup
2. Start recording
3. Make some changes
4. End recording (and call copyAndReverse to determine the forward changes)
5. Store the changes (serialize the ChangeDescription and store it)
6. At this point let's assume the server fails, and we didn't save the last state of the model

7. Start application again and read the last available model - process not controlled by me, but by the application startup
At the end of startup, we'll have the model in memory, as it was the last time it was saved before failure (in this case, as it was before step 2.)

8. Load stored ChangeDescription and apply them to model instances in memory
9. After this, I expect that the model instance loaded in step 7. has exactly the same state as it was after step 4.

Here are the code that simulates the workflow above:

   @Test
   public void testChangeRecorderReverse() throws Exception {
	
	//step 1
	Resource resource = createInitialModel(new ResourceSetImpl());
	storeModel("model_initial", resource);
	
	//step 2
	Map<EObject, URI> eObjectToProxyURIMap = new HashMap<EObject, URI>();
	ChangeRecorder changeRecorder = new ChangeRecorder();
	changeRecorder.setRecordingTransientFeatures(false);
	changeRecorder.setEObjectToProxyURIMap(eObjectToProxyURIMap);
	changeRecorder.beginRecording(Collections.singleton(resource.getResourceSet()));

	//step 3
	makeSomeChanges(resource);
	
	//step 4
	ChangeDescription changeDescription = changeRecorder.endRecording();
	
	//store the latest state of the model to be compared later
	storeModel("model_changed", resource);
	
	changeDescription.copyAndReverse(eObjectToProxyURIMap);

	//step 5
	storeChanges("changes.xml", changeDescription);

	//step 6 -> imagine we loose our latest state of the model here (a failure), so we need to load the previous state
	
	//step 7
	//reload initial model
	ResourceSet originalResourceSet = new ResourceSetImpl();
	resource = loadModel(originalResourceSet, "model_initial");
	
	//step 8
	// load changes using the same ResourceSet where the initial model state was loaded
	ChangeDescription loadedChangeDescription = loadChanges(originalResourceSet, "changes.xml");
	loadedChangeDescription.apply();

	//step 9
	storeModel("model_changed_using_redo", resource);

        //TODO perform some code to check if models are have the same state
   }


However it doesn't work as expected, as in some cases, the objects are duplicated in the lists, as posted before:
<writers name="Writer 2" books="#/1/@books.0 #/1/@books.0"/>

You can see the new test class in the attachment for more details, like the store() and load() methods.


--
Silvestre

[Updated on: Thu, 24 January 2013 18:23]

Report message to a moderator

Re: Forward (redo) change description without using applyAndReverse [message #1005308 is a reply to message #1005257] Thu, 24 January 2013 20:25 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 26287
Registered: July 2009
Senior Member
Silvestre,

If you think there's a bug, please open a bugzilla and include a self
contained test case, i.e., export all necessary projects to a zip and
attach it so I have something I can import and run without changes.
Please try to avoid absolute paths on the file system or anything else
that will make it not work if you tried it on Linux (though I do have
Windows)...



On 24/01/2013 7:21 PM, Silvestre Martins wrote:
> Yes, that's what I want.
> Just to add some info about this scenario - the expected usage of this for a recovery mechanism in case of failure, from my point of view, would be:
>
> 1. Read an initial model - process not controlled by me, but by the application startup
> 2. Start recording
> 3. Make some changes
> 4. End recording (and call copyAndReverse to determine the forward changes)
> 5. Store the changes (serialize the ChangeDescription and store it)
> 6. At this point let's assume the server fails, and we didn't save the last state of the model
>
> 7. Start application again and read the last available model - process not controlled by me, but by the application startup
> At the end of startup, we'll have the model in memory, as it was the last time it was saved before failure (in this case, as it was before step 2.)
>
> 8. Load stored ChangeDescription and apply them to model instances in memory
> 9. After this, I expect that the model instance loaded in step 7. has exactly the same state as it was after step 4.
>
> Here are the code that simulates the workflow above:
>
> @Test
> public void testChangeRecorderReverse() throws Exception {
>
> //step 1
> Resource resource = createInitialModel(new ResourceSetImpl());
> storeModel("model_initial", resource);
>
> //step 2
> Map<EObject, URI> eObjectToProxyURIMap = new HashMap<EObject, URI>();
> ChangeRecorder changeRecorder = new ChangeRecorder();
> changeRecorder.setRecordingTransientFeatures(false);
> changeRecorder.setEObjectToProxyURIMap(eObjectToProxyURIMap);
> changeRecorder.beginRecording(Collections.singleton(resource.getResourceSet()));
>
> //step 3
> makeSomeChanges(resource);
>
> //step 4
> ChangeDescription changeDescription = changeRecorder.endRecording();
>
> //store the latest state of the model to be compared later
> storeModel("model_changed", resource);
>
> changeDescription.copyAndReverse(eObjectToProxyURIMap);
>
> //step 5
> storeChanges("changes.xml", changeDescription);
>
> //step 6 -> imagine we loose our latest state of the model here (a failure), so we need to load the previous state
>
> //step 7
> //reload model
> ResourceSet originalResourceSet = new ResourceSetImpl();
> resource = loadModel(originalResourceSet, "model_initial");
>
> //step 8
> // load changes using the same ResourceSet where the initial model state was loaded
> ChangeDescription loadedChangeDescription = loadChanges(originalResourceSet, "changes.xml");
> loadedChangeDescription.apply();
>
> //step 9
> storeModel("model_changed_using_redo", resource);
>
> //TODO perform some code to check if models are have the same state
> }
>
> However it doesn't work as expected, as in some cases, the objects are duplicated in the lists, as posted before:
> <writers name="Writer 2" books="#/1/@books.0 #/1/@books.0"/>
>
> You can see the new test class in the attachment for more details, like the store() and load() methods.
>
>
> --
> Silvestre
Re: Forward (redo) change description without using applyAndReverse [message #1005341 is a reply to message #1005308] Thu, 24 January 2013 22:43 Go to previous messageGo to next message
Silvestre Martins is currently offline Silvestre MartinsFriend
Messages: 43
Registered: July 2009
Member
Hi Ed,
well, I'm not sure if it's a bug. But I think is better to create the bugzilla so it can be analyzed properly.

Here it goes:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=399026

Thanks,
Silvestre
Re: Forward (redo) change description without using applyAndReverse [message #1005798 is a reply to message #654230] Mon, 28 January 2013 19:11 Go to previous messageGo to next message
Silvestre Martins is currently offline Silvestre MartinsFriend
Messages: 43
Registered: July 2009
Member
During the investigations of this issue, I noticed another thing: we can use ChangeRecorder.setRecordingTransientFeatures(boolean) to decide if we want to track the transient changes or not.

For the scenario I described before, and assuming we are not able to determine whether the state of my transient data is still valid or not, I would want to also record the transient features, to support the rollback properly. However, for the serialization of forward (reverse) changes, this is not true, because I might have references to non-EMF objects, and in this case the deserialization will then fail.

At first glance, I see a work around for this: do not record transient features, serialize forward changes, then when needed, load original model, apply forward changes, serialize the entire model, and restart application (reading the model again) so the transient data is properly built using the regular application mechanisms.

I only see a limitation with this approach: then it wouldn't work properly for the rollback of transient data.
I was thinking if it makes sense to have some kind of hybrid approach, by recording the transient features, but having an additional setting in the ChangeDescription to indicate that we don't want to serialize those changes referring to transient features.

Does this makes sense at all? And more important, would this be possible (and easy to implement) with the current implementation of ChangeRecorder and ChangeDescription?

Another (and probably cheaper) solution would be to keep 2 different recorders, one for rollback and another for forward changes serialization.


--
Silvestre
Re: Forward (redo) change description without using applyAndReverse [message #1005819 is a reply to message #1005798] Mon, 28 January 2013 20:30 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 26287
Registered: July 2009
Senior Member
Silvestre,

Comments below.

On 28/01/2013 8:11 PM, Silvestre Martins wrote:
> During the investigations of this issue, I noticed another thing: we
> can use ChangeRecorder.setRecordingTransientFeatures(boolean) to
> decide if we want to track the transient changes or not.
>
> For the scenario I described before, and assuming we are not able to
> determine whether the state of my transient data is still valid or
> not, I would want to also record the transient features, to support
> the rollback properly. However, for the serialization of forward
> (reverse) changes, this is not true, because I might have references
> to non-EMF objects, and in this case the deserialization will then fail.
By references you mean data stored via EAttributes?
>
> At first glance, I see a work around for this: do not record transient
> features, serialize forward changes, then when needed, load original
> model, apply forward changes, serialize the entire model, and restart
> application (reading the model again) so the transient data is
> properly built using the regular application mechanisms.
How is the transient data built up?
>
> I only see a limitation with this approach: then it wouldn't work
> properly for the rollback of transient data.
> I was thinking if it makes sense to have some kind of hybrid approach,
> by recording the transient features, but having an additional setting
> in the ChangeDescription to indicate that we don't want to serialize
> those changes referring to transient features.
It wouldn't be hard to prune out all the feature changes for features
that are transient before serializing the ChangeDescription.
>
> Does this makes sense at all?
Probably I need a more concrete example.
> And more important, would this be possible (and easy to implement)
> with the current implementation of ChangeRecorder and ChangeDescription?
Certainly you can have many change recorders at once and it's easy to
walk the ChangeDescription to prune out things that don't make sense...
>
> Another (and probably cheaper) solution would be to keep 2 different
> recorders, one for rollback and another for forward changes
> serialization.
Are these features also marked derived? It certainly sounds like some
kind of derivation is involved...
>
>
> --
> Silvestre
Re: Forward (redo) change description without using applyAndReverse [message #1005830 is a reply to message #1005819] Mon, 28 January 2013 21:52 Go to previous messageGo to next message
Silvestre Martins is currently offline Silvestre MartinsFriend
Messages: 43
Registered: July 2009
Member
Hi Ed,
see comments below.

Thanks.

Ed Merks wrote on Mon, 28 January 2013 15:30]Silvestre,

Comments below.

On 28/01/2013 8:11 PM, Silvestre Martins wrote:
> During the investigations of this issue, I noticed another thing: we
> can use ChangeRecorder.setRecordingTransientFeatures(boolean) to
> decide if we want to track the transient changes or not.
>
> For the scenario I described before, and assuming we are not able to
> determine whether the state of my transient data is still valid or
> not, I would want to also record the transient features, to support
> the rollback properly. However, for the serialization of forward
> (reverse) changes, this is not true, because I might have references
> to non-EMF objects, and in this case the deserialization will then fail.
By references you mean data stored via EAttributes?
Yes.

>
> At first glance, I see a work around for this: do not record transient
> features, serialize forward changes, then when needed, load original
> model, apply forward changes, serialize the entire model, and restart
> application (reading the model again) so the transient data is
> properly built using the regular application mechanisms.
How is the transient data built up?
From calculations triggered by modifications from the model or explicitly from commands. Of course we could always trigger new calculations or refresh, but this would have additional cost, which would make the rollback to take too long.

>
> I only see a limitation with this approach: then it wouldn't work
> properly for the rollback of transient data.
> I was thinking if it makes sense to have some kind of hybrid approach,
> by recording the transient features, but having an additional setting
> in the ChangeDescription to indicate that we don't want to serialize
> those changes referring to transient features.
It wouldn't be hard to prune out all the feature changes for features
that are transient before serializing the ChangeDescription.
>
> Does this makes sense at all?
Probably I need a more concrete example.
> And more important, would this be possible (and easy to implement)
> with the current implementation of ChangeRecorder and ChangeDescription?
Certainly you can have many change recorders at once and it's easy to
walk the ChangeDescription to prune out things that don't make sense...
After thinking more about this, I actually prefer the approach of having 2 recorders, because I would not use both never: rollback and serialization of forward changes are never applied at same time. We can say the save of forward changes is some kind of "commit".

>
> Another (and probably cheaper) solution would be to keep 2 different
> recorders, one for rollback and another for forward changes
> serialization.
Are these features also marked derived? It certainly sounds like some
kind of derivation is involved...
More or less. In fact these data is derived from calculations, but they are not marked as derived. Maybe we could review if they should.

>
>
> --
> Silvestre
Re: Forward (redo) change description without using applyAndReverse [message #1005865 is a reply to message #1005830] Tue, 29 January 2013 06:40 Go to previous message
Ed Merks is currently offline Ed MerksFriend
Messages: 26287
Registered: July 2009
Senior Member
Silvestre,

Note that I ask about derived because a copier (like the one being used
in copyAndReverse) won't copy derived features because it's assumed that
the values are derived from other non-derived features. Also note that
you can call ChangeRecorder.summarize to get a change description and to
continue recording. If the only difference between the two change
recorders would be the recording of transient features (attributes), it
seems better to me to prune the one you're going to serialize...


On 28/01/2013 10:52 PM, Silvestre Martins wrote:
> Hi Ed,
> see comments below.
>
> Thanks.
>
> Ed Merks wrote on Mon, 28 January 2013 15:30]Silvestre,
>
> Comments below.
>
> On 28/01/2013 8:11 PM, Silvestre Martins wrote:
>> During the investigations of this issue, I noticed another thing: we
>> can use ChangeRecorder.setRecordingTransientFeatures(boolean) to
>> decide if we want to track the transient changes or not.
>>
>> For the scenario I described before, and assuming we are not able to
>> determine whether the state of my transient data is still valid or
>> not, I would want to also record the transient features, to support
>> the rollback properly. However, for the serialization of forward
>> (reverse) changes, this is not true, because I might have references
>> to non-EMF objects, and in this case the deserialization will then fail.
> By references you mean data stored via EAttributes?
> Yes.
>
>>
>> At first glance, I see a work around for this: do not record
>> transient features, serialize forward changes, then when needed, load
>> original model, apply forward changes, serialize the entire model,
>> and restart application (reading the model again) so the transient
>> data is properly built using the regular application mechanisms.
> How is the transient data built up?
> From calculations triggered by modifications from the model or
> explicitly from commands. Of course we could always trigger new
> calculations or refresh, but this would have additional cost, which
> would make the rollback to take too long.
>
>>
>> I only see a limitation with this approach: then it wouldn't work
>> properly for the rollback of transient data.
>> I was thinking if it makes sense to have some kind of hybrid
>> approach, by recording the transient features, but having an
>> additional setting in the ChangeDescription to indicate that we don't
>> want to serialize those changes referring to transient features.
> It wouldn't be hard to prune out all the feature changes for features
> that are transient before serializing the ChangeDescription.
>>
>> Does this makes sense at all?
> Probably I need a more concrete example.
>> And more important, would this be possible (and easy to implement)
>> with the current implementation of ChangeRecorder and ChangeDescription?
> Certainly you can have many change recorders at once and it's easy to
> walk the ChangeDescription to prune out things that don't make sense...
> After thinking more about this, I actually prefer the approach of
> having 2 recorders, because I would not use both never: rollback and
> serialization of forward changes are never applied at same time. We
> can say the save of forward changes is some kind of "commit".
>
>>
>> Another (and probably cheaper) solution would be to keep 2 different
>> recorders, one for rollback and another for forward changes
>> serialization.
> Are these features also marked derived? It certainly sounds like some
> kind of derivation is involved...
> More or less. In fact these data is derived from calculations, but
> they are not marked as derived. Maybe we could review if they should.
>
>>
>>
>> --
>> Silvestre
Previous Topic:deleting the namespace
Next Topic:Ecore with nested, Inner Class
Goto Forum:
  


Current Time: Sun Dec 21 12:52:51 GMT 2014

Powered by FUDForum. Page generated in 0.07262 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software