diff options
author | Eike Stepper | 2015-09-11 05:44:00 +0000 |
---|---|---|
committer | Eike Stepper | 2015-09-11 05:44:00 +0000 |
commit | b7c09e56a4b8809cd2af23a5c50643e63e2f4b9c (patch) | |
tree | e8600961dc9e7caf617b5641a7d27ddfe8124d5b | |
parent | 33ddea509a4c61b24e7c117d3416768702e03f05 (diff) | |
download | cdo-b7c09e56a4b8809cd2af23a5c50643e63e2f4b9c.tar.gz cdo-b7c09e56a4b8809cd2af23a5c50643e63e2f4b9c.tar.xz cdo-b7c09e56a4b8809cd2af23a5c50643e63e2f4b9c.zip |
[477130] Support interactive merging in CDOWorkspace.update()
https://bugs.eclipse.org/bugs/show_bug.cgi?id=477130
21 files changed, 1136 insertions, 215 deletions
diff --git a/features/org.eclipse.emf.cdo.compare-feature/feature.xml b/features/org.eclipse.emf.cdo.compare-feature/feature.xml index dfce15b70e..f65b7f7e2c 100644 --- a/features/org.eclipse.emf.cdo.compare-feature/feature.xml +++ b/features/org.eclipse.emf.cdo.compare-feature/feature.xml @@ -12,7 +12,7 @@ <feature id="org.eclipse.emf.cdo.compare" label="%featureName" - version="4.3.0.qualifier" + version="4.3.1.qualifier" provider-name="%providerName" license-feature="org.eclipse.emf.cdo.license" license-feature-version="0.0.0"> diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/.settings/.api_filters b/plugins/org.eclipse.emf.cdo.explorer.ui/.settings/.api_filters index 06b8f0cf25..390e7e1482 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/.settings/.api_filters +++ b/plugins/org.eclipse.emf.cdo.explorer.ui/.settings/.api_filters @@ -24,4 +24,13 @@ </message_arguments> </filter> </resource> + <resource path="src/org/eclipse/emf/cdo/explorer/ui/handlers/WorkspaceUpdateHandler.java" type="org.eclipse.emf.cdo.explorer.ui.handlers.WorkspaceUpdateHandler"> + <filter id="640712815"> + <message_arguments> + <message_argument value="CDOCompareEditorUtil"/> + <message_argument value="WorkspaceUpdateHandler"/> + <message_argument value="runWithTitle(String, Runnable)"/> + </message_arguments> + </filter> + </resource> </component> diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/handlers/WorkspaceCheckinHandler.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/handlers/WorkspaceCheckinHandler.java index 055c49d976..5e2a36bcc7 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/handlers/WorkspaceCheckinHandler.java +++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/handlers/WorkspaceCheckinHandler.java @@ -11,13 +11,21 @@ package org.eclipse.emf.cdo.explorer.ui.handlers; import org.eclipse.emf.cdo.internal.explorer.checkouts.OfflineCDOCheckout; +import org.eclipse.emf.cdo.internal.ui.dialogs.SearchField; +import org.eclipse.emf.cdo.util.CommitException; import org.eclipse.emf.cdo.workspace.CDOWorkspace; +import org.eclipse.net4j.util.ui.UIUtil; import org.eclipse.net4j.util.ui.handlers.AbstractBaseHandler; +import org.eclipse.emf.spi.cdo.InternalCDOTransaction.ChangeSetOutdatedException; + import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.handlers.HandlerUtil; /** * @author Eike Stepper @@ -47,15 +55,53 @@ public class WorkspaceCheckinHandler extends AbstractBaseHandler<OfflineCDOCheck } @Override - protected void doExecute(ExecutionEvent event, IProgressMonitor monitor) throws Exception + protected void doExecute(final ExecutionEvent event, IProgressMonitor monitor) throws Exception { OfflineCDOCheckout checkout = elements.get(0); CDOWorkspace workspace = checkout.getWorkspace(); if (workspace != null) { - // TODO Prompt for checkin comment. - // TODO Use progress monitor. - workspace.checkin(); + ChangeSetOutdatedException exception = null; + + try + { + // TODO Prompt for checkin comment. + // TODO Use progress monitor. + workspace.checkin(); + } + catch (CommitException ex) + { + Throwable cause = ex.getCause(); + if (cause instanceof ChangeSetOutdatedException) + { + exception = (ChangeSetOutdatedException)cause; + } + else + { + throw ex; + } + } + catch (ChangeSetOutdatedException ex) + { + exception = ex; + } + + if (exception != null) + { + SearchField.syncExec(new Runnable() + { + public void run() + { + Shell shell = HandlerUtil.getActiveShell(event); + if (shell == null) + { + shell = UIUtil.getShell(); + } + + MessageDialog.openError(shell, "Checkin Error", "Your checkout is outdated and needs to be updated."); + } + }); + } } } } diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/handlers/WorkspaceUpdateHandler.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/handlers/WorkspaceUpdateHandler.java index 02a4937cda..b9d4c68f35 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/handlers/WorkspaceUpdateHandler.java +++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/handlers/WorkspaceUpdateHandler.java @@ -10,11 +10,21 @@ */ package org.eclipse.emf.cdo.explorer.ui.handlers; +import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.internal.explorer.checkouts.OfflineCDOCheckout; -import org.eclipse.emf.cdo.transaction.CDOMerger; +import org.eclipse.emf.cdo.internal.ui.Support; +import org.eclipse.emf.cdo.transaction.CDOCommitContext; +import org.eclipse.emf.cdo.transaction.CDODefaultTransactionHandler2; +import org.eclipse.emf.cdo.transaction.CDOMerger.ConflictException; import org.eclipse.emf.cdo.transaction.CDOTransaction; +import org.eclipse.emf.cdo.ui.compare.CDOCompareEditorUtil; +import org.eclipse.emf.cdo.ui.internal.compare.CompareCDOMerger; +import org.eclipse.emf.cdo.util.CommitException; +import org.eclipse.emf.cdo.util.ConcurrentAccessException; +import org.eclipse.emf.cdo.view.CDOView; import org.eclipse.emf.cdo.workspace.CDOWorkspace; +import org.eclipse.net4j.util.ui.UIUtil; import org.eclipse.net4j.util.ui.handlers.AbstractBaseHandler; import org.eclipse.emf.spi.cdo.DefaultCDOMerger; @@ -22,6 +32,8 @@ import org.eclipse.emf.spi.cdo.DefaultCDOMerger; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.runtime.IProgressMonitor; +import java.util.Set; + /** * @author Eike Stepper */ @@ -35,16 +47,85 @@ public class WorkspaceUpdateHandler extends AbstractBaseHandler<OfflineCDOChecko @Override protected void doExecute(ExecutionEvent event, IProgressMonitor monitor) throws Exception { - OfflineCDOCheckout checkout = elements.get(0); - CDOWorkspace workspace = checkout.getWorkspace(); + final OfflineCDOCheckout checkout = elements.get(0); + + final CDOWorkspace workspace = checkout.getWorkspace(); if (workspace != null) { - // TODO Use progress monitor in update(). - CDOMerger merger = new DefaultCDOMerger.PerFeature.ManyValued(); - CDOTransaction transaction = workspace.update(merger); - transaction.commit(monitor); - - checkout.refresh(); + try + { + mergeDefault(checkout, workspace, monitor); + } + catch (ConflictException ex) + { + if (Support.COMPARE.isAvailable()) + { + mergeCompare(checkout, workspace); + } + else + { + throw ex; + } + } } } + + private void mergeCompare(final OfflineCDOCheckout checkout, final CDOWorkspace workspace) + { + CDOCompareEditorUtil.runWithTitle("Update " + checkout.getLabel(), new Runnable() + { + public void run() + { + CDOTransaction transaction = workspace.update(new CompareCDOMerger() + { + @Override + public void merge(CDOTransaction localTransaction, CDOView remoteView, Set<CDOID> affectedIDs) + throws ConflictException + { + remoteView.properties().put(CompareCDOMerger.PROP_COMPARISON_LABEL, "From remote"); + localTransaction.properties().put(CompareCDOMerger.PROP_COMPARISON_LABEL, "To local"); + + super.merge(localTransaction, remoteView, affectedIDs); + } + }); + + transaction.addTransactionHandler(new CDODefaultTransactionHandler2() + { + @Override + public void rolledBackTransaction(CDOTransaction transaction) + { + closeTransaction(transaction); + } + + @Override + public void committedTransaction(CDOTransaction transaction, CDOCommitContext commitContext) + { + checkout.refresh(); + closeTransaction(transaction); + } + + private void closeTransaction(final CDOTransaction transaction) + { + UIUtil.getDisplay().asyncExec(new Runnable() + { + public void run() + { + transaction.close(); + } + }); + } + }); + } + }); + } + + private void mergeDefault(final OfflineCDOCheckout checkout, final CDOWorkspace workspace, IProgressMonitor monitor) + throws ConcurrentAccessException, CommitException + { + CDOTransaction transaction = workspace.update(new DefaultCDOMerger.PerFeature.ManyValued()); + transaction.commit(monitor); + transaction.close(); + + checkout.refresh(); + } } diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/wizards/RepositoryClonePage.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/wizards/RepositoryClonePage.java index 66b58c3de2..7e764b05a7 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/wizards/RepositoryClonePage.java +++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/wizards/RepositoryClonePage.java @@ -75,6 +75,11 @@ public class RepositoryClonePage extends AbstractRepositoryPage { super.doValidate(properties); + if (controller == null) + { + return; + } + String connectorDescription = controller.getConnectorDescription(); if (StringUtil.isEmpty(connectorDescription)) { diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/wizards/RepositoryRemotePage.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/wizards/RepositoryRemotePage.java index f7463ead73..d77e59459e 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/wizards/RepositoryRemotePage.java +++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/wizards/RepositoryRemotePage.java @@ -16,6 +16,7 @@ import org.eclipse.emf.cdo.explorer.ui.checkouts.wizards.CheckoutWizardPage.Vali import org.eclipse.emf.cdo.internal.explorer.repositories.RemoteCDORepository; import org.eclipse.net4j.util.StringUtil; +import org.eclipse.net4j.util.ui.UIUtil; import org.eclipse.swt.widgets.Composite; @@ -44,7 +45,21 @@ public class RepositoryRemotePage extends AbstractRepositoryPage protected void validateController() { super.validateController(); - validate(); + + if (controller != null) + { + validate(); + } + else + { + UIUtil.getDisplay().asyncExec(new Runnable() + { + public void run() + { + validate(); + } + }); + } } }; } diff --git a/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF index 52181398f9..e9691e0909 100644 --- a/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF @@ -36,7 +36,7 @@ Require-Bundle: org.eclipse.net4j.tests;bundle-version="[4.0.0,5.0.0)";visibilit org.eclipse.emf.cdo.server.admin;bundle-version="[4.1.0,5.0.0)";visibility:=reexport, org.eclipse.gmf.runtime.notation;bundle-version="[1.5.0,2.0.0)";visibility:=reexport, org.eclipse.ocl.ecore;bundle-version="[3.0.0,4.0.0)", - org.apache.log4j;bundle-version="[1.2.15,1.3.0)", + org.apache.log4j;bundle-version="[1.2.0,2.0.0)", com.google.guava;bundle-version="[10.0.0,20.0.0)" Export-Package: base;version="4.0.200", base.impl;version="4.0.200", diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/WorkspaceTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/WorkspaceTest.java index a3dcea5334..463b834bea 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/WorkspaceTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/WorkspaceTest.java @@ -10,22 +10,29 @@ */ package org.eclipse.emf.cdo.tests; +import org.eclipse.emf.cdo.CDOObject; import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.commit.CDOChangeSet; import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.revision.CDOAllRevisionsProvider; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; +import org.eclipse.emf.cdo.compare.CDOCompareUtil; +import org.eclipse.emf.cdo.compare.CDOComparisonScope; import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.internal.server.mem.MEMStore; import org.eclipse.emf.cdo.server.IRepository; import org.eclipse.emf.cdo.server.IStore; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.session.CDOSessionConfiguration; import org.eclipse.emf.cdo.session.CDOSessionConfigurationFactory; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.server.InternalRepository; import org.eclipse.emf.cdo.spi.workspace.InternalCDOWorkspace; +import org.eclipse.emf.cdo.spi.workspace.InternalCDOWorkspaceBase; import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires; import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Skips; @@ -35,6 +42,7 @@ import org.eclipse.emf.cdo.tests.model1.Product1; import org.eclipse.emf.cdo.tests.model1.SalesOrder; import org.eclipse.emf.cdo.tests.model1.VAT; import org.eclipse.emf.cdo.tests.util.TestSessionConfiguration; +import org.eclipse.emf.cdo.transaction.CDOMerger; import org.eclipse.emf.cdo.transaction.CDOMerger.ConflictException; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.util.CDOUtil; @@ -45,13 +53,22 @@ import org.eclipse.emf.cdo.workspace.CDOWorkspaceBase; import org.eclipse.emf.cdo.workspace.CDOWorkspaceConfiguration; import org.eclipse.emf.cdo.workspace.CDOWorkspaceUtil; +import org.eclipse.emf.internal.cdo.transaction.CDOMerger2; + import org.eclipse.net4j.jvm.JVMUtil; import org.eclipse.net4j.util.io.IOUtil; import org.eclipse.net4j.util.lifecycle.ILifecycle; import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; +import org.eclipse.emf.common.util.BasicMonitor; import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.compare.Comparison; +import org.eclipse.emf.compare.Diff; +import org.eclipse.emf.compare.merge.BatchMerger; +import org.eclipse.emf.compare.merge.IBatchMerger; +import org.eclipse.emf.compare.merge.IMerger; +import org.eclipse.emf.compare.merge.IMerger.RegistryImpl; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.spi.cdo.DefaultCDOMerger; @@ -63,6 +80,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; /** * @author Eike Stepper @@ -1262,7 +1280,7 @@ public class WorkspaceTest extends AbstractCDOTest local.commit(); local.close(); - DefaultCDOMerger.PerFeature.ManyValued merger = new DefaultCDOMerger.PerFeature.ManyValued(); + DefaultCDOMerger merger = new DefaultCDOMerger.PerFeature.ManyValued(); local = workspace.update(merger); assertEquals(0, merger.getConflicts().size()); assertEquals(false, local.isDirty()); @@ -1274,7 +1292,7 @@ public class WorkspaceTest extends AbstractCDOTest assertEquals(1, countModifiedProduct(view)); } - public void testConflictMasterAndLocalModify() throws Exception + public void testConflictMasterAndLocalModify_DefaultMerger() throws Exception { CDOID id = CDOUtil.getCDOObject(products.get(1)).cdoID(); @@ -1289,7 +1307,7 @@ public class WorkspaceTest extends AbstractCDOTest local.commit(); local.close(); - DefaultCDOMerger.PerFeature.ManyValued merger = new DefaultCDOMerger.PerFeature.ManyValued(); + DefaultCDOMerger merger = new DefaultCDOMerger.PerFeature.ManyValued(); try { @@ -1310,6 +1328,149 @@ public class WorkspaceTest extends AbstractCDOTest assertEquals(1, countModifiedProduct(view)); } + public void testConflictMasterAndLocalModify_CompareMerger() throws Exception + { + disableLog4j(); + + @SuppressWarnings("unused") + CDOID id = CDOUtil.getCDOObject(products.get(1)).cdoID(); + + InternalCDOWorkspace workspace = checkout("MAIN", CDOBranchPoint.UNSPECIFIED_DATE); + assertNotSame(CDOBranchPoint.UNSPECIFIED_DATE, workspace.getTimeStamp()); + + @SuppressWarnings("unused") + InternalCDOWorkspaceBase base = workspace.getBase(); + + assertEquals(1, modifyProduct(transaction, 1, "MODIFIED_1_")); + transaction.commit(); + + CDOTransaction local = workspace.openTransaction(); + assertEquals(1, modifyProduct(local, 1, "MODIFIED_2_")); + local.commit(); + + local.close(); + + CDOMerger merger = new CDOMerger2() + { + @Deprecated + public CDOChangeSetData merge(CDOChangeSet target, CDOChangeSet source) throws UnsupportedOperationException + { + throw new UnsupportedOperationException(); + } + + public void merge(CDOTransaction localTransaction, CDOView remoteView, Set<CDOID> affectedIDs) + throws ConflictException + { + CDOComparisonScope scope = new CDOComparisonScope.Minimal(remoteView, localTransaction, null, affectedIDs); + Comparison comparison = CDOCompareUtil.compare(scope); + EList<Diff> differences = comparison.getDifferences(); + + IMerger.Registry mergerRegistry = RegistryImpl.createStandaloneInstance(); + + IBatchMerger merger = new BatchMerger(mergerRegistry); + merger.copyAllLeftToRight(differences, new BasicMonitor()); + } + }; + + local = workspace.update(merger); + + List<CDORevision> dirtyRevisions = getDirtyRevisions(local); + dump("dirtyRevisions", dirtyRevisions); + + List<CDORevision> storeRevisions = getStoreRevisions(workspace, dirtyRevisions); + dump("storeRevisions", storeRevisions); + + List<CDORevision> baseRevisions = getBaseRevisions(workspace); + dump("baseRevisions", baseRevisions); + + dump("COMMIT", null); + local.commit(); + + dirtyRevisions = getDirtyRevisions(local); + dump("dirtyRevisions", dirtyRevisions); + + storeRevisions = getStoreRevisions(workspace, dirtyRevisions); + dump("storeRevisions", storeRevisions); + + baseRevisions = getBaseRevisions(workspace); + dump("baseRevisions", baseRevisions); + + local.close(); + + CDOCommitInfo commitInfo = workspace.checkin(); + System.out.println(commitInfo); + } + + private void dump(String label, List<CDORevision> revisions) + { + System.out.println(); + System.out.println(label); + + if (revisions != null) + { + for (CDORevision revision : revisions) + { + System.out.println(" " + revision); + } + } + } + + private boolean containsID(List<CDORevision> revisions, CDOID id) + { + for (CDORevision revision : revisions) + { + if (revision.getID() == id) + { + return true; + } + } + + return false; + } + + private List<CDORevision> getDirtyRevisions(CDOTransaction transaction) + { + List<CDORevision> revisions = new ArrayList<CDORevision>(); + + for (CDOObject dirtyObject : transaction.getDirtyObjects().values()) + { + CDORevision revision = dirtyObject.cdoRevision(false); + revisions.add(revision); + } + + return revisions; + } + + private List<CDORevision> getStoreRevisions(InternalCDOWorkspace workspace, List<CDORevision> dirtyRevisions) + { + List<CDORevision> revisions = new ArrayList<CDORevision>(); + + MEMStore store = (MEMStore)workspace.getLocalRepository().getStore(); + for (InternalCDORevision revision : store.getCurrentRevisions()) + { + if (containsID(dirtyRevisions, revision.getID())) + { + revisions.add(revision); + } + } + + return revisions; + } + + private List<CDORevision> getBaseRevisions(InternalCDOWorkspace workspace) + { + List<CDORevision> revisions = new ArrayList<CDORevision>(); + + InternalCDOWorkspaceBase base = workspace.getBase(); + for (CDOID id : base.getIDs()) + { + CDORevision revision = base.getRevision(id); + revisions.add(revision); + } + + return revisions; + } + public void testRevertNoTransaction() throws Exception { // Checkout local diff --git a/plugins/org.eclipse.emf.cdo.ui.compare/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.ui.compare/META-INF/MANIFEST.MF index 072254f847..80de9744cd 100644 --- a/plugins/org.eclipse.emf.cdo.ui.compare/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.ui.compare/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.emf.cdo.ui.compare;singleton:=true -Bundle-Version: 4.3.0.qualifier +Bundle-Version: 4.3.1.qualifier Bundle-Activator: org.eclipse.emf.cdo.ui.internal.compare.bundle.OM$Activator Bundle-Vendor: %providerName Bundle-ClassPath: . @@ -16,6 +16,10 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)", org.eclipse.emf.cdo.compare;bundle-version="[4.2.0,5.0.0)";visibility:=reexport, org.eclipse.emf.compare.ide.ui;bundle-version="[3.0.0,5.0.0)", org.eclipse.emf.compare.edit;bundle-version="[3.0.0,5.0.0)" -Export-Package: org.eclipse.emf.cdo.ui.compare;version="4.3.0", - org.eclipse.emf.cdo.ui.internal.compare;version="4.3.0";x-internal:=true, - org.eclipse.emf.cdo.ui.internal.compare.bundle;version="4.3.0";x-internal:=true +Import-Package: com.google.common.base;version="[11.0.0,16.0.0)", + com.google.common.collect;version="[11.0.0,16.0.0)", + com.google.common.cache;version="[11.0.0,16.0.0)", + com.google.common.util.concurrent;version="[11.0.0,16.0.0)" +Export-Package: org.eclipse.emf.cdo.ui.compare;version="4.3.1", + org.eclipse.emf.cdo.ui.internal.compare;version="4.3.1";x-friends:="org.eclipse.emf.cdo.explorer.ui", + org.eclipse.emf.cdo.ui.internal.compare.bundle;version="4.3.1";x-internal:=true diff --git a/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/compare/CDOCompareEditorUtil.java b/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/compare/CDOCompareEditorUtil.java index 17b782a0b1..d33f2d4353 100644 --- a/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/compare/CDOCompareEditorUtil.java +++ b/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/compare/CDOCompareEditorUtil.java @@ -18,20 +18,24 @@ import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; import org.eclipse.emf.cdo.compare.CDOCompare; import org.eclipse.emf.cdo.compare.CDOCompareUtil; +import org.eclipse.emf.cdo.compare.CDOComparisonScope; import org.eclipse.emf.cdo.session.CDORepositoryInfo; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil; +import org.eclipse.emf.cdo.spi.common.revision.CDOIDMapper; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.transaction.CDOTransactionOpener; import org.eclipse.emf.cdo.ui.CDOItemProvider; +import org.eclipse.emf.cdo.ui.internal.compare.CompareCDOMerger; import org.eclipse.emf.cdo.ui.internal.compare.bundle.OM; import org.eclipse.emf.cdo.util.CDOUtil; import org.eclipse.emf.cdo.view.CDOView; import org.eclipse.emf.cdo.view.CDOViewOpener; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; +import org.eclipse.net4j.util.registry.IRegistry; import org.eclipse.net4j.util.ui.UIUtil; import org.eclipse.emf.common.notify.AdapterFactory; @@ -64,8 +68,10 @@ import org.eclipse.swt.widgets.Shell; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; /** * Static methods to open an EMF Compare dialog. @@ -75,6 +81,8 @@ import java.util.Map; */ public class CDOCompareEditorUtil { + private static final ThreadLocal<String> COMPARISON_TITLE = new ThreadLocal<String>(); + private static final ThreadLocal<Boolean> ACTIVATE_EDITOR = new ThreadLocal<Boolean>(); private static final ThreadLocal<Boolean> SUPPRESS_COMMIT = new ThreadLocal<Boolean>(); @@ -160,6 +168,23 @@ public class CDOCompareEditorUtil } /** + * @noreference This method is not intended to be referenced by clients. + */ + public static boolean openEditor(CDOView leftView, CDOView rightView, Set<CDOID> affectedIDs, boolean activate) + { + ACTIVATE_EDITOR.set(activate); + + try + { + return openDialog(leftView, rightView, affectedIDs); + } + finally + { + ACTIVATE_EDITOR.remove(); + } + } + + /** * @since 4.3 */ public static boolean openDialog(CDOSession session, CDOBranchPoint leftPoint, CDOBranchPoint rightPoint) @@ -249,11 +274,26 @@ public class CDOCompareEditorUtil /** * @since 4.3 */ - public static boolean openDialog(CDOView leftView, final CDOView rightView, CDOView[] originView, - CDOViewOpener viewOpener) + public static boolean openDialog(CDOView leftView, CDOView rightView, CDOView[] originView, CDOViewOpener viewOpener) + { + Input input = createComparisonInput(leftView, rightView, originView, viewOpener); + return openDialog(input, rightView); + } + + /** + * @noreference This method is not intended to be referenced by clients. + */ + public static boolean openDialog(CDOView leftView, CDOView rightView, Set<CDOID> affectedIDs) { - final Input input = createComparisonInput(leftView, rightView, originView, viewOpener); + Input input = createComparisonInput(leftView, rightView, affectedIDs); + return openDialog(input, rightView); + } + /** + * @noreference This method is not intended to be referenced by clients. + */ + public static boolean openDialog(final Input input, final CDOView rightView) + { if (input == null) { UIUtil.getDisplay().syncExec(new Runnable() @@ -319,6 +359,18 @@ public class CDOCompareEditorUtil CDOViewOpener viewOpener) { Comparison comparison = CDOCompareUtil.compare(leftView, rightView, originView, viewOpener); + return createComparisonInput(leftView, rightView, comparison); + } + + private static Input createComparisonInput(CDOView leftView, CDOView rightView, Set<CDOID> affectedIDs) + { + CDOComparisonScope scope = new CDOComparisonScope.Minimal(leftView, rightView, null, affectedIDs); + Comparison comparison = CDOCompareUtil.compare(scope); + return createComparisonInput(leftView, rightView, comparison); + } + + private static Input createComparisonInput(CDOView leftView, CDOView rightView, Comparison comparison) + { if (comparison.getDifferences().isEmpty()) { return null; @@ -348,19 +400,54 @@ public class CDOCompareEditorUtil } }; - Image leftImage = itemProvider.getImage(leftBranchPoint); - String leftLabel = itemProvider.getText(leftBranchPoint); - Image rightImage = itemProvider.getImage(rightBranchPoint); - String rightLabel = itemProvider.getText(rightBranchPoint); + IRegistry<String, Object> leftProperties = leftView.properties(); + Image leftImage = (Image)leftProperties.get(CompareCDOMerger.PROP_COMPARISON_IMAGE); + if (leftImage == null) + { + leftImage = itemProvider.getImage(leftBranchPoint); + } + + String leftLabel = (String)leftProperties.get(CompareCDOMerger.PROP_COMPARISON_LABEL); + if (leftLabel == null) + { + leftLabel = itemProvider.getText(leftBranchPoint); + } + + IRegistry<String, Object> rightProperties = rightView.properties(); + Image rightImage = (Image)rightProperties.get(CompareCDOMerger.PROP_COMPARISON_IMAGE); + if (rightImage == null) + { + rightImage = itemProvider.getImage(rightBranchPoint); + } + + String rightLabel = (String)rightProperties.get(CompareCDOMerger.PROP_COMPARISON_LABEL); + if (rightLabel == null) + { + rightLabel = itemProvider.getText(rightBranchPoint); + } + itemProvider.dispose(); boolean leftEditable = !leftView.isReadOnly(); boolean rightEditable = !rightView.isReadOnly(); - boolean merge = leftEditable || rightEditable; - if (merge) + + String title = COMPARISON_TITLE.get(); + if (title == null) { - leftLabel = "From " + leftLabel; - rightLabel = "Into " + rightLabel; + String repositoryName = ((InternalCDOView)leftView).getRepositoryName(); + + boolean merge = leftEditable || rightEditable; + if (merge) + { + title = "Merge " + repositoryName + " from " + leftLabel + " into " + rightLabel; + + leftLabel = "From " + leftLabel; + rightLabel = "Into " + rightLabel; + } + else + { + title = "Compare " + repositoryName + " between " + leftLabel + " and " + rightLabel; + } } CompareConfiguration configuration = new CompareConfiguration(); @@ -371,16 +458,29 @@ public class CDOCompareEditorUtil configuration.setRightLabel(rightLabel); configuration.setRightEditable(rightEditable); - String repositoryName = ((InternalCDOView)leftView).getRepositoryName(); - String title = (merge ? "Merge " : "Compare ") + repositoryName + " " + leftLabel + (merge ? " into " : " and ") - + rightLabel; - Input input = new Input(rightView, configuration, comparison, editingDomain, adapterFactory); input.setTitle(title); return input; } /** + * @noreference This method is not intended to be referenced by clients. + */ + public static void runWithTitle(String title, Runnable runnable) + { + COMPARISON_TITLE.set(title); + + try + { + runnable.run(); + } + finally + { + COMPARISON_TITLE.remove(); + } + } + + /** * @since 4.3 */ public static boolean isSuppressCommit() @@ -554,6 +654,8 @@ public class CDOCompareEditorUtil Collection<CDOObject> values = transaction.getNewObjects().values(); if (!values.isEmpty()) { + Map<CDOID, CDOID> idMappings = new HashMap<CDOID, CDOID>(); + CDOObject[] rightObjects = values.toArray(new CDOObject[values.size()]); for (CDOObject rightObject : rightObjects) { @@ -563,24 +665,43 @@ public class CDOCompareEditorUtil CDOObject leftObject = CDOUtil.getCDOObject(match.getLeft()); CDOID id = leftObject.cdoID(); + idMappings.put(rightObject.cdoID(), id); org.eclipse.emf.internal.cdo.transaction.CDOTransactionImpl.resurrectObject(rightObject, id); } } - } - try - { - if (!suppressCommit) + if (!idMappings.isEmpty()) { - transaction.commit(monitor); - setDirty(false); + CDOIDMapper idMapper = new CDOIDMapper(idMappings); + // idMapper.setAllowUnmappedTempIDs(true); + + for (CDOObject newObject : values) + { + InternalCDORevision revision = (InternalCDORevision)newObject.cdoRevision(); + revision.adjustReferences(idMapper); + } + + for (CDOObject dirtyObject : transaction.getDirtyObjects().values()) + { + InternalCDORevision revision = (InternalCDORevision)dirtyObject.cdoRevision(); + revision.adjustReferences(idMapper); + } } } - catch (Exception ex) + } + + try + { + if (!suppressCommit) { - OM.BUNDLE.coreException(ex); + transaction.commit(monitor); + setDirty(false); } } + catch (Exception ex) + { + OM.BUNDLE.coreException(ex); + } } } diff --git a/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/internal/compare/CompareCDOMerger.java b/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/internal/compare/CompareCDOMerger.java new file mode 100644 index 0000000000..e314b0e92b --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/internal/compare/CompareCDOMerger.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2015 Eike Stepper (Berlin, Germany) and others. + * 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: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.ui.internal.compare; + +import org.eclipse.emf.cdo.common.commit.CDOChangeSet; +import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.transaction.CDOTransaction; +import org.eclipse.emf.cdo.ui.compare.CDOCompareEditorUtil; +import org.eclipse.emf.cdo.view.CDOView; + +import org.eclipse.emf.internal.cdo.transaction.CDOMerger2; + +import org.eclipse.net4j.util.lifecycle.ILifecycle; +import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter; +import org.eclipse.net4j.util.ui.UIUtil; + +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; + +import java.util.Set; + +/** + * @author Eike Stepper + */ +public class CompareCDOMerger implements CDOMerger2 +{ + public static final String PROP_COMPARISON_LABEL = "comparison.label"; + public static final String PROP_COMPARISON_IMAGE = "comparison.image"; + + public CompareCDOMerger() + { + } + + @Deprecated + public CDOChangeSetData merge(CDOChangeSet target, CDOChangeSet source) throws UnsupportedOperationException + { + throw new UnsupportedOperationException(); + } + + public void merge(final CDOTransaction localTransaction, CDOView remoteView, Set<CDOID> affectedIDs) + throws ConflictException + { + final IEditorPart[] result = { null }; + + final IWorkbenchPage page = UIUtil.getActiveWorkbenchPage(); + final IPartListener listener = new IPartListener() + { + @SuppressWarnings("restriction") + public void partOpened(IWorkbenchPart part) + { + if (part instanceof org.eclipse.compare.internal.CompareEditor) + { + result[0] = (IEditorPart)part; + } + } + + public void partDeactivated(IWorkbenchPart part) + { + // Do nothing. + } + + public void partClosed(IWorkbenchPart part) + { + if (part == result[0]) + { + localTransaction.close(); + page.removePartListener(this); + } + } + + public void partBroughtToTop(IWorkbenchPart part) + { + // Do nothing. + } + + public void partActivated(IWorkbenchPart part) + { + // Do nothing. + } + }; + + page.addPartListener(listener); + + localTransaction.addListener(new LifecycleEventAdapter() + { + @Override + protected void onDeactivated(ILifecycle lifecycle) + { + if (result[0] != null) + { + UIUtil.getDisplay().asyncExec(new Runnable() + { + public void run() + { + page.closeEditor(result[0], false); + } + }); + } + } + }); + + CDOCompareEditorUtil.openEditor(remoteView, localTransaction, affectedIDs, true); + } +} diff --git a/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/internal/compare/CompareConflictHandler.java b/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/internal/compare/CompareConflictHandler.java index f052ca9b6a..5b9bcf99a6 100644 --- a/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/internal/compare/CompareConflictHandler.java +++ b/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/internal/compare/CompareConflictHandler.java @@ -23,7 +23,6 @@ import org.eclipse.emf.spi.cdo.CDOMergingConflictResolver; /** * @author Eike Stepper */ -@SuppressWarnings("restriction") public class CompareConflictHandler implements ConflictHandler { public CompareConflictHandler() @@ -54,7 +53,7 @@ public class CompareConflictHandler implements ConflictHandler try { CDOCompareEditorUtil.setSuppressCommit(true); - return CDOCompareEditorUtil.openDialog(remoteView, transaction, null); + return CDOCompareEditorUtil.openDialog(remoteView, transaction, (CDOView[])null); } finally { diff --git a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/ui/CDOLabelDecorator.java b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/ui/CDOLabelDecorator.java index f1826f0e05..e0f6eab7b4 100644 --- a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/ui/CDOLabelDecorator.java +++ b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/ui/CDOLabelDecorator.java @@ -105,7 +105,15 @@ public class CDOLabelDecorator implements ILabelDecorator public Image decorateImage(Image image, Object element) { - return decorate(image, element); + try + { + image = decorate(image, element); + } + catch (RuntimeException ignore) + { + } + + return image; } public String decorateText(String text, Object element) diff --git a/plugins/org.eclipse.emf.cdo.workspace/src/org/eclipse/emf/cdo/internal/workspace/CDOWorkspaceImpl.java b/plugins/org.eclipse.emf.cdo.workspace/src/org/eclipse/emf/cdo/internal/workspace/CDOWorkspaceImpl.java index 5bce99852c..9d3e791aa0 100644 --- a/plugins/org.eclipse.emf.cdo.workspace/src/org/eclipse/emf/cdo/internal/workspace/CDOWorkspaceImpl.java +++ b/plugins/org.eclipse.emf.cdo.workspace/src/org/eclipse/emf/cdo/internal/workspace/CDOWorkspaceImpl.java @@ -65,6 +65,7 @@ import org.eclipse.emf.cdo.transaction.CDODefaultTransactionHandler1; import org.eclipse.emf.cdo.transaction.CDODefaultTransactionHandler2; import org.eclipse.emf.cdo.transaction.CDODefaultTransactionHandler3; import org.eclipse.emf.cdo.transaction.CDOMerger; +import org.eclipse.emf.cdo.transaction.CDOMerger.ConflictException; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.transaction.CDOTransactionFinishedEvent; import org.eclipse.emf.cdo.util.CommitException; @@ -73,6 +74,8 @@ import org.eclipse.emf.cdo.util.ReadOnlyException; import org.eclipse.emf.cdo.view.CDOView; import org.eclipse.emf.cdo.workspace.CDOWorkspace; +import org.eclipse.emf.internal.cdo.transaction.CDOMerger2; + import org.eclipse.net4j.Net4jUtil; import org.eclipse.net4j.jvm.IJVMAcceptor; import org.eclipse.net4j.jvm.IJVMConnector; @@ -192,8 +195,7 @@ public class CDOWorkspaceImpl extends Notifier implements InternalCDOWorkspace protected void checkout() { final OMMonitor monitor = new Monitor(); - final IStoreAccessor.Raw accessor = getLocalWriter(null); - StoreThreadLocal.setAccessor(accessor); + final IStoreAccessor.Raw accessor = beginRawAccess(null); try { @@ -526,151 +528,218 @@ public class CDOWorkspaceImpl extends Notifier implements InternalCDOWorkspace timeStamp = remoteSession.getLastUpdateTime(); } - final long newTimeStamp = timeStamp; + long newTimeStamp = timeStamp; + + InternalCDOBranchManager branchManager = remoteSession.getBranchManager(); + CDOBranchPoint basePoint = branchManager.getBranch(this.branchPath).getPoint(this.timeStamp); + CDOBranchPoint remotePoint = branchManager.getBranch(branchPath).getPoint(newTimeStamp); + CDOBranchPointRange range = CDOBranchUtil.createRange(basePoint, remotePoint); + + CDOChangeSetData remoteData = remoteSession.getSessionProtocol().loadChangeSets(range)[0]; + CDOChangeSetData localData = getLocalChanges(); + + InternalCDOTransaction transaction; + + if (merger instanceof CDOMerger2) + { + CDOMerger2 merger2 = (CDOMerger2)merger; - final InternalCDOBranchManager branchManager = remoteSession.getBranchManager(); - final CDOBranchPoint basePoint = branchManager.getBranch(this.branchPath).getPoint(this.timeStamp); - final CDOBranchPoint remotePoint = branchManager.getBranch(branchPath).getPoint(newTimeStamp); + Set<CDOID> affectedIDs = new HashSet<CDOID>(); + addIDs(affectedIDs, remoteData); + addIDs(affectedIDs, localData); - final CDOBranchPointRange range = CDOBranchUtil.createRange(basePoint, remotePoint); + transaction = openLocalTransaction(remoteSession, remoteData, remotePoint, newTimeStamp); - final CDOChangeSetData remoteData = remoteSession.getSessionProtocol().loadChangeSets(range)[0]; - final CDOChangeSetData localData = getLocalChanges(); - final CDOChangeSetData result = getMergeResult(merger, basePoint, remotePoint, localData, remoteData); + InternalCDOBranch remoteBranch = remoteSession.getBranchManager().getBranch(branchPath); + CDOView remoteView = remoteSession.openView(remoteBranch); - final InternalCDOTransaction transaction = (InternalCDOTransaction)getLocalSession().openTransaction(); - initView(transaction); + merger2.merge(transaction, remoteView, affectedIDs); + } + else + { + CDOChangeSetData result = getMergeResult(merger, basePoint, remotePoint, localData, remoteData); + + transaction = openLocalTransaction(remoteSession, remoteData, remotePoint, newTimeStamp); + transaction.applyChangeSet(result, new BaseRevisionProvider(), this, null, false); + } - transaction.applyChangeSet(result, new BaseRevisionProvider(), this, null, false); - transaction.addTransactionHandler(new CDODefaultTransactionHandler3() + if (saveBranchPoint) { - @Override - public void rolledBackTransaction(CDOTransaction transaction) + CDOBranch branch = remotePoint.getBranch(); + branchID = branch.getID(); + this.branchPath = branch.getPathName(); + this.timeStamp = timeStamp; + saveProperties(); + } + + return transaction; + } + catch (ConflictException ex) + { + return handleMergeConflict(ex); + } + catch (RuntimeException ex) + { + closeRemoteSession(remoteSession); + throw ex; + } + catch (Error ex) + { + closeRemoteSession(remoteSession); + throw ex; + } + } + + private InternalCDOTransaction openLocalTransaction(final InternalCDOSession remoteSession, + final CDOChangeSetData remoteData, final CDOBranchPoint remotePoint, final long newTimeStamp) + { + InternalCDOTransaction transaction = (InternalCDOTransaction)getLocalSession().openTransaction(); + initView(transaction); + + transaction.addTransactionHandler(new CDODefaultTransactionHandler3() + { + @Override + public void committedTransaction(CDOTransaction transaction, CDOCommitContext commitContext, CDOCommitInfo result) + { + Set<CDOID> affectedIDs = getAffectedIDs(commitContext, remoteData); + + CDORevisionProvider local = CDOWorkspaceImpl.this; + CDORevisionProvider remote = new ManagedRevisionProvider(remoteSession.getRevisionManager(), remotePoint); + + updateBase(local, remote, affectedIDs); + setDirtyFromBase(); + setTimeStamp(newTimeStamp); + + fireEvent(new ObjectStatesChangedEventImpl(CDOWorkspaceImpl.this, affectedIDs)); + } + + private void updateBase(CDORevisionProvider local, CDORevisionProvider remote, Set<CDOID> affectedIDs) + { + IStoreAccessor.Raw accessor = null; + + try { - closeRemoteSession(remoteSession); + for (CDOID id : affectedIDs) + { + InternalCDORevision localRevision = getRevision(id, local); + InternalCDORevision remoteRevision = getRevision(id, remote); + accessor = updateBase(localRevision, remoteRevision, id, accessor); + } + } + finally + { + finishRawAccess(accessor); } + } - @Override - public void committedTransaction(CDOTransaction transaction, CDOCommitContext commitContext, - CDOCommitInfo result) + private IStoreAccessor.Raw updateBase(InternalCDORevision localRevision, InternalCDORevision remoteRevision, + CDOID id, IStoreAccessor.Raw accessor) + { + if (localRevision == null) { - try + if (remoteRevision == null) { - Set<CDOID> affectedIDs = getAffectedIDs(commitContext, remoteData); - - CDORevisionProvider local = CDOWorkspaceImpl.this; - CDORevisionProvider remote = new ManagedRevisionProvider(remoteSession.getRevisionManager(), remotePoint); - - updateBase(affectedIDs, local, remote); - setTimeStamp(newTimeStamp); - - fireEvent(new ObjectStatesChangedEventImpl(CDOWorkspaceImpl.this, affectedIDs)); + // Unchanged + base.deregisterObject(id); } - finally + else { - closeRemoteSession(remoteSession); + // Detached + InternalCDORevision baseRevision = remoteRevision.copy(); + baseRevision.setBranchPoint(localSessionHead); + + base.registerChangedOrDetachedObject(baseRevision); } } - - private void updateBase(Set<CDOID> affectedIDs, CDORevisionProvider local, CDORevisionProvider remote) + else { - for (CDOID id : affectedIDs) + if (remoteRevision == null) { - CDORevision localRevision = getRevision(id, local); - CDORevision remoteRevision = getRevision(id, remote); - if (localRevision == null) + // Added + base.registerAddedObject(id); + } + else + { + InternalCDORevision baseRevision = null; + if (localRevision.getVersion() != remoteRevision.getVersion()) { - if (remoteRevision == null) - { - // Unchanged - base.deregisterObject(id); - } - else - { - // Detached - InternalCDORevision baseRevision = ((InternalCDORevision)remoteRevision).copy(); - baseRevision.setBranchPoint(localSessionHead); + baseRevision = (InternalCDORevision)base.getRevision(id); + } - base.registerChangedOrDetachedObject(baseRevision); - } + // Unchanged + base.deregisterObject(id); + + CDORevisionDelta delta = localRevision.compare(remoteRevision); + if (!delta.isEmpty()) + { + // Changed + baseRevision = remoteRevision.copy(); + baseRevision.setBranchPoint(localSessionHead); + + base.registerChangedOrDetachedObject(baseRevision); } - else + else if (baseRevision != null) { - if (remoteRevision == null) - { - // Added - base.registerAddedObject(id); - } - else + // If the delta is empty but multiple local revisions exist replace them all by the remote revision. + // This compensates the missing checkin post processing as there is no base revision anymore. + accessor = beginRawAccess(accessor); + + int version = Math.abs(localRevision.getVersion()); + CDOBranch branch = localRevision.getBranch(); + EClass eClass = localRevision.getEClass(); + + for (int v = baseRevision.getVersion(); v <= version; v++) { - // Unchanged - base.deregisterObject(id); - - CDORevisionDelta delta = localRevision.compare(remoteRevision); - if (!delta.isEmpty()) - { - // Changed - InternalCDORevision baseRevision = ((InternalCDORevision)remoteRevision).copy(); - baseRevision.setBranchPoint(localSessionHead); - - base.registerChangedOrDetachedObject(baseRevision); - } + accessor.rawDelete(id, v, branch, eClass, new Monitor()); } + + localRevision = remoteRevision.copy(); + localRevision.setBranchPoint(localSessionHead); + + accessor.rawStore(localRevision, new Monitor()); } } } - private Set<CDOID> getAffectedIDs(CDOCommitContext commitContext, final CDOChangeSetData remoteData) - { - Set<CDOID> affectedIDs = new HashSet<CDOID>(); - - // Base IDs - affectedIDs.addAll(base.getIDs()); - - // Remote IDs - affectedIDs.addAll(remoteData.getChangeKinds().keySet()); - - // Local IDs - affectedIDs.addAll(commitContext.getNewObjects().keySet()); - affectedIDs.addAll(commitContext.getDirtyObjects().keySet()); - affectedIDs.addAll(commitContext.getDetachedObjects().keySet()); + return accessor; + } - return affectedIDs; - } + private Set<CDOID> getAffectedIDs(CDOCommitContext commitContext, final CDOChangeSetData remoteData) + { + Set<CDOID> affectedIDs = new HashSet<CDOID>(); + addIDs(affectedIDs, base.getIDs()); // Base IDs + addIDs(affectedIDs, remoteData.getChangeKinds()); // Remote IDs + addIDs(affectedIDs, commitContext); // Local IDs + return affectedIDs; + } - private CDORevision getRevision(CDOID id, CDORevisionProvider revisionProvider) + private InternalCDORevision getRevision(CDOID id, CDORevisionProvider revisionProvider) + { + CDORevision revision = revisionProvider.getRevision(id); + if (revision instanceof DetachedCDORevision) { - CDORevision revision = revisionProvider.getRevision(id); - if (revision instanceof DetachedCDORevision) - { - revision = null; - } - - return revision; + revision = null; } - }); - if (saveBranchPoint) - { - CDOBranch branch = remotePoint.getBranch(); - branchID = branch.getID(); - this.branchPath = branch.getPathName(); - this.timeStamp = timeStamp; - saveProperties(); + return (InternalCDORevision)revision; } + }); - return transaction; - } - catch (RuntimeException ex) + transaction.addListener(new LifecycleEventAdapter() { - closeRemoteSession(remoteSession); - throw ex; - } - catch (Error ex) - { - closeRemoteSession(remoteSession); - throw ex; - } + @Override + protected void onDeactivated(ILifecycle lifecycle) + { + closeRemoteSession(remoteSession); + } + }); + + return transaction; + } + + private InternalCDOTransaction handleMergeConflict(ConflictException ex) + { + throw ex; } private CDOChangeSetData getMergeResult(CDOMerger merger, CDOBranchPoint basePoint, CDOBranchPoint remotePoint, @@ -695,9 +764,7 @@ public class CDOWorkspaceImpl extends Notifier implements InternalCDOWorkspace public void revert(CDOChangeSetData revertData) { final CDOBranch localBranch = localSessionHead.getBranch(); - - IStoreAccessor.Raw accessor = getLocalWriter(null); - StoreThreadLocal.setAccessor(accessor); + IStoreAccessor.Raw accessor = beginRawAccess(null); final List<InternalCDORevision> changedRevisions = new ArrayList<InternalCDORevision>(); for (CDORevisionKey key : revertData.getChangedObjects()) @@ -864,12 +931,7 @@ public class CDOWorkspaceImpl extends Notifier implements InternalCDOWorkspace clearBase(); setTimeStamp(info.getTimeStamp()); - - for (CDOIDAndVersion key : changes.getNewObjects()) - { - ids.add(key.getID()); - } - + addIDs(ids, changes.getNewObjects()); return info; } finally @@ -911,23 +973,13 @@ public class CDOWorkspaceImpl extends Notifier implements InternalCDOWorkspace for (int v = baseRevision.getVersion(); v < localSessionRevision.getVersion(); v++) { - if (accessor == null) - { - accessor = getLocalWriter(null); - StoreThreadLocal.setAccessor(accessor); - } - + accessor = beginRawAccess(accessor); accessor.rawDelete(id, v, localSessionBranch, eClass, new Monitor()); } if (localSessionRevision.getVersion() != remoteRevision.getVersion()) { - if (accessor == null) - { - accessor = getLocalWriter(null); - StoreThreadLocal.setAccessor(accessor); - } - + accessor = beginRawAccess(accessor); accessor.rawDelete(id, localSessionRevision.getVersion(), localSessionBranch, eClass, new Monitor()); // Local session revisions are not cached and can directly be modified and stored in the local repository. @@ -946,6 +998,17 @@ public class CDOWorkspaceImpl extends Notifier implements InternalCDOWorkspace return ids; } + private IStoreAccessor.Raw beginRawAccess(IStoreAccessor.Raw accessor) + { + if (accessor == null) + { + accessor = getLocalWriter(null); + StoreThreadLocal.setAccessor(accessor); + } + + return accessor; + } + private void finishRawAccess(IStoreAccessor.Raw accessor) { if (accessor != null) @@ -1348,6 +1411,38 @@ public class CDOWorkspaceImpl extends Notifier implements InternalCDOWorkspace fixed = Boolean.parseBoolean(props.get(PROP_FIXED)); } + private void addIDs(Set<CDOID> result, Set<CDOID> ids) + { + result.addAll(ids); + } + + private void addIDs(Set<CDOID> result, Map<CDOID, ?> map) + { + addIDs(result, map.keySet()); + } + + private void addIDs(Set<CDOID> ids, List<? extends CDOIDAndVersion> keys) + { + for (CDOIDAndVersion key : keys) + { + ids.add(key.getID()); + } + } + + private void addIDs(Set<CDOID> ids, CDOChangeSetData changeSetData) + { + addIDs(ids, changeSetData.getNewObjects()); + addIDs(ids, changeSetData.getChangedObjects()); + addIDs(ids, changeSetData.getDetachedObjects()); + } + + private void addIDs(Set<CDOID> result, CDOCommitContext commitContext) + { + addIDs(result, commitContext.getNewObjects()); + addIDs(result, commitContext.getDirtyObjects()); + addIDs(result, commitContext.getDetachedObjects()); + } + /** * @author Eike Stepper */ diff --git a/plugins/org.eclipse.emf.cdo.workspace/src/org/eclipse/emf/cdo/internal/workspace/CachingCDOWorkspaceBase.java b/plugins/org.eclipse.emf.cdo.workspace/src/org/eclipse/emf/cdo/internal/workspace/CachingCDOWorkspaceBase.java new file mode 100644 index 0000000000..aaf9291d3f --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.workspace/src/org/eclipse/emf/cdo/internal/workspace/CachingCDOWorkspaceBase.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2015 Eike Stepper (Berlin, Germany) and others. + * 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: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.internal.workspace; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; +import org.eclipse.emf.cdo.spi.common.revision.StubCDORevision; +import org.eclipse.emf.cdo.spi.workspace.InternalCDOWorkspace; + +import org.eclipse.emf.ecore.EcorePackage; + +import java.io.File; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Eike Stepper + */ +public class CachingCDOWorkspaceBase extends FolderCDOWorkspaceBase +{ + private static final CDORevision ADDED = new StubCDORevision(EcorePackage.Literals.EOBJECT) + { + @Override + public String toString() + { + return "ADDED"; + } + }; + + private final Map<CDOID, CDORevision> revisions = new LinkedHashMap<CDOID, CDORevision>(); + + private final Map<CDOID, Integer> detachedVersions = new LinkedHashMap<CDOID, Integer>(); + + public CachingCDOWorkspaceBase(File folder) + { + super(folder); + } + + @Override + public void init(InternalCDOWorkspace workspace) + { + super.init(workspace); + + for (CDOID id : getIDs()) + { + CDORevision revision = getRevision(id); + if (revision == null) + { + revision = ADDED; + } + + revisions.put(id, revision); + } + + handleAddedAndDetachedObjects(new AddedAndDetachedHandler() + { + public void handleAddedAndDetachedHandler(CDOID id, int detachedVersion) + { + detachedVersions.put(id, detachedVersion); + } + }); + } + + @Override + protected void doRegisterChangedOrDetachedObject(InternalCDORevision revision) + { + super.doRegisterChangedOrDetachedObject(revision); + + CDOID id = revision.getID(); + if (revisions.containsKey(id)) + { + return; + } + + revisions.put(id, revision); + } + + @Override + protected void doRegisterAddedAndDetachedObject(InternalCDORevision revision) + { + super.doRegisterAddedAndDetachedObject(revision); + + CDOID id = revision.getID(); + int detachedVersion = revision.getVersion(); + detachedVersions.put(id, detachedVersion); + } + + @Override + protected void doRegisterAddedObject(CDOID id) + { + super.doRegisterAddedObject(id); + revisions.put(id, ADDED); + } + + @Override + protected void doDeregisterObject(CDOID id) + { + super.doDeregisterObject(id); + revisions.remove(id); + } + + @Override + protected void doClear() + { + super.doClear(); + revisions.clear(); + detachedVersions.clear(); + } +} diff --git a/plugins/org.eclipse.emf.cdo.workspace/src/org/eclipse/emf/cdo/internal/workspace/FolderCDOWorkspaceBase.java b/plugins/org.eclipse.emf.cdo.workspace/src/org/eclipse/emf/cdo/internal/workspace/FolderCDOWorkspaceBase.java index 414de9374c..916f4a1b35 100644 --- a/plugins/org.eclipse.emf.cdo.workspace/src/org/eclipse/emf/cdo/internal/workspace/FolderCDOWorkspaceBase.java +++ b/plugins/org.eclipse.emf.cdo.workspace/src/org/eclipse/emf/cdo/internal/workspace/FolderCDOWorkspaceBase.java @@ -84,44 +84,18 @@ public class FolderCDOWorkspaceBase extends AbstractCDOWorkspaceBase return file.length() == 0; } - public void deleteAddedAndDetachedObjects(IStoreAccessor.Raw accessor, CDOBranch branch) + public void deleteAddedAndDetachedObjects(final IStoreAccessor.Raw accessor, final CDOBranch branch) { - if (!addedAndDetachedFile.exists()) + handleAddedAndDetachedObjects(new AddedAndDetachedHandler() { - return; - } - - FileReader fileReader = null; - - try - { - fileReader = new FileReader(addedAndDetachedFile); - - @SuppressWarnings("resource") - BufferedReader lineReader = new BufferedReader(fileReader); - - String line; - while ((line = lineReader.readLine()) != null) + public void handleAddedAndDetachedHandler(CDOID id, int detachedVersion) { - String[] tokens = line.split("\t"); - - CDOID id = CDOIDUtil.read(tokens[0]); - int detachedVersion = Integer.parseInt(tokens[1]); - for (int v = 1; v <= detachedVersion; v++) { accessor.rawDelete(id, v, branch, null, new Monitor()); } } - } - catch (IOException ex) - { - throw new IllegalStateException("Could not read from " + addedAndDetachedFile, ex); - } - finally - { - IOUtil.close(fileReader); - } + }); } @Override @@ -217,6 +191,43 @@ public class FolderCDOWorkspaceBase extends AbstractCDOWorkspaceBase checkExists(file, false); } + protected final void handleAddedAndDetachedObjects(AddedAndDetachedHandler handler) + { + if (!addedAndDetachedFile.exists()) + { + return; + } + + FileReader fileReader = null; + + try + { + fileReader = new FileReader(addedAndDetachedFile); + + @SuppressWarnings("resource") + BufferedReader lineReader = new BufferedReader(fileReader); + + String line; + while ((line = lineReader.readLine()) != null) + { + String[] tokens = line.split("\t"); + + CDOID id = CDOIDUtil.read(tokens[0]); + int detachedVersion = Integer.parseInt(tokens[1]); + + handler.handleAddedAndDetachedHandler(id, detachedVersion); + } + } + catch (IOException ex) + { + throw new IllegalStateException("Could not read from " + addedAndDetachedFile, ex); + } + finally + { + IOUtil.close(fileReader); + } + } + protected CDOID getCDOID(String filename) { return CDOIDUtil.read(filename); @@ -333,6 +344,14 @@ public class FolderCDOWorkspaceBase extends AbstractCDOWorkspaceBase /** * @author Eike Stepper */ + public interface AddedAndDetachedHandler + { + public void handleAddedAndDetachedHandler(CDOID id, int detachedVersion); + } + + /** + * @author Eike Stepper + */ public static final class Factory extends org.eclipse.net4j.util.factory.Factory { public static final String TYPE = "folder"; diff --git a/plugins/org.eclipse.emf.cdo/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo/META-INF/MANIFEST.MF index 8b95bda95a..b50a2711a9 100644 --- a/plugins/org.eclipse.emf.cdo/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo/META-INF/MANIFEST.MF @@ -71,7 +71,9 @@ Export-Package: org.eclipse.emf.cdo;version="4.4.1", org.eclipse.emf.cdo.server, org.eclipse.emf.cdo.tests, org.eclipse.emf.cdo.defs, - org.eclipse.emf.cdo.ui", + org.eclipse.emf.cdo.ui, + org.eclipse.emf.cdo.workspace, + org.eclipse.emf.cdo.ui.compare", org.eclipse.emf.internal.cdo.util;version="4.4.1"; x-friends:="org.eclipse.emf.cdo.net4j, org.eclipse.emf.cdo.server, diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOMerger2.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOMerger2.java new file mode 100644 index 0000000000..a41796eb89 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOMerger2.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015 Eike Stepper (Berlin, Germany) and others. + * 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: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.internal.cdo.transaction; + +import org.eclipse.emf.cdo.common.commit.CDOChangeSet; +import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.transaction.CDOMerger; +import org.eclipse.emf.cdo.transaction.CDOTransaction; +import org.eclipse.emf.cdo.view.CDOView; + +import java.util.Set; + +/** + * @author Eike Stepper + */ +public interface CDOMerger2 extends CDOMerger +{ + /** + * @noreference This method is not intended to be referenced by clients. + */ + @Deprecated + public CDOChangeSetData merge(CDOChangeSet target, CDOChangeSet source) throws UnsupportedOperationException; + + public void merge(CDOTransaction localTransaction, CDOView remoteView, Set<CDOID> affectedIDs) + throws ConflictException; +} diff --git a/plugins/org.eclipse.net4j.tests/META-INF/MANIFEST.MF b/plugins/org.eclipse.net4j.tests/META-INF/MANIFEST.MF index 1eea6b04f3..6dc24f67b8 100644 --- a/plugins/org.eclipse.net4j.tests/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.net4j.tests/META-INF/MANIFEST.MF @@ -16,6 +16,7 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)";visibili org.eclipse.net4j.http.server;bundle-version="[4.0.0,5.0.0)";visibility:=reexport, org.eclipse.net4j.defs;bundle-version="[4.0.0,5.0.0)";visibility:=reexport, org.eclipse.net4j.util.defs;bundle-version="[4.0.0,5.0.0)";visibility:=reexport, + org.apache.log4j;bundle-version="[1.2.0,2.0.0)", org.junit;bundle-version="[4.0.0,5.0.0)";visibility:=reexport Export-Package: org.eclipse.net4j.tests;version="4.1.301", org.eclipse.net4j.tests.apps;version="4.1.301", diff --git a/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/AbstractOMTest.java b/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/AbstractOMTest.java index 143b436b09..29758f5a5a 100644 --- a/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/AbstractOMTest.java +++ b/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/AbstractOMTest.java @@ -33,6 +33,12 @@ import org.eclipse.net4j.util.om.log.PrintLogHandler; import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.net4j.util.om.trace.PrintTraceHandler; +import org.apache.log4j.Appender; +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Layout; +import org.apache.log4j.spi.ErrorHandler; +import org.apache.log4j.spi.Filter; +import org.apache.log4j.spi.LoggingEvent; import org.junit.Assert; import java.io.File; @@ -753,6 +759,65 @@ public abstract class AbstractOMTest extends TestCase skipTest(true); } + public static void disableLog4j() + { + BasicConfigurator.configure(new Appender() + { + public void setName(String arg0) + { + } + + public void setLayout(Layout arg0) + { + } + + public void setErrorHandler(ErrorHandler arg0) + { + } + + public boolean requiresLayout() + { + return false; + } + + public String getName() + { + return null; + } + + public Layout getLayout() + { + return null; + } + + public Filter getFilter() + { + return null; + } + + public ErrorHandler getErrorHandler() + { + return null; + } + + public void doAppend(LoggingEvent arg0) + { + } + + public void close() + { + } + + public void clearFilters() + { + } + + public void addFilter(Filter arg0) + { + } + }); + } + /** * @author Eike Stepper */ diff --git a/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/UIUtil.java b/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/UIUtil.java index 6aaa47ccda..ea63f40ca6 100644 --- a/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/UIUtil.java +++ b/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/UIUtil.java @@ -238,7 +238,18 @@ public final class UIUtil */ public static IWorkbenchWindow getActiveWorkbenchWindow() { - IWorkbenchWindow window = getWorkbench().getActiveWorkbenchWindow(); + IWorkbench workbench = getWorkbench(); + + IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); + if (window == null) + { + IWorkbenchWindow[] windows = workbench.getWorkbenchWindows(); + if (windows.length != 0) + { + window = windows[0]; + } + } + if (window == null) { throw new IllegalStateException("No active window available"); //$NON-NLS-1$ @@ -252,7 +263,18 @@ public final class UIUtil */ public static IWorkbenchPage getActiveWorkbenchPage() { - IWorkbenchPage page = getActiveWorkbenchWindow().getActivePage(); + IWorkbenchWindow window = getActiveWorkbenchWindow(); + + IWorkbenchPage page = window.getActivePage(); + if (page == null) + { + IWorkbenchPage[] pages = window.getPages(); + if (pages.length != 0) + { + page = pages[0]; + } + } + if (page == null) { throw new IllegalStateException("No active page available"); //$NON-NLS-1$ |