Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEsteban Dugueperoux2015-02-20 11:17:29 +0000
committerEsteban DUGUEPEROUX2015-02-26 11:02:20 +0000
commit1c7f627141c23d0b531aed77250be33321802ca0 (patch)
tree4199cc169acd5883237fbcb71b2ccc22892fec6f
parent051561733efbb093b4dd606d727041b0170ecbd3 (diff)
downloadorg.eclipse.sirius-1c7f627141c23d0b531aed77250be33321802ca0.tar.gz
org.eclipse.sirius-1c7f627141c23d0b531aed77250be33321802ca0.tar.xz
org.eclipse.sirius-1c7f627141c23d0b531aed77250be33321802ca0.zip
[452962] Have Saver registration done in a single place and correctly
- Have Saver registration/unregistration for both ResourceSetListener and Lifecycle in constructor/dispose(). - Add SaverTest to check that in case of rollback a save in postcommit is disarmed to avoid a save for the next executed command. - SaverTest is minimalist and can be run in standalone, it's for that SessionResourcesSynchronizer/DAnalysisSelectorService/DAnalysisSessionImpl and some others classes are changed. - To avoid "IllegalStateException: Cannot activate read/write transaction in read-only transaction context" when calling the SavingPolicy in postcommit and this SavingPolicy execute an EMF Command, have Saver call the SavingPolicy in TransactionalEditingDomainListener.transactionClosed(). Have WorkspaceBackEnd cleaned correctly on session close. Bug: 452962 Change-Id: Ibca4ebdb0a85eaf1ab9c0583b49a6f8630174cc4 Signed-off-by: Esteban Dugueperoux <esteban.dugueperoux@obeo.fr>
-rw-r--r--plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/resource/AbstractResourceSyncBackend.java9
-rw-r--r--plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/resource/WorkspaceBackend.java1
-rw-r--r--plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/suite/common/AllCommonPluginTests.java5
-rw-r--r--plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/unit/common/SaverTest.java177
-rw-r--r--plugins/org.eclipse.sirius/src/org/eclipse/sirius/business/internal/session/danalysis/DAnalysisSessionImpl.java36
-rw-r--r--plugins/org.eclipse.sirius/src/org/eclipse/sirius/business/internal/session/danalysis/Saver.java118
6 files changed, 262 insertions, 84 deletions
diff --git a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/resource/AbstractResourceSyncBackend.java b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/resource/AbstractResourceSyncBackend.java
index b58beb0333..f48950d645 100644
--- a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/resource/AbstractResourceSyncBackend.java
+++ b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/resource/AbstractResourceSyncBackend.java
@@ -43,16 +43,19 @@ public abstract class AbstractResourceSyncBackend {
this.client = client;
}
-
/**
* initialize and prepare the backend.
*/
- public abstract void install();
+ public void install() {
+
+ }
/**
* de-initialize the backend.
*/
- public abstract void uninstall();
+ public void uninstall() {
+ observedSet = null;
+ }
/**
* Specify which {@link ResourceSet} the backend should notify about.
diff --git a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/resource/WorkspaceBackend.java b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/resource/WorkspaceBackend.java
index 1a1d5f2ad3..1777318436 100644
--- a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/resource/WorkspaceBackend.java
+++ b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/internal/resource/WorkspaceBackend.java
@@ -57,6 +57,7 @@ public class WorkspaceBackend extends AbstractResourceSyncBackend {
workspace.removeResourceChangeListener(listener);
listener = null;
}
+ super.uninstall();
}
public ResourceSet getObservedSet() {
diff --git a/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/suite/common/AllCommonPluginTests.java b/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/suite/common/AllCommonPluginTests.java
index 8f194d8f0d..f1a4be8e31 100644
--- a/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/suite/common/AllCommonPluginTests.java
+++ b/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/suite/common/AllCommonPluginTests.java
@@ -59,6 +59,7 @@ import org.eclipse.sirius.tests.unit.common.OperationCanceledExceptionSessionTes
import org.eclipse.sirius.tests.unit.common.PreferencesTests;
import org.eclipse.sirius.tests.unit.common.RefreshEditorsPrecommitListenerTests;
import org.eclipse.sirius.tests.unit.common.RestoreSessionFromEditorInputTests;
+import org.eclipse.sirius.tests.unit.common.SaverTest;
import org.eclipse.sirius.tests.unit.common.SiriusCrossReferenceAdapterTests;
import org.eclipse.sirius.tests.unit.common.TransientSessionTests;
import org.eclipse.sirius.tests.unit.common.WorkspaceResourceSyncTestCase;
@@ -265,6 +266,7 @@ public class AllCommonPluginTests extends TestCase {
suite.addTestSuite(TransientSessionTests.class);
suite.addTestSuite(RestoreSessionFromEditorInputTests.class);
suite.addTestSuite(SiriusCrossReferenceAdapterTests.class);
+ suite.addTestSuite(SaverTest.class);
}
/**
@@ -280,7 +282,8 @@ public class AllCommonPluginTests extends TestCase {
suite.addTest(new JUnit4TestAdapter(DiagramMigrationTestCampaign10.class));
// This one takes too long (12 minutes) to be part of the Gerrit suite.
suite.addTestSuite(AcceleoMTInterpreterOnPackageImportTests.class);
- // The ones below are "blacklisted" for now because they caused at least one false-negative Gerrit Verification job
+ // The ones below are "blacklisted" for now because they caused at least
+ // one false-negative Gerrit Verification job
suite.addTestSuite(SessionManagerListener2Tests.class);
}
diff --git a/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/unit/common/SaverTest.java b/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/unit/common/SaverTest.java
new file mode 100644
index 0000000000..8545dfd3cf
--- /dev/null
+++ b/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/unit/common/SaverTest.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Obeo.
+ * All rights reserved. This program
+ * and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.tests.unit.common;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.ResourceSetChangeEvent;
+import org.eclipse.emf.transaction.ResourceSetListener;
+import org.eclipse.emf.transaction.ResourceSetListenerImpl;
+import org.eclipse.emf.transaction.RollbackException;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.sirius.business.api.helper.SiriusUtil;
+import org.eclipse.sirius.business.api.session.SavingPolicy;
+import org.eclipse.sirius.business.api.session.Session;
+import org.eclipse.sirius.business.api.session.SessionStatus;
+import org.eclipse.sirius.business.api.session.factory.SessionFactory;
+import org.eclipse.sirius.business.internal.resource.parser.AirDResourceFactory;
+import org.eclipse.sirius.business.internal.session.danalysis.DAnalysisSessionImpl;
+import org.eclipse.sirius.viewpoint.DAnalysis;
+
+/**
+ * Test for Bugzilla 445603.
+ *
+ * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a>
+ */
+public class SaverTest extends TestCase {
+
+ private File tempFile;
+
+ private Session session;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(SiriusUtil.SESSION_RESOURCE_EXTENSION, new AirDResourceFactory());
+ tempFile = File.createTempFile("test", "." + SiriusUtil.SESSION_RESOURCE_EXTENSION);
+ tempFile.delete();
+ URI sessionResourceURI = URI.createFileURI(tempFile.getCanonicalPath());
+ session = SessionFactory.INSTANCE.createSession(sessionResourceURI, new NullProgressMonitor());
+ session.open(new NullProgressMonitor());
+ }
+
+ /**
+ * Test that a session saving in middle of a EMF Transaction is done only
+ * after transaction closing.
+ */
+ public void testSaveInMiddleOfTransaction() {
+ // Make the session dirty
+ TransactionalEditingDomain domain = session.getTransactionalEditingDomain();
+ DAnalysis dAnalysis = (DAnalysis) session.getSessionResource().getContents().get(0);
+ Command updateDAnalysisCmd = new ChangeDAnalysisCmd(domain, dAnalysis);
+ domain.getCommandStack().execute(updateDAnalysisCmd);
+ assertEquals(SessionStatus.DIRTY, session.getStatus());
+
+ // Test that session is saved only after transaction closing
+ ResourceSetListener saverInMiddleOfTx = new SaverInMiddleOfTx(session, false);
+ domain.addResourceSetListener(saverInMiddleOfTx);
+ updateDAnalysisCmd = new ChangeDAnalysisCmd(domain, dAnalysis);
+ domain.getCommandStack().execute(updateDAnalysisCmd);
+ assertEquals(SessionStatus.SYNC, session.getStatus());
+ domain.removeResourceSetListener(saverInMiddleOfTx);
+
+ // Test also with a rollback
+ saverInMiddleOfTx = new SaverInMiddleOfTx(session, true);
+ domain.addResourceSetListener(saverInMiddleOfTx);
+
+ updateDAnalysisCmd = new ChangeDAnalysisCmd(domain, dAnalysis);
+ domain.getCommandStack().execute(updateDAnalysisCmd);
+ assertEquals(SessionStatus.SYNC, session.getStatus());
+ domain.removeResourceSetListener(saverInMiddleOfTx);
+
+ updateDAnalysisCmd = new ChangeDAnalysisCmd(domain, dAnalysis);
+ domain.getCommandStack().execute(updateDAnalysisCmd);
+ assertEquals(SessionStatus.DIRTY, session.getStatus());
+ }
+
+ /**
+ * Test that a session saving in middle of a EMF Transaction is done only
+ * after transaction closing and with a {@link SavingPolicy} executing a EMF
+ * Command does not throw exception "IllegalStateException: Cannot activate
+ * read/write transaction in read-only transaction context".
+ */
+ public void testSaveInMiddleOfTransactionWithSavingPolicyExecutingAEMFCommand() {
+ ((DAnalysisSessionImpl) session).setSaveInExclusiveTransaction(false);
+ final SavingPolicy savingPolicy = session.getSavingPolicy();
+ session.setSavingPolicy(new SavingPolicy() {
+
+ @Override
+ public Collection<Resource> save(Iterable<Resource> resourcesToSave, Map<?, ?> options, IProgressMonitor monitor) {
+ TransactionalEditingDomain domain = session.getTransactionalEditingDomain();
+ DAnalysis dAnalysis = (DAnalysis) session.getSessionResource().getContents().get(0);
+ Command updateDAnalysisCmd = new ChangeDAnalysisCmd(domain, dAnalysis);
+ domain.getCommandStack().execute(updateDAnalysisCmd);
+ return savingPolicy.save(resourcesToSave, options, monitor);
+ }
+ });
+ // Make the session dirty
+ TransactionalEditingDomain domain = session.getTransactionalEditingDomain();
+ DAnalysis dAnalysis = (DAnalysis) session.getSessionResource().getContents().get(0);
+ Command updateDAnalysisCmd = new ChangeDAnalysisCmd(domain, dAnalysis);
+ domain.getCommandStack().execute(updateDAnalysisCmd);
+ assertEquals(SessionStatus.DIRTY, session.getStatus());
+
+ // Test that session is saved only after transaction closing
+ ResourceSetListener saverInMiddleOfTx = new SaverInMiddleOfTx(session, false);
+ domain.addResourceSetListener(saverInMiddleOfTx);
+ updateDAnalysisCmd = new ChangeDAnalysisCmd(domain, dAnalysis);
+ domain.getCommandStack().execute(updateDAnalysisCmd);
+ assertEquals(SessionStatus.SYNC, session.getStatus());
+ domain.removeResourceSetListener(saverInMiddleOfTx);
+ }
+
+ private static class ChangeDAnalysisCmd extends RecordingCommand {
+
+ private DAnalysis dAnalysis;
+
+ public ChangeDAnalysisCmd(TransactionalEditingDomain domain, DAnalysis dAnalysis) {
+ super(domain);
+ this.dAnalysis = dAnalysis;
+ }
+
+ @Override
+ protected void doExecute() {
+ dAnalysis.setVersion(dAnalysis.getVersion() + "Changed");
+ }
+ }
+
+ private static class SaverInMiddleOfTx extends ResourceSetListenerImpl {
+
+ private Session session;
+
+ private boolean rollback;
+
+ public SaverInMiddleOfTx(Session session, boolean rollback) {
+ this.session = session;
+ this.rollback = rollback;
+ }
+
+ @Override
+ public Command transactionAboutToCommit(ResourceSetChangeEvent event) throws RollbackException {
+ session.save(new NullProgressMonitor());
+ if (rollback) {
+ throw new RollbackException(Status.CANCEL_STATUS);
+ } else {
+ assertEquals(SessionStatus.DIRTY, session.getStatus());
+ }
+ return super.transactionAboutToCommit(event);
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ session.close(new NullProgressMonitor());
+ session = null;
+ tempFile.delete();
+ tempFile = null;
+ super.tearDown();
+ }
+}
diff --git a/plugins/org.eclipse.sirius/src/org/eclipse/sirius/business/internal/session/danalysis/DAnalysisSessionImpl.java b/plugins/org.eclipse.sirius/src/org/eclipse/sirius/business/internal/session/danalysis/DAnalysisSessionImpl.java
index 71c5ff361e..8dc8288cde 100644
--- a/plugins/org.eclipse.sirius/src/org/eclipse/sirius/business/internal/session/danalysis/DAnalysisSessionImpl.java
+++ b/plugins/org.eclipse.sirius/src/org/eclipse/sirius/business/internal/session/danalysis/DAnalysisSessionImpl.java
@@ -13,7 +13,6 @@ package org.eclipse.sirius.business.internal.session.danalysis;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -142,7 +141,7 @@ public class DAnalysisSessionImpl extends DAnalysisSessionEObjectImpl implements
// Session's configuration
- private final Saver saver = new Saver(this);
+ private final Saver saver;
private ReloadingPolicy reloadingPolicy;
@@ -192,7 +191,7 @@ public class DAnalysisSessionImpl extends DAnalysisSessionEObjectImpl implements
Preconditions.checkNotNull(this.sessionResource, "A session must be inside a resource.");
this.transactionalEditingDomain = Preconditions.checkNotNull(TransactionUtil.getEditingDomain(mainDAnalysis), "A session must be associated to an EditingDomain");
this.mainDAnalysis = mainDAnalysis;
-
+ this.saver = new Saver(this);
this.interpreter = new ODesignGenericInterpreter();
this.representationsChangeAdapter = new RepresentationsChangeAdapter(this);
this.controlledResourcesDetector = new ControlledResourcesDetector(this);
@@ -303,8 +302,7 @@ public class DAnalysisSessionImpl extends DAnalysisSessionEObjectImpl implements
// resourceSet
// code to remove when AirDCrossReferenceAdapter is deleted
List<Adapter> adaptersToRemove = new ArrayList<Adapter>();
- for (Iterator<Adapter> iterator = resourceSet.eAdapters().iterator(); iterator.hasNext(); ) {
- Adapter next = iterator.next();
+ for (Adapter next : resourceSet.eAdapters()) {
if (next instanceof SiriusCrossReferenceAdapter) {
((SiriusCrossReferenceAdapter) next).disableResolveProxy();
adaptersToRemove.add(next);
@@ -984,6 +982,14 @@ public class DAnalysisSessionImpl extends DAnalysisSessionEObjectImpl implements
return this.saver.deferSaveToPostCommit;
}
+ /**
+ * Set to true to do saving in a read-only EMF Transaction, false otherwise.
+ * Note that if the {@link SavingPolicy} execute some EMF Command, this must
+ * be at false.
+ *
+ * @param saveInExclusiveTransaction
+ * specify if the saving is done in a read-only transaction
+ */
public void setSaveInExclusiveTransaction(boolean saveInExclusiveTransaction) {
this.saver.saveInExclusiveTransaction = saveInExclusiveTransaction;
}
@@ -1212,7 +1218,6 @@ public class DAnalysisSessionImpl extends DAnalysisSessionEObjectImpl implements
monitor.worked(1);
this.representationNameListener = new RepresentationNameListener(this);
monitor.worked(1);
- saver.initialize();
final Collection<DAnalysis> allAnalyses = allAnalyses();
if (allAnalyses.isEmpty()) {
@@ -1277,8 +1282,6 @@ public class DAnalysisSessionImpl extends DAnalysisSessionEObjectImpl implements
monitor.worked(1);
DViewOperations.on(this).updateSelectedViewpointsData(new SubProgressMonitor(monitor, 10));
initLocalTriggers();
-
- getTransactionalEditingDomain().addResourceSetListener(saver);
} catch (OperationCanceledException e) {
close(new SubProgressMonitor(monitor, 10));
throw e;
@@ -1306,9 +1309,6 @@ public class DAnalysisSessionImpl extends DAnalysisSessionEObjectImpl implements
if (!isOpen()) {
return;
}
- if (saver != null && getTransactionalEditingDomain() != null) {
- getTransactionalEditingDomain().removeResourceSetListener(saver);
- }
ViewpointRegistry.getInstance().removeListener(this.vsmUpdater);
this.vsmUpdater = null;
notifyListeners(SessionListener.CLOSING);
@@ -1400,10 +1400,9 @@ public class DAnalysisSessionImpl extends DAnalysisSessionEObjectImpl implements
// Disable resolveProxy for SiriusCrossreferencerAdapter.
// SiriusCrossreferencerAdapter on EObject are also on resource,
// consequently we manage only the resource itself.
- for (Iterator<Adapter> iterator = resource.eAdapters().iterator(); iterator.hasNext(); ) {
- Adapter next = iterator.next();
- if (next instanceof SiriusCrossReferenceAdapter) {
- ((SiriusCrossReferenceAdapter) next).disableResolveProxy();
+ for (Adapter adapter : resource.eAdapters()) {
+ if (adapter instanceof SiriusCrossReferenceAdapter) {
+ ((SiriusCrossReferenceAdapter) adapter).disableResolveProxy();
}
}
}
@@ -1419,10 +1418,9 @@ public class DAnalysisSessionImpl extends DAnalysisSessionEObjectImpl implements
// Enable resolveProxy for SiriusCrossreferencerAdapter.
// SiriusCrossreferencerAdapter on EObject are also on resource,
// consequently we manage only the resource itself.
- for (Iterator<Adapter> iterator = resource.eAdapters().iterator(); iterator.hasNext(); ) {
- Adapter next = iterator.next();
- if (next instanceof SiriusCrossReferenceAdapter) {
- ((SiriusCrossReferenceAdapter) next).enableResolveProxy();
+ for (Adapter adapter : resource.eAdapters()) {
+ if (adapter instanceof SiriusCrossReferenceAdapter) {
+ ((SiriusCrossReferenceAdapter) adapter).enableResolveProxy();
}
}
}
diff --git a/plugins/org.eclipse.sirius/src/org/eclipse/sirius/business/internal/session/danalysis/Saver.java b/plugins/org.eclipse.sirius/src/org/eclipse/sirius/business/internal/session/danalysis/Saver.java
index 9ec3b6366c..1e27288a9e 100644
--- a/plugins/org.eclipse.sirius/src/org/eclipse/sirius/business/internal/session/danalysis/Saver.java
+++ b/plugins/org.eclipse.sirius/src/org/eclipse/sirius/business/internal/session/danalysis/Saver.java
@@ -14,32 +14,33 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.emf.transaction.ResourceSetChangeEvent;
-import org.eclipse.emf.transaction.ResourceSetListenerImpl;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.TransactionalEditingDomain.Lifecycle;
import org.eclipse.emf.transaction.TransactionalEditingDomainEvent;
-import org.eclipse.emf.transaction.TransactionalEditingDomainListener;
import org.eclipse.emf.transaction.TransactionalEditingDomainListenerImpl;
import org.eclipse.emf.transaction.impl.InternalTransaction;
import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
/**
- * Encapsulates the decision of *when* to actually save the session's state
- * when Session.save() is called. If Session.save() is called while a
- * transaction is in progress and deferSaveToPostCommit is true, the actual
- * saving will be performed after the current transaction has been
- * successfully commited. Otherwise it is performed immediatly.
+ * Encapsulates the decision of *when* to actually save the session's state when
+ * Session.save() is called. If Session.save() is called while a transaction is
+ * in progress and deferSaveToPostCommit is true, the actual saving will be
+ * performed after the current transaction has been successfully commited.
+ * Otherwise it is performed immediatly.
*
* @author pcdavid
*/
-final class Saver extends ResourceSetListenerImpl {
+final class Saver extends TransactionalEditingDomainListenerImpl {
-
boolean deferSaveToPostCommit;
-
+
boolean saveInExclusiveTransaction;
-
+
AtomicBoolean domainDisposed = new AtomicBoolean(false);
+
+ private TransactionalEditingDomain domain;
+
private final DAnalysisSessionImpl session;
private AtomicBoolean saveOnPostCommit = new AtomicBoolean(false);
@@ -48,22 +49,7 @@ final class Saver extends ResourceSetListenerImpl {
private IProgressMonitor savedMonitor;
- /**
- * Make sure the Saver's state is reset after the transaction is
- * finished, even in case of rollback (in which case #resourceSetChanged
- * will not have need called).
- */
- private TransactionalEditingDomainListener domainListener = new TransactionalEditingDomainListenerImpl() {
- @Override
- public void transactionClosed(TransactionalEditingDomainEvent event) {
- disarm();
- }
-
- @Override
- public void editingDomainDisposing(TransactionalEditingDomainEvent event) {
- domainDisposed.set(true);
- }
- };
+ private AtomicBoolean isSaving = new AtomicBoolean();
/**
* Create a new Saver for the specified session.
@@ -73,51 +59,40 @@ final class Saver extends ResourceSetListenerImpl {
*/
public Saver(DAnalysisSessionImpl session) {
this.session = session;
- }
-
- public void initialize() {
- TransactionalEditingDomain ted = session.getTransactionalEditingDomain();
- if (ted instanceof TransactionalEditingDomain.Lifecycle) {
- TransactionalEditingDomain.Lifecycle lc = (TransactionalEditingDomain.Lifecycle) ted;
- lc.addTransactionalEditingDomainListener(domainListener);
- }
- }
-
- public void dispose() {
- TransactionalEditingDomain ted = session.getTransactionalEditingDomain();
- if (ted instanceof TransactionalEditingDomain.Lifecycle) {
- TransactionalEditingDomain.Lifecycle lc = (TransactionalEditingDomain.Lifecycle) ted;
- lc.removeTransactionalEditingDomainListener(domainListener);
+ domain = session.getTransactionalEditingDomain();
+ Lifecycle lifecycle = TransactionUtil.getAdapter(domain, Lifecycle.class);
+ if (lifecycle != null) {
+ lifecycle.addTransactionalEditingDomainListener(this);
}
- disarm();
- }
-
- @Override
- public boolean isPostcommitOnly() {
- return true;
}
+ /**
+ * Do saving after transaction closing in case the SavingPolicy trigger
+ * another transaction by executing a EMF Command.
+ */
@Override
- public void resourceSetChanged(ResourceSetChangeEvent event) {
- if (saveOnPostCommit.get()) {
- saveNow(this.savedOptions, this.savedMonitor, true);
+ public void transactionClosed(TransactionalEditingDomainEvent event) {
+ if (!event.getTransaction().isReadOnly()) {
+ if (saveOnPostCommit.get()) {
+ saveNow(this.savedOptions, this.savedMonitor, saveInExclusiveTransaction);
+ }
}
}
public void save(Map<?, ?> options, IProgressMonitor monitor) {
boolean tip = transactionInProgress();
if (tip && deferSaveToPostCommit) {
- saveOnPostCommit(options, monitor);
+ saveAfterTransactionClosing(options, monitor);
} else {
saveNow(options, monitor, saveInExclusiveTransaction && !tip && !domainDisposed.get());
}
}
/**
- * Arm the trigger so that the saving is performed on the next
- * post-commit.
+ * Arm the trigger so that the saving is performed after transaction
+ * closing.
*/
- private void saveOnPostCommit(Map<?, ?> options, IProgressMonitor monitor) {
+ private void saveAfterTransactionClosing(Map<?, ?> options, IProgressMonitor monitor) {
this.savedOptions = options;
this.savedMonitor = monitor;
this.saveOnPostCommit.set(true);
@@ -127,10 +102,23 @@ final class Saver extends ResourceSetListenerImpl {
* Save immediately and disarm the trigger.
*/
private void saveNow(Map<?, ?> options, IProgressMonitor monitor, boolean runExclusive) {
- try {
- session.doSave(options, monitor, runExclusive);
- } finally {
- disarm();
+ // This allows to have session saving thread safe, i.e. only one thread
+ // can do a save at a time
+ synchronized (isSaving) {
+ // In addition if the session saving or more specifically its
+ // SavingPolicy execute a EMF Command, and we have saveOnPostCommit
+ // at true, we risk a StackOverflow then to avoid that we check if
+ // we are already in a session saving call
+ if (!isSaving.get()) {
+ try {
+ isSaving.set(true);
+ session.doSave(options, monitor, runExclusive);
+ } finally {
+ disarm();
+ isSaving.set(false);
+
+ }
+ }
}
}
@@ -148,4 +136,12 @@ final class Saver extends ResourceSetListenerImpl {
return false;
}
-} \ No newline at end of file
+ public void dispose() {
+ Lifecycle lifecycle = TransactionUtil.getAdapter(domain, Lifecycle.class);
+ if (lifecycle != null) {
+ lifecycle.removeTransactionalEditingDomainListener(this);
+ }
+ disarm();
+ }
+
+}

Back to the top