diff options
Diffstat (limited to 'plugins/org.eclipse.emf.cdo/src/org/eclipse/emf')
27 files changed, 2958 insertions, 1070 deletions
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOState.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOState.java index 146aad0dbe..8a8d184945 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOState.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOState.java @@ -31,7 +31,8 @@ public enum CDOState INVALID_CONFLICT, /** - * An intermediary state for internal use only. This state marks the first of two phases during an attach operation. + * Indicates that the object had been changed in a transaction, + * but has then been changed back to its clean state. */ PREPARED } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/eresource/impl/CDOResourceImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/eresource/impl/CDOResourceImpl.java index 3ac5c5c9b5..31d14e559e 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/eresource/impl/CDOResourceImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/eresource/impl/CDOResourceImpl.java @@ -31,7 +31,7 @@ import org.eclipse.emf.cdo.view.CDOViewProvider; import org.eclipse.emf.cdo.view.CDOViewProviderRegistry; import org.eclipse.emf.internal.cdo.bundle.OM; -import org.eclipse.emf.internal.cdo.view.CDOStateMachine; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2; import org.eclipse.net4j.util.WrappedException; import org.eclipse.net4j.util.collection.Pair; @@ -347,7 +347,6 @@ public class CDOResourceImpl extends CDOResourceLeafImpl implements InternalCDOR setPath(newPath); } - @Override public Object eGet(int featureID, boolean resolve, boolean coreType) { @@ -355,7 +354,7 @@ public class CDOResourceImpl extends CDOResourceLeafImpl implements InternalCDOR { case EresourcePackage.CDO_RESOURCE__URI: return getURI(); - + default: return super.eGet(featureID, resolve, coreType); } @@ -369,7 +368,7 @@ public class CDOResourceImpl extends CDOResourceLeafImpl implements InternalCDOR case EresourcePackage.CDO_RESOURCE__URI: setURI((URI)newValue); break; - + default: super.eSet(featureID, newValue); } @@ -670,7 +669,6 @@ public class CDOResourceImpl extends CDOResourceLeafImpl implements InternalCDOR try { EObject eObjectByFragment = getEObjectByFragment(uriFragment); - if (eObjectByFragment != null) { return eObjectByFragment; @@ -1497,7 +1495,7 @@ public class CDOResourceImpl extends CDOResourceLeafImpl implements InternalCDOR */ private void attached(InternalCDOObject cdoObject, InternalCDOTransaction transaction) { - CDOStateMachine.INSTANCE.attach(cdoObject, transaction); + CDOStateMachine2.INSTANCE.attach(cdoObject, transaction); } /** @@ -1511,7 +1509,7 @@ public class CDOResourceImpl extends CDOResourceLeafImpl implements InternalCDOR if (view instanceof InternalCDOTransaction) // Bug 376075 { InternalCDOObject cdoObject = FSMUtil.adapt(object, view); - CDOStateMachine.INSTANCE.detach(cdoObject); + CDOStateMachine2.INSTANCE.detach(cdoObject); } } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOPushTransaction.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOPushTransaction.java index eacfbeeee4..5c2a19c1da 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOPushTransaction.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOPushTransaction.java @@ -196,11 +196,17 @@ public class CDOPushTransaction extends Notifier implements CDOTransaction return CDOPushTransaction.this; } + @Deprecated public Type getType() { return Type.COMMITTED; } + public Reason getReason() + { + return Reason.COMMITTED; + } + public Map<CDOID, CDOID> getIDMappings() { return Collections.emptyMap(); diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOSavepoint.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOSavepoint.java index a572d1f1ea..1be4cb9d15 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOSavepoint.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOSavepoint.java @@ -39,92 +39,102 @@ public interface CDOSavepoint extends CDOUserSavepoint, CDOChangeSetDataProvider public CDOSavepoint getPreviousSavepoint(); + public boolean isEmpty(); + /** * @since 3.0 */ - public boolean wasDirty(); + public Map<CDOID, CDOObject> getNewObjects(); /** * @since 3.0 */ - public Map<CDOID, CDORevision> getBaseNewObjects(); + public Map<CDOID, CDOObject> getDetachedObjects(); /** * @since 3.0 */ - public Map<CDOID, CDOObject> getNewObjects(); + public Map<CDOID, CDOObject> getDirtyObjects(); /** + * @since 4.2 + */ + public Map<CDOID, CDORevisionDelta> getRevisionDeltas2(); + + /** + * Return the list of new objects from this point without objects that are removed. + * * @since 3.0 */ - public Map<CDOID, CDOObject> getDetachedObjects(); + public Map<CDOID, CDOObject> getAllNewObjects(); /** - * Bug 283985 (Re-attachment) + * Return the list of new objects from this point. * * @since 3.0 */ - public Map<CDOID, CDOObject> getReattachedObjects(); + public Map<CDOID, CDOObject> getAllDirtyObjects(); /** * @since 3.0 */ - public Map<CDOID, CDOObject> getDirtyObjects(); + public Map<CDOID, CDOObject> getAllDetachedObjects(); /** - * The returned map delegates to {@link #getRevisionDeltas2()} and does <b>not</b> support the following methods: - * - * <ul> - * <li> {@link ConcurrentMap#putIfAbsent(Object, Object)} - * <li> {@link ConcurrentMap#remove(Object, Object)} - * <li> {@link ConcurrentMap#replace(Object, Object)} - * <li> {@link ConcurrentMap#replace(Object, Object, Object)} - * </ul> + * Return the list of all deltas without objects that are removed. * * @since 3.0 - * @deprecated As of 4.2 use {@link #getRevisionDeltas2()} instead. */ - @Deprecated - public ConcurrentMap<CDOID, CDORevisionDelta> getRevisionDeltas(); + public Map<CDOID, CDORevisionDelta> getAllRevisionDeltas(); /** - * @since 4.2 + * @since 4.0 */ - public Map<CDOID, CDORevisionDelta> getRevisionDeltas2(); + public CDOChangeSetData getAllChangeSetData(); /** * @since 3.0 + * @deprecated As of 4.3 no longer supported. */ - public Map<CDOID, CDORevision> getAllBaseNewObjects(); + @Deprecated + public boolean wasDirty(); /** - * Return the list of new objects from this point without objects that are removed. + * The returned map delegates to {@link #getRevisionDeltas2()} and does <b>not</b> support the following methods: + * + * <ul> + * <li> {@link ConcurrentMap#putIfAbsent(Object, Object)} + * <li> {@link ConcurrentMap#remove(Object, Object)} + * <li> {@link ConcurrentMap#replace(Object, Object)} + * <li> {@link ConcurrentMap#replace(Object, Object, Object)} + * </ul> * * @since 3.0 + * @deprecated As of 4.2 use {@link #getRevisionDeltas2()} instead. */ - public Map<CDOID, CDOObject> getAllNewObjects(); + @Deprecated + public ConcurrentMap<CDOID, CDORevisionDelta> getRevisionDeltas(); /** * @since 3.0 + * @deprecated As of 4.3 no longer supported. */ - public Map<CDOID, CDOObject> getAllDetachedObjects(); + @Deprecated + public Map<CDOID, CDORevision> getBaseNewObjects(); /** - * Return the list of new objects from this point. - * * @since 3.0 + * @deprecated As of 4.3 no longer supported. */ - public Map<CDOID, CDOObject> getAllDirtyObjects(); + @Deprecated + public Map<CDOID, CDORevision> getAllBaseNewObjects(); /** - * Return the list of all deltas without objects that are removed. + * Bug 283985 (Re-attachment) * * @since 3.0 + * @deprecated As of 4.3 no longer supported. */ - public Map<CDOID, CDORevisionDelta> getAllRevisionDeltas(); - - /** - * @since 4.0 - */ - public CDOChangeSetData getAllChangeSetData(); + @Deprecated + public Map<CDOID, CDOObject> getReattachedObjects(); } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOTransactionFinishedEvent.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOTransactionFinishedEvent.java index b2d4fb3fb2..1e40cf3b06 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOTransactionFinishedEvent.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOTransactionFinishedEvent.java @@ -27,18 +27,37 @@ import java.util.Map; */ public interface CDOTransactionFinishedEvent extends CDOViewEvent { + /** + * @deprecated As of 4.3 use {@link #getReason()}. + */ + @Deprecated public Type getType(); + public Reason getReason(); + public Map<CDOID, CDOID> getIDMappings(); /** - * Enumerates the possible {@link CDOTransactionFinishedEvent#getType() causes} for a {@link CDOTransaction - * transaction} to become finished. + * Enumerates the possible {@link CDOTransactionFinishedEvent#getType() causes} for a + * {@link CDOTransaction transaction} to become finished. * * @author Eike Stepper + * @deprecated As of 4.3 use {@link Reason}. */ + @Deprecated public enum Type { COMMITTED, ROLLED_BACK } + + /** + * Enumerates the possible {@link CDOTransactionFinishedEvent#getReason() causes} for a + * {@link CDOTransaction transaction} to become finished. + * + * @author Eike Stepper + */ + public enum Reason + { + COMMITTED, ROLLED_BACK, UNDONE, MERGED + } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/util/CDOUtil.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/util/CDOUtil.java index 21a7141534..6ba92ae0ac 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/util/CDOUtil.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/util/CDOUtil.java @@ -49,7 +49,7 @@ import org.eclipse.emf.internal.cdo.session.CDOCollectionLoadingPolicyImpl; import org.eclipse.emf.internal.cdo.transaction.CDOXATransactionImpl; import org.eclipse.emf.internal.cdo.transaction.CDOXATransactionImpl.CDOXAInternalAdapter; import org.eclipse.emf.internal.cdo.view.CDORevisionPrefetchingPolicyImpl; -import org.eclipse.emf.internal.cdo.view.CDOStateMachine; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2; import org.eclipse.net4j.util.AdapterUtil; import org.eclipse.net4j.util.container.IPluginContainer; @@ -426,7 +426,7 @@ public final class CDOUtil public static void load(EObject eObject, CDOView view) { InternalCDOObject cdoObject = FSMUtil.adapt(eObject, view); - CDOStateMachine.INSTANCE.read(cdoObject); + CDOStateMachine2.INSTANCE.read(cdoObject); for (Iterator<InternalCDOObject> it = FSMUtil.iterator(cdoObject.eContents(), (InternalCDOView)view); it.hasNext();) { @@ -479,7 +479,7 @@ public final class CDOUtil return null; } - CDORevision revision = CDOStateMachine.INSTANCE.read((InternalCDOObject)object); + CDORevision revision = CDOStateMachine2.INSTANCE.read((InternalCDOObject)object); return getRevisionByVersion(object, revision.getBranch(), version, revision); } @@ -493,7 +493,7 @@ public final class CDOUtil return null; } - CDORevision revision = CDOStateMachine.INSTANCE.read((InternalCDOObject)object); + CDORevision revision = CDOStateMachine2.INSTANCE.read((InternalCDOObject)object); return getRevisionByVersion(object, branch, version, revision); } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java index 3991de0369..96eabccd10 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java @@ -30,7 +30,7 @@ import org.eclipse.emf.cdo.view.CDOView; import org.eclipse.emf.internal.cdo.bundle.OM; import org.eclipse.emf.internal.cdo.messages.Messages; import org.eclipse.emf.internal.cdo.object.CDOLockImpl; -import org.eclipse.emf.internal.cdo.view.CDOStateMachine; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2; import org.eclipse.net4j.util.ObjectUtil; import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; @@ -198,7 +198,7 @@ public class CDOObjectImpl extends MinimalEStoreEObjectImpl implements InternalC @Deprecated public final void cdoReload() { - CDOStateMachine.INSTANCE.reload(this); + // CDOStateMachine2.INSTANCE.reload(this); } /** @@ -1186,7 +1186,7 @@ public class CDOObjectImpl extends MinimalEStoreEObjectImpl implements InternalC } /** - * Adjust the reference ONLY if the opposite reference used CDOID. This is true ONLY if the state of <cdo>this</code> + * Adjust the reference ONLY if the opposite reference used CDOID. This is true ONLY if the state of <code>this</code> * was not {@link CDOState#NEW}. */ private static void adjustOppositeReference(InternalCDOObject instance, InternalEObject object, EReference feature) @@ -1632,7 +1632,7 @@ public class CDOObjectImpl extends MinimalEStoreEObjectImpl implements InternalC { if (!FSMUtil.isTransient(CDOObjectImpl.this)) { - CDOStateMachine.INSTANCE.read(CDOObjectImpl.this); + CDOStateMachine2.INSTANCE.read(CDOObjectImpl.this); } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyListener.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyListener.java index 81b5f7c254..4f63d6f17d 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyListener.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyListener.java @@ -10,7 +10,7 @@ */ package org.eclipse.emf.internal.cdo.object; -import org.eclipse.emf.internal.cdo.view.CDOStateMachine; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2; import org.eclipse.emf.ecore.InternalEObject; @@ -76,7 +76,7 @@ public final class CDOLegacyListener extends CDOLegacyWrapper try { handlingCallback = true; - CDOStateMachine.INSTANCE.read(this); + CDOStateMachine2.INSTANCE.read(this); // TODO Optimize this when the list position index is added to the new callbacks resolveAllProxies(); @@ -95,7 +95,7 @@ public final class CDOLegacyListener extends CDOLegacyWrapper try { handlingCallback = true; - CDOStateMachine.INSTANCE.write(this); + CDOStateMachine2.INSTANCE.write(this, null); // TODO Optimize this when the list position index is added to the new callbacks resolveAllProxies(); diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java index 1805087e1a..9d7f701ffa 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java @@ -35,7 +35,7 @@ import org.eclipse.emf.cdo.view.CDOView; import org.eclipse.emf.internal.cdo.CDOObjectImpl; import org.eclipse.emf.internal.cdo.bundle.OM; -import org.eclipse.emf.internal.cdo.view.CDOStateMachine; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2; import org.eclipse.net4j.util.ReflectUtil; import org.eclipse.net4j.util.WrappedException; @@ -200,7 +200,7 @@ public abstract class CDOLegacyWrapper extends CDOObjectWrapper @Deprecated public void cdoReload() { - CDOStateMachine.INSTANCE.reload(this); + // CDOStateMachine2.INSTANCE.reload(this); } public CDOObjectHistory cdoHistory() @@ -305,7 +305,7 @@ public abstract class CDOLegacyWrapper extends CDOObjectWrapper */ public void cdoInternalPostRollback() { - CDOStateMachine.INSTANCE.read(this); + CDOStateMachine2.INSTANCE.read(this); } /** diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOCollectionLoadingPolicyImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOCollectionLoadingPolicyImpl.java index 3bff4c349b..242e6fa70c 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOCollectionLoadingPolicyImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOCollectionLoadingPolicyImpl.java @@ -66,7 +66,7 @@ public class CDOCollectionLoadingPolicyImpl implements CDOCollectionLoadingPolic doResolveProxy(revision, feature, 0, 0, Integer.MAX_VALUE); } - public Object resolveProxy(CDORevision rev, EStructuralFeature feature, int accessIndex, int serverIndex) + public Object resolveProxy(CDORevision revision, EStructuralFeature feature, int accessIndex, int serverIndex) { int chunkSize = resolveChunkSize; if (chunkSize == CDORevision.UNCHUNKED) @@ -75,26 +75,27 @@ public class CDOCollectionLoadingPolicyImpl implements CDOCollectionLoadingPolic chunkSize = Integer.MAX_VALUE; } - return doResolveProxy(rev, feature, accessIndex, serverIndex, chunkSize); + return doResolveProxy(revision, feature, accessIndex, serverIndex, chunkSize); } - private Object doResolveProxy(CDORevision rev, EStructuralFeature feature, int accessIndex, int serverIndex, + private Object doResolveProxy(CDORevision revision, EStructuralFeature feature, int accessIndex, int serverIndex, int chunkSize) { // Get proxy values - InternalCDORevision revision = (InternalCDORevision)rev; - int fetchIndex = serverIndex; - - MoveableList<Object> list = revision.getList(feature); + InternalCDORevision rev = (InternalCDORevision)revision; + MoveableList<Object> list = rev.getList(feature); int size = list.size(); + int fromIndex = accessIndex; int toIndex = accessIndex; + boolean minReached = false; boolean maxReached = false; - boolean alternation = false; + boolean towardsEnd = false; + for (int i = 0; i < chunkSize; i++) { - if (alternation) + if (towardsEnd) { if (!maxReached && toIndex < size - 1 && list.get(toIndex + 1) instanceof CDOElementProxy) { @@ -107,7 +108,7 @@ public class CDOCollectionLoadingPolicyImpl implements CDOCollectionLoadingPolic if (!minReached) { - alternation = false; + towardsEnd = false; } } else @@ -123,7 +124,7 @@ public class CDOCollectionLoadingPolicyImpl implements CDOCollectionLoadingPolic if (!maxReached) { - alternation = true; + towardsEnd = true; } } @@ -134,6 +135,6 @@ public class CDOCollectionLoadingPolicyImpl implements CDOCollectionLoadingPolic } CDOSessionProtocol protocol = ((InternalCDOSession)session).getSessionProtocol(); - return protocol.loadChunk(revision, feature, accessIndex, fetchIndex, fromIndex, toIndex); + return protocol.loadChunk(rev, feature, accessIndex, serverIndex, fromIndex, toIndex); } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSavepointImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSavepointImpl.java index d6050b513a..a795d9b42f 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSavepointImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSavepointImpl.java @@ -13,97 +13,59 @@ package org.eclipse.emf.internal.cdo.transaction; import org.eclipse.emf.cdo.CDOObject; -import org.eclipse.emf.cdo.common.branch.CDOBranchVersion; import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDUtil; import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.revision.CDORevisionKey; -import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta; import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; import org.eclipse.emf.cdo.internal.common.commit.CDOChangeSetDataImpl; -import org.eclipse.emf.cdo.internal.common.revision.delta.CDORevisionDeltaImpl; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDOFeatureDelta; -import org.eclipse.net4j.util.collection.MultiMap; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; import org.eclipse.emf.spi.cdo.CDOTransactionStrategy; +import org.eclipse.emf.spi.cdo.InternalCDOObject; import org.eclipse.emf.spi.cdo.InternalCDOSavepoint; +import org.eclipse.emf.spi.cdo.InternalCDOSavepoint.ChangeInfo.ChangeType; import org.eclipse.emf.spi.cdo.InternalCDOTransaction; +import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; +import java.util.WeakHashMap; import java.util.concurrent.ConcurrentMap; /** * @author Simon McDuff + * @author Eike Stepper * @since 2.0 */ public class CDOSavepointImpl extends CDOUserSavepointImpl implements InternalCDOSavepoint { - private final InternalCDOTransaction transaction; + private final Map<CDOID, ChangeInfo> changeInfos = CDOIDUtil.createMap(); - private Map<CDOID, CDORevision> baseNewObjects = CDOIDUtil.createMap(); + private final Map<InternalCDOObject, ChangeInfo> detachedInfos = new WeakHashMap<InternalCDOObject, ChangeInfo>(); - private Map<CDOID, CDOObject> newObjects = CDOIDUtil.createMap(); + private boolean inMemory; - // Bug 283985 (Re-attachment) - private Map<CDOID, CDOObject> reattachedObjects = CDOIDUtil.createMap(); + private File storage; - private Map<CDOID, CDOObject> detachedObjects = new HashMap<CDOID, CDOObject>() + public CDOSavepointImpl(InternalCDOTransaction transaction, InternalCDOSavepoint lastSavepoint) { - private static final long serialVersionUID = 1L; - - @Override - public CDOObject put(CDOID key, CDOObject object) + super(transaction, lastSavepoint); + if (lastSavepoint != null) { - synchronized (transaction) + for (ChangeInfo lastChangeInfo : lastSavepoint.getChangeInfos().values()) { - baseNewObjects.remove(key); - newObjects.remove(key); - reattachedObjects.remove(key); - dirtyObjects.remove(key); - revisionDeltas.remove(key); - return super.put(key, object); + ChangeInfo changeInfo = lastChangeInfo.setSavepoint(); + changeInfos.put(changeInfo.getID(), changeInfo); } } - }; - - private Map<CDOID, CDOObject> dirtyObjects = CDOIDUtil.createMap(); - - private Map<CDOID, CDORevisionDelta> revisionDeltas = new HashMap<CDOID, CDORevisionDelta>() - { - private static final long serialVersionUID = 1L; - - @Override - public CDORevisionDelta put(CDOID id, CDORevisionDelta delta) - { - transaction.clearResourcePathCacheIfNecessary(delta); - return super.put(id, delta); - } - - @Override - public void putAll(Map<? extends CDOID, ? extends CDORevisionDelta> m) - { - throw new UnsupportedOperationException(); - } - }; - - private boolean wasDirty; - - public CDOSavepointImpl(InternalCDOTransaction transaction, InternalCDOSavepoint lastSavepoint) - { - super(transaction, lastSavepoint); - this.transaction = transaction; - wasDirty = transaction.isDirty(); } @Override @@ -115,7 +77,7 @@ public class CDOSavepointImpl extends CDOUserSavepointImpl implements InternalCD @Override public InternalCDOSavepoint getFirstSavePoint() { - synchronized (transaction) + synchronized (super.getTransaction()) { return (InternalCDOSavepoint)super.getFirstSavePoint(); } @@ -124,7 +86,7 @@ public class CDOSavepointImpl extends CDOUserSavepointImpl implements InternalCD @Override public InternalCDOSavepoint getPreviousSavepoint() { - synchronized (transaction) + synchronized (super.getTransaction()) { return (InternalCDOSavepoint)super.getPreviousSavepoint(); } @@ -133,66 +95,278 @@ public class CDOSavepointImpl extends CDOUserSavepointImpl implements InternalCD @Override public InternalCDOSavepoint getNextSavepoint() { - synchronized (transaction) + synchronized (super.getTransaction()) { return (InternalCDOSavepoint)super.getNextSavepoint(); } } + public ChangeInfo addChangeInfo(ChangeInfo changeInfo) + { + if (changeInfo.getType() == ChangeType.DETACHED) + { + detachedInfos.put(changeInfo.getObject(), changeInfo); + } + + return changeInfos.put(changeInfo.getID(), changeInfo); + } + + public ChangeInfo removeChangeInfo(CDOID id) + { + ChangeInfo changeInfo = changeInfos.remove(id); + if (changeInfo != null && changeInfo.getType() == ChangeType.DETACHED) + { + detachedInfos.remove(changeInfo.getObject()); + } + + return changeInfo; + } + + public ChangeInfo removeChangeInfo(CDOObject object) + { + ChangeInfo changeInfo = detachedInfos.remove(object); + if (changeInfo != null) + { + changeInfos.remove(changeInfo.getID()); + } + + return changeInfo; + } + + public ChangeInfo getChangeInfo(CDOID id) + { + return changeInfos.get(id); + } + + public ChangeInfo getDetachedInfo(CDOObject object) + { + return detachedInfos.get(object); + } + + public Map<CDOID, ChangeInfo> getChangeInfos() + { + return Collections.unmodifiableMap(changeInfos); + } + + public Map<InternalCDOObject, ChangeInfo> getDetachedInfos() + { + return Collections.unmodifiableMap(detachedInfos); + } + public void clear() { - synchronized (transaction) + synchronized (super.getTransaction()) { - newObjects.clear(); - dirtyObjects.clear(); - revisionDeltas.clear(); - baseNewObjects.clear(); - detachedObjects.clear(); - reattachedObjects.clear(); + changeInfos.clear(); + detachedInfos.clear(); } } - public boolean wasDirty() + public boolean isInMemory() { - return wasDirty; + return storage == null; } - public Map<CDOID, CDOObject> getNewObjects() + public void setInMemory(boolean inMemory) { - return newObjects; + this.inMemory = inMemory; + if (isInMemory()) + { + if (!inMemory) + { + unload(); + } + } + else + { + if (!inMemory) + { + load(); + } + } } - public Map<CDOID, CDOObject> getDetachedObjects() + private void load() { - return detachedObjects; } - // Bug 283985 (Re-attachment) - public Map<CDOID, CDOObject> getReattachedObjects() + private void unload() + { + } + + public boolean isEmpty() + { + return changeInfos.isEmpty(); + } + + public Map<CDOID, CDOObject> getObjects(ChangeInfo.ChangeType type, Map<CDOID, ChangeInfo> baseline) { - return reattachedObjects; + Map<CDOID, CDOObject> result = CDOIDUtil.createMap(); + for (ChangeInfo changeInfo : changeInfos.values()) + { + if (changeInfo.getType() == type) + { + InternalCDOObject object = changeInfo.getObject(); + if (object != null) + { + CDOID id = changeInfo.getID(); + if (baseline != null) + { + ChangeInfo baselineInfo = baseline.get(id); + if (baselineInfo != null && baselineInfo.getType() == type) + { + // Ignore the object if it has the same change kind in the baseline + continue; + } + } + + result.put(id, object); + } + } + } + + return Collections.unmodifiableMap(result); + } + + public Map<CDOID, CDOObject> getNewObjects() + { + InternalCDOSavepoint previousSavepoint = getPreviousSavepoint(); + Map<CDOID, ChangeInfo> baseline = previousSavepoint == null ? null : previousSavepoint.getChangeInfos(); + return getObjects(ChangeType.NEW, baseline); } public Map<CDOID, CDOObject> getDirtyObjects() { - return dirtyObjects; + InternalCDOSavepoint previousSavepoint = getPreviousSavepoint(); + Map<CDOID, ChangeInfo> baseline = previousSavepoint == null ? null : previousSavepoint.getChangeInfos(); + return getObjects(ChangeType.DIRTY, baseline); } - @Deprecated - public Set<CDOID> getSharedDetachedObjects() + public Map<CDOID, CDOObject> getDetachedObjects() { + InternalCDOSavepoint previousSavepoint = getPreviousSavepoint(); + Map<CDOID, ChangeInfo> baseline = previousSavepoint == null ? null : previousSavepoint.getChangeInfos(); + return getObjects(ChangeType.DETACHED, baseline); + } + + public Map<CDOID, CDORevisionDelta> getRevisionDeltas2() + { + int xxx; throw new UnsupportedOperationException(); } - @Deprecated - public void recalculateSharedDetachedObjects() + public CDOChangeSetData getChangeSetData() { + int xxx; throw new UnsupportedOperationException(); } + public CDOChangeSetData getAllChangeSetData() + { + synchronized (super.getTransaction()) + { + List<CDOIDAndVersion> revisions = new ArrayList<CDOIDAndVersion>(); + List<CDORevisionKey> deltas = new ArrayList<CDORevisionKey>(); + List<CDOIDAndVersion> detached = new ArrayList<CDOIDAndVersion>(); + + for (ChangeInfo changeInfo : changeInfos.values()) + { + switch (changeInfo.getType()) + { + case NEW: + revisions.add(changeInfo.getObject().cdoRevision()); + break; + + case DIRTY: + deltas.add(changeInfo.getRevisionDelta()); + break; + + case DETACHED: + detached.add(changeInfo.getCleanRevision()); + } + } + + return new CDOChangeSetDataImpl(revisions, deltas, detached); + } + } + + /** + * Return the list of all deltas without objects that are removed. + */ + public Map<CDOID, CDORevisionDelta> getAllRevisionDeltas() + { + Map<CDOID, CDORevisionDelta> result = CDOIDUtil.createMap(); + for (ChangeInfo changeInfo : changeInfos.values()) + { + CDORevisionDelta revisionDelta = changeInfo.getRevisionDelta(); + if (revisionDelta != null) + { + result.put(changeInfo.getID(), revisionDelta); + } + } + + return Collections.unmodifiableMap(result); + } + + /** + * Return the list of new objects from this point. + */ + public Map<CDOID, CDOObject> getAllDirtyObjects() + { + return getObjects(ChangeType.DIRTY, null); + } + + /** + * Return the list of new objects from this point without objects that are removed. + */ + public Map<CDOID, CDOObject> getAllNewObjects() + { + return getObjects(ChangeType.NEW, null); + } + + public Map<CDOID, CDOObject> getAllDetachedObjects() + { + return getObjects(ChangeType.DETACHED, null); + } + + public boolean isNewObject(CDOID id) + { + if (id.isTemporary()) + { + return true; + } + + ChangeInfo changeInfo = changeInfos.get(id); + if (changeInfo != null && changeInfo.getType() == ChangeType.NEW) + { + return true; + } + + return false; + } + + public boolean isDetachedObject(CDOID id) + { + ChangeInfo changeInfo = changeInfos.get(id); + return changeInfo != null && changeInfo.getType() == ChangeType.DETACHED; + } + + public void rollback() + { + InternalCDOTransaction transaction = getTransaction(); + synchronized (transaction) + { + LifecycleUtil.checkActive(transaction); + + CDOTransactionStrategy transactionStrategy = transaction.getTransactionStrategy(); + transactionStrategy.rollback(transaction, this); + } + } + @Deprecated public ConcurrentMap<CDOID, CDORevisionDelta> getRevisionDeltas() { + final Map<CDOID, CDORevisionDelta> revisionDeltas = getRevisionDeltas2(); return new ConcurrentMap<CDOID, CDORevisionDelta>() { public int size() @@ -289,277 +463,51 @@ public class CDOSavepointImpl extends CDOUserSavepointImpl implements InternalCD }; } - public Map<CDOID, CDORevisionDelta> getRevisionDeltas2() - { - return revisionDeltas; - } - - public CDOChangeSetData getChangeSetData() - { - synchronized (transaction) - { - return createChangeSetData(newObjects, revisionDeltas, detachedObjects); - } - } - - public CDOChangeSetData getAllChangeSetData() - { - synchronized (transaction) - { - return createChangeSetData(getAllNewObjects(), getAllRevisionDeltas(), getAllDetachedObjects()); - } - } - - private CDOChangeSetData createChangeSetData(Map<CDOID, CDOObject> newObjects, - Map<CDOID, CDORevisionDelta> revisionDeltas, Map<CDOID, CDOObject> detachedObjects) + @Deprecated + public boolean wasDirty() { - List<CDOIDAndVersion> newList = new ArrayList<CDOIDAndVersion>(newObjects.size()); - for (CDOObject object : newObjects.values()) - { - newList.add(object.cdoRevision()); - } - - List<CDORevisionKey> changedList = new ArrayList<CDORevisionKey>(revisionDeltas.size()); - for (CDORevisionDelta delta : revisionDeltas.values()) - { - changedList.add(delta); - } - - List<CDOIDAndVersion> detachedList = new ArrayList<CDOIDAndVersion>(detachedObjects.size()); - for (CDOID id : detachedObjects.keySet()) - { - detachedList.add(CDOIDUtil.createIDAndVersion(id, CDOBranchVersion.UNSPECIFIED_VERSION)); - } - - return new CDOChangeSetDataImpl(newList, changedList, detachedList); + throw new UnsupportedOperationException(); } + @Deprecated public Map<CDOID, CDORevision> getBaseNewObjects() { - return baseNewObjects; - } - - /** - * Return the list of new objects from this point. - */ - public Map<CDOID, CDOObject> getAllDirtyObjects() - { - synchronized (transaction) - { - if (getPreviousSavepoint() == null) - { - return Collections.unmodifiableMap(getDirtyObjects()); - } - - MultiMap.ListBased<CDOID, CDOObject> dirtyObjects = new MultiMap.ListBased<CDOID, CDOObject>(); - for (InternalCDOSavepoint savepoint = this; savepoint != null; savepoint = savepoint.getPreviousSavepoint()) - { - dirtyObjects.getDelegates().add(savepoint.getDirtyObjects()); - } - - return dirtyObjects; - } + throw new UnsupportedOperationException(); } - /** - * Return the list of new objects from this point without objects that are removed. - */ - public Map<CDOID, CDOObject> getAllNewObjects() + @Deprecated + public Map<CDOID, CDORevision> getAllBaseNewObjects() { - synchronized (transaction) - { - if (getPreviousSavepoint() == null) - { - return Collections.unmodifiableMap(getNewObjects()); - } - - Map<CDOID, CDOObject> newObjects = CDOIDUtil.createMap(); - for (InternalCDOSavepoint savepoint = getFirstSavePoint(); savepoint != null; savepoint = savepoint - .getNextSavepoint()) - { - newObjects.putAll(savepoint.getNewObjects()); - for (CDOID removedID : savepoint.getDetachedObjects().keySet()) - { - newObjects.remove(removedID); - } - } - - return newObjects; - } + throw new UnsupportedOperationException(); } - /** - * @since 2.0 - */ - public Map<CDOID, CDORevision> getAllBaseNewObjects() + @Deprecated + public Map<CDOID, CDOObject> getReattachedObjects() { - synchronized (transaction) - { - if (getPreviousSavepoint() == null) - { - return Collections.unmodifiableMap(getBaseNewObjects()); - } - - MultiMap.ListBased<CDOID, CDORevision> newObjects = new MultiMap.ListBased<CDOID, CDORevision>(); - for (InternalCDOSavepoint savepoint = this; savepoint != null; savepoint = savepoint.getPreviousSavepoint()) - { - newObjects.getDelegates().add(savepoint.getBaseNewObjects()); - } - - return newObjects; - } + throw new UnsupportedOperationException(); } - /** - * Return the list of all deltas without objects that are removed. - */ - public Map<CDOID, CDORevisionDelta> getAllRevisionDeltas() + @Deprecated + public Set<CDOID> getSharedDetachedObjects() { - synchronized (transaction) - { - if (getPreviousSavepoint() == null) - { - return Collections.unmodifiableMap(getRevisionDeltas2()); - } - - // We need to combined the result for all delta in different Savepoint - Map<CDOID, CDORevisionDelta> allRevisionDeltas = CDOIDUtil.createMap(); - for (InternalCDOSavepoint savepoint = getFirstSavePoint(); savepoint != null; savepoint = savepoint - .getNextSavepoint()) - { - for (CDORevisionDelta revisionDelta : savepoint.getRevisionDeltas2().values()) - { - CDOID id = revisionDelta.getID(); - if (!isNewObject(id)) - { - CDORevisionDeltaImpl oldRevisionDelta = (CDORevisionDeltaImpl)allRevisionDeltas.get(id); - if (oldRevisionDelta == null) - { - allRevisionDeltas.put(id, revisionDelta.copy()); - } - else - { - for (CDOFeatureDelta delta : revisionDelta.getFeatureDeltas()) - { - CDOFeatureDelta copy = ((InternalCDOFeatureDelta)delta).copy(); - oldRevisionDelta.addFeatureDelta(copy, null); - } - } - } - } - - Set<CDOID> reattachedObjects = savepoint.getReattachedObjects().keySet(); - for (CDOID detachedID : savepoint.getDetachedObjects().keySet()) - { - if (!reattachedObjects.contains(detachedID)) - { - allRevisionDeltas.remove(detachedID); - } - } - } - - return Collections.unmodifiableMap(allRevisionDeltas); - } + throw new UnsupportedOperationException(); } - public Map<CDOID, CDOObject> getAllDetachedObjects() + @Deprecated + public void recalculateSharedDetachedObjects() { - synchronized (transaction) - { - if (getPreviousSavepoint() == null && reattachedObjects.isEmpty()) - { - return Collections.unmodifiableMap(getDetachedObjects()); - } - - Map<CDOID, CDOObject> detachedObjects = CDOIDUtil.createMap(); - for (InternalCDOSavepoint savepoint = getFirstSavePoint(); savepoint != null; savepoint = savepoint - .getNextSavepoint()) - { - for (Entry<CDOID, CDOObject> entry : savepoint.getDetachedObjects().entrySet()) - { - CDOID detachedID = entry.getKey(); - if (!isNewObject(detachedID)) - { - CDOObject detachedObject = entry.getValue(); - detachedObjects.put(detachedID, detachedObject); - } - } - - for (CDOID reattachedID : savepoint.getReattachedObjects().keySet()) - { - detachedObjects.remove(reattachedID); - } - } - - return detachedObjects; - } + throw new UnsupportedOperationException(); } - public boolean isNewObject(CDOID id) + @Deprecated + public void attachObject(InternalCDOObject object) { - if (id.isTemporary()) - { - return true; - } - - synchronized (transaction) - { - for (InternalCDOSavepoint savepoint = this; savepoint != null; savepoint = savepoint.getPreviousSavepoint()) - { - if (savepoint.getNewObjects().containsKey(id)) - { - return true; - } - } - } - - return false; + throw new UnsupportedOperationException(); } - // TODO Not sure if this new implementation is needed. The existing one passes all tests. - // public boolean isNewObject(CDOID id) - // { - // if (id.isTemporary()) - // { - // return true; - // } - // - // boolean isNew = false; - // boolean wasNew = false; - // synchronized (transaction) - // { - // for (InternalCDOSavepoint savepoint = this; savepoint != null; savepoint = savepoint.getPreviousSavepoint()) - // { - // if (savepoint.getNewObjects().containsKey(id)) - // { - // isNew = true; - // wasNew = true; - // } - // - // if (isNew && savepoint.getDetachedObjects().containsKey(id)) - // { - // isNew = false; - // } - // - // if (!isNew && wasNew && savepoint.getReattachedObjects().containsKey(id)) - // { - // isNew = true; - // } - // } - // } - // - // return isNew; - // } - - public void rollback() + @Deprecated + public void removeObject(InternalCDOObject object) { - synchronized (transaction) - { - InternalCDOTransaction transaction = getTransaction(); - LifecycleUtil.checkActive(transaction); - - CDOTransactionStrategy transactionStrategy = transaction.getTransactionStrategy(); - transactionStrategy.rollback(transaction, this); - } + throw new UnsupportedOperationException(); } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSingleTransactionStrategyImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSingleTransactionStrategyImpl.java index bcd2ace85a..baf3936435 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSingleTransactionStrategyImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSingleTransactionStrategyImpl.java @@ -95,7 +95,7 @@ public class CDOSingleTransactionStrategyImpl implements CDOTransactionStrategy throw new CommitException(rollbackMessage); default: - throw new IllegalStateException("Invalid rollbackreason: " + rollbackReason); + throw new IllegalStateException("Invalid rollback reason: " + rollbackReason); } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java index 360e004d7d..c6f5df5a7f 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java @@ -53,9 +53,7 @@ import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.revision.CDORevisionFactory; import org.eclipse.emf.cdo.common.revision.CDORevisionKey; import org.eclipse.emf.cdo.common.revision.CDORevisionProvider; -import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta; -import org.eclipse.emf.cdo.common.revision.delta.CDOOriginSizeProvider; import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; import org.eclipse.emf.cdo.common.util.CDOException; import org.eclipse.emf.cdo.eresource.CDOBinaryResource; @@ -80,6 +78,7 @@ import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; import org.eclipse.emf.cdo.spi.common.protocol.CDODataInputImpl; import org.eclipse.emf.cdo.spi.common.protocol.CDODataOutputImpl; import org.eclipse.emf.cdo.spi.common.revision.CDOIDMapper; +import org.eclipse.emf.cdo.spi.common.revision.CDOReferenceAdjuster; import org.eclipse.emf.cdo.spi.common.revision.CDORevisionUnchunker; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; @@ -92,13 +91,13 @@ import org.eclipse.emf.cdo.transaction.CDOSavepoint; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.transaction.CDOTransactionConflictEvent; import org.eclipse.emf.cdo.transaction.CDOTransactionFinishedEvent; +import org.eclipse.emf.cdo.transaction.CDOTransactionFinishedEvent.Reason; import org.eclipse.emf.cdo.transaction.CDOTransactionHandler; import org.eclipse.emf.cdo.transaction.CDOTransactionHandler1; import org.eclipse.emf.cdo.transaction.CDOTransactionHandler2; import org.eclipse.emf.cdo.transaction.CDOTransactionHandler3; import org.eclipse.emf.cdo.transaction.CDOTransactionHandlerBase; import org.eclipse.emf.cdo.transaction.CDOTransactionStartedEvent; -import org.eclipse.emf.cdo.transaction.CDOUserSavepoint; import org.eclipse.emf.cdo.util.CDOURIUtil; import org.eclipse.emf.cdo.util.CDOUtil; import org.eclipse.emf.cdo.util.CommitException; @@ -117,7 +116,7 @@ import org.eclipse.emf.internal.cdo.query.CDOQueryImpl; import org.eclipse.emf.internal.cdo.util.CommitIntegrityCheck; import org.eclipse.emf.internal.cdo.util.CompletePackageClosure; import org.eclipse.emf.internal.cdo.util.IPackageClosure; -import org.eclipse.emf.internal.cdo.view.CDOStateMachine; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2; import org.eclipse.emf.internal.cdo.view.CDOViewImpl; import org.eclipse.net4j.util.CheckUtil; @@ -145,7 +144,6 @@ import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.ecore.impl.EClassImpl.FeatureSubsetSupplier; import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.Resource.Internal; import org.eclipse.emf.ecore.util.EContentsEList; import org.eclipse.emf.ecore.util.EContentsEList.FeatureIterator; import org.eclipse.emf.ecore.util.ECrossReferenceEList; @@ -156,6 +154,8 @@ import org.eclipse.emf.spi.cdo.CDOTransactionStrategy; import org.eclipse.emf.spi.cdo.FSMUtil; import org.eclipse.emf.spi.cdo.InternalCDOObject; import org.eclipse.emf.spi.cdo.InternalCDOSavepoint; +import org.eclipse.emf.spi.cdo.InternalCDOSavepoint.ChangeInfo; +import org.eclipse.emf.spi.cdo.InternalCDOSavepoint.ChangeInfo.ChangeType; import org.eclipse.emf.spi.cdo.InternalCDOSession; import org.eclipse.emf.spi.cdo.InternalCDOSession.MergeData; import org.eclipse.emf.spi.cdo.InternalCDOTransaction; @@ -242,9 +242,12 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa private Set<? extends EObject> committables; /** - * A map to hold a clean (i.e. unmodified) revision for objects that have been modified or detached. - */ - private Map<InternalCDOObject, InternalCDORevision> cleanRevisions = new ResolvingRevisionMap(); + * A map to hold a clean (i.e. unmodified) revision for objects that have been modified or detached. + */ + // private Map<InternalCDOObject, InternalCDORevision> cleanRevisions = new HashMap<InternalCDOObject, + // InternalCDORevision>(); + + // private Map<InternalCDOObject, InternalCDORevision> _cleanRevisions = new ResolvingRevisionMap(); public CDOTransactionImpl(CDOBranch branch) { @@ -377,6 +380,36 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa } } + public void handleAttachingObject(CDOObject object) + { + CDOTransactionHandler1[] handlers = getTransactionHandlers1(); + for (int i = 0; i < handlers.length; i++) + { + CDOTransactionHandler1 handler = handlers[i]; + handler.attachingObject(this, object); + } + } + + public void handleModifyingObject(CDOObject object, CDOFeatureDelta featureDelta) + { + CDOTransactionHandler1[] handlers = getTransactionHandlers1(); + for (int i = 0; i < handlers.length; i++) + { + CDOTransactionHandler1 handler = handlers[i]; + handler.modifyingObject(this, object, featureDelta); + } + } + + public void handleDetachingObject(CDOObject object) + { + CDOTransactionHandler1[] handlers = getTransactionHandlers1(); + for (int i = 0; i < handlers.length; i++) + { + CDOTransactionHandler1 handler = handlers[i]; + handler.detachingObject(this, object); + } + } + @Override public boolean isDirty() { @@ -388,9 +421,52 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa return dirty; } + public IListener[] updateDirtyState(boolean undone) + { + if (lastSavepoint.isEmpty()) + { + // Becomes clean + if (dirty) + { + dirty = false; + + IListener[] listeners = getListeners(); + if (undone) + { + if (listeners != null) + { + fireEvent(new FinishedEvent(Reason.UNDONE, null), listeners); + } + } + else + { + // Let the caller fire a specific CDOTransactionFinishedEvent + return listeners; + } + } + } + else + { + // Becomes dirty + if (!dirty) + { + dirty = true; + + IListener[] listeners = getListeners(); + if (listeners != null) + { + fireEvent(new StartedEvent(), listeners); + } + } + } + + return null; + } + + @Deprecated public void setDirty(boolean dirty) { - this.dirty = dirty; + throw new UnsupportedOperationException(); } @Override @@ -437,9 +513,8 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa return conflicts; } - public synchronized CDOChangeSetData getChangeSetData() + public CDOChangeSetData getChangeSetData() { - checkActive(); return lastSavepoint.getAllChangeSetData(); } @@ -524,8 +599,14 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa Map<CDOID, InternalCDORevision> oldRevisions = applyChangedObjects(changeSetData.getChangedObjects(), ancestorProvider, targetProvider, keepVersions, resultData.getChangedObjects()); + IListener[] listeners = updateDirtyState(false); + if (listeners != null) + { + fireEvent(new FinishedEvent(Reason.MERGED, null), listeners); + } + // Delta notifications - Collection<CDORevisionDelta> notificationDeltas = lastSavepoint.getRevisionDeltas2().values(); + Collection<CDORevisionDelta> notificationDeltas = lastSavepoint.getAllRevisionDeltas().values(); if (!notificationDeltas.isEmpty() || !detachedSet.isEmpty()) { sendDeltaNotifications(notificationDeltas, detachedSet, oldRevisions); @@ -594,10 +675,9 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa object.cdoInternalSetState(CDOState.NEW); object.cdoInternalPostLoad(); - registerObject(object); - registerAttached(object, true); + int xxx; + // registerAttached(object, true); result.add(revision); - dirty = true; } } } @@ -612,9 +692,8 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa if (object != null) { result.add(CDOIDUtil.createIDAndVersion(id, CDOBranchVersion.UNSPECIFIED_VERSION)); - CDOStateMachine.INSTANCE.detach(object); + CDOStateMachine2.INSTANCE.detach(object); detachedSet.add(object); - dirty = true; } } @@ -627,10 +706,6 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa { Map<CDOID, InternalCDORevision> oldRevisions = CDOIDUtil.createMap(); - Map<CDOID, CDOObject> detachedObjects = lastSavepoint.getDetachedObjects(); - Map<CDOID, CDOObject> dirtyObjects = lastSavepoint.getDirtyObjects(); - Map<CDOID, CDORevisionDelta> revisionDeltas = lastSavepoint.getRevisionDeltas2(); - for (CDORevisionKey key : changedObjects) { InternalCDORevisionDelta ancestorGoalDelta = (InternalCDORevisionDelta)key; @@ -671,21 +746,17 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa throw new ChangeSetOutdatedException(); } - revisionDeltas.put(id, targetGoalDelta); result.add(targetGoalDelta); - // handle reattached objects. - if (detachedObjects.containsKey(id)) + // Handle reattached objects. + if (lastSavepoint.isDetachedObject(id)) { - CDOStateMachine.INSTANCE.internalReattach(object, this); + CDOStateMachine2.INSTANCE.attach(object, this); } object.cdoInternalSetRevision(goalRevision); object.cdoInternalSetState(CDOState.DIRTY); revisionChanged = true; - - dirtyObjects.put(id, object); - dirty = true; } if (revisionChanged) @@ -793,8 +864,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa } else { - Map<CDOID, CDOObject> dirtyObjects = getLastSavepoint().getDirtyObjects(); - setDirty(!dirtyObjects.isEmpty()); + setDirty(!lastSavepoint.isEmpty()); } } @@ -1028,7 +1098,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa { if (node.isRoot()) { - CDOStateMachine.INSTANCE.attach(node, this); + CDOStateMachine2.INSTANCE.attach(node, this); } else { @@ -1046,7 +1116,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa */ public synchronized void detach(CDOResourceImpl cdoResource) { - CDOStateMachine.INSTANCE.detach(cdoResource); + CDOStateMachine2.INSTANCE.detach(cdoResource); } /** @@ -1120,7 +1190,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa } CDOID id = super.getRootOrTopLevelResourceNodeID(name); - if (getLastSavepoint().getAllDetachedObjects().containsKey(id) || getDirtyObjects().containsKey(id)) + if (lastSavepoint.getAllDetachedObjects().containsKey(id) || getDirtyObjects().containsKey(id)) { throw new CDOException(MessageFormat.format(Messages.getString("CDOTransactionImpl.1"), name)); //$NON-NLS-1$ } @@ -1157,10 +1227,17 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa return null; } - if (isObjectNew(id) && isObjectDetached(id)) - { - throw new ObjectNotFoundException(id, this); - } + // ChangeInfo changeInfo = lastSavepoint.getChangeInfo(id); + // if (changeInfo != null) + // { + // return changeInfo.getObject(); + // } + + int xxx; + // if (/* isObjectNew(id) && */isObjectDetached(id)) + // { + // throw new ObjectNotFoundException(id, this); + // } return super.getObject(id, loadOnDemand); } @@ -1173,7 +1250,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa private boolean isObjectDetached(CDOID id) { - return lastSavepoint.getAllDetachedObjects().containsKey(id); + return lastSavepoint.isDetachedObject(id); } /** @@ -1181,7 +1258,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa */ public synchronized InternalCDOCommitContext createCommitContext() { - return new CDOCommitContextImpl(this); + return new CDOCommitContextImpl(); } public/* synchronized */CDOCommitInfo commit() throws CommitException @@ -1247,8 +1324,8 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa } finally { - getSession().endLocalCommit(token); clearResourcePathCacheIfNecessary(null); + getSession().endLocalCommit(token); } } @@ -1262,7 +1339,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa CDOTransactionStrategy strategy = getTransactionStrategy(); strategy.rollback(this, firstSavepoint); - cleanUp(null); + cleanUp(null, null); } private void removeObject(CDOID id, final CDOObject object) @@ -1289,7 +1366,143 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa internal.cdoInternalSetState(CDOState.TRANSIENT); } - private Set<CDOID> rollbackCompletely(CDOUserSavepoint savepoint) + /** + * @author Eike Stepper + */ + private static final class RollbackSupport + { + private static final int CLEAN = 0; + + private static final int NEW = 1; + + private static final int CHANGED = 2; + + private static final int DETACHED = 3; + + /** + * Finite state machine for rollback transitions. + */ + private static final Transition[][] FSM = new Transition[4][4]; + + static + { + FSM[CLEAN][CLEAN] = Transition.FAIL; + FSM[CLEAN][NEW] = new UndoTransition(); + FSM[CLEAN][CHANGED] = new UndoTransition(); + FSM[CLEAN][DETACHED] = new UndoTransition(); + + FSM[NEW][CLEAN] = null; + FSM[NEW][NEW] = Transition.IGNORE; + FSM[NEW][CHANGED] = Transition.FAIL; + FSM[NEW][DETACHED] = Transition.FAIL; + + FSM[CHANGED][CLEAN] = null; + FSM[CHANGED][NEW] = Transition.FAIL; + FSM[CHANGED][CHANGED] = Transition.IGNORE; + FSM[CHANGED][DETACHED] = null; + + FSM[DETACHED][CLEAN] = null; + FSM[DETACHED][NEW] = Transition.FAIL; + FSM[DETACHED][CHANGED] = null; + FSM[DETACHED][DETACHED] = Transition.IGNORE; + } + + public static Set<CDOID> rollbackTo(InternalCDOSavepoint formerSavepoint, InternalCDOSavepoint latestSavepoint) + { + Set<CDOID> idsOfNewObjectsWithDeltas = new HashSet<CDOID>(); + + Map<CDOID, ChangeInfo> latestChangeInfos = latestSavepoint.getChangeInfos(); + Map<CDOID, ChangeInfo> formerChangeInfos = formerSavepoint.getChangeInfos(); + + // Handle all former infos and remove the corresponding latest infos + for (ChangeInfo formerChangeInfo : formerChangeInfos.values()) + { + ChangeInfo latestChangeInfo = latestChangeInfos.remove(formerChangeInfo.getID()); + rollbackTo(formerChangeInfo, latestChangeInfo); + } + + // Handle remanining latest infos + for (ChangeInfo latestChangeInfo : latestChangeInfos.values()) + { + ChangeInfo formerChangeInfo = formerChangeInfos.get(latestChangeInfo.getID()); + rollbackTo(formerChangeInfo, latestChangeInfo); + } + + return idsOfNewObjectsWithDeltas; + } + + private static void rollbackTo(ChangeInfo formerChangeInfo, ChangeInfo latestChangeInfo) + { + int formerKind = getIndex(formerChangeInfo); + int latestKind = getIndex(latestChangeInfo); + + Transition transition = FSM[formerKind][latestKind]; + if (transition != null) + { + transition.execute(formerChangeInfo, latestChangeInfo); + } + } + + private static int getIndex(ChangeInfo changeInfo) + { + if (changeInfo == null) + { + return CLEAN; + } + + ChangeType type = changeInfo.getType(); + switch (type) + { + case NEW: + return NEW; + + case DIRTY: + return CHANGED; + + case DETACHED: + return DETACHED; + + default: + throw new IllegalStateException("Illegal change kind: " + type); + } + } + + /** + * @author Eike Stepper + */ + public interface Transition + { + public static final Transition IGNORE = new Transition() + { + public void execute(ChangeInfo formerChangeInfo, ChangeInfo latestChangeInfo) + { + // Do nothing + } + }; + + public static final Transition FAIL = new Transition() + { + public void execute(ChangeInfo formerChangeInfo, ChangeInfo latestChangeInfo) + { + throw new IllegalStateException("Impossible to rollback from " + latestChangeInfo + " to " + formerChangeInfo); + } + }; + + public void execute(ChangeInfo formerChangeInfo, ChangeInfo latestChangeInfo); + } + + /** + * @author Eike Stepper + */ + private static final class UndoTransition implements Transition + { + public void execute(ChangeInfo formerChangeInfo, ChangeInfo latestChangeInfo) + { + } + } + } + + private Set<CDOID> rollbackCompletely(InternalCDOSavepoint savepoint) { Set<CDOID> idsOfNewObjectsWithDeltas = new HashSet<CDOID>(); @@ -1330,7 +1543,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa if (idOrObject instanceof CDOObjectImpl) { CDOObjectImpl impl = (CDOObjectImpl)idOrObject; - Internal directResource = impl.eDirectResource(); + Resource.Internal directResource = impl.eDirectResource(); EObject container = impl.eContainer(); if (!toBeDetached.contains(directResource) && !toBeDetached.contains(container)) { @@ -1341,7 +1554,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa else if (idOrObject instanceof CDOObjectWrapper) { CDOObjectWrapper wrapper = (CDOObjectWrapper)idOrObject; - Internal directResource = wrapper.eDirectResource(); + Resource.Internal directResource = wrapper.eDirectResource(); EObject container = wrapper.eContainer(); if (!toBeDetached.contains(directResource) && !toBeDetached.contains(container)) { @@ -1378,7 +1591,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa else { InternalCDOObject detachedObject = (InternalCDOObject)detachedObjectEntry.getValue(); - InternalCDORevision cleanRev = cleanRevisions.get(detachedObject); + InternalCDORevision cleanRev = getCleanRevision(detachedObject); cleanObject(detachedObject, cleanRev); } } @@ -1395,7 +1608,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa // they were already reset to TRANSIENT earlier in this method if (!reattachedObjectsMap.values().contains(internalDirtyObject)) { - CDOStateMachine.INSTANCE.rollback(internalDirtyObject); + CDOStateMachine2.INSTANCE.rollback(internalDirtyObject); } } } @@ -1487,63 +1700,70 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa } } - dirty = savepoint.wasDirty(); + IListener[] listeners = updateDirtyState(false); + if (listeners != null) + { + fireEvent(new FinishedEvent(Reason.ROLLED_BACK, null), listeners); + } } /** * @since 2.0 */ + @Deprecated public synchronized void detachObject(InternalCDOObject object) { - CDOTransactionHandler1[] handlers = getTransactionHandlers1(); - for (int i = 0; i < handlers.length; i++) - { - CDOTransactionHandler1 handler = handlers[i]; - handler.detachingObject(this, object); - } - - // deregister object - CDOID id = object.cdoID(); - if (object.cdoState() == CDOState.NEW) - { - Map<CDOID, CDOObject> map = lastSavepoint.getNewObjects(); + throw new UnsupportedOperationException(); - // Determine if we added object - if (map.containsKey(id)) - { - map.remove(id); - } - else - { - lastSavepoint.getDetachedObjects().put(id, object); - } + // CDOTransactionHandler1[] handlers = getTransactionHandlers1(); + // for (int i = 0; i < handlers.length; i++) + // { + // CDOTransactionHandler1 handler = handlers[i]; + // handler.detachingObject(this, object); + // } + // + // if (lastSavepoint.detachObject(object)) + // { + // deregisterObject(object); + // } + // + // if (!dirty) + // { + // dirty = true; + // IListener[] listeners = getListeners(); + // if (listeners != null) + // { + // fireEvent(new StartedEvent(), listeners); + // } + // } + } - // deregister object - deregisterObject(object); - } - else - { - if (!cleanRevisions.containsKey(object)) - { - cleanRevisions.put(object, object.cdoRevision()); - } + public String dumpSavepoint() + { + int xxx; - lastSavepoint.getDetachedObjects().put(id, object); + StringBuilder builder = new StringBuilder(); + dumpSavepoint(builder, "Dirty", dirty); + dumpSavepoint(builder, "Objects", getObjects().size()); - // Object may have been reattached previously, in which case it must - // here be removed from the collection of reattached objects - lastSavepoint.getReattachedObjects().remove(id); - } + Map<CDOID, ChangeInfo> changeInfos = lastSavepoint.getChangeInfos(); + List<CDOID> ids = new ArrayList<CDOID>(changeInfos.keySet()); + Collections.sort(ids); - if (!dirty) + for (CDOID id : ids) { - dirty = true; - IListener[] listeners = getListeners(); - if (listeners != null) - { - fireEvent(new StartedEvent(), listeners); - } + dumpSavepoint(builder, id.toString(), changeInfos.get(id)); } + + return builder.toString(); + } + + private void dumpSavepoint(StringBuilder builder, String property, Object value) + { + builder.append(property); + builder.append(" = "); + builder.append(value); + builder.append("\n"); } /** @@ -1644,7 +1864,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa IListener[] listeners = getListeners(); if (listeners != null) { - fireEvent(new FinishedEvent(CDOTransactionFinishedEvent.Type.ROLLED_BACK, idMappings), listeners); + fireEvent(new FinishedEvent(CDOTransactionFinishedEvent.Reason.ROLLED_BACK, idMappings), listeners); } CDOTransactionHandler2[] handlers = getTransactionHandlers2(); @@ -1677,12 +1897,14 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa */ public synchronized InternalCDOSavepoint handleSetSavepoint() { - addToBase(lastSavepoint.getNewObjects()); + // addToBase(lastSavepoint.getNewObjects()); + InternalCDOSavepoint previousSavepoint = lastSavepoint; lastSavepoint = createSavepoint(lastSavepoint); + return lastSavepoint; } - private CDOSavepointImpl createSavepoint(InternalCDOSavepoint lastSavepoint) + protected CDOSavepointImpl createSavepoint(InternalCDOSavepoint lastSavepoint) { return new CDOSavepointImpl(this, lastSavepoint); } @@ -1712,16 +1934,11 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa return "CDOTransaction"; //$NON-NLS-1$ } - public synchronized void registerAttached(InternalCDOObject object, boolean isNew) + public synchronized void attachObject(InternalCDOObject object) { if (TRACER.isEnabled()) { - TRACER.format("Registering new object {0}", object); //$NON-NLS-1$ - } - - if (isNew) - { - registerNewPackage(object.eClass().getEPackage()); + TRACER.format("Attaching object {0}", object); //$NON-NLS-1$ } CDOTransactionHandler1[] handlers = getTransactionHandlers1(); @@ -1731,10 +1948,38 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa handler.attachingObject(this, object); } - if (isNew) - { - registerNew(lastSavepoint.getNewObjects(), object); - } + registerNewPackage(object.eClass().getEPackage()); + registerObject(object); + } + + public synchronized void _registerAttached(InternalCDOObject object, boolean isNew) + { + throw new UnsupportedOperationException(); + + // if (TRACER.isEnabled()) + // { + // TRACER.format("Registering new object {0}", object); //$NON-NLS-1$ + // } + // + // if (isNew) + // { + // registerNewPackage(object.eClass().getEPackage()); + // } + // + // registerObject(object); + // + // CDOTransactionHandler1[] handlers = getTransactionHandlers1(); + // for (int i = 0; i < handlers.length; i++) + // { + // CDOTransactionHandler1 handler = handlers[i]; + // handler.attachingObject(this, object); + // } + // + // int xxx; + // // if (isNew) + // // { + // // registerNew(lastSavepoint.getNewObjects(), object); + // // } } private void registerNewPackage(EPackage ePackage) @@ -1749,109 +1994,122 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa /** * Receives notification for new and dirty objects */ - public synchronized void registerFeatureDelta(final InternalCDOObject object, final CDOFeatureDelta featureDelta) + public synchronized void _registerFeatureDelta(final InternalCDOObject object, final CDOFeatureDelta featureDelta) { - CDOID id = object.cdoID(); - boolean needToSaveFeatureDelta = true; - - if (object.cdoState() == CDOState.NEW) - { - // Register Delta for new objects only if objectA doesn't belong to - // this savepoint - if (getLastSavepoint().getPreviousSavepoint() == null || featureDelta == null) - { - needToSaveFeatureDelta = false; - } - else - { - Map<CDOID, CDOObject> map = getLastSavepoint().getNewObjects(); - needToSaveFeatureDelta = !map.containsKey(id); - } - } - - if (needToSaveFeatureDelta) - { - final InternalCDORevision revision = object.cdoRevision(); - - CDORevisionDelta revisionDelta = lastSavepoint.getRevisionDeltas2().get(id); - if (revisionDelta == null) - { - revisionDelta = CDORevisionUtil.createDelta(revision); - lastSavepoint.getRevisionDeltas2().put(id, revisionDelta); - } - - ((InternalCDORevisionDelta)revisionDelta).addFeatureDelta(featureDelta, new CDOOriginSizeProvider() - { - public int getOriginSize() - { - EStructuralFeature feature = featureDelta.getFeature(); - InternalCDORevision cleanRevision = cleanRevisions.get(object); - if (cleanRevision == null) - { - // Clean revision has *not yet* been registered, in this case the object revision *is still clean* - cleanRevision = revision; - } - - CDOList list = cleanRevision.getList(feature); - return list.size(); - } - }); - } - - CDOTransactionHandler1[] handlers = getTransactionHandlers1(); - for (int i = 0; i < handlers.length; i++) - { - CDOTransactionHandler1 handler = handlers[i]; - handler.modifyingObject(this, object, featureDelta); - } - } + throw new UnsupportedOperationException(); - public synchronized void registerRevisionDelta(CDORevisionDelta revisionDelta) + // CDOID id = object.cdoID(); + // boolean needToSaveFeatureDelta = true; + // + // if (object.cdoState() == CDOState.NEW) + // { + // // Register Delta for new objects only if objectA doesn't belong to + // // this savepoint + // if (lastSavepoint.getPreviousSavepoint() == null || featureDelta == null) + // { + // needToSaveFeatureDelta = false; + // } + // else + // { + // Map<CDOID, CDOObject> map = lastSavepoint.getNewObjects(); + // needToSaveFeatureDelta = !map.containsKey(id); + // } + // } + // + // if (needToSaveFeatureDelta) + // { + // final InternalCDORevision revision = object.cdoRevision(); + // + // CDORevisionDelta revisionDelta = lastSavepoint.getRevisionDeltas2().get(id); + // if (revisionDelta == null) + // { + // revisionDelta = CDORevisionUtil.createDelta(revision); + // lastSavepoint.getRevisionDeltas2().put(id, revisionDelta); + // } + // + // ((InternalCDORevisionDelta)revisionDelta).addFeatureDelta(featureDelta, new CDOOriginSizeProvider() + // { + // public int getOriginSize() + // { + // EStructuralFeature feature = featureDelta.getFeature(); + // InternalCDORevision cleanRevision = _cleanRevisions.get(object); + // if (cleanRevision == null) + // { + // // Clean revision has *not yet* been registered, in this case the object revision *is still clean* + // cleanRevision = revision; + // } + // + // CDOList list = cleanRevision.getList(feature); + // return list.size(); + // } + // }); + // } + // + // CDOTransactionHandler1[] handlers = getTransactionHandlers1(); + // for (int i = 0; i < handlers.length; i++) + // { + // CDOTransactionHandler1 handler = handlers[i]; + // handler.modifyingObject(this, object, featureDelta); + // } + } + + public synchronized void _registerRevisionDelta(CDORevisionDelta revisionDelta) { - Map<CDOID, CDORevisionDelta> revisionDeltas = lastSavepoint.getRevisionDeltas2(); - CDOID id = revisionDelta.getID(); - if (!revisionDeltas.containsKey(id)) - { - revisionDeltas.put(id, revisionDelta); - } + throw new UnsupportedOperationException(); + + // Map<CDOID, CDORevisionDelta> revisionDeltas = lastSavepoint.getRevisionDeltas2(); + // CDOID id = revisionDelta.getID(); + // if (!revisionDeltas.containsKey(id)) + // { + // revisionDeltas.put(id, revisionDelta); + // } } - public synchronized void registerDirty(InternalCDOObject object, CDOFeatureDelta featureDelta) + public synchronized void _registerDirty(InternalCDOObject object, CDOFeatureDelta featureDelta) { - if (TRACER.isEnabled()) - { - TRACER.format("Registering dirty object {0}", object); //$NON-NLS-1$ - } - - if (featureDelta != null) - { - registerFeatureDelta(object, featureDelta); - } + throw new UnsupportedOperationException(); - registerNew(lastSavepoint.getDirtyObjects(), object); + // if (TRACER.isEnabled()) + // { + // TRACER.format("Registering dirty object {0}", object); //$NON-NLS-1$ + // } + // + // if (featureDelta != null) + // { + // registerFeatureDelta(object, featureDelta); + // } + // + // int xxx; + // // registerNew(lastSavepoint.getDirtyObjects(), object); + // registerNew(null, object); } /** * TODO Simon: Should this method go to CDOSavePointImpl? */ @SuppressWarnings({ "rawtypes", "unchecked" }) - private void registerNew(Map map, InternalCDOObject object) + private void _registerNew(Map map, InternalCDOObject object) { - Object old = map.put(object.cdoID(), object); - if (old != null) - { - throw new IllegalStateException(MessageFormat.format(Messages.getString("CDOTransactionImpl.10"), object)); //$NON-NLS-1$ - } + throw new UnsupportedOperationException(); - if (!dirty) - { - dirty = true; - IListener[] listeners = getListeners(); - if (listeners != null) - { - fireEvent(new StartedEvent(), listeners); - } - } + // if (map != null) + // { + // Object old = map.put(object.cdoID(), object); + // if (old != null) + // { + // throw new IllegalStateException(MessageFormat.format(Messages.getString("CDOTransactionImpl.10"), object)); //$NON-NLS-1$ + // } + // } + // + // if (!dirty) + // { + // dirty = true; + // IListener[] listeners = getListeners(); + // if (listeners != null) + // { + // fireEvent(new StartedEvent(), listeners); + // } + // } } public synchronized List<CDOPackageUnit> analyzeNewPackages() @@ -1923,45 +2181,51 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa return newPackages; } - private void cleanUp(CDOCommitContext commitContext) + private IListener[] cleanUp(CDOCommitContext commitContext, CommitTransactionResult result) { - if (commitContext == null || !commitContext.isPartialCommit()) + if (commitContext != null) { - if (commitContext != null) + for (CDOObject object : commitContext.getDetachedObjects().values()) { - for (CDOObject object : commitContext.getDetachedObjects().values()) - { - cleanUpLockState(object); - } + cleanUpLockState(object); + lastSavepoint.removeChangeInfo(object); } + } - lastSavepoint = firstSavepoint; - firstSavepoint.clear(); - firstSavepoint.setNextSavepoint(null); + firstSavepoint = lastSavepoint; // Last savepoint may contain left-overs from partial commit + lastSavepoint.setPreviousSavepoint(null); + conflict = 0; // TODO Left-overs from partial commit? - cleanRevisions.clear(); - dirty = false; - conflict = 0; - idGenerator.reset(); + if (commitContext != null && commitContext.isPartialCommit()) + { + // collapseSavepoints(commitContext); } else { - collapseSavepoints(commitContext); + // lastSavepoint = firstSavepoint; + // firstSavepoint.clear(); + // firstSavepoint.setNextSavepoint(null); + // conflict = 0; + idGenerator.reset(); + } - for (CDOObject object : commitContext.getDetachedObjects().values()) + // Reset partial-commit filter + committables = null; + + IListener[] listeners = updateDirtyState(false); + if (listeners != null) + { + if (result != null) { - cleanRevisions.remove(object); - cleanUpLockState(object); + fireEvent(new FinishedEvent(Reason.COMMITTED, result.getIDMappings()), listeners); } - - for (CDOObject object : commitContext.getDirtyObjects().values()) + else { - cleanRevisions.remove(object); + fireEvent(new FinishedEvent(Reason.ROLLED_BACK, null), listeners); } } - // Reset partial-commit filter - committables = null; + return listeners; } private void cleanUpLockState(CDOObject object) @@ -2156,7 +2420,8 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa { InternalCDOObject object = newInstance(revision); registerObject(object); - registerAttached(object, true); + int xxx; + // registerAttached(object, true); newObjects.add(object); } @@ -2176,8 +2441,9 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa int oldVersion = object.cdoRevision().getVersion(); merger.merge(object, delta); - registerRevisionDelta(delta); - registerDirty(object, null); + int xxx; + // registerRevisionDelta(delta); + // registerDirty(object, null); if (delta.getVersion() < oldVersion) { @@ -2268,13 +2534,24 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa return lastSavepoint.getAllDetachedObjects(); } + private CDOID getDetachedID(CDOObject object) + { + ChangeInfo changeInfo = lastSavepoint.getDetachedInfo(object); + if (changeInfo != null) + { + return changeInfo.getID(); + } + + return null; + } + @Override protected synchronized CDOID getXRefTargetID(CDOObject target) { - CDORevisionKey key = cleanRevisions.get(target); - if (key != null) + CDOID detachedID = getDetachedID(target); + if (detachedID != null) { - return key.getID(); + return detachedID; } return super.getXRefTargetID(target); @@ -2301,12 +2578,11 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa } // The super implementation will return null for a transient (unattached) object; - // but in a tx, an transient object may previously have been attached. So we consult - // the cleanRevisions if that's the case. - CDORevisionKey revKey = cleanRevisions.get(object); - if (revKey != null && getDetachedObjects().containsValue(object)) + // but in a tx, an transient object may previously have been attached. + CDOID detachedID = getDetachedID(object); + if (detachedID != null) { - id = revKey.getID(); + id = detachedID; } return id; @@ -2467,7 +2743,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa // doesn't apply: it must be removed for sure.) if (referencer.cdoState() == CDOState.DIRTY && referencerClassInfo.isPersistent(reference)) { - InternalCDORevision cleanRevision = cleanRevisions.get(referencer); + InternalCDORevision cleanRevision = getCleanRevision(referencer); if (reference.isMany()) { @@ -2567,27 +2843,63 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa return committables; } - public synchronized Map<InternalCDOObject, InternalCDORevision> getCleanRevisions() + @Deprecated + public synchronized Map<InternalCDOObject, InternalCDORevision> _getCleanRevisions() { - return cleanRevisions; + throw new UnsupportedOperationException(); + + // new AbstractMap<InternalCDOObject, InternalCDORevision>() + // { + // @Override + // public Set<java.util.Map.Entry<InternalCDOObject, InternalCDORevision>> entrySet() + // { + // return new AbstractSet<java.util.Map.Entry<InternalCDOObject, InternalCDORevision>>() + // { + // @Override + // public Iterator<java.util.Map.Entry<InternalCDOObject, InternalCDORevision>> iterator() + // { + // return null; + // } + // + // @Override + // public int size() + // { + // return 0; + // } + // }; + // } + // }; + // + // return cleanRevisions; + } + + public InternalCDORevision getCleanRevision(CDOObject object) + { + ChangeInfo changeInfo = lastSavepoint.getChangeInfos().get(object.cdoID()); + if (changeInfo != null) + { + return changeInfo.getCleanRevision(); + } + + return null; } @Override protected InternalCDORevision getViewedRevision(InternalCDOObject object) { - InternalCDORevision rev = super.getViewedRevision(object); + InternalCDORevision revision = super.getViewedRevision(object); // Bug 336590: If we have a clean revision for this object, return that instead - if (rev != null) + if (revision != null) { - InternalCDORevision cleanRev = cleanRevisions.get(object); - if (cleanRev != null) + InternalCDORevision cleanRevision = getCleanRevision(object); + if (cleanRevision != null) { - return cleanRev; + return cleanRevision; } } - return rev; + return revision; } @Override @@ -2595,7 +2907,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa { if (object.cdoState() == CDOState.TRANSIENT) { - InternalCDORevision revision = cleanRevisions.get(object); + InternalCDORevision revision = getCleanRevision(object); if (revision == null) { throw new IllegalStateException("No revision for transient object " + object); @@ -2729,8 +3041,6 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa */ private final class CDOCommitContextImpl implements InternalCDOCommitContext { - private InternalCDOTransaction transaction; - /** * Tracks whether this commit is *actually* partial or not. (Having tx.committables != null does not in itself mean * that the commit will be partial, because the committables could cover all dirty/new/detached objects. But this @@ -2752,104 +3062,87 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa private Map<ByteArrayWrapper, CDOLob<?>> lobs = new HashMap<ByteArrayWrapper, CDOLob<?>>(); - public CDOCommitContextImpl(InternalCDOTransaction transaction) + public CDOCommitContextImpl() { - this.transaction = transaction; calculateCommitData(); } private void calculateCommitData() { - List<CDOPackageUnit> newPackageUnits = analyzeNewPackages(); + newObjects = CDOIDUtil.createMap(); + revisionDeltas = CDOIDUtil.createMap(); + detachedObjects = CDOIDUtil.createMap(); + dirtyObjects = CDOIDUtil.createMap(); - newObjects = filterCommittables(transaction.getNewObjects()); - List<CDOIDAndVersion> revisions = new ArrayList<CDOIDAndVersion>(newObjects.size()); - for (CDOObject newObject : newObjects.values()) - { - revisions.add(newObject.cdoRevision()); - } + List<CDOPackageUnit> newPackageUnits = analyzeNewPackages(); - revisionDeltas = filterCommittables(transaction.getRevisionDeltas()); - List<CDORevisionKey> deltas = new ArrayList<CDORevisionKey>(revisionDeltas.size()); - for (CDORevisionDelta delta : revisionDeltas.values()) - { - deltas.add(delta); - } + List<CDOIDAndVersion> revisions = new ArrayList<CDOIDAndVersion>(); + List<CDORevisionKey> deltas = new ArrayList<CDORevisionKey>(); + List<CDOIDAndVersion> detached = new ArrayList<CDOIDAndVersion>(); - detachedObjects = filterCommittables(transaction.getDetachedObjects()); - List<CDOIDAndVersion> detached = new ArrayList<CDOIDAndVersion>(detachedObjects.size()); - for (Entry<CDOID, CDOObject> entry : detachedObjects.entrySet()) + Collection<ChangeInfo> changeInfos = getLastSavepoint().getChangeInfos().values(); + for (ChangeInfo changeInfo : changeInfos) { - CDOObject object = entry.getValue(); - InternalCDORevision cleanRevision = cleanRevisions.get(object); - if (cleanRevision == null) + InternalCDOObject object = changeInfo.getObject(); + if (committables != null) { - // Can happen after merged detachments - CDORevision revision = object.cdoRevision(); - detached.add(CDOIDUtil.createIDAndVersion(revision)); - } - else if (cleanRevision.getBranch() == getBranch()) - { - detached.add(CDOIDUtil.createIDAndVersion(cleanRevision)); + isPartialCommit = true; + if (!committables.contains(object)) + { + continue; + } } - else + + CDOID id = changeInfo.getID(); + switch (changeInfo.getType()) { - detached.add(cleanRevision); + case NEW: + InternalCDORevision revision = object.cdoRevision(); + revisions.add(revision); + newObjects.put(id, object); + break; + + case DIRTY: + InternalCDORevisionDelta revisionDelta = changeInfo.getRevisionDelta(); + deltas.add(revisionDelta); + revisionDeltas.put(changeInfo.getID(), revisionDelta); + dirtyObjects.put(id, object); + break; + + case DETACHED: + InternalCDORevision key = changeInfo.getCleanRevision(); + detached.add(key); + if (object != null) + { + detachedObjects.put(id, object); + } } } - dirtyObjects = filterCommittables(transaction.getDirtyObjects()); - CDOLockState[] locksOnNewObjectsArray = getLockStates(newObjects.keySet(), false); locksOnNewObjects = Arrays.asList(locksOnNewObjectsArray); commitData = CDOCommitInfoUtil.createCommitData(newPackageUnits, revisions, deltas, detached); } - private <T> Map<CDOID, T> filterCommittables(Map<CDOID, T> map) - { - if (committables == null) - { - // No partial commit filter -- nothing to do - return map; - } - - Map<CDOID, T> newMap = CDOIDUtil.createMap(); - for (Entry<CDOID, T> entry : map.entrySet()) - { - CDOID id = entry.getKey(); - CDOObject o = getObject(id); - if (committables.contains(o)) - { - newMap.put(id, entry.getValue()); - } - else - { - isPartialCommit = true; - } - } - - return newMap; - } - public String getUserID() { - return transaction.getSession().getUserID(); + return getSession().getUserID(); } public int getViewID() { - return transaction.getViewID(); + return CDOTransactionImpl.this.getViewID(); } public CDOBranch getBranch() { - return transaction.getBranch(); + return CDOTransactionImpl.this.getBranch(); } public InternalCDOTransaction getTransaction() { - return transaction; + return CDOTransactionImpl.this; } public boolean isPartialCommit() @@ -2859,12 +3152,12 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa public boolean isAutoReleaseLocks() { - return transaction.options().isAutoReleaseLocksEnabled(); + return options().isAutoReleaseLocksEnabled(); } public String getCommitComment() { - return transaction.getCommitComment(); + return CDOTransactionImpl.this.getCommitComment(); } public CDOCommitData getCommitData() @@ -2984,18 +3277,29 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa } } + private void preCommit(Map<CDOID, CDOObject> objects, Map<ByteArrayWrapper, CDOLob<?>> lobs) + { + if (!objects.isEmpty()) + { + for (CDOObject object : objects.values()) + { + collectLobs((InternalCDORevision)object.cdoRevision(), lobs); + ((InternalCDOObject)object).cdoInternalPreCommit(); + } + } + } + public void postCommit(CommitTransactionResult result) { try { InternalCDOSession session = getSession(); - long timeStamp = result.getTimeStamp(); boolean clearResourcePathCache = result.isClearResourcePathCache(); if (result.getRollbackMessage() != null) { - CDOCommitInfo commitInfo = new FailureCommitInfo(timeStamp, result.getPreviousTimeStamp()); - session.invalidate(commitInfo, transaction, clearResourcePathCache); + CDOCommitInfo commitInfo = new FailureCommitInfo(result.getTimeStamp(), result.getPreviousTimeStamp()); + session.invalidate(commitInfo, CDOTransactionImpl.this, clearResourcePathCache); return; } @@ -3012,31 +3316,22 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa ((InternalCDOPackageUnit)newPackageUnit).setState(CDOPackageUnit.State.LOADED); } - postCommit(getNewObjects(), result); - postCommit(getDirtyObjects(), result); + transitionObjects(getNewObjects(), result); + transitionObjects(getDirtyObjects(), result); - for (CDORevisionDelta delta : getRevisionDeltas().values()) - { - ((InternalCDORevisionDelta)delta).adjustReferences(result.getReferenceAdjuster()); - } - - for (CDOID id : getDetachedObjects().keySet()) - { - removeObject(id); - } - - CDOCommitInfo commitInfo = makeCommitInfo(timeStamp, result.getPreviousTimeStamp()); + CDOCommitInfo commitInfo = makeCommitInfo(result); if (!commitInfo.isEmpty()) { - session.invalidate(commitInfo, transaction, clearResourcePathCache); + session.invalidate(commitInfo, CDOTransactionImpl.this, clearResourcePathCache); } // Bug 290032 - Sticky views if (session.isSticky()) { CDOBranchPoint commitBranchPoint = CDOBranchUtil.copyBranchPoint(result); - for (CDOObject object : getNewObjects().values()) // Note: keyset() does not work because ID mappings are - // not applied there! + + // Note: keyset() does not work because ID mappings are not applied there! + for (CDOObject object : getNewObjects().values()) { session.setCommittedSinceLastRefresh(object.cdoID(), commitBranchPoint); } @@ -3059,29 +3354,21 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa if (handler instanceof CDOTransactionHandler3) { CDOTransactionHandler3 handler3 = (CDOTransactionHandler3)handler; - handler3.committedTransaction(transaction, this, commitInfo); + handler3.committedTransaction(CDOTransactionImpl.this, this, commitInfo); } else { - handler.committedTransaction(transaction, this); + handler.committedTransaction(CDOTransactionImpl.this, this); } } - getChangeSubscriptionManager().committedTransaction(transaction, this); - getAdapterManager().committedTransaction(transaction, this); + getChangeSubscriptionManager().committedTransaction(CDOTransactionImpl.this, this); + getAdapterManager().committedTransaction(CDOTransactionImpl.this, this); - cleanUp(this); - - IListener[] listeners = getListeners(); - if (listeners != null) + IListener[] listeners = cleanUp(this, result); + if (listeners != null && branchChanged) { - if (branchChanged) - { - fireViewTargetChangedEvent(oldBranch.getHead(), listeners); - } - - Map<CDOID, CDOID> idMappings = result.getIDMappings(); - fireEvent(new FinishedEvent(CDOTransactionFinishedEvent.Type.COMMITTED, idMappings), listeners); + fireViewTargetChangedEvent(oldBranch.getHead(), listeners); } CDOLockState[] newLockStates = result.getNewLockStates(); @@ -3100,27 +3387,67 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa } } - private CDOCommitInfo makeCommitInfo(long timeStamp, long previousTimeStamp) + private void transitionObjects(Map<CDOID, CDOObject> objects, CommitTransactionResult result) { - InternalCDOSession session = getSession(); - CDOBranch branch = getBranch(); - String userID = session.getUserID(); - String comment = getCommitComment(); - - InternalCDOCommitInfoManager commitInfoManager = session.getCommitInfoManager(); - return commitInfoManager.createCommitInfo(branch, timeStamp, previousTimeStamp, userID, comment, commitData); + if (!objects.isEmpty()) + { + for (CDOObject object : objects.values()) + { + CDOStateMachine2.INSTANCE.commit((InternalCDOObject)object, result); + } + } } - private void preCommit(Map<CDOID, CDOObject> objects, Map<ByteArrayWrapper, CDOLob<?>> lobs) + private CDOCommitInfo makeCommitInfo(CommitTransactionResult result) { - if (!objects.isEmpty()) + final CDOReferenceAdjuster defaultReferenceAdjuster = result.getReferenceAdjuster(); + CDOReferenceAdjuster referenceAdjuster = new CDOReferenceAdjuster() { - for (CDOObject object : objects.values()) + public Object adjustReference(Object idOrObject, EStructuralFeature feature, int index) { - collectLobs((InternalCDORevision)object.cdoRevision(), lobs); - ((InternalCDOObject)object).cdoInternalPreCommit(); + if (idOrObject == null || idOrObject == CDOID.NULL) + { + return idOrObject; + } + + // Adjust remaining CDOIDs to detached objects + if (idOrObject instanceof CDOID) + { + ChangeInfo changeInfo = lastSavepoint.getChangeInfo((CDOID)idOrObject); + if (changeInfo != null && changeInfo.getType() == ChangeType.DETACHED) + { + return changeInfo.getObject(); + } + } + + // Return detached objects to avoid dangling reference exceptions below + if (idOrObject instanceof InternalCDOObject) + { + ChangeInfo changeInfo = lastSavepoint.getDetachedInfo((InternalCDOObject)idOrObject); + if (changeInfo != null) + { + return changeInfo.getObject(); + } + } + + return defaultReferenceAdjuster.adjustReference(idOrObject, feature, index); } + }; + + for (CDORevisionDelta delta : getRevisionDeltas().values()) + { + ((InternalCDORevisionDelta)delta).adjustReferences(referenceAdjuster); } + + InternalCDOSession session = getSession(); + CDOBranch branch = getBranch(); + String userID = session.getUserID(); + String comment = getCommitComment(); + long timeStamp = result.getTimeStamp(); + long previousTimeStamp = result.getPreviousTimeStamp(); + + InternalCDOCommitInfoManager commitInfoManager = session.getCommitInfoManager(); + return commitInfoManager.createCommitInfo(branch, timeStamp, previousTimeStamp, userID, comment, commitData); } private void collectLobs(InternalCDORevision revision, Map<ByteArrayWrapper, CDOLob<?>> lobs) @@ -3139,17 +3466,6 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa } } } - - private void postCommit(Map<CDOID, CDOObject> objects, CommitTransactionResult result) - { - if (!objects.isEmpty()) - { - for (CDOObject object : objects.values()) - { - CDOStateMachine.INSTANCE.commit((InternalCDOObject)object, result); - } - } - } } /** @@ -3177,19 +3493,32 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa { private static final long serialVersionUID = 1L; - private Type type; + private Reason reason; private Map<CDOID, CDOID> idMappings; - private FinishedEvent(Type type, Map<CDOID, CDOID> idMappings) + private FinishedEvent(Reason type, Map<CDOID, CDOID> idMappings) { - this.type = type; + reason = type; this.idMappings = idMappings; } + @Deprecated public Type getType() { - return type; + switch (reason) + { + case COMMITTED: + return Type.COMMITTED; + + default: + return Type.ROLLED_BACK; + } + } + + public Reason getReason() + { + return reason; } public Map<CDOID, CDOID> getIDMappings() @@ -3200,8 +3529,13 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa @Override public String toString() { - return MessageFormat.format("CDOTransactionFinishedEvent[source={0}, type={1}, idMappings={2}]", getSource(), //$NON-NLS-1$ - getType(), idMappings == null ? 0 : idMappings.size()); + String prefix = "CDOTransactionFinishedEvent[source={0}, reason={1}"; + if (idMappings == null) + { + return MessageFormat.format(prefix + "]", getSource(), getReason()); + } + + return MessageFormat.format(prefix + ", idMappings={2}]", getSource(), getReason(), idMappings.size()); } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/util/CommitIntegrityCheck.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/util/CommitIntegrityCheck.java index 38658f4b00..4d55407789 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/util/CommitIntegrityCheck.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/util/CommitIntegrityCheck.java @@ -139,7 +139,7 @@ public class CommitIntegrityCheck { // Getting the deltas from the TX is not a good idea... // We better recompute a fresh delta: - InternalCDORevision cleanRev = transaction.getCleanRevisions().get(dirtyObject); + InternalCDORevision cleanRev = transaction.getCleanRevision(dirtyObject); CheckUtil.checkNull(cleanRev, "Could not obtain clean revision for dirty object " + dirtyObject); InternalCDOClassInfo classInfo = dirtyObject.cdoClassInfo(); @@ -275,7 +275,7 @@ public class CommitIntegrityCheck else if (featureDelta instanceof CDOClearFeatureDelta) { EStructuralFeature feat = ((CDOClearFeatureDelta)featureDelta).getFeature(); - InternalCDORevision cleanRev = transaction.getCleanRevisions().get(dirtyObject); + InternalCDORevision cleanRev = transaction.getCleanRevision(dirtyObject); int n = cleanRev.size(feat); for (int i = 0; i < n; i++) { @@ -287,7 +287,7 @@ public class CommitIntegrityCheck else if (featureDelta instanceof CDOUnsetFeatureDelta) { EStructuralFeature feat = ((CDOUnsetFeatureDelta)featureDelta).getFeature(); - InternalCDORevision cleanRev = transaction.getCleanRevisions().get(dirtyObject); + InternalCDORevision cleanRev = transaction.getCleanRevision(dirtyObject); Object idOrObject = cleanRev.getValue(feat); CDOID id = (CDOID)transaction.convertObjectToID(idOrObject); checkIncluded(id, "removed child / refTarget of", dirtyObject); @@ -436,7 +436,7 @@ public class CommitIntegrityCheck // that we can find the pre-detach revision in tx.getFormerRevisions(). However, // the object may have already been dirty prior to detachment, so we check the // clean revisions first. - InternalCDORevision cleanRev = transaction.getCleanRevisions().get(referencer); + InternalCDORevision cleanRev = transaction.getCleanRevision(referencer); CheckUtil.checkState(cleanRev, "cleanRev"); InternalCDOClassInfo referencerClassInfo = ((InternalCDOObject)referencer).cdoClassInfo(); @@ -491,7 +491,7 @@ public class CommitIntegrityCheck private void checkFormerContainerIncluded(CDOObject detachedObject) throws CommitIntegrityException { - InternalCDORevision rev = transaction.getCleanRevisions().get(detachedObject); + InternalCDORevision rev = transaction.getCleanRevision(detachedObject); CheckUtil.checkNull(rev, "Could not obtain clean revision for detached object " + detachedObject); CDOID id = getContainerOrResourceID(rev); diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java index 4c114278ad..ad90c58834 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java @@ -37,6 +37,7 @@ import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta; import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; import org.eclipse.emf.cdo.common.util.CDOCommonUtil; import org.eclipse.emf.cdo.common.util.CDOException; +import org.eclipse.emf.cdo.common.util.PartialCollectionLoadingNotSupportedException; import org.eclipse.emf.cdo.eresource.CDOBinaryResource; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.eresource.CDOResourceFolder; @@ -66,6 +67,7 @@ import org.eclipse.emf.cdo.view.CDOViewTargetChangedEvent; import org.eclipse.emf.internal.cdo.bundle.OM; import org.eclipse.emf.internal.cdo.messages.Messages; import org.eclipse.emf.internal.cdo.object.CDOLegacyAdapter; +import org.eclipse.emf.internal.cdo.object.CDONotificationBuilder; import org.eclipse.emf.internal.cdo.query.CDOQueryImpl; import org.eclipse.emf.internal.cdo.transaction.CDOTransactionImpl; @@ -90,6 +92,7 @@ import org.eclipse.net4j.util.ref.ReferenceValueMap2; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.notify.NotificationChain; import org.eclipse.emf.common.notify.impl.AdapterImpl; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; @@ -111,7 +114,6 @@ import org.eclipse.core.runtime.Platform; import java.text.MessageFormat; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -1131,10 +1133,35 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb } cleanObject(object, revision); - CDOStateMachine.INSTANCE.dispatchLoadNotification(object); + dispatchLoadNotification(object); return object; } + public void dispatchLoadNotification(InternalCDOObject object) + { + if (options().isLoadNotificationEnabled()) + { + try + { + InternalCDORevision revision = object.cdoRevision(); + CDONotificationBuilder builder = new CDONotificationBuilder(this); + + NotificationChain notification = builder.buildNotification(object, revision); + if (notification != null) + { + notification.dispatch(); + } + } + catch (PartialCollectionLoadingNotSupportedException ex) + { + if (TRACER.isEnabled()) + { + TRACER.trace(ex); + } + } + } + } + private CDOResource newResourceInstance(InternalCDORevision revision) { String path = getResourcePath(revision); @@ -1510,7 +1537,7 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb Pair<CDORevision, CDORevisionDelta> oldInfo = Pair.create(changedObject.cdoRevision(), delta); // if (!isLocked(changedObject)) { - CDOStateMachine.INSTANCE.invalidate((InternalCDOObject)changedObject, key); + CDOStateMachine2.INSTANCE.invalidate((InternalCDOObject)changedObject, key); } revisionDeltas.put(changedObject, delta); @@ -1535,7 +1562,7 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb CDORevisionDelta.DETACHED); // if (!isLocked(detachedObject)) { - CDOStateMachine.INSTANCE.detachRemote(detachedObject); + CDOStateMachine2.INSTANCE.detachRemote(detachedObject); } detachedObjects.add(detachedObject); @@ -1590,30 +1617,31 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb @Deprecated public synchronized int reload(CDOObject... objects) { - Collection<InternalCDOObject> internalObjects; - if (objects != null && objects.length != 0) - { - internalObjects = new ArrayList<InternalCDOObject>(objects.length); - for (CDOObject object : objects) - { - if (object instanceof InternalCDOObject) - { - internalObjects.add((InternalCDOObject)object); - } - } - } - else - { - internalObjects = new ArrayList<InternalCDOObject>(this.objects.values()); - } - - int result = internalObjects.size(); - if (result != 0) - { - CDOStateMachine.INSTANCE.reload(internalObjects.toArray(new InternalCDOObject[result])); - } - - return result; + // Collection<InternalCDOObject> internalObjects; + // if (objects != null && objects.length != 0) + // { + // internalObjects = new ArrayList<InternalCDOObject>(objects.length); + // for (CDOObject object : objects) + // { + // if (object instanceof InternalCDOObject) + // { + // internalObjects.add((InternalCDOObject)object); + // } + // } + // } + // else + // { + // internalObjects = new ArrayList<InternalCDOObject>(this.objects.values()); + // } + // + // int result = internalObjects.size(); + // if (result != 0) + // { + // CDOStateMachine2.INSTANCE.reload(internalObjects.toArray(new InternalCDOObject[result])); + // } + // + // return result; + return 0; } public void close() @@ -1733,7 +1761,7 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb protected InternalCDORevision getViewedRevision(InternalCDOObject object) { - return CDOStateMachine.INSTANCE.readNoLoad(object); + return CDOStateMachine2.INSTANCE.readNoLoad(object); } public synchronized CDOChangeSetData compareRevisions(CDOBranchPoint source) diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStateMachine.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStateMachine.java index 22d87db5e2..8fc8e81ba9 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStateMachine.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStateMachine.java @@ -101,17 +101,6 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent init(CDOState.TRANSIENT, CDOEvent.COMMIT, FAIL); init(CDOState.TRANSIENT, CDOEvent.ROLLBACK, FAIL); - init(CDOState.PREPARED, CDOEvent.PREPARE, FAIL); - init(CDOState.PREPARED, CDOEvent.ATTACH, new AttachTransition()); - init(CDOState.PREPARED, CDOEvent.DETACH, FAIL); - init(CDOState.PREPARED, CDOEvent.REATTACH, FAIL); - init(CDOState.PREPARED, CDOEvent.READ, IGNORE); - init(CDOState.PREPARED, CDOEvent.WRITE, FAIL); - init(CDOState.PREPARED, CDOEvent.INVALIDATE, FAIL); - init(CDOState.PREPARED, CDOEvent.DETACH_REMOTE, FAIL); - init(CDOState.PREPARED, CDOEvent.COMMIT, FAIL); - init(CDOState.PREPARED, CDOEvent.ROLLBACK, FAIL); - init(CDOState.NEW, CDOEvent.PREPARE, FAIL); init(CDOState.NEW, CDOEvent.ATTACH, FAIL); init(CDOState.NEW, CDOEvent.DETACH, new DetachTransition()); @@ -191,11 +180,11 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * The object is already attached in EMF world. It contains all the information needed to know where it will be - * connected. - * - * @since 2.0 - */ + * The object is already attached in EMF world. It contains all the information needed to know where it will be + * connected. + * + * @since 2.0 + */ public void attach(InternalCDOObject object, InternalCDOTransaction transaction) { synchronized (transaction) @@ -211,24 +200,9 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } } - private void attachOrReattach(InternalCDOObject object, InternalCDOTransaction transaction) - { - // Bug 283985 (Re-attachment): - // If the object going through a prepareTransition is present in cleanRevisions, - // then it was detached earlier, and so we can infer that it is being re-attached - if (transaction.getCleanRevisions().containsKey(object)) - { - reattachObject(object, transaction); - } - else - { - attachObject(object); - } - } - /** - * Phase 1: TRANSIENT --> PREPARED - */ + * Phase 1: TRANSIENT --> PREPARED + */ private void prepare(InternalCDOObject object, Pair<InternalCDOTransaction, List<InternalCDOObject>> transactionAndContents) { @@ -240,32 +214,34 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent process(object, CDOEvent.PREPARE, transactionAndContents); } - /** - * Phase 2: PREPARED --> NEW - */ - private void attachObject(InternalCDOObject object) + private void attachOrReattach(InternalCDOObject object, InternalCDOTransaction transaction) { - if (TRACER.isEnabled()) + // Bug 283985 (Re-attachment): + // If the object going through a prepareTransition is present in cleanRevisions, + // then it was detached earlier, and so we can infer that it is being re-attached + if (transaction.getCleanRevision(object) != null) { - TRACER.format("ATTACH: {0}", object); //$NON-NLS-1$ - } - - process(object, CDOEvent.ATTACH, null); - } + if (TRACER.isEnabled()) + { + TRACER.format("REATTACH: {0}", object); + } - private void reattachObject(InternalCDOObject object, InternalCDOTransaction transaction) - { - if (TRACER.isEnabled()) - { - TRACER.format("REATTACH: {0}", object); + process(object, CDOEvent.REATTACH, transaction); } + else + { + if (TRACER.isEnabled()) + { + TRACER.format("ATTACH: {0}", object); //$NON-NLS-1$ + } - process(object, CDOEvent.REATTACH, transaction); + process(object, CDOEvent.ATTACH, null); + } } /** - * @since 2.0 - */ + * @since 2.0 + */ public void detach(InternalCDOObject object) { synchronized (getMonitor(object)) @@ -303,8 +279,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @since 2.0 - */ + * @since 2.0 + */ public InternalCDORevision read(InternalCDOObject object) { synchronized (getMonitor(object)) @@ -321,8 +297,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @since 2.0 - */ + * @since 2.0 + */ public InternalCDORevision readNoLoad(InternalCDOObject object) { synchronized (getMonitor(object)) @@ -344,16 +320,16 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @since 2.0 - */ + * @since 2.0 + */ public void write(InternalCDOObject object) { write(object, null); } /** - * @since 2.0 - */ + * @since 2.0 + */ public void write(InternalCDOObject object, CDOFeatureDelta featureDelta) { synchronized (getMonitor(object)) @@ -373,8 +349,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @since 2.0 - */ + * @since 2.0 + */ public void reload(InternalCDOObject... objects) { if (objects == null || objects.length == 0) @@ -398,8 +374,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @since 3.0 - */ + * @since 3.0 + */ public void invalidate(InternalCDOObject object, CDORevisionKey key) { synchronized (getMonitor(object)) @@ -414,8 +390,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @since 2.0 - */ + * @since 2.0 + */ public void detachRemote(InternalCDOObject object) { synchronized (getMonitor(object)) @@ -430,8 +406,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @since 2.0 - */ + * @since 2.0 + */ public void commit(InternalCDOObject object, CommitTransactionResult result) { synchronized (getMonitor(object)) @@ -446,8 +422,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @since 2.0 - */ + * @since 2.0 + */ public void rollback(InternalCDOObject object) { synchronized (getMonitor(object)) @@ -486,8 +462,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * Removes clutter from the trace log - */ + * Removes clutter from the trace log + */ private void trace(InternalCDOObject object, CDOEvent event) { CDOState state = object.cdoState(); @@ -509,7 +485,7 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent public void internalReattach(InternalCDOObject object, InternalCDOTransaction transaction) { InternalCDORevisionManager revisionManager = transaction.getSession().getRevisionManager(); - InternalCDORevision cleanRevision = transaction.getCleanRevisions().get(object).copy(); + InternalCDORevision cleanRevision = transaction.getCleanRevision(object).copy(); CDOID id = cleanRevision.getID(); // Bug 373096: Determine clean revision of the CURRENT/LAST savepoint @@ -546,8 +522,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } else { - transaction.registerRevisionDelta(revisionDelta); - transaction.registerDirty(object, (CDOFeatureDelta)null); + // transaction.registerRevisionDelta(revisionDelta); + // transaction.registerDirty(object, (CDOFeatureDelta)null); changeState(object, CDOState.DIRTY); } @@ -583,20 +559,20 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * Prepares a tree of transient objects to be subsequently {@link AttachTransition attached} to a CDOView. - * <p> - * Execution is recursive and includes: - * <ol> - * <li>Assignment of a new {@link CDOIDTemp} - * <li>Assignment of a new {@link CDORevision} - * <li>Bidirectional association with the {@link CDOView} - * <li>Registration with the {@link CDOTransaction} - * <li>Changing state to {@link CDOState#PREPARED PREPARED} - * </ol> - * - * @see AttachTransition - * @author Eike Stepper - */ + * Prepares a tree of transient objects to be subsequently {@link AttachTransition attached} to a CDOView. + * <p> + * Execution is recursive and includes: + * <ol> + * <li>Assignment of a new {@link CDOIDTemp} + * <li>Assignment of a new {@link CDORevision} + * <li>Bidirectional association with the {@link CDOView} + * <li>Registration with the {@link CDOTransaction} + * <li>Changing state to {@link CDOState#PREPARED PREPARED} + * </ol> + * + * @see AttachTransition + * @author Eike Stepper + */ private final class PrepareTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Pair<InternalCDOTransaction, List<InternalCDOObject>>> { @@ -608,10 +584,12 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent // If the object going through a prepareTransition is present in cleanRevisions, // then it was detached earlier, and so we can infer that it is being re-attached - boolean reattaching = transaction.getCleanRevisions().containsKey(object); + boolean reattaching = transaction.getCleanRevision(object) != null; if (!reattaching) { + // TRANSIENT + // Prepare object CDOID id = transaction.createIDForNewObject(object.cdoInternalInstance()); object.cdoInternalSetView(transaction); @@ -633,7 +611,7 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent transaction.registerObject(object); } - transaction.registerAttached(object, !reattaching); + // transaction.registerAttached(object, !reattaching); // Prepare content tree for (Iterator<InternalEObject> it = getPersistentContents(object); it.hasNext();) @@ -680,23 +658,23 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * Attaches a tree of {@link PrepareTransition prepared} objects to a CDOView. - * <p> - * Execution is recursive and includes: - * <ol> - * <li>Calling {@link InternalCDOObject#cdoInternalPostAttach()},<br> - * which includes for {@link CDOObjectImpl}: - * <ol> - * <li>Population of the CDORevision with the current values in - * {@link EStoreEObjectImpl#eSetting(org.eclipse.emf.ecore.EStructuralFeature) eSettings} - * <li>Unsetting {@link EStoreEObjectImpl#eSetting(org.eclipse.emf.ecore.EStructuralFeature) eSettings} - * </ol> - * <li>Changing state to {@link CDOState#NEW NEW} - * </ol> - * - * @see PrepareTransition - * @author Eike Stepper - */ + * Attaches a tree of {@link PrepareTransition prepared} objects to a CDOView. + * <p> + * Execution is recursive and includes: + * <ol> + * <li>Calling {@link InternalCDOObject#cdoInternalPostAttach()},<br> + * which includes for {@link CDOObjectImpl}: + * <ol> + * <li>Population of the CDORevision with the current values in + * {@link EStoreEObjectImpl#eSetting(org.eclipse.emf.ecore.EStructuralFeature) eSettings} + * <li>Unsetting {@link EStoreEObjectImpl#eSetting(org.eclipse.emf.ecore.EStructuralFeature) eSettings} + * </ol> + * <li>Changing state to {@link CDOState#NEW NEW} + * </ol> + * + * @see PrepareTransition + * @author Eike Stepper + */ private final class AttachTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object> { public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL) @@ -707,10 +685,10 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * Bug 283985 (Re-attachment) - * - * @author Caspar De Groot - */ + * Bug 283985 (Re-attachment) + * + * @author Caspar De Groot + */ private final class ReattachTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, InternalCDOTransaction> { @@ -806,8 +784,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @author Eike Stepper - */ + * @author Eike Stepper + */ private static final class DetachTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, List<InternalCDOObject>> { @@ -836,8 +814,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @author Eike Stepper - */ + * @author Eike Stepper + */ final private class CommitTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, CommitTransactionResult> { @@ -873,8 +851,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @author Eike Stepper - */ + * @author Eike Stepper + */ private final class RollbackTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object> { public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL) @@ -896,8 +874,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @author Eike Stepper - */ + * @author Eike Stepper + */ private final class WriteTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object> { public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object featureDelta) @@ -909,20 +887,20 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent throw new NoPermissionException(cleanRevision); } - transaction.getCleanRevisions().put(object, cleanRevision); + // transaction.getCleanRevisions().put(object, cleanRevision); // Copy revision InternalCDORevision revision = object.cdoRevision().copy(); object.cdoInternalSetRevision(revision); - transaction.registerDirty(object, (CDOFeatureDelta)featureDelta); + // transaction.registerDirty(object, (CDOFeatureDelta)featureDelta); changeState(object, CDOState.DIRTY); } } /** - * @author Simon McDuff - */ + * @author Simon McDuff + */ private static final class WriteNewTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object> { public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object featureDelta) @@ -934,13 +912,13 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } InternalCDOTransaction transaction = object.cdoView().toTransaction(); - transaction.registerFeatureDelta(object, (CDOFeatureDelta)featureDelta); + // transaction.registerFeatureDelta(object, (CDOFeatureDelta)featureDelta); } } /** - * @author Simon McDuff - */ + * @author Simon McDuff + */ private static final class RewriteTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object> { public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object featureDelta) @@ -952,20 +930,20 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } InternalCDOTransaction transaction = object.cdoView().toTransaction(); - transaction.registerFeatureDelta(object, (CDOFeatureDelta)featureDelta); + // transaction.registerFeatureDelta(object, (CDOFeatureDelta)featureDelta); } } /** - * @author Simon McDuff - */ + * @author Simon McDuff + */ private static class DetachRemoteTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object> { static final DetachRemoteTransition INSTANCE = new DetachRemoteTransition(); public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL) { - CDOStateMachine.INSTANCE.changeState(object, CDOState.INVALID); + // INSTANCE.changeState(object, CDOState.INVALID); InternalCDOView view = object.cdoView(); view.deregisterObject(object); @@ -974,8 +952,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @author Eike Stepper - */ + * @author Eike Stepper + */ private class InvalidateTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, CDORevisionKey> { public void execute(InternalCDOObject object, CDOState state, CDOEvent event, CDORevisionKey key) @@ -1054,9 +1032,9 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @author Eike Stepper - * @since 2.0 - */ + * @author Eike Stepper + * @since 2.0 + */ private class ConflictTransition extends InvalidateTransition { @Override @@ -1073,8 +1051,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @author Simon McDuff - */ + * @author Simon McDuff + */ private final class InvalidConflictTransition extends ConflictTransition { @Override @@ -1088,8 +1066,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @author Eike Stepper - */ + * @author Eike Stepper + */ private final class LoadTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object> { private boolean forWrite; @@ -1130,8 +1108,8 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent } /** - * @author Simon McDuff - */ + * @author Simon McDuff + */ private static final class InvalidTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object> { public static final InvalidTransition INSTANCE = new InvalidTransition(); diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStateMachine2.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStateMachine2.java new file mode 100644 index 0000000000..a9a700a4e0 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStateMachine2.java @@ -0,0 +1,1455 @@ +/* + * Copyright (c) 2011-2013 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 + * Simon McDuff - maintenance + */ +package org.eclipse.emf.internal.cdo.view; + +import org.eclipse.emf.cdo.CDOState; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.branch.CDOBranchVersion; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; +import org.eclipse.emf.cdo.common.revision.CDOList; +import org.eclipse.emf.cdo.common.revision.CDORevisable; +import org.eclipse.emf.cdo.common.revision.CDORevisionFactory; +import org.eclipse.emf.cdo.common.revision.CDORevisionKey; +import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; +import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOOriginSizeProvider; +import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; +import org.eclipse.emf.cdo.common.security.NoPermissionException; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionCache; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager; +import org.eclipse.emf.cdo.view.CDOInvalidationPolicy; + +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2.Attached.Clean; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2.Attached.Conflict; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2.Attached.Dirty; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2.Attached.New; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2.Attached.Proxy; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2.Attached.Undone; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2.Unattached.Detached; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2.Unattached.Transient; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2.Unusable.Invalid; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2.Unusable.Invalid_Conflict; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.EContentsEList; +import org.eclipse.emf.spi.cdo.CDOSessionProtocol.CommitTransactionResult; +import org.eclipse.emf.spi.cdo.FSMUtil; +import org.eclipse.emf.spi.cdo.InternalCDOObject; +import org.eclipse.emf.spi.cdo.InternalCDOSavepoint; +import org.eclipse.emf.spi.cdo.InternalCDOSavepoint.ChangeInfo; +import org.eclipse.emf.spi.cdo.InternalCDOSession; +import org.eclipse.emf.spi.cdo.InternalCDOTransaction; +import org.eclipse.emf.spi.cdo.InternalCDOView; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * @author Eike Stepper + */ +public final class CDOStateMachine2 +{ + public static final CDOStateMachine2 INSTANCE = new CDOStateMachine2(); + + private static final State TRANSIENT = new Transient(); + + private static final State CLEAN = new Clean(); + + private static final State PROXY = new Proxy(); + + private static final State CONFLICT = new Conflict(); + + private static final State INVALID = new Invalid(); + + private static final State INVALID_CONFLICT = new Invalid_Conflict(); + + static final ThreadLocal<Boolean> SWITCHING_TARGET = new InheritableThreadLocal<Boolean>(); + + private CDOStateMachine2() + { + } + + public void attach(InternalCDOObject object, InternalCDOTransaction transaction) + { + synchronized (transaction) + { + State state = getState(object, transaction, false); + traceEvent("Attach", object, state); + state.attach(object, transaction); + } + } + + public void detach(InternalCDOObject object) + { + synchronized (getMonitor(object)) + { + // Accumulate objects that need to be detached. + // In case of errors, we will keep the graph exactly like it was before. + List<Runnable> runnables = new ArrayList<Runnable>(); + detach(object, runnables); + + for (Runnable runnable : runnables) + { + runnable.run(); + } + } + } + + private void detach(InternalCDOObject object, List<Runnable> runnables) + { + State state = getState(object, null, false); + traceEvent("Detach", object, state); + state.detach(object, runnables); + } + + public InternalCDORevision read(InternalCDOObject object) + { + synchronized (getMonitor(object)) + { + State state = getState(object, null, false); + traceEvent("Read", object, state); + return state.read(object); + } + } + + public InternalCDORevision readNoLoad(InternalCDOObject object) + { + synchronized (getMonitor(object)) + { + switch (object.cdoState()) + { + case TRANSIENT: + case NEW: + case CONFLICT: + case INVALID_CONFLICT: + case INVALID: + case PROXY: + return null; + } + + return object.cdoRevision(); + } + } + + public InternalCDORevision write(InternalCDOObject object, CDOFeatureDelta featureDelta) + { + synchronized (getMonitor(object)) + { + return writeWithoutViewLock(object, featureDelta); + } + } + + private InternalCDORevision writeWithoutViewLock(InternalCDOObject object, CDOFeatureDelta featureDelta) + { + State state = getState(object, null, false); + traceEvent("Write", object, state); + return state.write(object, featureDelta); + } + + public void commit(InternalCDOObject object, CommitTransactionResult result) + { + synchronized (getMonitor(object)) + { + State state = getState(object, null, false); + traceEvent("Commit", object, state); + state.commit(object, result); + } + } + + public void rollback(InternalCDOObject object) + { + synchronized (getMonitor(object)) + { + State state = getState(object, null, true); + traceEvent("Rollback", object, state); + state.rollback(object); + } + } + + public void invalidate(InternalCDOObject object, CDORevisionKey key) + { + synchronized (getMonitor(object)) + { + State state = getState(object, null, false); + traceEvent("Invalidate", object, state); + state.invalidate(object, key); + } + } + + public void detachRemote(InternalCDOObject object) + { + synchronized (getMonitor(object)) + { + State state = getState(object, null, false); + traceEvent("DetachRemote", object, state); + state.detachRemote(object); + } + } + + private void transition(InternalCDOObject object, State state) + { + trace(" Transition " + getLabel(object) + " to " + state); + object.cdoInternalSetState(state.getCDOState()); + } + + private Object getMonitor(InternalCDOObject object) + { + InternalCDOView view = object.cdoView(); + if (view != null) + { + return view; + } + + // In TRANSIENT and PREPARED the object is not yet attached to a view + return object; + } + + private State getState(InternalCDOObject object, InternalCDOTransaction transaction, boolean remove) + { + CDOState cdoState = object.cdoState(); + switch (cdoState) + { + case TRANSIENT: + return getUnattachedState(object, transaction); + + case NEW: + case DIRTY: + case PREPARED: + return getAttachedState(object, remove); + + case CLEAN: + return CLEAN; + + case PROXY: + return PROXY; + + case CONFLICT: + return CONFLICT; + + case INVALID: + return INVALID; + + case INVALID_CONFLICT: + return INVALID_CONFLICT; + + default: + throw new IllegalStateException("Illegal state: " + cdoState); + } + } + + private State getUnattachedState(InternalCDOObject object, InternalCDOTransaction transaction) + { + if (transaction != null) + { + ChangeInfo detachedInfo = transaction.getLastSavepoint().getDetachedInfo(object); + if (detachedInfo != null) + { + return (State)detachedInfo; + } + } + + return TRANSIENT; + } + + private State getAttachedState(InternalCDOObject object, boolean remove) + { + InternalCDOSavepoint savepoint = object.cdoView().toTransaction().getLastSavepoint(); + CDOID id = object.cdoID(); + + if (remove) + { + return (State)savepoint.removeChangeInfo(id); + } + + return (State)savepoint.getChangeInfo(id); + } + + private static String getLabel(InternalCDOObject object) + { + String label = object.toString(); + + int pos = label.indexOf('['); + if (pos != -1) + { + label = label.substring(0, pos); + } + + return label; + } + + private static void traceEvent(String event, InternalCDOObject object, State state) + { + int xxx; + // trace(event + " for " + getLabel(object) + " in " + state); + } + + private static void trace(String message) + { + int xxx; + // System.out.println(message); + } + + /** + * @author Eike Stepper + */ + public static abstract class State + { + public static final String FAIL_PREFIX = "Impossible to handle "; + + public abstract CDOState getCDOState(); + + public void attach(InternalCDOObject object, InternalCDOTransaction transaction) + { + throw fail(object, "Attach"); + } + + public void detach(InternalCDOObject object, List<Runnable> runnables) + { + throw fail(object, "Detach"); + } + + public InternalCDORevision read(InternalCDOObject object) + { + throw fail(object, "Read"); + } + + public InternalCDORevision write(InternalCDOObject object, CDOFeatureDelta featureDelta) + { + throw fail(object, "Write"); + } + + public void commit(InternalCDOObject object, CommitTransactionResult result) + { + throw fail(object, "Commit"); + } + + public void rollback(InternalCDOObject object) + { + throw fail(object, "Rollback"); + } + + public void invalidate(InternalCDOObject object, CDORevisionKey key) + { + throw fail(object, "Invalidate"); + } + + public void detachRemote(InternalCDOObject object) + { + throw fail(object, "DetachRemote"); + } + + @Override + public String toString() + { + return getClass().getSimpleName().toUpperCase(); + } + + protected void doRemoteDetach(InternalCDOObject object) + { + INSTANCE.transition(object, INVALID); + + InternalCDOView view = object.cdoView(); + view.deregisterObject(object); + object.cdoInternalPostDetach(true); + } + + protected final void ignore() + { + // trace(" IGNORE"); + } + + private IllegalStateException fail(InternalCDOObject object, String event) + { + String message = FAIL_PREFIX + event + " for " + getLabel(object) + " in " + this; + return new IllegalStateException(message); + } + } + + /** + * @author Eike Stepper + */ + public static abstract class Unattached extends State + { + @Override + public final CDOState getCDOState() + { + return CDOState.TRANSIENT; + } + + @Override + public void attach(InternalCDOObject object, InternalCDOTransaction transaction) + { + // Prepare content tree + for (Iterator<InternalEObject> it = getPersistentContents(object); it.hasNext();) + { + InternalEObject content = it.next(); + Resource.Internal directResource = content.eDirectResource(); + + boolean objectIsResource = directResource == object; + if (objectIsResource || directResource == null) + { + InternalCDOObject adapted = FSMUtil.adapt(content, transaction); + INSTANCE.attach(adapted, transaction); + } + } + } + + @Override + public void detach(InternalCDOObject object, List<Runnable> runnables) + { + ignore(); + } + + @Override + public final InternalCDORevision read(InternalCDOObject object) + { + // Can happen during detach + return object.cdoRevision(); + } + + @Override + public final InternalCDORevision write(InternalCDOObject object, CDOFeatureDelta featureDelta) + { + // Can happen during detach + return object.cdoRevision(); + } + + @Override + public void invalidate(InternalCDOObject object, CDORevisionKey key) + { + ignore(); + } + + @Override + public void detachRemote(InternalCDOObject object) + { + ignore(); + } + + protected void registerNewPackage(EClass eClass, InternalCDOSession session) + { + checkPackageRegistrationProblems(session, eClass); + + EPackage ePackage = eClass.getEPackage(); + CDOPackageRegistry packageRegistry = session.getPackageRegistry(); + if (!packageRegistry.containsKey(ePackage.getNsURI())) + { + packageRegistry.putEPackage(ePackage); + } + } + + private void checkPackageRegistrationProblems(InternalCDOSession session, EClass eClass) + { + if (session.options().isGeneratedPackageEmulationEnabled()) + { + // Check that there are no multiple EPackages with the same URI in system. Bug 335004 + String packageURI = eClass.getEPackage().getNsURI(); + Object packageObject = session.getPackageRegistry().get(packageURI); + if (packageObject instanceof InternalCDOPackageInfo) + { + packageObject = ((InternalCDOPackageInfo)packageObject).getEPackage(false); + } + + if (packageObject instanceof EPackage && packageObject != eClass.getEPackage()) + { + throw new IllegalStateException(MessageFormat.format( + "Global EPackage {0} for EClass {1} is different from EPackage found in CDOPackageRegistry", packageURI, + eClass)); + } + } + } + + private Iterator<InternalEObject> getPersistentContents(InternalCDOObject object) + { + EStructuralFeature[] features = object.cdoClassInfo().getAllPersistentContainments(); + return new EContentsEList.ResolvingFeatureIteratorImpl<InternalEObject>(object, features); + } + + /** + * @author Eike Stepper + */ + public static final class Transient extends Unattached + { + @Override + public void attach(InternalCDOObject object, InternalCDOTransaction transaction) + { + // TODO Permission check needed? + transaction.handleAttachingObject(object); + + EClass eClass = object.eClass(); + CDOID id = transaction.createIDForNewObject(object.cdoInternalInstance()); + CDOBranchPoint branchPoint = transaction.getBranch().getHead(); + + InternalCDOSession session = transaction.getSession(); + registerNewPackage(eClass, session); + + // Create new revision + CDORevisionFactory revisionFactory = session.getRevisionManager().getFactory(); + InternalCDORevision revision = (InternalCDORevision)revisionFactory.createRevision(eClass); + revision.setID(id); + revision.setBranchPoint(branchPoint); + + object.cdoInternalSetView(transaction); + object.cdoInternalSetRevision(revision); + + transaction.registerObject(object); // Object must have ID + object.cdoInternalPostAttach(); // Object must have CDOState.TRANSIENT and an empty revision + + New newState = new New(object, null); + transaction.getLastSavepoint().addChangeInfo(newState); + INSTANCE.transition(object, newState); + super.attach(object, transaction); + } + } + + /** + * @author Eike Stepper + */ + public static final class Detached extends Unattached implements ChangeInfo + { + private final InternalCDOObject object; + + private final InternalCDORevision cleanRevision; + + private final InternalCDORevision baseRevision; + + public Detached(InternalCDOObject object, InternalCDORevision cleanRevision, InternalCDORevision baseRevision) + { + if (cleanRevision == null) + { + throw new IllegalArgumentException("cleanRevision is null"); + } + + this.object = object; + this.cleanRevision = cleanRevision; + this.baseRevision = baseRevision; + } + + public ChangeType getType() + { + return ChangeType.DETACHED; + } + + public CDOID getID() + { + return cleanRevision.getID(); + } + + public int getVersion() + { + return cleanRevision.getVersion(); + } + + public InternalCDOObject getObject() + { + return object; + } + + public InternalCDORevision getCleanRevision() + { + return cleanRevision; + } + + public InternalCDORevision getBaseRevision() + { + return baseRevision; + } + + public InternalCDORevisionDelta getRevisionDelta() + { + return null; + } + + public ChangeInfo setSavepoint() + { + InternalCDORevision newBaseRevision = null; // TODO Compute from instance + return new Detached(object, cleanRevision, newBaseRevision); + } + + @Override + public void attach(InternalCDOObject object, InternalCDOTransaction transaction) + { + // TODO Permission check needed? + transaction.handleAttachingObject(object); + + CDOID id = getID(); + EClass eClass = object.eClass(); + CDOBranchPoint branchPoint = transaction.getBranch().getHead(); + + InternalCDOSession session = transaction.getSession(); + registerNewPackage(eClass, session); + + InternalCDORevision cleanRevision = getCleanRevision(); + + // Create new revision + CDORevisionFactory revisionFactory = session.getRevisionManager().getFactory(); + InternalCDORevision revision = (InternalCDORevision)revisionFactory.createRevision(eClass); + revision.setID(id); + revision.setVersion(cleanRevision.getVersion()); + revision.setBranchPoint(branchPoint); + + object.cdoInternalSetView(transaction); + object.cdoInternalSetRevision(revision); + + transaction.registerObject(object); // Object must have ID + object.cdoInternalPostAttach(); // Object must have CDOState.TRANSIENT and an empty revision + + InternalCDOSavepoint savepoint = transaction.getLastSavepoint(); + savepoint.removeChangeInfo(id); + + State newState; + InternalCDORevisionDelta revisionDelta = revision.compare(cleanRevision); + if (revisionDelta.isEmpty()) + { + if (savepoint.getPreviousSavepoint() != null) + { + newState = new Undone(object, cleanRevision, baseRevision); + savepoint.addChangeInfo((ChangeInfo)newState); + } + else + { + newState = CLEAN; + savepoint.removeChangeInfo(id); + } + } + else + { + newState = new Dirty(object, cleanRevision, baseRevision, revisionDelta); + savepoint.addChangeInfo((ChangeInfo)newState); + } + + INSTANCE.transition(object, newState); + transaction.updateDirtyState(true); + super.attach(object, transaction); + } + + @Override + protected void registerNewPackage(EClass eClass, InternalCDOSession session) + { + // Do nothing + } + + @Override + public String toString() + { + return super.toString() + "[" + cleanRevision + "]"; + } + } + } + + /** + * @author Eike Stepper + */ + public static abstract class Attached extends State + { + public InternalCDORevision getCleanRevision(InternalCDOObject object) + { + // TODO What about states that are no ChangeInfo (i.e. not New or Dirty)? + return null; + } + + public InternalCDORevision getBaseRevision() + { + // TODO What about states that are no ChangeInfo (i.e. not New or Dirty)? + return null; + } + + @Override + public final void detach(final InternalCDOObject object, List<Runnable> runnables) + { + final InternalCDOTransaction transaction = object.cdoView().toTransaction(); + transaction.handleDetachingObject(object); + + runnables.add(new Runnable() + { + public void run() + { + State newState = doDetach(object, transaction.getLastSavepoint()); + + transaction.deregisterObject(object); + object.cdoInternalSetView(null); + object.cdoInternalSetID(null); + + INSTANCE.transition(object, newState); + } + }); + + boolean isResource = object instanceof Resource; + + // Prepare content tree + for (Iterator<EObject> it = object.eContents().iterator(); it.hasNext();) + { + InternalEObject eObject = (InternalEObject)it.next(); + boolean isDirectlyConnected = isResource && eObject.eDirectResource() == object; + if (isDirectlyConnected || eObject.eDirectResource() == null) + { + InternalCDOObject adapted = FSMUtil.adapt(eObject, transaction); + if (adapted != null) + { + INSTANCE.detach(adapted, runnables); + } + } + } + } + + protected State doDetach(InternalCDOObject object, InternalCDOSavepoint savepoint) + { + revisionToInstance(object); + + InternalCDORevision cleanRevision = getCleanRevision(object); + InternalCDORevision baseRevision = getBaseRevision(); + + Detached detached = new Detached(object, cleanRevision, baseRevision); + savepoint.addChangeInfo(detached); + return detached; + } + + private void revisionToInstance(InternalCDOObject object) + { + object.cdoInternalSetState(CDOState.TRANSIENT); + + try + { + object.cdoInternalPostDetach(false); // postDetach() requires the object to be TRANSIENT + } + finally + { + object.cdoInternalSetState(getCDOState()); + } + } + + @Override + public InternalCDORevision read(InternalCDOObject object) + { + // Ignore + return object.cdoRevision(); + } + + protected final InternalCDORevision getWritableRevision(InternalCDOObject object) + { + InternalCDORevision cleanRevision = object.cdoRevision(); + if (!cleanRevision.isWritable()) + { + throw new NoPermissionException(cleanRevision); + } + + return cleanRevision; + } + + protected final void doCommit(InternalCDOObject object, CommitTransactionResult result) + { + InternalCDOTransaction transaction = object.cdoView().toTransaction(); + InternalCDORevision revision = object.cdoRevision(); + Map<CDOID, CDOID> idMappings = result.getIDMappings(); + + // Adjust object + CDOID oldID = object.cdoID(); + CDOID newID = idMappings.get(oldID); + if (newID != null) + { + revision.setID(newID); + transaction.remapObject(oldID); + } + + // Adjust revision + revision.adjustForCommit(transaction.getBranch(), result.getTimeStamp()); + revision.adjustReferences(result.getReferenceAdjuster()); + // TODO Adjust possible CDOElementProxies! + revision.freeze(); + + InternalCDORevisionManager revisionManager = transaction.getSession().getRevisionManager(); + revisionManager.addRevision(revision); + + transaction.getLastSavepoint().removeChangeInfo(oldID); + INSTANCE.transition(object, CLEAN); + } + + /** + * @author Eike Stepper + */ + public static final class Proxy extends Attached + { + @Override + public CDOState getCDOState() + { + return CDOState.PROXY; + } + + @Override + public InternalCDORevision read(InternalCDOObject object) + { + load(object, false); + return object.cdoRevision(); + } + + @Override + public InternalCDORevision write(InternalCDOObject object, CDOFeatureDelta featureDelta) + { + load(object, true); + return INSTANCE.writeWithoutViewLock(object, featureDelta); + } + + @Override + public void invalidate(InternalCDOObject object, CDORevisionKey key) + { + ignore(); + } + + @Override + public void detachRemote(InternalCDOObject object) + { + doRemoteDetach(object); + } + + protected final void load(InternalCDOObject object, boolean forWrite) + { + object.cdoInternalPreLoad(); + + InternalCDOView view = object.cdoView(); + InternalCDORevision revision = view.getRevision(object.cdoID(), true); + if (revision == null) + { + INSTANCE.detachRemote(object); + CDOInvalidationPolicy policy = view.options().getInvalidationPolicy(); + policy.handleInvalidObject(object); + } + + if (forWrite && !revision.isWritable()) + { + throw new NoPermissionException(revision); + } + + object.cdoInternalSetRevision(revision); + INSTANCE.transition(object, CLEAN); + object.cdoInternalPostLoad(); + view.dispatchLoadNotification(object); + } + } + + /** + * @author Eike Stepper + */ + public static class Clean extends Attached + { + @Override + public CDOState getCDOState() + { + return CDOState.CLEAN; + } + + @Override + public InternalCDORevision getCleanRevision(InternalCDOObject object) + { + return object.cdoRevision(); + } + + @Override + public InternalCDORevision write(InternalCDOObject object, final CDOFeatureDelta featureDelta) + { + final InternalCDORevision cleanRevision = getWritableRevision(object); + + InternalCDOTransaction transaction = object.cdoView().toTransaction(); + transaction.handleModifyingObject(object, featureDelta); + + InternalCDORevisionDelta revisionDelta = (InternalCDORevisionDelta)CDORevisionUtil.createDelta(cleanRevision); + boolean mergeIsEmpty = revisionDelta.mergeFeatureDelta(featureDelta, new CDOOriginSizeProvider.Caching() + { + @Override + protected CDOList getList() + { + EStructuralFeature feature = featureDelta.getFeature(); + return cleanRevision.getList(feature); + } + }); + + if (mergeIsEmpty) + { + return cleanRevision; + } + + // Copy revision + InternalCDORevision revision = cleanRevision.copy(); + featureDelta.apply(revision); + object.cdoInternalSetRevision(revision); + + Dirty dirty = new Dirty(object, cleanRevision, cleanRevision, revisionDelta); + transaction.getLastSavepoint().addChangeInfo(dirty); + + INSTANCE.transition(object, dirty); + transaction.updateDirtyState(false); + + return revision; + } + + @Override + public void invalidate(InternalCDOObject object, CDORevisionKey key) + { + InternalCDORevision oldRevision = object.cdoRevision(); + InternalCDORevision newRevision = null; + + InternalCDOView view = object.cdoView(); + InternalCDORevisionCache cache = view.getSession().getRevisionManager().getCache(); + + if (SWITCHING_TARGET.get() == Boolean.TRUE) + { + CDORevisionDelta delta = (CDORevisionDelta)key; + CDORevisable target = delta.getTarget(); + newRevision = (InternalCDORevision)cache.getRevisionByVersion(delta.getID(), target); + if (newRevision == null) + { + newRevision = oldRevision.copy(); + view.getSession().resolveAllElementProxies(newRevision); + delta.apply(newRevision); + newRevision.setBranchPoint(target); + cache.addRevision(newRevision); + } + + object.cdoInternalSetRevision(newRevision); + INSTANCE.transition(object, CLEAN); + object.cdoInternalPostLoad(); + return; + } + + if (key == null || key.getVersion() >= oldRevision.getVersion()) + { + CDORevisionKey newKey = null; + if (key != null) + { + int newVersion = getNewVersion(key); + newKey = CDORevisionUtil.createRevisionKey(key.getID(), key.getBranch(), newVersion); + } + + if (newKey != null) + { + newRevision = (InternalCDORevision)cache.getRevisionByVersion(newKey.getID(), newKey); + } + + if (newRevision != null) + { + object.cdoInternalSetRevision(newRevision); + INSTANCE.transition(object, CLEAN); + object.cdoInternalPostLoad(); + } + else + { + INSTANCE.transition(object, PROXY); + + CDOInvalidationPolicy policy = view.options().getInvalidationPolicy(); + policy.handleInvalidation(object, key); + object.cdoInternalPostInvalidate(); + } + } + } + + @Override + public void detachRemote(InternalCDOObject object) + { + doRemoteDetach(object); + } + + private static int getNewVersion(CDORevisionKey key) + { + if (key instanceof CDORevisionDelta) + { + CDORevisionDelta delta = (CDORevisionDelta)key; + CDORevisable target = delta.getTarget(); + if (target != null && key.getBranch() == target.getBranch()) + { + return target.getVersion(); + } + } + + return key.getVersion() + 1; + } + } + + /** + * @author Eike Stepper + */ + public static final class Undone extends Clean implements ChangeInfo + { + private final InternalCDOObject object; + + private final InternalCDORevision cleanRevision; + + private final InternalCDORevision baseRevision; + + public Undone(InternalCDOObject object, InternalCDORevision cleanRevision, InternalCDORevision baseRevision) + { + this.object = object; + this.cleanRevision = cleanRevision; + this.baseRevision = baseRevision; + } + + @Override + public CDOState getCDOState() + { + return CDOState.PREPARED; + } + + public ChangeType getType() + { + return ChangeType.UNDONE; + } + + public CDOID getID() + { + return object.cdoID(); + } + + public InternalCDOObject getObject() + { + return object; + } + + @Override + public InternalCDORevision getCleanRevision(InternalCDOObject object) + { + return cleanRevision; + } + + public InternalCDORevision getCleanRevision() + { + return cleanRevision; + } + + @Override + public InternalCDORevision getBaseRevision() + { + return baseRevision; + } + + public InternalCDORevisionDelta getRevisionDelta() + { + return null; + } + + public ChangeInfo setSavepoint() + { + InternalCDORevision newBaseRevision = object.cdoRevision().copy(); + return new Undone(object, cleanRevision, newBaseRevision); + } + } + + /** + * @author Eike Stepper + */ + public static final class New extends Attached implements ChangeInfo + { + private final InternalCDOObject object; + + private final InternalCDORevision baseRevision; + + public New(InternalCDOObject object, InternalCDORevision baseRevision) + { + this.object = object; + this.baseRevision = baseRevision; + } + + @Override + public CDOState getCDOState() + { + return CDOState.NEW; + } + + public ChangeType getType() + { + return ChangeType.NEW; + } + + public CDOID getID() + { + return object.cdoID(); + } + + public int getVersion() + { + return CDOBranchVersion.UNSPECIFIED_VERSION; + } + + public InternalCDOObject getObject() + { + return object; + } + + @Override + public InternalCDORevision getCleanRevision(InternalCDOObject object) + { + return null; + } + + public InternalCDORevision getCleanRevision() + { + return null; + } + + @Override + public InternalCDORevision getBaseRevision() + { + return baseRevision; + } + + public InternalCDORevisionDelta getRevisionDelta() + { + return null; + } + + public ChangeInfo setSavepoint() + { + InternalCDORevision newBaseRevision = object.cdoRevision().copy(); + return new New(object, newBaseRevision); + } + + @Override + public InternalCDORevision write(InternalCDOObject object, CDOFeatureDelta featureDelta) + { + InternalCDORevision revision = getWritableRevision(object); // Check write permission + + InternalCDOTransaction transaction = object.cdoView().toTransaction(); + transaction.handleModifyingObject(object, featureDelta); + + featureDelta.apply(revision); + return revision; + } + + @Override + public void commit(InternalCDOObject object, CommitTransactionResult result) + { + doCommit(object, result); + } + + @Override + public String toString() + { + return super.toString() + "[" + object.cdoRevision() + "]"; + } + + @Override + protected State doDetach(InternalCDOObject object, InternalCDOSavepoint savepoint) + { + savepoint.removeChangeInfo(object.cdoID()); + return TRANSIENT; + } + } + + /** + * @author Eike Stepper + */ + public static final class Dirty extends Attached implements ChangeInfo + { + private final InternalCDOObject object; + + private final InternalCDORevision cleanRevision; + + private final InternalCDORevision baseRevision; + + private InternalCDORevisionDelta revisionDelta; + + public Dirty(InternalCDOObject object, InternalCDORevision cleanRevision, InternalCDORevision baseRevision, + InternalCDORevisionDelta revisionDelta) + { + this.object = object; + this.cleanRevision = cleanRevision; + this.baseRevision = baseRevision; + this.revisionDelta = revisionDelta; + } + + @Override + public CDOState getCDOState() + { + return CDOState.DIRTY; + } + + public ChangeType getType() + { + return ChangeType.DIRTY; + } + + public CDOID getID() + { + return cleanRevision.getID(); + } + + public int getVersion() + { + return cleanRevision.getVersion(); + } + + public InternalCDOObject getObject() + { + return object; + } + + @Override + public InternalCDORevision getCleanRevision(InternalCDOObject object) + { + return cleanRevision; + } + + public InternalCDORevision getCleanRevision() + { + return cleanRevision; + } + + @Override + public InternalCDORevision getBaseRevision() + { + return baseRevision; + } + + public InternalCDORevisionDelta getRevisionDelta() + { + return revisionDelta; + } + + public ChangeInfo setSavepoint() + { + InternalCDORevision newBaseRevision = object.cdoRevision().copy(); + return new Dirty(object, cleanRevision, newBaseRevision, revisionDelta); + } + + @Override + public InternalCDORevision write(InternalCDOObject object, final CDOFeatureDelta featureDelta) + { + InternalCDORevision revision = getWritableRevision(object); + + InternalCDOTransaction transaction = object.cdoView().toTransaction(); + transaction.handleModifyingObject(object, featureDelta); + + final EStructuralFeature feature = featureDelta.getFeature(); + featureDelta.apply(revision); + + if (revision.isUnchunked()) + { + if (isOnlyFeatureDelta(feature)) + { + if (isClean(revision, feature)) + { + undo(object, transaction); + return cleanRevision; + } + } + } + + boolean mergeIsEmpty = revisionDelta.mergeFeatureDelta(featureDelta, new CDOOriginSizeProvider.Caching() + { + @Override + protected CDOList getList() + { + return cleanRevision.getList(feature); + } + }); + + if (mergeIsEmpty && revisionDelta.isEmpty()) + { + undo(object, transaction); + return cleanRevision; + } + + return revision; + } + + private boolean isOnlyFeatureDelta(final EStructuralFeature feature) + { + Map<EStructuralFeature, CDOFeatureDelta> featureDeltas = revisionDelta.getFeatureDeltaMap(); + return featureDeltas.size() == 1 && featureDeltas.containsKey(feature); + } + + private boolean isClean(InternalCDORevision revision, EStructuralFeature feature) + { + if (feature.isMany()) + { + CDOList list = revision.getList(feature); + CDOList cleanList = cleanRevision.getList(feature); + + int size = list.size(); + if (size != cleanList.size()) + { + return false; + } + + for (int i = size - 1; i >= 0; --i) + { + Object value = list.get(i); + Object cleanValue = cleanList.get(i); + if (!CDORevisionUtil.areValuesEqual(value, cleanValue)) + { + return false; + } + } + + return true; + } + + Object value = revision.getValue(feature); + Object cleanValue = cleanRevision.getValue(feature); + return CDORevisionUtil.areValuesEqual(value, cleanValue); + } + + private void undo(InternalCDOObject object, InternalCDOTransaction transaction) + { + object.cdoInternalSetRevision(cleanRevision); + + State newState; + InternalCDOSavepoint savepoint = transaction.getLastSavepoint(); + if (savepoint.getPreviousSavepoint() != null) + { + newState = new Undone(object, cleanRevision, baseRevision); + savepoint.addChangeInfo((ChangeInfo)newState); + } + else + { + newState = CLEAN; + savepoint.removeChangeInfo(getID()); + } + + INSTANCE.transition(object, newState); + transaction.updateDirtyState(true); + } + + @Override + public void invalidate(InternalCDOObject object, CDORevisionKey key) + { + InternalCDORevision oldRevision = object.cdoRevision(); + if (key == null || key.getVersion() >= oldRevision.getVersion() - 1) + { + INSTANCE.transition(object, CONFLICT); + InternalCDOTransaction transaction = object.cdoView().toTransaction(); + transaction.setConflict(object); + } + } + + @Override + public void commit(InternalCDOObject object, CommitTransactionResult result) + { + doCommit(object, result); + } + + @Override + public void detachRemote(InternalCDOObject object) + { + INSTANCE.transition(object, INVALID_CONFLICT); + + InternalCDOTransaction transaction = object.cdoView().toTransaction(); + transaction.setConflict(object); + } + + @Override + public String toString() + { + return super.toString() + "[" + getRevisionDelta() + "]"; + } + } + + /** + * @author Eike Stepper + */ + public static final class Conflict extends Attached + { + @Override + public CDOState getCDOState() + { + return CDOState.CONFLICT; + } + + @Override + public void invalidate(InternalCDOObject object, CDORevisionKey key) + { + ignore(); + } + + @Override + public void detachRemote(InternalCDOObject object) + { + ignore(); + } + } + } + + /** + * @author Eike Stepper + */ + public static abstract class Unusable extends State + { + @Override + public void detach(InternalCDOObject object, List<Runnable> runnables) + { + ignore(); + } + + /** + * @author Eike Stepper + */ + public static final class Invalid extends Unusable + { + @Override + public CDOState getCDOState() + { + return CDOState.INVALID; + } + + @Override + public void invalidate(InternalCDOObject object, CDORevisionKey key) + { + ignore(); + } + + @Override + public void detachRemote(InternalCDOObject object) + { + ignore(); + } + } + + /** + * @author Eike Stepper + */ + public static final class Invalid_Conflict extends Unusable + { + @Override + public CDOState getCDOState() + { + return CDOState.INVALID_CONFLICT; + } + + @Override + public void invalidate(InternalCDOObject object, CDORevisionKey key) + { + ignore(); + } + + @Override + public void rollback(InternalCDOObject object) + { + doRemoteDetach(object); + } + + @Override + public void detachRemote(InternalCDOObject object) + { + ignore(); + } + } + } +} diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStoreImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStoreImpl.java index 9b9cabd551..58d64c9db3 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStoreImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStoreImpl.java @@ -54,6 +54,7 @@ import org.eclipse.emf.ecore.util.FeatureMapUtil; import org.eclipse.emf.spi.cdo.CDOStore; import org.eclipse.emf.spi.cdo.FSMUtil; import org.eclipse.emf.spi.cdo.InternalCDOObject; +import org.eclipse.emf.spi.cdo.InternalCDOSession; import org.eclipse.emf.spi.cdo.InternalCDOView; import java.text.MessageFormat; @@ -110,10 +111,7 @@ public final class CDOStoreImpl implements CDOStore CDOID newResourceID = newResource == null ? CDOID.NULL : newResource.cdoID(); CDOFeatureDelta delta = new CDOContainerFeatureDeltaImpl(newResourceID, newContainerID, newContainerFeatureID); - InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); - revision.setResourceID(newResourceID); - revision.setContainerID(newContainerID); - revision.setContainingFeatureID(newContainerFeatureID); + getRevisionForWriting(cdoObject, delta); } } @@ -397,15 +395,18 @@ public final class CDOStoreImpl implements CDOStore TRACER.format("set({0}, {1}, {2}, {3})", cdoObject, feature, index, value); //$NON-NLS-1$ } - value = convertToCDO(cdoObject, feature, value); - InternalCDORevision oldRevision = getRevisionForReading(cdoObject); Object oldValue = oldRevision.get(feature, index); oldValue = convertToEMF(eObject, oldRevision, feature, index, oldValue); - CDOFeatureDelta delta = new CDOSetFeatureDeltaImpl(feature, index, value, oldValue); - InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); - revision.set(feature, index, value); + if (!ObjectUtil.equals(value, oldValue)) + { + value = convertToCDO(cdoObject, feature, value); + + CDOFeatureDelta delta = new CDOSetFeatureDeltaImpl(feature, index, value, oldValue); + InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); + revision.set(feature, index, value); + } return oldValue; } @@ -422,28 +423,7 @@ public final class CDOStoreImpl implements CDOStore } CDOFeatureDelta delta = new CDOUnsetFeatureDeltaImpl(feature); - InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); - - if (feature.isUnsettable()) - { - revision.unset(feature); - } - else - { - if (feature.isMany()) - { - Object value = revision.getValue(feature); - - @SuppressWarnings("unchecked") - List<Object> list = (List<Object>)value; - list.clear(); - } - else - { - Object defaultValue = convertToCDO(cdoObject, feature, feature.getDefaultValue()); - revision.set(feature, NO_INDEX, defaultValue); - } - } + getRevisionForWriting(cdoObject, delta); } } @@ -457,18 +437,13 @@ public final class CDOStoreImpl implements CDOStore TRACER.format("add({0}, {1}, {2}, {3})", cdoObject, feature, index, value); //$NON-NLS-1$ } - if (feature.isMany()) - { - value = convertToCDO(cdoObject, feature, value); - } - else - { - throw new UnsupportedOperationException("ADD is not supported for single-valued features"); - } + checkManyValued(feature); + value = convertToCDO(cdoObject, feature, value); CDOFeatureDelta delta = new CDOAddFeatureDeltaImpl(feature, index, value); - InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); - revision.add(feature, index, value); + getRevisionForWriting(cdoObject, delta); + // InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); + // revision.add(feature, index, value); } } @@ -482,39 +457,47 @@ public final class CDOStoreImpl implements CDOStore TRACER.format("remove({0}, {1}, {2})", cdoObject, feature, index); //$NON-NLS-1$ } - Object oldValue = null; + Object oldValue = getListElement(cdoObject, feature, index); + oldValue = convertToEMF(eObject, cdoObject.cdoRevision(), feature, index, oldValue); - // Bug 293283 / Bug 314387 - if (feature.isMany()) - { - InternalCDORevision readLockedRevision = getRevisionForReading(cdoObject); - CDOList list = readLockedRevision.getList(feature); - int size = list.size(); - if (index < 0 || size <= index) - { - throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); - } - } - else - { - throw new UnsupportedOperationException("REMOVE is not supported for single-valued features"); - } + CDOFeatureDelta delta = new CDORemoveFeatureDeltaImpl(feature, index, oldValue); + getRevisionForWriting(cdoObject, delta); - CDOFeatureDelta delta = new CDORemoveFeatureDeltaImpl(feature, index); - InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); + // InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); + // try + // { + // oldValue = convertToEMF(eObject, revision, feature, index, oldValue); + // } + // finally + // { + // revision.remove(feature, index); + // } - oldValue = revision.get(feature, index); + return oldValue; + } + } - try - { - oldValue = convertToEMF(eObject, revision, feature, index, oldValue); - } - finally - { - revision.remove(feature, index); - } + private Object getListElement(InternalCDOObject object, EStructuralFeature feature, int index) + { + checkManyValued(feature); - return oldValue; + // Bug 293283 / Bug 314387 + InternalCDORevision readLockedRevision = getRevisionForReading(object); + CDOList list = readLockedRevision.getList(feature); + int size = list.size(); + if (index < 0 || size <= index) + { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + + return readLockedRevision.get(feature, index); + } + + private void checkManyValued(EStructuralFeature feature) + { + if (!feature.isMany()) + { + throw new UnsupportedOperationException("Single-valued features have no list elements"); } } @@ -529,9 +512,10 @@ public final class CDOStoreImpl implements CDOStore } CDOFeatureDelta delta = new CDOClearFeatureDeltaImpl(feature); - InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); - // TODO Handle containment remove!!! - revision.clear(feature); + getRevisionForWriting(cdoObject, delta); + // InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); + // // TODO Handle containment remove!!! + // revision.clear(feature); } } @@ -545,12 +529,14 @@ public final class CDOStoreImpl implements CDOStore TRACER.format("move({0}, {1}, {2}, {3})", cdoObject, feature, target, source); //$NON-NLS-1$ } - CDOFeatureDelta delta = new CDOMoveFeatureDeltaImpl(feature, target, source); + Object value = getListElement(cdoObject, feature, source); + CDOFeatureDelta delta = new CDOMoveFeatureDeltaImpl(feature, target, source, value); + InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); - Object result = revision.move(feature, target, source); + // value = revision.move(feature, target, source); - result = convertToEMF(eObject, revision, feature, target, result); - return result; + value = convertToEMF(eObject, revision, feature, target, value); + return value; } } @@ -644,11 +630,13 @@ public final class CDOStoreImpl implements CDOStore CDOID id = (CDOID)value; CDOList list = revision.getList(feature); CDORevisionPrefetchingPolicy policy = view.options().getRevisionPrefetchingPolicy(); - InternalCDORevisionManager revisionManager = view.getSession().getRevisionManager(); + + InternalCDOSession session = view.getSession(); + InternalCDORevisionManager revisionManager = session.getRevisionManager(); List<CDOID> listOfIDs = policy.loadAhead(revisionManager, view, eObject, feature, list, index, id); if (!listOfIDs.isEmpty()) { - int initialChunkSize = view.getSession().options().getCollectionLoadingPolicy().getInitialChunkSize(); + int initialChunkSize = session.options().getCollectionLoadingPolicy().getInitialChunkSize(); revisionManager.getRevisions(listOfIDs, view, initialChunkSize, CDORevision.DEPTH_NONE, true); } } @@ -718,19 +706,21 @@ public final class CDOStoreImpl implements CDOStore private static InternalCDORevision getRevisionForReading(InternalCDOObject cdoObject) { - CDOStateMachine.INSTANCE.read(cdoObject); - return getRevision(cdoObject); + return safe(CDOStateMachine2.INSTANCE.read(cdoObject)); } private static InternalCDORevision getRevisionForWriting(InternalCDOObject cdoObject, CDOFeatureDelta delta) { - CDOStateMachine.INSTANCE.write(cdoObject, delta); - return getRevision(cdoObject); + return safe(CDOStateMachine2.INSTANCE.write(cdoObject, delta)); } private static InternalCDORevision getRevision(InternalCDOObject cdoObject) { - InternalCDORevision revision = cdoObject.cdoRevision(); + return safe(cdoObject.cdoRevision()); + } + + private static InternalCDORevision safe(InternalCDORevision revision) + { if (revision == null) { throw new IllegalStateException("revision == null"); diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java index 7d0c16ad58..4a0916c31f 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java @@ -242,13 +242,13 @@ public class CDOViewImpl extends AbstractCDOView try { - CDOStateMachine.SWITCHING_TARGET.set(Boolean.TRUE); + CDOStateMachine2.SWITCHING_TARGET.set(Boolean.TRUE); doInvalidate(branchPoint.getBranch(), CDOBranchPoint.UNSPECIFIED_DATE, allChangedObjects, allDetachedObjects, oldRevisions, true); } finally { - CDOStateMachine.SWITCHING_TARGET.remove(); + CDOStateMachine2.SWITCHING_TARGET.remove(); } IListener[] listeners = getListeners(); @@ -504,7 +504,7 @@ public class CDOViewImpl extends AbstractCDOView InternalCDORevision revision = (InternalCDORevision)object.cdoRevision(); if (revision == null) { - revision = CDOStateMachine.INSTANCE.read((InternalCDOObject)object); + revision = CDOStateMachine2.INSTANCE.read((InternalCDOObject)object); } return revision; 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 index e806f97c9a..08e64b74a3 100644 --- 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 @@ -36,7 +36,7 @@ import org.eclipse.emf.cdo.view.CDOViewInvalidationEvent; import org.eclipse.emf.internal.cdo.bundle.OM; import org.eclipse.emf.internal.cdo.messages.Messages; import org.eclipse.emf.internal.cdo.object.CDOObjectMerger; -import org.eclipse.emf.internal.cdo.view.CDOStateMachine; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2; import org.eclipse.net4j.util.collection.Pair; import org.eclipse.net4j.util.event.IEvent; @@ -129,12 +129,12 @@ public abstract class AbstractObjectConflictResolver extends AbstractConflictRes @Deprecated public static void rollbackObject(CDOObject object) { - CDOStateMachine.INSTANCE.rollback((InternalCDOObject)object); + CDOStateMachine2.INSTANCE.rollback((InternalCDOObject)object); } public static void readObject(CDOObject object) { - CDOStateMachine.INSTANCE.read((InternalCDOObject)object); + CDOStateMachine2.INSTANCE.read((InternalCDOObject)object); } /** @@ -377,7 +377,7 @@ public abstract class AbstractObjectConflictResolver extends AbstractConflictRes for (CDOFeatureDelta remoteFeatureDelta : remoteDelta.getFeatureDeltas()) { // TODO Add public API for this: - ((InternalCDORevisionDelta)localDelta).addFeatureDelta(remoteFeatureDelta, null); + ((InternalCDORevisionDelta)localDelta).mergeFeatureDelta(remoteFeatureDelta, null); } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOMergingConflictResolver.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOMergingConflictResolver.java index debb6d3035..d7ff1efc0f 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOMergingConflictResolver.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOMergingConflictResolver.java @@ -105,7 +105,6 @@ public class CDOMergingConflictResolver extends AbstractChangeSetsConflictResolv InternalCDOTransaction transaction = (InternalCDOTransaction)getTransaction(); InternalCDOSavepoint savepoint = transaction.getLastSavepoint(); - Map<InternalCDOObject, InternalCDORevision> cleanRevisions = transaction.getCleanRevisions(); Map<CDOID, CDOObject> dirtyObjects = savepoint.getDirtyObjects(); // final ObjectsMapUpdater newObjectsUpdater = new ObjectsMapUpdater(savepoint.getNewObjects()); final ObjectsMapUpdater detachedObjectsUpdater = new ObjectsMapUpdater(savepoint.getDetachedObjects()); @@ -125,7 +124,7 @@ public class CDOMergingConflictResolver extends AbstractChangeSetsConflictResolv int newVersion = localRevision.getVersion() + 1; // Compute new local revision - InternalCDORevision cleanRevision = cleanRevisions.get(object); + InternalCDORevision cleanRevision = transaction.getCleanRevision(object); if (cleanRevision == null) { // In this case the object revision *is clean* @@ -159,7 +158,8 @@ public class CDOMergingConflictResolver extends AbstractChangeSetsConflictResolv localDeltas.put(id, newLocalDelta); object.cdoInternalSetState(CDOState.DIRTY); - cleanRevisions.put(object, newCleanRevision); + int xxx; + // cleanRevisions.put(object, newCleanRevision); dirtyObjects.put(id, object); newLocalDelta.accept(new CDOFeatureDeltaVisitorImpl() diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/DefaultCDOMerger.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/DefaultCDOMerger.java index 71298728de..03219df1bb 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/DefaultCDOMerger.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/DefaultCDOMerger.java @@ -548,7 +548,7 @@ public class DefaultCDOMerger implements CDOMerger CDOFeatureDelta featureDelta = changedInTarget(targetFeatureDelta); if (featureDelta != null) { - result.addFeatureDelta(featureDelta, null); + result.mergeFeatureDelta(featureDelta, null); } } else @@ -556,7 +556,7 @@ public class DefaultCDOMerger implements CDOMerger CDOFeatureDelta featureDelta = changedInSourceAndTarget(targetFeatureDelta, sourceFeatureDelta); if (featureDelta != null) { - result.addFeatureDelta(featureDelta, null); + result.mergeFeatureDelta(featureDelta, null); } else { @@ -583,8 +583,8 @@ public class DefaultCDOMerger implements CDOMerger } } - ((InternalCDORevisionDelta)conflict.getTargetDelta()).addFeatureDelta(targetFeatureDelta, null); - ((InternalCDORevisionDelta)conflict.getSourceDelta()).addFeatureDelta(sourceFeatureDelta, null); + ((InternalCDORevisionDelta)conflict.getTargetDelta()).mergeFeatureDelta(targetFeatureDelta, null); + ((InternalCDORevisionDelta)conflict.getSourceDelta()).mergeFeatureDelta(sourceFeatureDelta, null); } } } @@ -599,7 +599,7 @@ public class DefaultCDOMerger implements CDOMerger CDOFeatureDelta featureDelta = changedInSource(sourceFeatureDelta); if (featureDelta != null) { - result.addFeatureDelta(featureDelta, null); + result.mergeFeatureDelta(featureDelta, null); } } } @@ -781,7 +781,7 @@ public class DefaultCDOMerger implements CDOMerger for (int i = 0; i < originSize; i++) { - expandedDeltas.add(new CDORemoveFeatureDeltaImpl(feature, 0)); + expandedDeltas.add(new CDORemoveFeatureDeltaImpl(feature, 0, CDOFeatureDelta.UNKNOWN_VALUE)); } return expandedDeltas; diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/FSMUtil.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/FSMUtil.java index 3628e4a80b..4e875db3b1 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/FSMUtil.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/FSMUtil.java @@ -43,7 +43,7 @@ public final class FSMUtil public static boolean isTransient(CDOObject object) { CDOState state = object.cdoState(); - return state == CDOState.TRANSIENT || state == CDOState.PREPARED; + return state == CDOState.TRANSIENT; } public static boolean isInvalid(CDOObject object) diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOObject.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOObject.java index d025792d30..d6ef1b59e0 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOObject.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOObject.java @@ -42,9 +42,19 @@ public interface InternalCDOObject extends CDOObject, InternalEObject, InternalC public InternalCDORevision cdoRevision(); + /** + * Migrates the object values from the instance to the revision. + * <p> + * This object must be in state PREPARED, so that eStore() uses the instance and cdoStore() uses the revision. + */ public void cdoInternalPostAttach(); - public void cdoInternalPostDetach(boolean remote); + /** + * Migrates the object values from the revision to the instance. + * <p> + * This object must be in state TRANSIENT, so that eStore() uses the instance and cdoStore() uses the revision. + */ + public void cdoInternalPostDetach(boolean remote); // TODO Rename to preDetach public void cdoInternalPostInvalidate(); diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSavepoint.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSavepoint.java index 3e1469c605..91d6b3090d 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSavepoint.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOSavepoint.java @@ -10,14 +10,28 @@ */ package org.eclipse.emf.spi.cdo; +import org.eclipse.emf.cdo.CDOObject; import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIdentifiable; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; import org.eclipse.emf.cdo.transaction.CDOSavepoint; +import org.eclipse.emf.cdo.transaction.CDOTransaction; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine2; + +import java.util.Map; import java.util.Set; /** - * If the meaning of this type isn't clear, there really should be more of a description here... - * + * A {@link CDOSavepoint} has to capture enough data to support the following use cases: + * <ul> + * <li> <b>Detection</b> of undo operations (netted out deltas) in comparison to the transaction's baseline. + * <li> <b>Commit</b> of the entire {@link CDOTransaction}. + * <li> <b>Rollback</b> to the initial state of this savepoint. + * <li> <b>Support</b> of all other {@link CDOStateMachine2} transitions. + * </ul> + * * @author Eike Stepper * @since 3.0 * @noextend This interface is not intended to be extended by clients. @@ -33,8 +47,33 @@ public interface InternalCDOSavepoint extends CDOSavepoint, InternalCDOUserSavep public InternalCDOSavepoint getNextSavepoint(); + public ChangeInfo addChangeInfo(ChangeInfo changeInfo); + + public ChangeInfo removeChangeInfo(CDOObject object); + + public ChangeInfo removeChangeInfo(CDOID id); + + public ChangeInfo getChangeInfo(CDOID id); + + public ChangeInfo getDetachedInfo(CDOObject object); + + public Map<CDOID, ChangeInfo> getChangeInfos(); + + public Map<InternalCDOObject, ChangeInfo> getDetachedInfos(); + + /** + * @since 4.1 + */ + public boolean isNewObject(CDOID id); + + public boolean isDetachedObject(CDOID id); + public void clear(); + public boolean isInMemory(); + + public void setInMemory(boolean inMemory); + @Deprecated public Set<CDOID> getSharedDetachedObjects(); @@ -42,7 +81,58 @@ public interface InternalCDOSavepoint extends CDOSavepoint, InternalCDOUserSavep public void recalculateSharedDetachedObjects(); /** - * @since 4.1 + * Adds the given object to this savepoint and returns <code>true</code> if it was TRANSIENT, + * <code>false</code> otherwise (DETACHED). + * + * @deprecated As of 4.3 no longer supported. */ - public boolean isNewObject(CDOID id); + @Deprecated + public void attachObject(InternalCDOObject object); + + /** + * Removes the given object from this savepoint and returns <code>true</code> if it was NEW, + * <code>false</code> otherwise (CLEAN | DIRTY). + * + * @deprecated As of 4.3 no longer supported. + */ + @Deprecated + public void removeObject(InternalCDOObject object); + + /** + * @author Eike Stepper + */ + public interface ChangeInfo extends CDOIdentifiable + { + public ChangeType getType(); + + /** + * Returns the object or <code>null</code>. + */ + public InternalCDOObject getObject(); + + /** + * Returns the revision delta or <code>null</code>. + */ + public InternalCDORevisionDelta getRevisionDelta(); + + /** + * Returns the clean revision or <code>null</code>. The clean revision is used to identify undoing operations. + */ + public InternalCDORevision getCleanRevision(); + + /** + * Returns the base revision or <code>null</code>. The base revision is used to rollback to savepoints. + */ + public InternalCDORevision getBaseRevision(); + + public ChangeInfo setSavepoint(); + + /** + * @author Eike Stepper + */ + public enum ChangeType + { + NEW, DIRTY, CONFLICT, UNDONE, DETACHED + } + } } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOTransaction.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOTransaction.java index d8aceb5b95..5021434097 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOTransaction.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOTransaction.java @@ -11,6 +11,7 @@ */ package org.eclipse.emf.spi.cdo; +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.CDOChangeSetData; @@ -27,6 +28,7 @@ import org.eclipse.emf.cdo.transaction.CDOCommitContext; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.net4j.util.collection.Pair; +import org.eclipse.net4j.util.event.IListener; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.spi.cdo.CDOSessionProtocol.CommitTransactionResult; @@ -77,38 +79,37 @@ public interface InternalCDOTransaction extends CDOTransaction, InternalCDOUserT public void setTransactionStrategy(CDOTransactionStrategy transactionStrategy); /** - * @return never <code>null</code>; + * @return Never <code>null</code>; */ public CDOResourceFolder getOrCreateResourceFolder(List<String> names); - public void detachObject(InternalCDOObject object); + public void attachObject(InternalCDOObject object); - /** - * @deprecated {@link #createIDForNewObject(EObject)} is called since 4.1. - */ - @Deprecated - public CDOIDTemp getNextTemporaryID(); + public void detachObject(InternalCDOObject object); /** * @since 4.1 */ public CDOID createIDForNewObject(EObject object); + public void handleAttachingObject(CDOObject object); + + public void handleModifyingObject(CDOObject object, CDOFeatureDelta featureDelta); + + public void handleDetachingObject(CDOObject object); + /** * @since 4.0 */ - public void registerAttached(InternalCDOObject object, boolean isNew); + public void _registerAttached(InternalCDOObject object, boolean isNew); - public void registerDirty(InternalCDOObject object, CDOFeatureDelta featureDelta); + public void _registerDirty(InternalCDOObject object, CDOFeatureDelta featureDelta); - public void registerFeatureDelta(InternalCDOObject object, CDOFeatureDelta featureDelta); + public void _registerFeatureDelta(InternalCDOObject object, CDOFeatureDelta featureDelta); - public void registerRevisionDelta(CDORevisionDelta revisionDelta); + public void _registerRevisionDelta(CDORevisionDelta revisionDelta); - /** - * @since 4.2 - */ - public void setDirty(boolean dirty); + public IListener[] updateDirtyState(boolean undone); public void setConflict(InternalCDOObject object); @@ -117,30 +118,47 @@ public interface InternalCDOTransaction extends CDOTransaction, InternalCDOUserT * May be <code>null</code> if changeSetData does not result from a * {@link #merge(CDOBranchPoint, org.eclipse.emf.cdo.transaction.CDOMerger) merge} or if the merge was not in * a {@link CDOBranch#isLocal() local} branch. + * @since 4.1 + */ + public ApplyChangeSetResult applyChangeSet(CDOChangeSetData changeSetData, CDORevisionProvider ancestorProvider, + CDORevisionProvider targetProvider, CDOBranchPoint source, boolean keepVersions) + throws ChangeSetOutdatedException; + + /** * @since 4.0 - * @deprecated Use - * {@link #applyChangeSet(CDOChangeSetData, CDORevisionProvider, CDORevisionProvider, CDOBranchPoint, boolean)} + * @deprecated As of 4.3 use {@link #getCleanRevision(InternalCDOObject)}. */ @Deprecated - public Pair<CDOChangeSetData, Pair<Map<CDOID, CDOID>, List<CDOID>>> applyChangeSetData( - CDOChangeSetData changeSetData, CDORevisionProvider ancestorProvider, CDORevisionProvider targetProvider, - CDOBranchPoint source); + public Map<InternalCDOObject, InternalCDORevision> _getCleanRevisions(); + + public InternalCDORevision getCleanRevision(CDOObject object); + + /** + * @deprecated As of 4.1 use {@link #createIDForNewObject(EObject)}. + */ + @Deprecated + public CDOIDTemp getNextTemporaryID(); + + /** + * @since 4.2 + * @deprecated As of 4.3 use {@link #updateDirtyState(boolean)}. + */ + @Deprecated + public void setDirty(boolean dirty); /** * @param source * May be <code>null</code> if changeSetData does not result from a * {@link #merge(CDOBranchPoint, org.eclipse.emf.cdo.transaction.CDOMerger) merge} or if the merge was not in * a {@link CDOBranch#isLocal() local} branch. - * @since 4.1 - */ - public ApplyChangeSetResult applyChangeSet(CDOChangeSetData changeSetData, CDORevisionProvider ancestorProvider, - CDORevisionProvider targetProvider, CDOBranchPoint source, boolean keepVersions) - throws ChangeSetOutdatedException; - - /** * @since 4.0 + * @deprecated Use + * {@link #applyChangeSet(CDOChangeSetData, CDORevisionProvider, CDORevisionProvider, CDOBranchPoint, boolean)} */ - public Map<InternalCDOObject, InternalCDORevision> getCleanRevisions(); + @Deprecated + public Pair<CDOChangeSetData, Pair<Map<CDOID, CDOID>, List<CDOID>>> applyChangeSetData( + CDOChangeSetData changeSetData, CDORevisionProvider ancestorProvider, CDORevisionProvider targetProvider, + CDOBranchPoint source); /** * Provides a context for a commit operation. diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOView.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOView.java index a9b4e7259e..35e25f229c 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOView.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOView.java @@ -106,6 +106,8 @@ public interface InternalCDOView extends CDOView, CDOIDProvider, ILifecycle */ public void collectViewedRevisions(Map<CDOID, InternalCDORevision> revisions); + public void dispatchLoadNotification(InternalCDOObject object); + public void remapObject(CDOID oldID); /** |