Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 173879 Details for
Bug 319409
Provide "revert to the history revision" operation
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read
this important communication.
[patch]
patch v1
patch_revert_3_0_1_private_api.txt (text/plain), 81.62 KB, created by
Egidijus Vaisnora
on 2010-07-09 12:09:07 EDT
(
hide
)
Description:
patch v1
Filename:
MIME Type:
Creator:
Egidijus Vaisnora
Created:
2010-07-09 12:09:07 EDT
Size:
81.62 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.emf.cdo >Index: src/org/eclipse/emf/internal/cdo/CDOStateMachine.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStateMachine.java,v >retrieving revision 1.152 >diff -u -r1.152 CDOStateMachine.java >--- src/org/eclipse/emf/internal/cdo/CDOStateMachine.java 3 Jun 2010 08:35:20 -0000 1.152 >+++ src/org/eclipse/emf/internal/cdo/CDOStateMachine.java 9 Jul 2010 15:24:50 -0000 >@@ -11,16 +11,21 @@ > */ > package org.eclipse.emf.internal.cdo; > >+import org.eclipse.emf.cdo.CDOObject; > import org.eclipse.emf.cdo.CDOState; > import org.eclipse.emf.cdo.common.id.CDOID; > import org.eclipse.emf.cdo.common.id.CDOIDTemp; >+import org.eclipse.emf.cdo.common.model.CDOModelUtil; > import org.eclipse.emf.cdo.common.model.EMFUtil; > 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.CDORevisionManager; > import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta; > import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; > import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDeltaUtil; >+import org.eclipse.emf.cdo.eresource.CDOResource; >+import org.eclipse.emf.cdo.internal.common.revision.CDORevisionImpl; > import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; > import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager; > import org.eclipse.emf.cdo.transaction.CDOTransaction; >@@ -35,21 +40,27 @@ > import org.eclipse.net4j.util.fsm.ITransition; > import org.eclipse.net4j.util.om.trace.ContextTracer; > >+import org.eclipse.emf.common.util.EList; > import org.eclipse.emf.ecore.EClass; > import org.eclipse.emf.ecore.EObject; >+import org.eclipse.emf.ecore.EReference; > import org.eclipse.emf.ecore.EStructuralFeature; > import org.eclipse.emf.ecore.InternalEObject; >+import org.eclipse.emf.ecore.InternalEObject.EStore; > import org.eclipse.emf.ecore.impl.EStoreEObjectImpl; > import org.eclipse.emf.ecore.resource.Resource; >+import org.eclipse.emf.ecore.util.EcoreUtil; > import org.eclipse.emf.spi.cdo.CDOSessionProtocol.CommitTransactionResult; > import org.eclipse.emf.spi.cdo.InternalCDOObject; > import org.eclipse.emf.spi.cdo.InternalCDOTransaction; > import org.eclipse.emf.spi.cdo.InternalCDOView; > > import java.util.ArrayList; >+import java.util.HashSet; > import java.util.Iterator; > import java.util.List; > import java.util.Map; >+import java.util.Set; > import java.util.concurrent.locks.ReentrantLock; > > /** >@@ -83,6 +94,7 @@ > init(CDOState.TRANSIENT, CDOEvent.DETACH_REMOTE, FAIL); > init(CDOState.TRANSIENT, CDOEvent.COMMIT, FAIL); > init(CDOState.TRANSIENT, CDOEvent.ROLLBACK, FAIL); >+ init(CDOState.TRANSIENT, CDOEvent.REVERT, FAIL); // For future TRANSIENT could be involved into revert > > init(CDOState.PREPARED, CDOEvent.PREPARE, FAIL); > init(CDOState.PREPARED, CDOEvent.ATTACH, new AttachTransition()); >@@ -94,6 +106,7 @@ > init(CDOState.PREPARED, CDOEvent.DETACH_REMOTE, FAIL); > init(CDOState.PREPARED, CDOEvent.COMMIT, FAIL); > init(CDOState.PREPARED, CDOEvent.ROLLBACK, FAIL); >+ init(CDOState.PREPARED, CDOEvent.REVERT, FAIL); > > init(CDOState.NEW, CDOEvent.PREPARE, FAIL); > init(CDOState.NEW, CDOEvent.ATTACH, FAIL); >@@ -105,6 +118,7 @@ > init(CDOState.NEW, CDOEvent.DETACH_REMOTE, FAIL); > init(CDOState.NEW, CDOEvent.COMMIT, new CommitTransition(false)); > init(CDOState.NEW, CDOEvent.ROLLBACK, FAIL); >+ init(CDOState.NEW, CDOEvent.REVERT, new RevertTransition()); // resurrected objects has state NEW > > init(CDOState.CLEAN, CDOEvent.PREPARE, FAIL); > init(CDOState.CLEAN, CDOEvent.ATTACH, FAIL); >@@ -116,6 +130,7 @@ > init(CDOState.CLEAN, CDOEvent.DETACH_REMOTE, DetachRemoteTransition.INSTANCE); > init(CDOState.CLEAN, CDOEvent.COMMIT, FAIL); > init(CDOState.CLEAN, CDOEvent.ROLLBACK, FAIL); >+ init(CDOState.CLEAN, CDOEvent.REVERT, new RevertTransition()); > > init(CDOState.DIRTY, CDOEvent.PREPARE, FAIL); > init(CDOState.DIRTY, CDOEvent.ATTACH, FAIL); >@@ -127,6 +142,7 @@ > init(CDOState.DIRTY, CDOEvent.DETACH_REMOTE, new InvalidConflictTransition()); > init(CDOState.DIRTY, CDOEvent.COMMIT, new CommitTransition(true)); > init(CDOState.DIRTY, CDOEvent.ROLLBACK, new RollbackTransition()); >+ init(CDOState.DIRTY, CDOEvent.REVERT, FAIL); // for future DIRTY could be involved into revert > > init(CDOState.PROXY, CDOEvent.PREPARE, FAIL); > init(CDOState.PROXY, CDOEvent.ATTACH, FAIL); >@@ -138,6 +154,7 @@ > init(CDOState.PROXY, CDOEvent.DETACH_REMOTE, DetachRemoteTransition.INSTANCE); > init(CDOState.PROXY, CDOEvent.COMMIT, FAIL); > init(CDOState.PROXY, CDOEvent.ROLLBACK, FAIL); >+ init(CDOState.PROXY, CDOEvent.REVERT, FAIL); > > init(CDOState.CONFLICT, CDOEvent.PREPARE, FAIL); > init(CDOState.CONFLICT, CDOEvent.ATTACH, IGNORE); >@@ -149,6 +166,7 @@ > init(CDOState.CONFLICT, CDOEvent.DETACH_REMOTE, IGNORE); > init(CDOState.CONFLICT, CDOEvent.COMMIT, IGNORE); > init(CDOState.CONFLICT, CDOEvent.ROLLBACK, new RollbackTransition()); >+ init(CDOState.CONFLICT, CDOEvent.REVERT, FAIL); > > init(CDOState.INVALID, CDOEvent.PREPARE, InvalidTransition.INSTANCE); > init(CDOState.INVALID, CDOEvent.ATTACH, InvalidTransition.INSTANCE); >@@ -160,6 +178,7 @@ > init(CDOState.INVALID, CDOEvent.DETACH_REMOTE, IGNORE); > init(CDOState.INVALID, CDOEvent.COMMIT, InvalidTransition.INSTANCE); > init(CDOState.INVALID, CDOEvent.ROLLBACK, InvalidTransition.INSTANCE); >+ init(CDOState.INVALID, CDOEvent.REVERT, FAIL); > > init(CDOState.INVALID_CONFLICT, CDOEvent.PREPARE, InvalidTransition.INSTANCE); > init(CDOState.INVALID_CONFLICT, CDOEvent.ATTACH, InvalidTransition.INSTANCE); >@@ -171,6 +190,7 @@ > init(CDOState.INVALID_CONFLICT, CDOEvent.DETACH_REMOTE, IGNORE); > init(CDOState.INVALID_CONFLICT, CDOEvent.COMMIT, InvalidTransition.INSTANCE); > init(CDOState.INVALID_CONFLICT, CDOEvent.ROLLBACK, DetachRemoteTransition.INSTANCE); >+ init(CDOState.INVALID_CONFLICT, CDOEvent.REVERT, FAIL); > } > > /** >@@ -221,7 +241,7 @@ > { > if (TRACER.isEnabled()) > { >- TRACER.format("PREPARE: {0} --> {1}", object, transactionAndContents.getElement1()); //$NON-NLS-1$ >+ TRACER.format("PREPARE: {0} --> {1}", object, transactionAndContents.getElement1()); > } > > process(object, CDOEvent.PREPARE, transactionAndContents); >@@ -400,6 +420,286 @@ > } > } > } >+ >+ /** >+ * Revert given historical data >+ * >+ * @since 3.0 >+ */ >+ public void revert(CDOTransaction activeTransaction, CDOObject... historicalObjects) >+ { >+ // Objects eligible for revert, don't contains unmodified and resurrected >+ Set<CDOObject> modifiedObjects = new HashSet<CDOObject>(); >+ >+ Set<CDOObject> resurrectedObjects = new HashSet<CDOObject>(); >+ >+ // IDs of all data passed to revert >+ Set<CDOID> revertedIDs = new HashSet<CDOID>(); >+ >+ ReentrantLock lock = lockView((InternalCDOView)activeTransaction); >+ >+ try >+ { >+ // PHASE 1 - sorting objects and resurrecting deleted objects. Resurrection is required to be passed first >+ for (int i = 0; i < historicalObjects.length; i++) >+ { >+ InternalCDORevision historicalRevision = (InternalCDORevision)historicalObjects[i].cdoRevision(); >+ CDOID id = historicalRevision.getID(); >+ revertedIDs.add(id); >+ >+ // Detect objects which do not need to be reverted. >+ // Assume that object has no reason to be reverted, if object is not revised and object is not registered to >+ // active transaction (it could be currently DIRTY or TRANSIENT, but not committed yet) >+ if (historicalRevision.getRevised() == 0 && !activeTransaction.isObjectRegistered(id)) >+ { >+ continue; >+ } >+ >+ InternalCDORevision revision = ((InternalCDOTransaction)activeTransaction).getRevision( >+ historicalRevision.getID(), true); >+ InternalCDOObject object = null; >+ >+ // if revision doesn't exist in current transaction or it is revised, we need to resurrect it >+ if (revision == null) >+ { >+ object = resurrect(historicalRevision, (InternalCDOTransaction)activeTransaction); >+ resurrectedObjects.add(object); >+ } >+ >+ modifiedObjects.add(historicalObjects[i]); >+ } >+ >+ // PHASE 2 - revert process >+ Set<CDOID> detach = new HashSet<CDOID>(); >+ Set<CDOID> temporalSet = new HashSet<CDOID>(); >+ for (Iterator<CDOObject> it = modifiedObjects.iterator(); it.hasNext();) >+ { >+ CDOObject historicalObject = it.next(); >+ InternalCDORevision historicalRevision = (InternalCDORevision)historicalObject.cdoRevision(); >+ InternalCDOObject object = (InternalCDOObject)activeTransaction.getObject(historicalRevision.getID(), true); >+ >+ // Collect all contained object IDs at current revision and mark them for detaching >+ collectContainedIDs(object, detach, true); >+ >+ // Revert process >+ process(object, CDOEvent.REVERT, historicalRevision); >+ >+ // Need to check, which objects was left after revert not contained by parent. >+ // If such object is found - it must be detached >+ temporalSet.clear(); >+ >+ // cannot collect recursive, because not all containment tree is reverted >+ collectContainedIDs(object, temporalSet, false); >+ detach.removeAll(temporalSet); >+ >+ if (resurrectedObjects.contains(object)) >+ { >+ // Entering only if object is resurrected during revert. >+ // If object's holder is not reverting, hence resurrected object must be manually attached to container. >+ // Drawback is that container order could be lost comparing to historical >+ CDOID containerID = (CDOID)object.cdoRevision().getContainerID(); >+ >+ // Restoring container >+ if (containerID != null && !containerID.isNull()) >+ { >+ if (!revertedIDs.contains(containerID)) >+ { >+ // Object container is not reverted. Hence we need to attach resurrected data manually. >+ // Tricky thing is to calculate correct index in container, where resurrected object must be attached >+ CDOObject container = activeTransaction.getObject(containerID); >+ EStructuralFeature feature = ((InternalCDOObject)container).cdoInternalDynamicFeature(object >+ .cdoRevision().getContainingFeatureID()); >+ >+ if (feature.isMany()) >+ { >+ // Obtaining old index of object which is before restoring object >+ EList<?> historicalList = (EList<?>)historicalObject.eContainer().eGet(feature); >+ EList<?> currentList = (EList<?>)container.eGet(feature); >+ >+ int indexToInsert = findInListIndex(historicalObject, historicalList, currentList); >+ object.eStore().add((InternalEObject)container, feature, indexToInsert, object); >+ } >+ else >+ { >+ Object currentObject = container.eGet(feature); >+ object.eStore().add((InternalEObject)container, feature, EStore.NO_INDEX, object); >+ if (currentObject instanceof InternalCDOObject) >+ { >+ // We have unset currentObject from parent. Arrange it for detaching >+ collectContainedIDs(((InternalCDOObject)currentObject), detach, true); >+ } >+ } >+ } >+ } >+ >+ CDOID resourceID = object.cdoRevision().getResourceID(); >+ if (resourceID != null && !resourceID.isNull()) >+ { >+ if (!revertedIDs.contains(resourceID)) >+ { >+ // resource is not reverted. Hence we need to attach resurrected data >+ CDOResource resource = (CDOResource)activeTransaction.getObject(resourceID); >+ object.cdoRevision().setResourceID(CDOID.NULL); >+ int indexToInsert = findInListIndex(historicalObject, historicalObject.cdoResource().getContents(), >+ resource.getContents()); >+ resource.getContents().add(indexToInsert, object); >+ } >+ } >+ } >+ } >+ >+ // PHASE 3 collect object which are not contained into resource or container - they must be detached >+ // target for detaching are objects, which was removed from container but still points to it >+ for (Iterator<CDOID> iterator = detach.iterator(); iterator.hasNext();) >+ { >+ CDOID cdoid = iterator.next(); >+ InternalCDOObject object = (InternalCDOObject)activeTransaction.getObject(cdoid, true); >+ deleteDeatachedObject(object, revertedIDs); >+ } >+ } >+ finally >+ { >+ lock.unlock(); >+ } >+ } >+ >+ /** >+ * Analyze objects recursively and delete it if it is eligible for detaching. If id is from the reverted ID's - it is >+ * not eligible for removing. If detaching object is not found in the container to which it points - it is eligible >+ * for detaching >+ */ >+ private void deleteDeatachedObject(CDOObject object, Set<CDOID> revertedIds) >+ { >+ >+ if (!revertedIds.contains(object.cdoID())) >+ { >+ // Containing children must be removed silently, because they can be already attached to new parent >+ if (object instanceof InternalCDOObject) >+ { >+ for (EReference containmentReference : object.eClass().getEAllContainments()) >+ { >+ if (EMFUtil.isPersistent(containmentReference)) >+ { >+ ((InternalCDOObject)object).cdoRevision().clear(containmentReference); >+ } >+ } >+ >+ // Object is removed >+ EcoreUtil.remove(object); >+ detach((InternalCDOObject)object); >+ } >+ } >+ } >+ >+ private int findInListIndex(CDOObject historicalObject, EList<?> historicalList, EList<?> currentList) >+ { >+ int oldIndex = historicalList.indexOf(historicalObject); >+ int indexToInsert = -1; >+ for (int i = oldIndex - 1; i >= 0 && indexToInsert == -1; i--) >+ { >+ CDOObject cdoObject = (CDOObject)historicalList.get(i); >+ for (int j = currentList.size(); j <= 0; j--) >+ { >+ if (((CDOObject)currentList.get(j)).cdoID().equals(cdoObject)) >+ { >+ indexToInsert = j; >+ break; >+ } >+ } >+ } >+ >+ if (indexToInsert == -1) >+ { >+ // Inserting at the beginning >+ indexToInsert = 0; >+ } >+ else if (indexToInsert > currentList.size()) >+ { >+ indexToInsert = currentList.size(); >+ } >+ >+ return indexToInsert; >+ } >+ >+ private void collectContainedIDs(InternalCDOObject object, Set<CDOID> containedIDs, boolean recursive) >+ { >+ for (EReference containmentReference : object.eClass().getEAllContainments()) >+ { >+ if (containmentReference.isMany()) >+ { >+ int size = object.eStore().size(object, containmentReference); >+ for (int k = 0; k < size; k++) >+ { >+ Object object2 = object.eStore().get(object, containmentReference, k); >+ if (object2 instanceof InternalCDOObject) >+ { >+ InternalCDOObject internalObject = (InternalCDOObject)object2; >+ if (recursive && !containedIDs.contains(internalObject.cdoID())) >+ { >+ collectContainedIDs(internalObject, containedIDs, recursive); >+ } >+ containedIDs.add(internalObject.cdoID()); >+ } >+ } >+ } >+ else >+ { >+ Object object2 = object.eStore().get(object, containmentReference, EStore.NO_INDEX); >+ if (object2 instanceof InternalCDOObject) >+ { >+ InternalCDOObject internalObject = (InternalCDOObject)object2; >+ if (recursive && !containedIDs.contains(internalObject.cdoID())) >+ { >+ collectContainedIDs(internalObject, containedIDs, recursive); >+ } >+ containedIDs.add(internalObject.cdoID()); >+ } >+ } >+ >+ } >+ } >+ >+ private InternalCDOObject resurrect(InternalCDORevision historicalRevision, InternalCDOTransaction transaction) >+ { >+ // need to find latest version >+ CDORevisionManager revisionManager = transaction.getSession().getRevisionManager(); >+ CDOID id = historicalRevision.getID(); >+ InternalCDORevision latestRevision = historicalRevision; >+ >+ // searching latest revision to obtain version >+ for (int i = historicalRevision.getVersion() + 1; true; i++) >+ { >+ revisionManager.getRevision(id, transaction, 0, 0, true); >+ InternalCDORevision revisionByVersion = (InternalCDORevision)revisionManager.getRevisionByVersion(id, transaction >+ .getBranch().getVersion(i), CDORevision.DEPTH_NONE, true); >+ if (revisionByVersion != null) >+ { >+ latestRevision = revisionByVersion; >+ } >+ else >+ { >+ break; >+ } >+ } >+ >+ EClass eClass = historicalRevision.getEClass(); >+ >+ InternalCDOObject object = (InternalCDOObject)EcoreUtil.create(eClass); >+ >+ InternalCDORevision createRevision = (InternalCDORevision)CDORevisionFactory.DEFAULT.createRevision(eClass); >+ createRevision.setID(id); >+ createRevision.setVersion(latestRevision.getVersion()); >+ createRevision.setBranchPoint(transaction); >+ object.cdoInternalSetRevision(createRevision); >+ object.cdoInternalSetView(transaction); >+ object.cdoInternalSetID(createRevision.getID()); >+ object.cdoInternalSetState(CDOState.NEW); >+ >+ transaction.registerObject(object); >+ transaction.registerNew(object); >+ >+ return object; >+ } > > /** > * @since 3.0 >@@ -701,7 +1001,7 @@ > // CDORevision originalRevision = revisionManager.getRevisionByVersion(id, branchVersion, -1, true); > CDORevisionDelta revisionDelta = CDORevisionDeltaUtil.create(formerRevision, revision); > transaction.registerRevisionDelta(revisionDelta); >- transaction.registerDirty(object, null); >+ transaction.registerDirty(object, (CDOFeatureDelta)null); > changeState(object, CDOState.DIRTY); > > // Add the object to the set of reattached objects >@@ -710,6 +1010,45 @@ > } > > /** >+ * @author Egidijus Vaisnora >+ */ >+ private final class RevertTransition implements >+ ITransition<CDOState, CDOEvent, InternalCDOObject, InternalCDORevision> >+ { >+ >+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event, InternalCDORevision historicalRevision) >+ { >+ >+ InternalCDORevision originalRevision = object.cdoRevision(); >+ InternalCDORevision originalRevisionModify = originalRevision.copy(); >+ >+ EStructuralFeature[] allPersistentFeatures = CDOModelUtil >+ .getAllPersistentFeatures(historicalRevision.getEClass()); >+ for (int j = 0; j < allPersistentFeatures.length; j++) >+ { >+ >+ ((CDORevisionImpl)originalRevisionModify).setValue(allPersistentFeatures[j], >+ historicalRevision.getValue(allPersistentFeatures[j])); >+ } >+ originalRevisionModify.setContainerID(historicalRevision.getContainerID()); >+ originalRevisionModify.setContainingFeatureID(historicalRevision.getContainingFeatureID()); >+ originalRevisionModify.setResourceID(historicalRevision.getResourceID()); >+ >+ object.cdoInternalSetRevision(originalRevisionModify); >+ >+ // NEW objects are resurrected objects or really new >+ if (object.cdoState() != CDOState.NEW) >+ { >+ CDORevisionDelta delta = CDORevisionDeltaUtil.create(originalRevision, originalRevisionModify); >+ InternalCDOTransaction transaction = object.cdoView().toTransaction(); >+ transaction.registerDirty(object, delta); >+ changeState(object, CDOState.DIRTY); >+ } >+ } >+ >+ } >+ >+ /** > * @author Eike Stepper > */ > private static final class DetachTransition implements >@@ -978,5 +1317,10 @@ > */ > enum CDOEvent > { >- PREPARE, ATTACH, DETACH, REATTACH, READ, WRITE, INVALIDATE, DETACH_REMOTE, COMMIT, ROLLBACK >+ PREPARE, ATTACH, DETACH, REATTACH, READ, WRITE, INVALIDATE, DETACH_REMOTE, COMMIT, ROLLBACK, >+ >+ /** >+ * Event for reverting object to historical state >+ */ >+ REVERT > } >Index: src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java,v >retrieving revision 1.91 >diff -u -r1.91 CDOTransactionImpl.java >--- src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java 13 Jun 2010 07:01:00 -0000 1.91 >+++ src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java 9 Jul 2010 15:24:50 -0000 >@@ -263,6 +263,22 @@ > return conflict != 0; > } > >+ /** >+ * Historical cdo objects, taken from audit view. These objects will be used to restore CDOObjects in current >+ * transaction. If CDOObject doesn't exist for given historical CDOID, it will initiate new CDO object creation with >+ * old (historical) CDOID - object will be resurrected. Object, attached in current CDOObject but not found in >+ * historical CDOObject, will be detached. >+ * <p> >+ * <strong>Note:</strong> Doesn't support revert for CDOObjects, which in current transaction have state >+ * {@link CDOState#DIRTY DIRTY} and {@link CDOState#TRANSIENT TRANSIENT} >+ * >+ * @since 3.0 >+ */ >+ public void revert(CDOObject... historicalObjects) >+ { >+ CDOStateMachine.INSTANCE.revert(this, historicalObjects); >+ } >+ > public void setConflict(InternalCDOObject object) > { > ConflictEvent event = new ConflictEvent(object, conflict == 0); >@@ -1401,6 +1417,36 @@ > lastSavepoint.getRevisionDeltas().putIfAbsent(revisionDelta.getID(), revisionDelta); > } > >+ public void registerDirty(InternalCDOObject object, CDORevisionDelta revisionDelta) >+ { >+ if (TRACER.isEnabled()) >+ { >+ TRACER.format("Registering dirty object {0}", object); >+ } >+ >+ // rewriting old revision delta >+ ConcurrentMap<CDOID, CDORevisionDelta> revisionDeltas = lastSavepoint.getRevisionDeltas(); >+ if (revisionDeltas.containsKey(object.cdoID())) >+ { >+ // recursively add feature deltas >+ if (revisionDelta != null) >+ { >+ List<CDOFeatureDelta> featureDeltas = revisionDelta.getFeatureDeltas(); >+ for (int i = 0; i < featureDeltas.size(); i++) >+ { >+ registerFeatureDelta(object, featureDeltas.get(i)); >+ } >+ } >+ } >+ else >+ { >+ revisionDeltas.put(object.cdoID(), revisionDelta); >+ >+ registerNew(lastSavepoint.getDirtyObjects(), object); >+ } >+ >+ } >+ > public void registerDirty(InternalCDOObject object, CDOFeatureDelta featureDelta) > { > if (TRACER.isEnabled()) >@@ -1654,7 +1700,7 @@ > CDORevision revision = object.cdoRevision().copy(); > merger.merge(object, delta); > registerRevisionDelta(delta); >- registerDirty(object, null); >+ registerDirty(object, (CDOFeatureDelta)null); > > if (delta.getVersion() < revision.getVersion()) > { >Index: src/org/eclipse/emf/spi/cdo/InternalCDOTransaction.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOTransaction.java,v >retrieving revision 1.13.4.1 >diff -u -r1.13.4.1 InternalCDOTransaction.java >--- src/org/eclipse/emf/spi/cdo/InternalCDOTransaction.java 6 Jul 2010 09:31:14 -0000 1.13.4.1 >+++ src/org/eclipse/emf/spi/cdo/InternalCDOTransaction.java 9 Jul 2010 15:24:50 -0000 >@@ -75,6 +75,14 @@ > > public void registerNew(InternalCDOObject object); > >+ /** >+ * Registers object as dirty with given <code>revisionDelta</code>. If changes are registered, merges registered >+ * changes with a new given revision delta >+ * >+ * @since 3.0 >+ */ >+ public void registerDirty(InternalCDOObject object, CDORevisionDelta revisionDelta); >+ > public void registerDirty(InternalCDOObject object, CDOFeatureDelta featureDelta); > > public void registerFeatureDelta(InternalCDOObject object, CDOFeatureDelta featureDelta); >@@ -88,8 +96,8 @@ > /** > * @since 3.0 > */ >- public CDOChangeSetData applyChangeSetData(CDOChangeSetData changeSetData, >- CDORevisionAvailabilityInfo ancestorInfo, CDORevisionAvailabilityInfo targetInfo, CDORevisionAvailabilityInfo sourceInfo); >+ public CDOChangeSetData applyChangeSetData(CDOChangeSetData changeSetData, CDORevisionAvailabilityInfo ancestorInfo, >+ CDORevisionAvailabilityInfo targetInfo, CDORevisionAvailabilityInfo sourceInfo); > > /** > * @since 3.0 >#P org.eclipse.emf.cdo.common >Index: src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionManagerImpl.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionManagerImpl.java,v >retrieving revision 1.19 >diff -u -r1.19 CDORevisionManagerImpl.java >--- src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionManagerImpl.java 15 Mar 2010 08:26:17 -0000 1.19 >+++ src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionManagerImpl.java 9 Jul 2010 15:24:52 -0000 >@@ -208,8 +208,8 @@ > public InternalCDORevision getRevisionByVersion(CDOID id, CDOBranchVersion branchVersion, int referenceChunk, > boolean loadOnDemand) > { >- checkArg(branchVersion.getVersion() >= CDOBranchVersion.FIRST_VERSION, "Invalid version: " >- + branchVersion.getVersion()); >+ checkArg(branchVersion.getVersion() >= CDOBranchVersion.FIRST_VERSION, >+ "Invalid version: " + branchVersion.getVersion()); > acquireAtomicRequestLock(loadAndAddLock); > > try >@@ -400,8 +400,8 @@ > CDOBranchVersion target = pointer.getTarget(); > if (target instanceof InternalCDORevision) > { >- revision = new PointerCDORevision(pointer.getEClass(), pointer.getID(), pointer.getBranch(), pointer >- .getRevised(), CDOBranchUtil.copyBranchVersion(target)); >+ revision = new PointerCDORevision(pointer.getEClass(), pointer.getID(), pointer.getBranch(), >+ pointer.getRevised(), CDOBranchUtil.copyBranchVersion(target)); > } > } > >Index: src/org/eclipse/emf/cdo/spi/common/revision/DetachedCDORevision.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/DetachedCDORevision.java,v >retrieving revision 1.4 >diff -u -r1.4 DetachedCDORevision.java >--- src/org/eclipse/emf/cdo/spi/common/revision/DetachedCDORevision.java 9 Mar 2010 07:40:16 -0000 1.4 >+++ src/org/eclipse/emf/cdo/spi/common/revision/DetachedCDORevision.java 9 Jul 2010 15:24:52 -0000 >@@ -27,11 +27,22 @@ > > private long timeStamp; > >+ private long revised; >+ > public DetachedCDORevision(EClass eClass, CDOID id, CDOBranch branch, int version, long timeStamp) > { >+ this(eClass, id, branch, version, timeStamp, UNSPECIFIED_DATE); >+ } >+ >+ /** >+ * @since 3.0.1 >+ */ >+ public DetachedCDORevision(EClass eClass, CDOID id, CDOBranch branch, int version, long timeStamp, long revised) >+ { > super(eClass, id, branch); > this.version = version; > this.timeStamp = timeStamp; >+ this.revised = revised; > } > > @Override >@@ -49,7 +60,7 @@ > @Override > public long getRevised() > { >- return UNSPECIFIED_DATE; >+ return revised; > } > > @Override >@@ -57,4 +68,10 @@ > { > return MessageFormat.format("DetachedCDORevision[{0}:{1}v{2}]", getID(), getBranch().getID(), version); > } >+ >+ @Override >+ public void setRevised(long revised) >+ { >+ this.revised = revised; >+ } > } >Index: src/org/eclipse/emf/cdo/spi/common/revision/RevisionInfo.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/RevisionInfo.java,v >retrieving revision 1.9 >diff -u -r1.9 RevisionInfo.java >--- src/org/eclipse/emf/cdo/spi/common/revision/RevisionInfo.java 9 Mar 2010 07:40:17 -0000 1.9 >+++ src/org/eclipse/emf/cdo/spi/common/revision/RevisionInfo.java 9 Jul 2010 15:24:52 -0000 >@@ -10,6 +10,7 @@ > */ > package org.eclipse.emf.cdo.spi.common.revision; > >+import org.eclipse.emf.cdo.common.branch.CDOBranch; > import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; > import org.eclipse.emf.cdo.common.branch.CDOBranchVersion; > import org.eclipse.emf.cdo.common.id.CDOID; >@@ -192,7 +193,16 @@ > result = (InternalCDORevision)in.readCDORevision(); > } > >- protected void doWriteResult(CDODataOutput out, InternalCDORevision revision, int referenceChunk) throws IOException >+ protected InternalCDORevision doReadResult(CDODataInput in) throws IOException >+ { >+ return doReadResult(in, getID(), requestedBranchPoint.getBranch()); >+ } >+ >+ /** >+ * @since 3.0.1 >+ */ >+ public static void doWriteResult(CDODataOutput out, InternalCDORevision revision, int referenceChunk) >+ throws IOException > { > if (revision == null) > { >@@ -221,6 +231,7 @@ > out.writeByte(DETACHED_RESULT); > out.writeCDOClassifierRef(detached.getEClass()); > out.writeLong(detached.getTimeStamp()); >+ out.writeLong(detached.getRevised()); > out.writeInt(detached.getVersion()); > } > else >@@ -230,7 +241,7 @@ > } > } > >- protected InternalCDORevision doReadResult(CDODataInput in) throws IOException >+ public static InternalCDORevision doReadResult(CDODataInput in, CDOID id, CDOBranch branch) throws IOException > { > byte type = in.readByte(); > switch (type) >@@ -242,16 +253,17 @@ > { > EClassifier classifier = in.readCDOClassifierRefAndResolve(); > long revised = in.readLong(); >- InternalCDORevision target = doReadResult(in); >- return new PointerCDORevision((EClass)classifier, id, requestedBranchPoint.getBranch(), revised, target); >+ InternalCDORevision target = doReadResult(in, id, branch); >+ return new PointerCDORevision((EClass)classifier, id, branch, revised, target); > } > > case DETACHED_RESULT: > { > EClassifier classifier = in.readCDOClassifierRefAndResolve(); > long timeStamp = in.readLong(); >+ long revised = in.readLong(); > int version = in.readInt(); >- return new DetachedCDORevision((EClass)classifier, id, requestedBranchPoint.getBranch(), version, timeStamp); >+ return new DetachedCDORevision((EClass)classifier, id, branch, version, timeStamp, revised); > } > > case NORMAL_RESULT: >#P org.eclipse.emf.cdo.net4j >Index: src/org/eclipse/emf/cdo/internal/net4j/protocol/LoadRevisionByVersionRequest.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LoadRevisionByVersionRequest.java,v >retrieving revision 1.6 >diff -u -r1.6 LoadRevisionByVersionRequest.java >--- src/org/eclipse/emf/cdo/internal/net4j/protocol/LoadRevisionByVersionRequest.java 4 Mar 2010 06:36:00 -0000 1.6 >+++ src/org/eclipse/emf/cdo/internal/net4j/protocol/LoadRevisionByVersionRequest.java 9 Jul 2010 15:24:53 -0000 >@@ -17,6 +17,7 @@ > import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; > import org.eclipse.emf.cdo.internal.net4j.bundle.OM; > import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; >+import org.eclipse.emf.cdo.spi.common.revision.RevisionInfo; > > import org.eclipse.net4j.util.om.trace.ContextTracer; > >@@ -71,7 +72,7 @@ > @Override > protected InternalCDORevision confirming(CDODataInput in) throws IOException > { >- return (InternalCDORevision)in.readCDORevision(); >+ return RevisionInfo.doReadResult(in, id, branchVersion.getBranch()); > } > > @Override >#P org.eclipse.emf.cdo.server.db >Index: src/org/eclipse/emf/cdo/server/internal/db/DBRevisionHandler.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBRevisionHandler.java,v >retrieving revision 1.3 >diff -u -r1.3 DBRevisionHandler.java >--- src/org/eclipse/emf/cdo/server/internal/db/DBRevisionHandler.java 17 Mar 2010 15:06:09 -0000 1.3 >+++ src/org/eclipse/emf/cdo/server/internal/db/DBRevisionHandler.java 9 Jul 2010 15:24:54 -0000 >@@ -21,8 +21,8 @@ > { > if (revision.getVersion() < CDOBranchVersion.FIRST_VERSION - 1) > { >- revision = new DetachedCDORevision(revision.getEClass(), revision.getID(), revision.getBranch(), -revision >- .getVersion(), revision.getTimeStamp()); >+ revision = new DetachedCDORevision(revision.getEClass(), revision.getID(), revision.getBranch(), >+ -revision.getVersion(), revision.getTimeStamp(), revision.getRevised()); > } > > delegate.handleRevision(revision); >Index: src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java,v >retrieving revision 1.126 >diff -u -r1.126 DBStoreAccessor.java >--- src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java 14 Jun 2010 07:29:57 -0000 1.126 >+++ src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java 9 Jul 2010 15:24:54 -0000 >@@ -206,7 +206,8 @@ > int version = revision.getVersion(); > if (version < CDOBranchVersion.FIRST_VERSION - 1) > { >- return new DetachedCDORevision(eClass, id, revision.getBranch(), -version, revision.getTimeStamp()); >+ return new DetachedCDORevision(eClass, id, revision.getBranch(), -version, revision.getTimeStamp(), >+ revision.getRevised()); > } > > return revision; >@@ -240,6 +241,13 @@ > > // if audit support is present, just use the audit method > success = ((IClassMappingAuditSupport)mapping).readRevisionByVersion(this, revision, listChunk); >+ if (success && revision.getVersion() < CDOBranchVersion.FIRST_VERSION) >+ { >+ // it is detached revision >+ revision = new DetachedCDORevision(eClass, id, revision.getBranch(), -revision.getVersion(), >+ revision.getTimeStamp(), revision.getRevised()); >+ >+ } > } > else > { >Index: src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java,v >retrieving revision 1.25 >diff -u -r1.25 HorizontalAuditClassMapping.java >--- src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java 25 May 2010 09:29:20 -0000 1.25 >+++ src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java 9 Jul 2010 15:24:54 -0000 >@@ -15,6 +15,7 @@ > > import org.eclipse.emf.cdo.common.branch.CDOBranch; > 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.id.CDOIDUtil; > import org.eclipse.emf.cdo.common.revision.CDORevision; >@@ -153,7 +154,7 @@ > > builder = new StringBuilder(sqlSelectAttributesPrefix); > >- builder.append(CDODBSchema.ATTRIBUTES_VERSION); >+ builder.append("ABS(" + CDODBSchema.ATTRIBUTES_VERSION + ")"); > builder.append("=?)"); //$NON-NLS-1$ > > sqlSelectAttributesByVersion = builder.toString(); >@@ -293,7 +294,7 @@ > boolean success = readValuesFromStatement(pstmt, revision, accessor); > > // Read multival tables only if revision exists >- if (success) >+ if (success && revision.getVersion() >= CDOBranchVersion.FIRST_VERSION) > { > readLists(accessor, revision, listChunk); > } >Index: src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingClassMapping.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingClassMapping.java,v >retrieving revision 1.21 >diff -u -r1.21 HorizontalBranchingClassMapping.java >--- src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingClassMapping.java 25 May 2010 09:29:20 -0000 1.21 >+++ src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingClassMapping.java 9 Jul 2010 15:24:54 -0000 >@@ -327,7 +327,7 @@ > boolean success = readValuesFromStatement(pstmt, revision, accessor); > > // Read multival tables only if revision exists >- if (success) >+ if (success && revision.getVersion() >= CDOBranchVersion.FIRST_VERSION) > { > readLists(accessor, revision, listChunk); > } >#P org.eclipse.emf.cdo.server.hibernate >Index: src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateCommitContext.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateCommitContext.java,v >retrieving revision 1.13 >diff -u -r1.13 HibernateCommitContext.java >--- src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateCommitContext.java 7 Feb 2010 08:17:29 -0000 1.13 >+++ src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateCommitContext.java 9 Jul 2010 15:24:55 -0000 >@@ -62,6 +62,7 @@ > { > newObjects.put(cdoRevision.getID(), cdoRevision); > } >+ > } > > public InternalCDORevision getDirtyObject(CDOID id) >#P org.eclipse.emf.cdo.server.net4j >Index: src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LoadRevisionByVersionIndication.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LoadRevisionByVersionIndication.java,v >retrieving revision 1.6 >diff -u -r1.6 LoadRevisionByVersionIndication.java >--- src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LoadRevisionByVersionIndication.java 4 Mar 2010 06:35:44 -0000 1.6 >+++ src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LoadRevisionByVersionIndication.java 9 Jul 2010 15:24:56 -0000 >@@ -15,8 +15,9 @@ > import org.eclipse.emf.cdo.common.protocol.CDODataInput; > import org.eclipse.emf.cdo.common.protocol.CDODataOutput; > import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; >-import org.eclipse.emf.cdo.common.revision.CDORevision; > import org.eclipse.emf.cdo.server.internal.net4j.bundle.OM; >+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; >+import org.eclipse.emf.cdo.spi.common.revision.RevisionInfo; > > import org.eclipse.net4j.util.om.trace.ContextTracer; > >@@ -66,8 +67,8 @@ > @Override > protected void responding(CDODataOutput out) throws IOException > { >- CDORevision revision = getRepository().getRevisionManager().getRevisionByVersion(id, branchVersion, referenceChunk, >- true); >- out.writeCDORevision(revision, referenceChunk); >+ InternalCDORevision revision = getRepository().getRevisionManager().getRevisionByVersion(id, branchVersion, >+ referenceChunk, true); >+ RevisionInfo.doWriteResult(out, revision, referenceChunk); > } > } >#P org.eclipse.emf.cdo.server.objectivity >Index: src/org/eclipse/emf/cdo/server/internal/objectivity/ObjectivityStoreAccessor.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo.server.objectivity/src/org/eclipse/emf/cdo/server/internal/objectivity/ObjectivityStoreAccessor.java,v >retrieving revision 1.11 >diff -u -r1.11 ObjectivityStoreAccessor.java >--- src/org/eclipse/emf/cdo/server/internal/objectivity/ObjectivityStoreAccessor.java 14 Jun 2010 07:29:55 -0000 1.11 >+++ src/org/eclipse/emf/cdo/server/internal/objectivity/ObjectivityStoreAccessor.java 9 Jul 2010 15:24:57 -0000 >@@ -887,7 +887,7 @@ > } > EClass eClass = ObjySchema.getEClass(getStore(), objyObject.objyClass()); > return new DetachedCDORevision(eClass, id, branchPoint.getBranch(), -objyRevision.getVersion(), >- objyRevision.getCreationTime()); >+ objyRevision.getCreationTime(), objyRevision.getRevisedTime()); > } > > CDOBranchPoint branchPoint2 = revision.getBranch().getPoint(objyRevision.getCreationTime()); >#P org.eclipse.emf.cdo.tests >Index: src/org/eclipse/emf/cdo/tests/AllConfigs.java >=================================================================== >RCS file: /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.cdo/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java,v >retrieving revision 1.8.2.3 >diff -u -r1.8.2.3 AllConfigs.java >--- src/org/eclipse/emf/cdo/tests/AllConfigs.java 6 Jul 2010 11:31:17 -0000 1.8.2.3 >+++ src/org/eclipse/emf/cdo/tests/AllConfigs.java 9 Jul 2010 15:24:58 -0000 >@@ -144,6 +144,8 @@ > testClasses.add(DynamicPackageTest.class); > testClasses.add(LegacyTest.class); > testClasses.add(XRefTest.class); >+ testClasses.add(RevertTest.class); >+ testClasses.add(DetachedCDORevisionConsistencyTest.class); > > // Specific for MEMStore > testClasses.add(MEMStoreQueryTest.class); >Index: src/org/eclipse/emf/cdo/tests/DetachedCDORevisionConsistencyTest.java >=================================================================== >RCS file: src/org/eclipse/emf/cdo/tests/DetachedCDORevisionConsistencyTest.java >diff -N src/org/eclipse/emf/cdo/tests/DetachedCDORevisionConsistencyTest.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/emf/cdo/tests/DetachedCDORevisionConsistencyTest.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,322 @@ >+/** >+ * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * Eike Stepper - initial API and implementation >+ */ >+package org.eclipse.emf.cdo.tests; >+ >+import org.eclipse.emf.cdo.CDOObject; >+import org.eclipse.emf.cdo.common.id.CDOID; >+import org.eclipse.emf.cdo.common.revision.CDORevision; >+import org.eclipse.emf.cdo.common.revision.CDORevisionManager; >+import org.eclipse.emf.cdo.eresource.CDOResource; >+import org.eclipse.emf.cdo.net4j.CDOSession; >+import org.eclipse.emf.cdo.spi.common.revision.DetachedCDORevision; >+import org.eclipse.emf.cdo.spi.server.InternalRepository; >+import org.eclipse.emf.cdo.tests.RevertTest.RevertEqualityHelper; >+import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; >+import org.eclipse.emf.cdo.tests.model1.Category; >+import org.eclipse.emf.cdo.tests.model1.Company; >+import org.eclipse.emf.cdo.tests.model1.Customer; >+import org.eclipse.emf.cdo.tests.model1.OrderDetail; >+import org.eclipse.emf.cdo.tests.model1.Product1; >+import org.eclipse.emf.cdo.tests.model1.PurchaseOrder; >+import org.eclipse.emf.cdo.tests.model1.SalesOrder; >+import org.eclipse.emf.cdo.tests.model1.Supplier; >+import org.eclipse.emf.cdo.transaction.CDOTransaction; >+import org.eclipse.emf.cdo.util.CDOUtil; >+import org.eclipse.emf.cdo.util.CommitException; >+import org.eclipse.emf.cdo.util.ObjectNotFoundException; >+import org.eclipse.emf.cdo.view.CDOView; >+ >+import org.eclipse.emf.internal.cdo.transaction.CDOTransactionImpl; >+ >+import org.eclipse.emf.common.util.TreeIterator; >+import org.eclipse.emf.ecore.EObject; >+import org.eclipse.emf.ecore.util.EcoreUtil; >+ >+import java.util.ArrayList; >+import java.util.Calendar; >+import java.util.HashSet; >+import java.util.Iterator; >+import java.util.List; >+import java.util.Set; >+ >+import junit.framework.Assert; >+ >+/** >+ * Test checks if detached revision (holes) breaks server environment >+ * >+ * @author Egidijus Vaisnora >+ */ >+public class DetachedCDORevisionConsistencyTest extends AbstractCDOTest >+{ >+ private static final String RESOURCE_NAME = "resource"; >+ >+ private long timeStampOfInitialCommit; >+ >+ private long timeStampOfHoleCommit; >+ >+ private Set<CDOID> cdoid; >+ >+ @Override >+ protected void doSetUp() throws Exception >+ { >+ super.doSetUp(); >+ >+ // create model history >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ // creating initial commit >+ Company createdCompany = getModel1Factory().createCompany(); >+ createdCompany.setName("CompanyTesting"); >+ createdCompany.setCity("City"); >+ createdCompany.setStreet("Street"); >+ >+ Supplier createSupplier = getModel1Factory().createSupplier(); >+ createSupplier.setName("CompanySupplier"); >+ createSupplier.setCity("CitySupplier"); >+ createSupplier.setStreet("StreetSupplier"); >+ createdCompany.getSuppliers().add(createSupplier); >+ >+ Category category = getModel1Factory().createCategory(); >+ category.setName("Category"); >+ createdCompany.getCategories().add(category); >+ resource.getContents().add(createdCompany); >+ >+ Customer customer = getModel1Factory().createCustomer(); >+ customer.setCity("city"); >+ customer.setName("name"); >+ customer.setStreet("street"); >+ createdCompany.getCustomers().add(customer); >+ >+ // product 1 >+ Product1 createProduct1 = getModel1Factory().createProduct1(); >+ createProduct1.setDescription("description"); >+ createProduct1.setName("product name"); >+ category.getProducts().add(createProduct1); >+ >+ // second product >+ Product1 createProduct2 = getModel1Factory().createProduct1(); >+ createProduct2.setDescription("description"); >+ createProduct2.setName("product name"); >+ category.getProducts().add(createProduct2); >+ >+ // customer >+ Customer createCustomer = getModel1Factory().createCustomer(); >+ createCustomer.setName("customer name"); >+ createdCompany.getCustomers().add(createCustomer); >+ >+ // purchase order >+ OrderDetail createOrderDetail = getModel1Factory().createOrderDetail(); >+ createOrderDetail.setPrice(12f); >+ createOrderDetail.setProduct(createProduct1); >+ >+ PurchaseOrder createPurchaseOrder = getModel1Factory().createPurchaseOrder(); >+ createPurchaseOrder.setDate(Calendar.getInstance().getTime()); >+ createPurchaseOrder.getOrderDetails().add(createOrderDetail); >+ createdCompany.getPurchaseOrders().add(createPurchaseOrder); >+ >+ // sale order >+ OrderDetail createOrderDetail2 = getModel1Factory().createOrderDetail(); >+ createOrderDetail.setPrice(13f); >+ createOrderDetail.setProduct(createProduct2); >+ >+ SalesOrder createSaleOrder = getModel1Factory().createSalesOrder(); >+ createSaleOrder.setId(-1); >+ createSaleOrder.setCustomer(createCustomer); >+ createSaleOrder.getOrderDetails().add(createOrderDetail2); >+ resource.getContents().add(createSaleOrder); >+ >+ timeStampOfInitialCommit = openTransaction.commit().getTimeStamp(); >+ >+ // collect id's >+ cdoid = new HashSet<CDOID>(); >+ for (TreeIterator<EObject> allContents = resource.getAllContents(); allContents.hasNext();) >+ { >+ CDOObject next = (CDOObject)allContents.next(); >+ cdoid.add(next.cdoID()); >+ } >+ >+ // making holes - detaching >+ List<EObject> contents = new ArrayList<EObject>(resource.getContents()); >+ for (int i = 0; i < contents.size(); i++) >+ { >+ EcoreUtil.delete(contents.get(i), true); >+ } >+ >+ timeStampOfHoleCommit = openTransaction.commit().getTimeStamp(); >+ >+ session.close(); >+ } >+ >+ /** >+ * Restart repository and check project loading is working >+ * >+ * @throws Exception >+ */ >+ public void testReloadingRevisions() throws Exception >+ { >+ >+ List<Integer> detachedVersions = new ArrayList<Integer>(); >+ List<Long> versionTimestamps = new ArrayList<Long>(); >+ detachedVersions.add(2); >+ versionTimestamps.add(timeStampOfInitialCommit); >+ versionTimestamps.add(timeStampOfHoleCommit); >+ clearServerRevisionCache(); >+ >+ // load whole deleted resource >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getResource(RESOURCE_NAME); >+ >+ // loading >+ CDOUtil.load(resource, openTransaction); >+ >+ Assert.assertEquals(resource.getContents().size(), 0); >+ session.close(); >+ >+ // revert, create version 3 >+ clearServerRevisionCache(); >+ long restoredTimestamp = revertResource(RESOURCE_NAME, timeStampOfInitialCommit); >+ versionTimestamps.add(restoredTimestamp); >+ >+ // assert >+ clearServerRevisionCache(); >+ assertResources(RESOURCE_NAME, timeStampOfInitialCommit, restoredTimestamp, null); >+ >+ // revert to deleted, create version 4 >+ clearServerRevisionCache(); >+ long restoredHolesTimestamp = revertResource(RESOURCE_NAME, timeStampOfHoleCommit); >+ detachedVersions.add(4); >+ versionTimestamps.add(restoredHolesTimestamp); >+ >+ // assert >+ clearServerRevisionCache(); >+ assertResources(RESOURCE_NAME, timeStampOfHoleCommit, restoredHolesTimestamp, cdoid); >+ >+ org.eclipse.emf.cdo.session.CDOSession openSession = openSession(); >+ CDORevisionManager revisionManager = openSession.getRevisionManager(); >+ for (int i = 0; i < versionTimestamps.size(); i++) >+ { >+ clearServerRevisionCache(); >+ int version = i + 1; >+ boolean detachedVersion = detachedVersions.contains(version); >+ for (Iterator<CDOID> it = cdoid.iterator(); it.hasNext();) >+ { >+ CDOID next = it.next(); >+ >+ CDORevision revisionByVersion = revisionManager.getRevisionByVersion(next, openSession.getBranchManager() >+ .getMainBranch().getVersion(version), CDORevision.DEPTH_NONE, true); >+ assertRevisionTakenByVersion(revisionByVersion, detachedVersion); >+ >+ CDORevision revisionByTimestamp = revisionManager.getRevision(next, openSession.getBranchManager() >+ .getMainBranch().getPoint(versionTimestamps.get(i)), CDORevision.DEPTH_NONE, 0, true); >+ assertRevisionTakenByTimestamp(revisionByTimestamp, detachedVersion); >+ } >+ >+ } >+ openSession.close(); >+ >+ } >+ >+ private void clearServerRevisionCache() >+ { >+ InternalRepository repository = getScenario().getRepositoryConfig() >+ .getRepository(IRepositoryConfig.REPOSITORY_NAME); >+ clearCache(repository.getRevisionManager()); >+ } >+ >+ private long revertResource(String resourceName, long timestamp) throws CommitException >+ { >+ CDOSession session = (CDOSession)openSession(); >+ CDOView openAudit = session.openView(timestamp); >+ CDOResource historicalResource = openAudit.getResource(resourceName); >+ List<CDOObject> tmpObjects = collectAllRevertDataFromResource(historicalResource); >+ >+ CDOTransaction openTransaction2 = session.openTransaction(); >+ ((CDOTransactionImpl)openTransaction2).revert(tmpObjects.toArray(new CDOObject[tmpObjects.size()])); >+ long timestampCommit = openTransaction2.commit().getTimeStamp(); >+ session.close(); >+ return timestampCommit; >+ } >+ >+ private List<CDOObject> collectAllRevertDataFromResource(CDOResource historicalResource) >+ { >+ List<CDOObject> tmpObjects = new ArrayList<CDOObject>(); >+ tmpObjects.add(historicalResource); >+ for (TreeIterator<EObject> allContents = historicalResource.getAllContents(); allContents.hasNext();) >+ { >+ CDOObject next = (CDOObject)allContents.next(); >+ tmpObjects.add(next); >+ } >+ >+ return tmpObjects; >+ } >+ >+ private void assertResources(String resourceName, long timestamp1, long timestamp2, Set<CDOID> detached) >+ { >+ CDOSession session; >+ session = (CDOSession)openSession(); >+ CDOView historyView1 = session.openView(timestamp1); >+ CDOResource historyResource1 = historyView1.getResource(resourceName); >+ CDOView historyView2 = session.openView(timestamp2); >+ CDOResource currentResource2 = historyView2.getResource(resourceName); >+ >+ // assertTrue(EcoreUtil.equals(currentResource, historyResource)); >+ assertTrue(new RevertEqualityHelper().equals(currentResource2.getContents(), historyResource1.getContents())); >+ >+ if (detached != null) >+ { >+ for (Iterator<CDOID> iterator = detached.iterator(); iterator.hasNext();) >+ { >+ CDOID cdoid = iterator.next(); >+ try >+ { >+ historyView2.getObject(cdoid); >+ fail(); >+ } >+ catch (ObjectNotFoundException ex) >+ { >+ // Expected exception >+ } >+ } >+ } >+ >+ session.close(); >+ } >+ >+ private void assertRevisionTakenByTimestamp(CDORevision revision, boolean detached) >+ { >+ if (detached) >+ { >+ Assert.assertNull(revision); >+ } >+ else >+ { >+ Assert.assertNotNull(revision); >+ } >+ >+ } >+ >+ private void assertRevisionTakenByVersion(CDORevision revision, boolean detached) >+ { >+ if (detached) >+ { >+ Assert.assertTrue(revision instanceof DetachedCDORevision); >+ // Assert.assertNull(revision); >+ } >+ else >+ { >+ Assert.assertNotNull(revision); >+ } >+ >+ } >+} >Index: src/org/eclipse/emf/cdo/tests/RevertTest.java >=================================================================== >RCS file: src/org/eclipse/emf/cdo/tests/RevertTest.java >diff -N src/org/eclipse/emf/cdo/tests/RevertTest.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/emf/cdo/tests/RevertTest.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,804 @@ >+/** >+ * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, Germany) and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * Eike Stepper - initial API and implementation >+ */ >+package org.eclipse.emf.cdo.tests; >+ >+import org.eclipse.emf.cdo.CDOObject; >+import org.eclipse.emf.cdo.CDOState; >+import org.eclipse.emf.cdo.common.id.CDOID; >+import org.eclipse.emf.cdo.eresource.CDOResource; >+import org.eclipse.emf.cdo.net4j.CDOSession; >+import org.eclipse.emf.cdo.spi.server.InternalRepository; >+import org.eclipse.emf.cdo.tests.bundle.OM; >+import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; >+import org.eclipse.emf.cdo.tests.model1.Category; >+import org.eclipse.emf.cdo.tests.model1.Company; >+import org.eclipse.emf.cdo.tests.model1.Customer; >+import org.eclipse.emf.cdo.tests.model1.OrderDetail; >+import org.eclipse.emf.cdo.tests.model1.Product1; >+import org.eclipse.emf.cdo.tests.model1.PurchaseOrder; >+import org.eclipse.emf.cdo.tests.model1.SalesOrder; >+import org.eclipse.emf.cdo.tests.model1.Supplier; >+import org.eclipse.emf.cdo.transaction.CDOTransaction; >+import org.eclipse.emf.cdo.util.CommitException; >+import org.eclipse.emf.cdo.util.ObjectNotFoundException; >+import org.eclipse.emf.cdo.view.CDOView; >+ >+import org.eclipse.emf.internal.cdo.CDOObjectImpl; >+import org.eclipse.emf.internal.cdo.transaction.CDOTransactionImpl; >+ >+import org.eclipse.emf.common.util.EList; >+import org.eclipse.emf.common.util.TreeIterator; >+import org.eclipse.emf.ecore.EAttribute; >+import org.eclipse.emf.ecore.EObject; >+import org.eclipse.emf.ecore.util.EcoreUtil; >+import org.eclipse.emf.ecore.util.EcoreUtil.EqualityHelper; >+ >+import java.util.ArrayList; >+import java.util.Calendar; >+import java.util.Collections; >+import java.util.HashSet; >+import java.util.Iterator; >+import java.util.List; >+import java.util.Set; >+ >+/** >+ * Revert testing subject: >+ * <ul> >+ * <li>simple attribute values >+ * <li>deleted object revert when is reverting non deleted parent along with deleted child >+ * <li>deleted object revert when deleted object with all recursive content is selected to revert, but parent is not for >+ * revert >+ * <li>moved object revert >+ * <li>roll-back for revert changes. Roll-back of revert changes locally is tested for failure, because TRANSIENT and >+ * DIRTY are not supported yet >+ * >+ * @author Egidijus Vaisnora >+ */ >+public class RevertTest extends AbstractCDOTest >+{ >+ private static final String RESOURCE_NAME = "resource"; >+ >+ private static final String TESTING_COMPANY_NAME = "CompanyTesting"; >+ >+ private static final String TESTING_COMPANY2_NAME = "CompanyTestingAnother"; >+ >+ private static final int TESTING_SALESORDER_ID = -1; >+ >+ private long timeStampOfCommit; >+ >+ @Override >+ protected void doSetUp() throws Exception >+ { >+ super.doSetUp(); >+ >+ // create model history >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ // creating initial commit >+ Company createdCompany = getModel1Factory().createCompany(); >+ createdCompany.setName(TESTING_COMPANY_NAME); >+ createdCompany.setCity("City"); >+ createdCompany.setStreet("Street"); >+ >+ Supplier createSupplier = getModel1Factory().createSupplier(); >+ createSupplier.setName("CompanySupplier"); >+ createSupplier.setCity("CitySupplier"); >+ createSupplier.setStreet("StreetSupplier"); >+ createdCompany.getSuppliers().add(createSupplier); >+ >+ Category category = getModel1Factory().createCategory(); >+ category.setName("Category"); >+ createdCompany.getCategories().add(category); >+ resource.getContents().add(createdCompany); >+ >+ Category category2 = getModel1Factory().createCategory(); >+ category2.setName("Category2"); >+ createdCompany.getCategories().add(category2); >+ resource.getContents().add(createdCompany); >+ >+ Customer customer = getModel1Factory().createCustomer(); >+ customer.setCity("city"); >+ customer.setName("name"); >+ customer.setStreet("street"); >+ createdCompany.getCustomers().add(customer); >+ >+ // product 1 >+ Product1 createProduct1 = getModel1Factory().createProduct1(); >+ createProduct1.setDescription("description"); >+ createProduct1.setName("product name"); >+ category.getProducts().add(createProduct1); >+ >+ // second product >+ Product1 createProduct2 = getModel1Factory().createProduct1(); >+ createProduct2.setDescription("description"); >+ createProduct2.setName("product name"); >+ category.getProducts().add(createProduct2); >+ >+ // customer >+ Customer createCustomer = getModel1Factory().createCustomer(); >+ createCustomer.setName("customer name"); >+ createdCompany.getCustomers().add(createCustomer); >+ >+ // purchase order >+ OrderDetail createOrderDetail = getModel1Factory().createOrderDetail(); >+ createOrderDetail.setPrice(12f); >+ createOrderDetail.setProduct(createProduct1); >+ >+ PurchaseOrder createPurchaseOrder = getModel1Factory().createPurchaseOrder(); >+ createPurchaseOrder.setDate(Calendar.getInstance().getTime()); >+ createPurchaseOrder.getOrderDetails().add(createOrderDetail); >+ createdCompany.getPurchaseOrders().add(createPurchaseOrder); >+ >+ // sale order >+ OrderDetail createOrderDetail2 = getModel1Factory().createOrderDetail(); >+ createOrderDetail.setPrice(13f); >+ createOrderDetail.setProduct(createProduct2); >+ >+ SalesOrder createSaleOrder = getModel1Factory().createSalesOrder(); >+ createSaleOrder.setId(TESTING_SALESORDER_ID); >+ createSaleOrder.setCustomer(createCustomer); >+ createSaleOrder.getOrderDetails().add(createOrderDetail2); >+ resource.getContents().add(createSaleOrder); >+ >+ Company createdCompany2 = getModel1Factory().createCompany(); >+ createdCompany2.setName(TESTING_COMPANY2_NAME); >+ createdCompany2.setCity("City2"); >+ createdCompany2.setStreet("Street2"); >+ resource.getContents().add(createdCompany2); >+ >+ timeStampOfCommit = openTransaction.commit().getTimeStamp(); >+ session.close(); >+ } >+ >+ /** >+ * Testing simple attribute value revert. Collecting values from given resource, changing EAttribute values and >+ * committing. Reverting to the previous version and comparing models >+ */ >+ public void testEAttributeValueRevert() throws CommitException >+ { >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ // simple property modification >+ for (TreeIterator<EObject> it = resource.getAllContents(); it.hasNext();) >+ { >+ EObject next = it.next(); >+ EList<EAttribute> eAllStructuralFeatures = next.eClass().getEAllAttributes(); >+ for (int i = 0; i < eAllStructuralFeatures.size(); i++) >+ { >+ EAttribute eAttribute = eAllStructuralFeatures.get(i); >+ changeAttribute(next, eAttribute); >+ } >+ } >+ >+ openTransaction.commit(); >+ session.close(); >+ >+ // revert session >+ revertResource(RESOURCE_NAME, timeStampOfCommit); >+ >+ // asserting >+ assertResources(RESOURCE_NAME, timeStampOfCommit, null); >+ } >+ >+ /** >+ * Test that object doesn't obtain new CDO version after revert, if it was not eligible for revert >+ */ >+ public void testVoidReverse() throws CommitException >+ { >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ // revert session >+ revertResource(RESOURCE_NAME, timeStampOfCommit); >+ >+ // simple property modification >+ for (TreeIterator<EObject> it = resource.getAllContents(); it.hasNext();) >+ { >+ EObject next = it.next(); >+ assertEquals(CDOState.CLEAN, ((CDOObject)next).cdoState()); >+ } >+ >+ session.close(); >+ } >+ >+ /** >+ * Removes objects and reverts removed object from historical revision. Second attempt is to remove all root object >+ * contents along with object >+ */ >+ public void testRemovedObjectsRevertInResource() throws CommitException >+ { >+ // modifying model >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ Company found = findTestingCompany(resource, TESTING_COMPANY_NAME); >+ >+ EList<Category> categories = found.getCategories(); >+ List<Product1> products = new ArrayList<Product1>(); >+ for (int i = 0; i < categories.size(); i++) >+ { >+ products.addAll(categories.get(i).getProducts()); >+ } >+ >+ for (int i = 0; i < products.size(); i++) >+ { >+ EcoreUtil.delete(products.get(i), true); >+ } >+ >+ openTransaction.commit(); >+ session.close(); >+ >+ revertResource(RESOURCE_NAME, timeStampOfCommit); >+ assertResources(RESOURCE_NAME, timeStampOfCommit, null); >+ >+ // remove all contents >+ session = (CDOSession)openSession(); >+ openTransaction = session.openTransaction(); >+ CDOResource object = openTransaction.getResource(RESOURCE_NAME); >+ List<EObject> eContents = new ArrayList<EObject>(object.eContents()); >+ for (Iterator<EObject> it = eContents.iterator(); it.hasNext();) >+ { >+ EObject next = it.next(); >+ EcoreUtil.delete(next, true); >+ } >+ >+ openTransaction.commit(); >+ session.close(); >+ >+ revertResource(RESOURCE_NAME, timeStampOfCommit); >+ assertResources(RESOURCE_NAME, timeStampOfCommit, null); >+ } >+ >+ /** >+ * When historical object contains less references then reverting one, then extra references are removed from the >+ * containment. After revert, removed such object doesn't have parent and must be "garbage collected" >+ */ >+ public void testAdditinalObjectDeletingAfterRevert() throws CommitException >+ { >+ // modifying model >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ Company found = findTestingCompany(resource, TESTING_COMPANY_NAME); >+ >+ Category createCategory = getModel1Factory().createCategory(); >+ found.getCategories().add(createCategory); >+ >+ openTransaction.commit(); >+ CDOID deletedObject = ((CDOObjectImpl)createCategory).cdoID(); >+ session.close(); >+ >+ revertResource(RESOURCE_NAME, timeStampOfCommit); >+ assertResources(RESOURCE_NAME, timeStampOfCommit, Collections.singleton(deletedObject)); >+ } >+ >+ /** >+ * Reverting object move. Consist of single object move. Second part makes move of child object of moved object >+ */ >+ public void testObjectAndItsChildMoveRevert() throws CommitException >+ { >+ // TEST1 move of child >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ Company found = findTestingCompany(resource, TESTING_COMPANY_NAME); >+ >+ EList<Category> categories = found.getCategories(); >+ >+ Category category = categories.get(0); >+ Category category2 = categories.get(1); >+ >+ category2.getProducts().add(category.getProducts().remove(0)); >+ >+ openTransaction.commit(); >+ session.close(); >+ >+ revertResource(RESOURCE_NAME, timeStampOfCommit); >+ assertResources(RESOURCE_NAME, timeStampOfCommit, null); >+ >+ // TEST2 move of moved child >+ session = (CDOSession)openSession(); >+ openTransaction = session.openTransaction(); >+ resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ Company found1 = null; >+ Company found2 = null; >+ EList<EObject> contents = resource.getContents(); >+ for (int i = 0; i < contents.size() && (found1 == null || found2 == null); i++) >+ { >+ EObject eObject = contents.get(i); >+ if (eObject instanceof Company) >+ { >+ if (found1 == null) >+ { >+ found1 = (Company)eObject; >+ } >+ else >+ { >+ found2 = (Company)eObject; >+ } >+ } >+ } >+ >+ EList<Category> categoriesFound1 = found1.getCategories(); >+ Category category1Found1 = categoriesFound1.get(0); >+ Category category2Found1 = categoriesFound1.get(1); >+ >+ // move of category >+ found2.getCategories().add(category1Found1); >+ >+ // move of product >+ category2Found1.getProducts().add(category1Found1.getProducts().get(0)); >+ >+ openTransaction.commit(); >+ session.close(); >+ >+ revertResource(RESOURCE_NAME, timeStampOfCommit); >+ assertResources(RESOURCE_NAME, timeStampOfCommit, null); >+ } >+ >+ /** >+ * Moving object child to another object, while old parent was removed >+ */ >+ public void testObjectMoveWithRemoveRevert() throws CommitException >+ { >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ Company found = findTestingCompany(resource, TESTING_COMPANY_NAME); >+ Company found2 = findTestingCompany(resource, TESTING_COMPANY2_NAME); >+ found2.getPurchaseOrders().add(found.getPurchaseOrders().remove(0)); >+ >+ // delete parent of purchase order >+ EcoreUtil.delete(found, true); >+ >+ openTransaction.commit(); >+ session.close(); >+ >+ revertResource(RESOURCE_NAME, timeStampOfCommit); >+ assertResources(RESOURCE_NAME, timeStampOfCommit, null); >+ } >+ >+ /** >+ * Removes objects and reverts removed object recursively. Parent of removed object is not reverted and after revert >+ * must ensure to attache deleted object to parent >+ */ >+ public void testRemovedObjectRecursiveRevert() throws CommitException >+ { >+ // modifying model >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ Company found = findTestingCompany(resource, TESTING_COMPANY_NAME); >+ CDOID revertId = ((CDOObject)found).cdoID(); >+ SalesOrder findTestingSalesOrder = findTestingSalesOrder(resource); >+ CDOID salesOrderId = ((CDOObject)findTestingSalesOrder).cdoID(); >+ >+ EcoreUtil.delete(found, true); >+ >+ openTransaction.commit(); >+ session.close(); >+ >+ /* >+ * When deleting company, we delete customer along with modified salesOrder, which had reference pointing to >+ * customer. Revert restores deleted objects - reverts customer reference to SalesOrder, but doesn't restore >+ * SalesOrder reference to Customer. Therefore passing SalesOrder to revert too >+ */ >+ revertObject(revertId, timeStampOfCommit, true, salesOrderId); >+ assertResources(RESOURCE_NAME, timeStampOfCommit, null); >+ } >+ >+ /** >+ * Testing general revert roll-back. After revert, roll-back must clear changes made by revert. >+ */ >+ public void testRevertRollback() throws CommitException >+ { >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ editingModelForRollback(resource); >+ >+ long timeStampCommit = openTransaction.commit().getTimeStamp(); >+ session.close(); >+ >+ session = (CDOSession)openSession(); >+ CDOView openAudit = session.openView(timeStampOfCommit); >+ CDOResource historicalResource = openAudit.getResource(RESOURCE_NAME); >+ List<CDOObject> tmpObjects = collectAllRevertDataFromResource(historicalResource); >+ >+ CDOTransactionImpl openTransaction2 = (CDOTransactionImpl)session.openTransaction(); >+ openTransaction2.revert(tmpObjects.toArray(new CDOObject[tmpObjects.size()])); >+ >+ openTransaction2.rollback(); >+ openTransaction2.commit(); >+ session.close(); >+ >+ assertResources(RESOURCE_NAME, timeStampCommit, null); >+ } >+ >+ /** >+ * Testing case when revert need to restore state, where it doesn't contain objects. Revert to deletion >+ */ >+ public void testHoleRevert() throws CommitException >+ { >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ Set<CDOID> ids = new HashSet<CDOID>(); >+ for (Iterator<EObject> it = resource.getAllContents(); it.hasNext();) >+ { >+ ids.add(((CDOObject)it.next()).cdoID()); >+ >+ } >+ >+ List<EObject> contents = new ArrayList<EObject>(resource.getContents()); >+ for (int i = 0; i < contents.size(); i++) >+ { >+ EcoreUtil.delete(contents.get(i)); >+ } >+ long holesTimestamp = openTransaction.commit().getTimeStamp(); >+ session.close(); >+ >+ revertResource(RESOURCE_NAME, timeStampOfCommit); >+ >+ revertResource(RESOURCE_NAME, holesTimestamp); >+ >+ assertResources(RESOURCE_NAME, holesTimestamp, ids); >+ } >+ >+ /** >+ * Testing case when revert need to restore state of deleted object, which was deleted somewhere between current and >+ * revert time-stamps. Covers version calculation, when version is restoring for detached element >+ */ >+ public void testVersionNumberCalculationOnRevert() throws CommitException >+ { >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ List<EObject> contents = new ArrayList<EObject>(resource.getContents()); >+ for (int i = 0; i < contents.size(); i++) >+ { >+ EcoreUtil.delete(contents.get(i)); >+ } >+ long holesTimestamp = openTransaction.commit().getTimeStamp(); >+ session.close(); >+ >+ revertResource(RESOURCE_NAME, timeStampOfCommit); >+ revertResource(RESOURCE_NAME, holesTimestamp); >+ >+ InternalRepository repository = getScenario().getRepositoryConfig() >+ .getRepository(IRepositoryConfig.REPOSITORY_NAME); >+ clearCache(repository.getRevisionManager()); >+ >+ revertResource(RESOURCE_NAME, timeStampOfCommit); >+ assertResources(RESOURCE_NAME, timeStampOfCommit, null); >+ >+ } >+ >+ /** >+ * Complex situation - moved content from deleted object to newly created. Revert must restore deleted object, detach >+ * object which was newly created ("garbage collected"), while containment of deleted object is moved back to restored >+ * object >+ */ >+ public void testObjectCreationMoveDeleteRevert() throws CommitException >+ { >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ // apply editing >+ Company found = findTestingCompany(resource, TESTING_COMPANY_NAME); >+ >+ Category createCategoryNew = getModel1Factory().createCategory(); >+ createCategoryNew.getProducts().addAll(found.getCategories().get(0).getProducts()); >+ >+ Company found2 = findTestingCompany(resource, TESTING_COMPANY2_NAME); >+ found2.getCategories().add(createCategoryNew); >+ >+ EcoreUtil.delete(found, true); >+ found2.setName("ChangedCompanyName"); >+ >+ openTransaction.commit(); >+ // removed id on revert >+ CDOID removedId = ((CDOObject)createCategoryNew).cdoID(); >+ session.close(); >+ >+ // getting back to the beginning >+ revertResource(RESOURCE_NAME, timeStampOfCommit); >+ assertResources(RESOURCE_NAME, timeStampOfCommit, Collections.singleton(removedId)); >+ } >+ >+ /** >+ * If object was reverted after it was edited, changes must be applied from the revert. Currently this test is testing >+ * for failure, because TRANSIENT and DIRTY are not supported yet >+ */ >+ public void testEditedObjectRevertFailure() throws CommitException >+ { >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ editingModelForRollback(resource); >+ >+ CDOView openAudit = session.openView(timeStampOfCommit); >+ CDOResource historicalResource = openAudit.getResource(RESOURCE_NAME); >+ List<CDOObject> tmpObjects = collectAllRevertDataFromResource(historicalResource); >+ >+ try >+ { >+ ((CDOTransactionImpl)openTransaction).revert(tmpObjects.toArray(new CDOObject[tmpObjects.size()])); >+ fail(); >+ } >+ catch (IllegalStateException ex) >+ { >+ // NOT supported yet >+ OM.LOG.info("Not supported revert for objects with state: TRANSIENT, DIRTY", ex); >+ } >+ >+ // openTransaction.commit(); >+ session.close(); >+ >+ // assertResources(RESOURCE_NAME, timeStampOfCommit, null); >+ } >+ >+ /** >+ * Testing object revert till specified saving point. Expected behavior is to roll-back only changes made by revert, >+ * but leave changes applied before revert. At current time it is testing for failure, because TRANSIENT and DIRTY are >+ * not supported yet >+ */ >+ public void testRevertRollbackToSavePointFailure() throws CommitException >+ { >+ CDOSession session = (CDOSession)openSession(); >+ CDOTransaction openTransaction = session.openTransaction(); >+ CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ >+ // apply editing >+ editingModelForRollback(resource); >+ openTransaction.commit(); >+ >+ // long timeStampOfComparingModel = openTransaction.getLastCommitTime(); >+ session.close(); >+ >+ // getting back to the beginning >+ revertResource(RESOURCE_NAME, timeStampOfCommit); >+ >+ // applying editing again >+ session = (CDOSession)openSession(); >+ openTransaction = session.openTransaction(); >+ resource = openTransaction.getOrCreateResource(RESOURCE_NAME); >+ editingModelForRollback(resource); >+ >+ // creating save point >+ // CDOSavepoint setSavepoint = openTransaction.setSavepoint(); >+ >+ // reverting, but not committing >+ CDOView openAudit = session.openView(timeStampOfCommit); >+ CDOResource historicalResource = openAudit.getResource(RESOURCE_NAME); >+ List<CDOObject> tmpObjects = collectAllRevertDataFromResource(historicalResource); >+ try >+ { >+ ((CDOTransactionImpl)openTransaction).revert(tmpObjects.toArray(new CDOObject[tmpObjects.size()])); >+ fail(); >+ } >+ catch (IllegalStateException ex) >+ { >+ // NOT supported yet >+ OM.LOG.info("Not supported revert for objects with state: TRANSIENT, DIRTY", ex); >+ } >+ >+ // roll-backing to save point >+ // openTransaction.rollback(setSavepoint); >+ >+ // it must be equal >+ // assertResources(RESOURCE_NAME, timeStampOfComparingModel, null); >+ } >+ >+ private void editingModelForRollback(CDOResource resource) throws CommitException >+ { >+ Company found = findTestingCompany(resource, TESTING_COMPANY_NAME); >+ >+ Category createCategoryNew = getModel1Factory().createCategory(); >+ createCategoryNew.getProducts().addAll(found.getCategories().get(0).getProducts()); >+ >+ Company found2 = findTestingCompany(resource, TESTING_COMPANY2_NAME); >+ found2.getCategories().add(createCategoryNew); >+ >+ EcoreUtil.delete(found, true); >+ found2.setName("ChangedCompanyName"); >+ } >+ >+ private Company findTestingCompany(CDOResource resource, String name) >+ { >+ Company found = null; >+ EList<EObject> contents = resource.getContents(); >+ for (int i = 0; i < contents.size() && found == null; i++) >+ { >+ EObject eObject = contents.get(i); >+ if (eObject instanceof Company && name.equals(((Company)eObject).getName())) >+ { >+ found = (Company)eObject; >+ } >+ } >+ >+ return found; >+ } >+ >+ private SalesOrder findTestingSalesOrder(CDOResource resource) >+ { >+ SalesOrder found = null; >+ EList<EObject> contents = resource.getContents(); >+ for (int i = 0; i < contents.size() && found == null; i++) >+ { >+ EObject eObject = contents.get(i); >+ if (eObject instanceof SalesOrder && ((SalesOrder)eObject).getId() == TESTING_SALESORDER_ID) >+ { >+ found = (SalesOrder)eObject; >+ } >+ } >+ >+ return found; >+ } >+ >+ private long revertResource(String resourceName, long timestamp) throws CommitException >+ { >+ CDOSession session = (CDOSession)openSession(); >+ CDOView openAudit = session.openView(timestamp); >+ CDOResource historicalResource = openAudit.getResource(resourceName); >+ List<CDOObject> tmpObjects = collectAllRevertDataFromResource(historicalResource); >+ >+ CDOTransaction openTransaction2 = session.openTransaction(); >+ ((CDOTransactionImpl)openTransaction2).revert(tmpObjects.toArray(new CDOObject[tmpObjects.size()])); >+ long ret = 0; >+ if (openTransaction2.isDirty()) >+ { >+ ret = openTransaction2.commit().getTimeStamp(); >+ } >+ >+ session.close(); >+ return ret; >+ } >+ >+ private List<CDOObject> collectAllRevertDataFromResource(CDOResource historicalResource) >+ { >+ List<CDOObject> tmpObjects = new ArrayList<CDOObject>(); >+ tmpObjects.add(historicalResource); >+ for (TreeIterator<EObject> allContents = historicalResource.getAllContents(); allContents.hasNext();) >+ { >+ CDOObject next = (CDOObject)allContents.next(); >+ tmpObjects.add(next); >+ } >+ >+ return tmpObjects; >+ } >+ >+ private void assertResources(String resourceName, long timestamp, Set<CDOID> detached) >+ { >+ CDOSession session; >+ session = (CDOSession)openSession(); >+ CDOView currentView = session.openView(); >+ CDOResource currentResource = currentView.getResource(resourceName); >+ CDOView historyView = session.openView(timestamp); >+ CDOResource historyResource = historyView.getResource(resourceName); >+ >+ // assertTrue(EcoreUtil.equals(currentResource, historyResource)); >+ assertTrue(new RevertEqualityHelper().equals(currentResource.getContents(), historyResource.getContents())); >+ >+ if (detached != null) >+ { >+ for (Iterator<CDOID> iterator = detached.iterator(); iterator.hasNext();) >+ { >+ CDOID cdoid = iterator.next(); >+ try >+ { >+ currentView.getObject(cdoid); >+ fail(); >+ } >+ catch (ObjectNotFoundException ex) >+ { >+ // Expected exception >+ } >+ } >+ } >+ >+ session.close(); >+ } >+ >+ private void revertObject(CDOID objectId, long timestamp, boolean recursively, CDOID... additionalIds) >+ throws CommitException >+ { >+ CDOSession session; >+ session = (CDOSession)openSession(); >+ CDOView openAudit = session.openView(timestamp); >+ CDOObject historicalObject = openAudit.getObject(objectId); >+ List<CDOObject> tmpObjects = new ArrayList<CDOObject>(); >+ tmpObjects.add(historicalObject); >+ if (recursively) >+ { >+ for (TreeIterator<EObject> allContents = historicalObject.eAllContents(); allContents.hasNext();) >+ { >+ CDOObject next = (CDOObject)allContents.next(); >+ tmpObjects.add(next); >+ } >+ } >+ >+ for (CDOID id : additionalIds) >+ { >+ CDOObject object = openAudit.getObject(id); >+ tmpObjects.add(object); >+ } >+ >+ CDOTransaction openTransaction2 = session.openTransaction(); >+ ((CDOTransactionImpl)openTransaction2).revert(tmpObjects.toArray(new CDOObject[tmpObjects.size()])); >+ openTransaction2.commit(); >+ session.close(); >+ } >+ >+ private void changeAttribute(EObject next, EAttribute eAttribute) >+ { >+ Object value = next.eGet(eAttribute); >+ if (eAttribute.getEType().getInstanceClass() == String.class) >+ { >+ next.eSet(eAttribute, String.valueOf(value) + String.valueOf(value)); >+ } >+ else if (eAttribute.getEType().getInstanceClass() == Float.TYPE) >+ { >+ next.eSet(eAttribute, ((Float)value).floatValue() + 1); >+ } >+ else if (eAttribute.getEType().getInstanceClass() == Double.TYPE) >+ { >+ next.eSet(eAttribute, ((Double)value).doubleValue() + 1); >+ } >+ else if (eAttribute.getEType().getInstanceClass() == Integer.TYPE) >+ { >+ next.eSet(eAttribute, ((Integer)value).intValue() + 1); >+ } >+ else if (eAttribute.getEType().getInstanceClass() == Long.TYPE) >+ { >+ next.eSet(eAttribute, ((Long)value).longValue() + 1); >+ } >+ else if (eAttribute.getEType().getInstanceClass() == java.util.Date.class) >+ { >+ next.eSet(eAttribute, Calendar.getInstance().getTime()); >+ } >+ } >+ >+ public static class RevertEqualityHelper extends EqualityHelper >+ { >+ private static final long serialVersionUID = -729066319986556429L; >+ >+ @Override >+ public boolean equals(EObject eObject1, EObject eObject2) >+ { >+ boolean eq = super.equals(eObject1, eObject2); >+ if (eq) >+ { >+ if (eObject1 instanceof CDOObject) >+ { >+ eq = ((CDOObject)eObject1).cdoID().equals(((CDOObject)eObject2).cdoID()); >+ } >+ } >+ return eq; >+ } >+ } >+ >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 319409
: 173879