Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2009-01-13 09:11:40 +0000
committerEike Stepper2009-01-13 09:11:40 +0000
commit6c5233a735c56100605f46b59f4e46a7c1cf40dc (patch)
tree12242648387b11bbc99fa4e332a10c95396a69cb /plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/AbstractObjectConflictResolver.java
parent5635ec88448a920dc02e0d649441aa5c4146b259 (diff)
downloadcdo-6c5233a735c56100605f46b59f4e46a7c1cf40dc.tar.gz
cdo-6c5233a735c56100605f46b59f4e46a7c1cf40dc.tar.xz
cdo-6c5233a735c56100605f46b59f4e46a7c1cf40dc.zip
Prepare common query
Diffstat (limited to 'plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/AbstractObjectConflictResolver.java')
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/AbstractObjectConflictResolver.java370
1 files changed, 370 insertions, 0 deletions
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/AbstractObjectConflictResolver.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/AbstractObjectConflictResolver.java
new file mode 100644
index 0000000000..b7fefee024
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/AbstractObjectConflictResolver.java
@@ -0,0 +1,370 @@
+/***************************************************************************
+ * Copyright (c) 2004 - 2008 Eike Stepper, Germany.
+ * 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.spi.cdo;
+
+import org.eclipse.emf.cdo.CDODeltaNotification;
+import org.eclipse.emf.cdo.CDOObject;
+import org.eclipse.emf.cdo.CDOState;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.model.CDOFeature;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
+import org.eclipse.emf.cdo.common.util.CDOException;
+import org.eclipse.emf.cdo.internal.common.revision.delta.CDORevisionMerger;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
+import org.eclipse.emf.cdo.transaction.CDOCommitContext;
+import org.eclipse.emf.cdo.transaction.CDODefaultTransactionHandler;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.transaction.CDOTransactionHandler;
+import org.eclipse.emf.cdo.view.CDOAdapterPolicy;
+import org.eclipse.emf.cdo.view.CDOConflictResolver;
+
+import org.eclipse.emf.internal.cdo.CDOObjectMerger;
+import org.eclipse.emf.internal.cdo.CDOStateMachine;
+import org.eclipse.emf.internal.cdo.bundle.OM;
+
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.ecore.EObject;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Eike Stepper
+ * @since 2.0
+ */
+public abstract class AbstractObjectConflictResolver implements CDOConflictResolver
+{
+ private CDOTransaction transaction;
+
+ public AbstractObjectConflictResolver()
+ {
+ }
+
+ public CDOTransaction getTransaction()
+ {
+ return transaction;
+ }
+
+ public void setTransaction(CDOTransaction transaction)
+ {
+ if (this.transaction != transaction)
+ {
+ if (this.transaction != null)
+ {
+ unhookTransaction(this.transaction);
+ }
+
+ this.transaction = transaction;
+
+ if (this.transaction != null)
+ {
+ hookTransaction(this.transaction);
+ }
+ }
+ }
+
+ public void resolveConflicts(Set<CDOObject> conflicts)
+ {
+ Map<CDOID, CDORevisionDelta> revisionDeltas = transaction.getRevisionDeltas();
+ for (CDOObject conflict : conflicts)
+ {
+ CDORevisionDelta revisionDelta = revisionDeltas.get(conflict.cdoID());
+ resolveConflict(conflict, revisionDelta);
+ }
+ }
+
+ /**
+ * Resolves the conflict of a single object in the current transaction.
+ */
+ protected abstract void resolveConflict(CDOObject conflict, CDORevisionDelta revisionDelta);
+
+ protected void hookTransaction(CDOTransaction transaction)
+ {
+ }
+
+ protected void unhookTransaction(CDOTransaction transaction)
+ {
+ }
+
+ public static void rollbackObject(CDOObject object)
+ {
+ CDOStateMachine.INSTANCE.rollback((InternalCDOObject)object);
+ }
+
+ public static void readObject(CDOObject object)
+ {
+ CDOStateMachine.INSTANCE.read((InternalCDOObject)object);
+ }
+
+ /**
+ * TODO See {@link CDOObjectMerger}!!!
+ */
+ public static void changeObject(CDOObject object, CDORevisionDelta revisionDelta)
+ {
+ readObject(object);
+
+ InternalCDORevision revision = (InternalCDORevision)object.cdoRevision().copy();
+ int originVersion = revision.getVersion();
+ revision.setTransactional();
+
+ ((InternalCDORevisionDelta)revisionDelta).setOriginVersion(originVersion);
+ ((InternalCDORevisionDelta)revisionDelta).setDirtyVersion(revision.getVersion());
+
+ CDORevisionMerger merger = new CDORevisionMerger();
+ merger.merge(revision, revisionDelta);
+ ((InternalCDOObject)object).cdoInternalSetRevision(revision);
+ ((InternalCDOObject)object).cdoInternalSetState(CDOState.DIRTY);
+ }
+
+ /**
+ * A conflict resolver implementation that takes all the new remote state of the conflicting objects and then applies
+ * the locally existing changes of the current transaction.
+ *
+ * @author Eike Stepper
+ * @since 2.0
+ */
+ public static class TakeRemoteChangesThenApplyLocalChanges extends AbstractObjectConflictResolver
+ {
+ public TakeRemoteChangesThenApplyLocalChanges()
+ {
+ }
+
+ @Override
+ protected void resolveConflict(CDOObject conflict, CDORevisionDelta revisionDelta)
+ {
+ rollbackObject(conflict);
+ changeObject(conflict, revisionDelta);
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ * @since 2.0
+ */
+ public static abstract class ThreeWayMerge extends AbstractObjectConflictResolver implements CDOAdapterPolicy
+ {
+ private ChangeSubscriptionAdapter adapter = new ChangeSubscriptionAdapter();
+
+ private CDOTransactionHandler handler = new CDODefaultTransactionHandler()
+ {
+ @Override
+ public void modifyingObject(CDOTransaction transaction, CDOObject object, CDOFeatureDelta ignored)
+ {
+ if (getTransaction() == transaction)
+ {
+ adapter.attach(object);
+ }
+ }
+
+ @Override
+ public void committedTransaction(CDOTransaction transaction, CDOCommitContext commitContext)
+ {
+ if (getTransaction() == transaction)
+ {
+ adapter.reset();
+ }
+ }
+
+ @Override
+ public void rolledBackTransaction(CDOTransaction transaction)
+ {
+ // Reset the accumulation only if it rolled back the transaction completely
+ if (getTransaction() == transaction && transaction.getLastSavepoint().getPreviousSavepoint() == null)
+ {
+ adapter.reset();
+ }
+ }
+ };
+
+ public ThreeWayMerge()
+ {
+ }
+
+ public boolean isValid(EObject object, Adapter adapter)
+ {
+ return adapter instanceof ChangeSubscriptionAdapter;
+ }
+
+ @Override
+ protected void hookTransaction(CDOTransaction transaction)
+ {
+ transaction.options().addChangeSubscriptionPolicy(this);
+ transaction.addHandler(handler);
+ }
+
+ @Override
+ protected void unhookTransaction(CDOTransaction transaction)
+ {
+ transaction.removeHandler(handler);
+ transaction.options().removeChangeSubscriptionPolicy(this);
+ }
+
+ @Override
+ protected void resolveConflict(CDOObject conflict, CDORevisionDelta revisionDelta)
+ {
+ resolveConflict(conflict, revisionDelta, adapter.getRevisionDeltas(conflict));
+ }
+
+ protected abstract void resolveConflict(CDOObject conflict, CDORevisionDelta localDelta,
+ List<CDORevisionDelta> remoteDeltas);
+
+ /**
+ * @author Eike Stepper
+ * @since 2.0
+ */
+ public static class ChangeSubscriptionAdapter extends AdapterImpl
+ {
+ private Set<CDOObject> notifiers = new HashSet<CDOObject>();
+
+ private Map<CDOObject, List<CDORevisionDelta>> deltas = new HashMap<CDOObject, List<CDORevisionDelta>>();
+
+ public ChangeSubscriptionAdapter()
+ {
+ }
+
+ public List<CDORevisionDelta> getRevisionDeltas(CDOObject notifier)
+ {
+ List<CDORevisionDelta> list = deltas.get(notifier);
+ if (list == null)
+ {
+ return Collections.emptyList();
+ }
+
+ return list;
+ }
+
+ public Set<CDOObject> getNotifiers()
+ {
+ return notifiers;
+ }
+
+ public Map<CDOObject, List<CDORevisionDelta>> getDeltas()
+ {
+ return deltas;
+ }
+
+ public void attach(CDOObject notifier)
+ {
+ if (notifiers.add(notifier))
+ {
+ notifier.eAdapters().add(this);
+ }
+ }
+
+ public void reset()
+ {
+ for (CDOObject notifier : notifiers)
+ {
+ notifier.eAdapters().remove(this);
+ }
+
+ notifiers.clear();
+ deltas.clear();
+ }
+
+ @Override
+ public void notifyChanged(Notification msg)
+ {
+ try
+ {
+ if (msg instanceof CDODeltaNotification)
+ {
+ CDODeltaNotification deltaNotification = (CDODeltaNotification)msg;
+ Object notifier = deltaNotification.getNotifier();
+ if (!deltaNotification.hasNext() && notifiers.contains(notifier))
+ {
+ CDORevisionDelta revisionDelta = deltaNotification.getRevisionDelta();
+ List<CDORevisionDelta> list = deltas.get(notifier);
+ if (list == null)
+ {
+ list = new ArrayList<CDORevisionDelta>(1);
+ deltas.put((CDOObject)notifier, list);
+ }
+
+ list.add(revisionDelta);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ OM.LOG.error(ex);
+ }
+ }
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ * @since 2.0
+ */
+ public static class MergeLocalChangesPerFeature extends ThreeWayMerge
+ {
+ public MergeLocalChangesPerFeature()
+ {
+ }
+
+ @Override
+ protected void resolveConflict(CDOObject conflict, CDORevisionDelta localDelta, List<CDORevisionDelta> remoteDeltas)
+ {
+ if (hasFeatureConflicts(localDelta, remoteDeltas))
+ {
+ // TODO localDelta may be corrupt already and the transaction will not be able to restore it!!!
+ throw new CDOException("Object has feature-level conflicts");
+ }
+
+ rollbackObject(conflict);
+
+ // Add remote deltas to local delta
+ for (CDORevisionDelta remoteDelta : remoteDeltas)
+ {
+ for (CDOFeatureDelta remoteFeatureDelta : remoteDelta.getFeatureDeltas())
+ {
+ // TODO Add public API for this:
+ ((InternalCDORevisionDelta)localDelta).addFeatureDelta(remoteFeatureDelta);
+ }
+ }
+
+ changeObject(conflict, localDelta);
+ }
+
+ protected boolean hasFeatureConflicts(CDORevisionDelta localDelta, List<CDORevisionDelta> remoteDeltas)
+ {
+ Set<CDOFeature> features = new HashSet<CDOFeature>();
+ for (CDOFeatureDelta localFeatureDelta : localDelta.getFeatureDeltas())
+ {
+ features.add(localFeatureDelta.getFeature());
+ }
+
+ for (CDORevisionDelta remoteDelta : remoteDeltas)
+ {
+ for (CDOFeatureDelta remoteFeatureDelta : remoteDelta.getFeatureDeltas())
+ {
+ CDOFeature feature = remoteFeatureDelta.getFeature();
+ if (features.contains(feature))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+}

Back to the top