Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 319409
Collapse All | Expand All

(-)src/org/eclipse/emf/internal/cdo/CDOStateMachine.java (-3 / +347 lines)
Lines 11-26 Link Here
11
 */
11
 */
12
package org.eclipse.emf.internal.cdo;
12
package org.eclipse.emf.internal.cdo;
13
13
14
import org.eclipse.emf.cdo.CDOObject;
14
import org.eclipse.emf.cdo.CDOState;
15
import org.eclipse.emf.cdo.CDOState;
15
import org.eclipse.emf.cdo.common.id.CDOID;
16
import org.eclipse.emf.cdo.common.id.CDOID;
16
import org.eclipse.emf.cdo.common.id.CDOIDTemp;
17
import org.eclipse.emf.cdo.common.id.CDOIDTemp;
18
import org.eclipse.emf.cdo.common.model.CDOModelUtil;
17
import org.eclipse.emf.cdo.common.model.EMFUtil;
19
import org.eclipse.emf.cdo.common.model.EMFUtil;
18
import org.eclipse.emf.cdo.common.revision.CDORevision;
20
import org.eclipse.emf.cdo.common.revision.CDORevision;
19
import org.eclipse.emf.cdo.common.revision.CDORevisionFactory;
21
import org.eclipse.emf.cdo.common.revision.CDORevisionFactory;
20
import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
22
import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
23
import org.eclipse.emf.cdo.common.revision.CDORevisionManager;
21
import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
24
import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
22
import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
25
import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
23
import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDeltaUtil;
26
import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDeltaUtil;
27
import org.eclipse.emf.cdo.eresource.CDOResource;
28
import org.eclipse.emf.cdo.internal.common.revision.CDORevisionImpl;
24
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
29
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
25
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
30
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
26
import org.eclipse.emf.cdo.transaction.CDOTransaction;
31
import org.eclipse.emf.cdo.transaction.CDOTransaction;
Lines 35-55 Link Here
35
import org.eclipse.net4j.util.fsm.ITransition;
40
import org.eclipse.net4j.util.fsm.ITransition;
36
import org.eclipse.net4j.util.om.trace.ContextTracer;
41
import org.eclipse.net4j.util.om.trace.ContextTracer;
37
42
43
import org.eclipse.emf.common.util.EList;
38
import org.eclipse.emf.ecore.EClass;
44
import org.eclipse.emf.ecore.EClass;
39
import org.eclipse.emf.ecore.EObject;
45
import org.eclipse.emf.ecore.EObject;
46
import org.eclipse.emf.ecore.EReference;
40
import org.eclipse.emf.ecore.EStructuralFeature;
47
import org.eclipse.emf.ecore.EStructuralFeature;
41
import org.eclipse.emf.ecore.InternalEObject;
48
import org.eclipse.emf.ecore.InternalEObject;
49
import org.eclipse.emf.ecore.InternalEObject.EStore;
42
import org.eclipse.emf.ecore.impl.EStoreEObjectImpl;
50
import org.eclipse.emf.ecore.impl.EStoreEObjectImpl;
43
import org.eclipse.emf.ecore.resource.Resource;
51
import org.eclipse.emf.ecore.resource.Resource;
52
import org.eclipse.emf.ecore.util.EcoreUtil;
44
import org.eclipse.emf.spi.cdo.CDOSessionProtocol.CommitTransactionResult;
53
import org.eclipse.emf.spi.cdo.CDOSessionProtocol.CommitTransactionResult;
45
import org.eclipse.emf.spi.cdo.InternalCDOObject;
54
import org.eclipse.emf.spi.cdo.InternalCDOObject;
46
import org.eclipse.emf.spi.cdo.InternalCDOTransaction;
55
import org.eclipse.emf.spi.cdo.InternalCDOTransaction;
47
import org.eclipse.emf.spi.cdo.InternalCDOView;
56
import org.eclipse.emf.spi.cdo.InternalCDOView;
48
57
49
import java.util.ArrayList;
58
import java.util.ArrayList;
59
import java.util.HashSet;
50
import java.util.Iterator;
60
import java.util.Iterator;
51
import java.util.List;
61
import java.util.List;
52
import java.util.Map;
62
import java.util.Map;
63
import java.util.Set;
53
import java.util.concurrent.locks.ReentrantLock;
64
import java.util.concurrent.locks.ReentrantLock;
54
65
55
/**
66
/**
Lines 83-88 Link Here
83
    init(CDOState.TRANSIENT, CDOEvent.DETACH_REMOTE, FAIL);
94
    init(CDOState.TRANSIENT, CDOEvent.DETACH_REMOTE, FAIL);
84
    init(CDOState.TRANSIENT, CDOEvent.COMMIT, FAIL);
95
    init(CDOState.TRANSIENT, CDOEvent.COMMIT, FAIL);
85
    init(CDOState.TRANSIENT, CDOEvent.ROLLBACK, FAIL);
96
    init(CDOState.TRANSIENT, CDOEvent.ROLLBACK, FAIL);
97
    init(CDOState.TRANSIENT, CDOEvent.REVERT, FAIL); // For future TRANSIENT could be involved into revert
86
98
87
    init(CDOState.PREPARED, CDOEvent.PREPARE, FAIL);
99
    init(CDOState.PREPARED, CDOEvent.PREPARE, FAIL);
88
    init(CDOState.PREPARED, CDOEvent.ATTACH, new AttachTransition());
100
    init(CDOState.PREPARED, CDOEvent.ATTACH, new AttachTransition());
Lines 94-99 Link Here
94
    init(CDOState.PREPARED, CDOEvent.DETACH_REMOTE, FAIL);
106
    init(CDOState.PREPARED, CDOEvent.DETACH_REMOTE, FAIL);
95
    init(CDOState.PREPARED, CDOEvent.COMMIT, FAIL);
107
    init(CDOState.PREPARED, CDOEvent.COMMIT, FAIL);
96
    init(CDOState.PREPARED, CDOEvent.ROLLBACK, FAIL);
108
    init(CDOState.PREPARED, CDOEvent.ROLLBACK, FAIL);
109
    init(CDOState.PREPARED, CDOEvent.REVERT, FAIL);
97
110
98
    init(CDOState.NEW, CDOEvent.PREPARE, FAIL);
111
    init(CDOState.NEW, CDOEvent.PREPARE, FAIL);
99
    init(CDOState.NEW, CDOEvent.ATTACH, FAIL);
112
    init(CDOState.NEW, CDOEvent.ATTACH, FAIL);
Lines 105-110 Link Here
105
    init(CDOState.NEW, CDOEvent.DETACH_REMOTE, FAIL);
118
    init(CDOState.NEW, CDOEvent.DETACH_REMOTE, FAIL);
106
    init(CDOState.NEW, CDOEvent.COMMIT, new CommitTransition(false));
119
    init(CDOState.NEW, CDOEvent.COMMIT, new CommitTransition(false));
107
    init(CDOState.NEW, CDOEvent.ROLLBACK, FAIL);
120
    init(CDOState.NEW, CDOEvent.ROLLBACK, FAIL);
121
    init(CDOState.NEW, CDOEvent.REVERT, new RevertTransition()); // resurrected objects has state NEW
108
122
109
    init(CDOState.CLEAN, CDOEvent.PREPARE, FAIL);
123
    init(CDOState.CLEAN, CDOEvent.PREPARE, FAIL);
110
    init(CDOState.CLEAN, CDOEvent.ATTACH, FAIL);
124
    init(CDOState.CLEAN, CDOEvent.ATTACH, FAIL);
Lines 116-121 Link Here
116
    init(CDOState.CLEAN, CDOEvent.DETACH_REMOTE, DetachRemoteTransition.INSTANCE);
130
    init(CDOState.CLEAN, CDOEvent.DETACH_REMOTE, DetachRemoteTransition.INSTANCE);
117
    init(CDOState.CLEAN, CDOEvent.COMMIT, FAIL);
131
    init(CDOState.CLEAN, CDOEvent.COMMIT, FAIL);
118
    init(CDOState.CLEAN, CDOEvent.ROLLBACK, FAIL);
132
    init(CDOState.CLEAN, CDOEvent.ROLLBACK, FAIL);
133
    init(CDOState.CLEAN, CDOEvent.REVERT, new RevertTransition());
119
134
120
    init(CDOState.DIRTY, CDOEvent.PREPARE, FAIL);
135
    init(CDOState.DIRTY, CDOEvent.PREPARE, FAIL);
121
    init(CDOState.DIRTY, CDOEvent.ATTACH, FAIL);
136
    init(CDOState.DIRTY, CDOEvent.ATTACH, FAIL);
Lines 127-132 Link Here
127
    init(CDOState.DIRTY, CDOEvent.DETACH_REMOTE, new InvalidConflictTransition());
142
    init(CDOState.DIRTY, CDOEvent.DETACH_REMOTE, new InvalidConflictTransition());
128
    init(CDOState.DIRTY, CDOEvent.COMMIT, new CommitTransition(true));
143
    init(CDOState.DIRTY, CDOEvent.COMMIT, new CommitTransition(true));
129
    init(CDOState.DIRTY, CDOEvent.ROLLBACK, new RollbackTransition());
144
    init(CDOState.DIRTY, CDOEvent.ROLLBACK, new RollbackTransition());
145
    init(CDOState.DIRTY, CDOEvent.REVERT, FAIL); // for future DIRTY could be involved into revert
130
146
131
    init(CDOState.PROXY, CDOEvent.PREPARE, FAIL);
147
    init(CDOState.PROXY, CDOEvent.PREPARE, FAIL);
132
    init(CDOState.PROXY, CDOEvent.ATTACH, FAIL);
148
    init(CDOState.PROXY, CDOEvent.ATTACH, FAIL);
Lines 138-143 Link Here
138
    init(CDOState.PROXY, CDOEvent.DETACH_REMOTE, DetachRemoteTransition.INSTANCE);
154
    init(CDOState.PROXY, CDOEvent.DETACH_REMOTE, DetachRemoteTransition.INSTANCE);
139
    init(CDOState.PROXY, CDOEvent.COMMIT, FAIL);
155
    init(CDOState.PROXY, CDOEvent.COMMIT, FAIL);
140
    init(CDOState.PROXY, CDOEvent.ROLLBACK, FAIL);
156
    init(CDOState.PROXY, CDOEvent.ROLLBACK, FAIL);
157
    init(CDOState.PROXY, CDOEvent.REVERT, FAIL);
141
158
142
    init(CDOState.CONFLICT, CDOEvent.PREPARE, FAIL);
159
    init(CDOState.CONFLICT, CDOEvent.PREPARE, FAIL);
143
    init(CDOState.CONFLICT, CDOEvent.ATTACH, IGNORE);
160
    init(CDOState.CONFLICT, CDOEvent.ATTACH, IGNORE);
Lines 149-154 Link Here
149
    init(CDOState.CONFLICT, CDOEvent.DETACH_REMOTE, IGNORE);
166
    init(CDOState.CONFLICT, CDOEvent.DETACH_REMOTE, IGNORE);
150
    init(CDOState.CONFLICT, CDOEvent.COMMIT, IGNORE);
167
    init(CDOState.CONFLICT, CDOEvent.COMMIT, IGNORE);
151
    init(CDOState.CONFLICT, CDOEvent.ROLLBACK, new RollbackTransition());
168
    init(CDOState.CONFLICT, CDOEvent.ROLLBACK, new RollbackTransition());
169
    init(CDOState.CONFLICT, CDOEvent.REVERT, FAIL);
152
170
153
    init(CDOState.INVALID, CDOEvent.PREPARE, InvalidTransition.INSTANCE);
171
    init(CDOState.INVALID, CDOEvent.PREPARE, InvalidTransition.INSTANCE);
154
    init(CDOState.INVALID, CDOEvent.ATTACH, InvalidTransition.INSTANCE);
172
    init(CDOState.INVALID, CDOEvent.ATTACH, InvalidTransition.INSTANCE);
Lines 160-165 Link Here
160
    init(CDOState.INVALID, CDOEvent.DETACH_REMOTE, IGNORE);
178
    init(CDOState.INVALID, CDOEvent.DETACH_REMOTE, IGNORE);
161
    init(CDOState.INVALID, CDOEvent.COMMIT, InvalidTransition.INSTANCE);
179
    init(CDOState.INVALID, CDOEvent.COMMIT, InvalidTransition.INSTANCE);
162
    init(CDOState.INVALID, CDOEvent.ROLLBACK, InvalidTransition.INSTANCE);
180
    init(CDOState.INVALID, CDOEvent.ROLLBACK, InvalidTransition.INSTANCE);
181
    init(CDOState.INVALID, CDOEvent.REVERT, FAIL);
163
182
164
    init(CDOState.INVALID_CONFLICT, CDOEvent.PREPARE, InvalidTransition.INSTANCE);
183
    init(CDOState.INVALID_CONFLICT, CDOEvent.PREPARE, InvalidTransition.INSTANCE);
165
    init(CDOState.INVALID_CONFLICT, CDOEvent.ATTACH, InvalidTransition.INSTANCE);
184
    init(CDOState.INVALID_CONFLICT, CDOEvent.ATTACH, InvalidTransition.INSTANCE);
Lines 171-176 Link Here
171
    init(CDOState.INVALID_CONFLICT, CDOEvent.DETACH_REMOTE, IGNORE);
190
    init(CDOState.INVALID_CONFLICT, CDOEvent.DETACH_REMOTE, IGNORE);
172
    init(CDOState.INVALID_CONFLICT, CDOEvent.COMMIT, InvalidTransition.INSTANCE);
191
    init(CDOState.INVALID_CONFLICT, CDOEvent.COMMIT, InvalidTransition.INSTANCE);
173
    init(CDOState.INVALID_CONFLICT, CDOEvent.ROLLBACK, DetachRemoteTransition.INSTANCE);
192
    init(CDOState.INVALID_CONFLICT, CDOEvent.ROLLBACK, DetachRemoteTransition.INSTANCE);
193
    init(CDOState.INVALID_CONFLICT, CDOEvent.REVERT, FAIL);
174
  }
194
  }
175
195
176
  /**
196
  /**
Lines 221-227 Link Here
221
  {
241
  {
222
    if (TRACER.isEnabled())
242
    if (TRACER.isEnabled())
223
    {
243
    {
224
      TRACER.format("PREPARE: {0} --> {1}", object, transactionAndContents.getElement1()); //$NON-NLS-1$
244
      TRACER.format("PREPARE: {0} --> {1}", object, transactionAndContents.getElement1());
225
    }
245
    }
226
246
227
    process(object, CDOEvent.PREPARE, transactionAndContents);
247
    process(object, CDOEvent.PREPARE, transactionAndContents);
Lines 400-405 Link Here
400
      }
420
      }
401
    }
421
    }
402
  }
422
  }
423
  
424
  /**
425
   * Revert given historical data
426
   * 
427
   * @since 3.0
428
   */
429
  public void revert(CDOTransaction activeTransaction, CDOObject... historicalObjects)
430
  {
431
    // Objects eligible for revert, don't contains unmodified and resurrected
432
    Set<CDOObject> modifiedObjects = new HashSet<CDOObject>();
433
434
    Set<CDOObject> resurrectedObjects = new HashSet<CDOObject>();
435
436
    // IDs of all data passed to revert
437
    Set<CDOID> revertedIDs = new HashSet<CDOID>();
438
439
    ReentrantLock lock = lockView((InternalCDOView)activeTransaction);
440
441
    try
442
    {
443
      // PHASE 1 - sorting objects and resurrecting deleted objects. Resurrection is required to be passed first
444
      for (int i = 0; i < historicalObjects.length; i++)
445
      {
446
        InternalCDORevision historicalRevision = (InternalCDORevision)historicalObjects[i].cdoRevision();
447
        CDOID id = historicalRevision.getID();
448
        revertedIDs.add(id);
449
450
        // Detect objects which do not need to be reverted.
451
        // Assume that object has no reason to be reverted, if object is not revised and object is not registered to
452
        // active transaction (it could be currently DIRTY or TRANSIENT, but not committed yet)
453
        if (historicalRevision.getRevised() == 0 && !activeTransaction.isObjectRegistered(id))
454
        {
455
          continue;
456
        }
457
458
        InternalCDORevision revision = ((InternalCDOTransaction)activeTransaction).getRevision(
459
            historicalRevision.getID(), true);
460
        InternalCDOObject object = null;
461
462
        // if revision doesn't exist in current transaction or it is revised, we need to resurrect it
463
        if (revision == null)
464
        {
465
          object = resurrect(historicalRevision, (InternalCDOTransaction)activeTransaction);
466
          resurrectedObjects.add(object);
467
        }
468
469
        modifiedObjects.add(historicalObjects[i]);
470
      }
471
472
      // PHASE 2 - revert process
473
      Set<CDOID> detach = new HashSet<CDOID>();
474
      Set<CDOID> temporalSet = new HashSet<CDOID>();
475
      for (Iterator<CDOObject> it = modifiedObjects.iterator(); it.hasNext();)
476
      {
477
        CDOObject historicalObject = it.next();
478
        InternalCDORevision historicalRevision = (InternalCDORevision)historicalObject.cdoRevision();
479
        InternalCDOObject object = (InternalCDOObject)activeTransaction.getObject(historicalRevision.getID(), true);
480
481
        // Collect all contained object IDs at current revision and mark them for detaching
482
        collectContainedIDs(object, detach, true);
483
484
        // Revert process
485
        process(object, CDOEvent.REVERT, historicalRevision);
486
487
        // Need to check, which objects was left after revert not contained by parent.
488
        // If such object is found - it must be detached
489
        temporalSet.clear();
490
491
        // cannot collect recursive, because not all containment tree is reverted
492
        collectContainedIDs(object, temporalSet, false);
493
        detach.removeAll(temporalSet);
494
495
        if (resurrectedObjects.contains(object))
496
        {
497
          // Entering only if object is resurrected during revert.
498
          // If object's holder is not reverting, hence resurrected object must be manually attached to container.
499
          // Drawback is that container order could be lost comparing to historical
500
          CDOID containerID = (CDOID)object.cdoRevision().getContainerID();
501
502
          // Restoring container
503
          if (containerID != null && !containerID.isNull())
504
          {
505
            if (!revertedIDs.contains(containerID))
506
            {
507
              // Object container is not reverted. Hence we need to attach resurrected data manually.
508
              // Tricky thing is to calculate correct index in container, where resurrected object must be attached
509
              CDOObject container = activeTransaction.getObject(containerID);
510
              EStructuralFeature feature = ((InternalCDOObject)container).cdoInternalDynamicFeature(object
511
                  .cdoRevision().getContainingFeatureID());
512
513
              if (feature.isMany())
514
              {
515
                // Obtaining old index of object which is before restoring object
516
                EList<?> historicalList = (EList<?>)historicalObject.eContainer().eGet(feature);
517
                EList<?> currentList = (EList<?>)container.eGet(feature);
518
519
                int indexToInsert = findInListIndex(historicalObject, historicalList, currentList);
520
                object.eStore().add((InternalEObject)container, feature, indexToInsert, object);
521
              }
522
              else
523
              {
524
                Object currentObject = container.eGet(feature);
525
                object.eStore().add((InternalEObject)container, feature, EStore.NO_INDEX, object);
526
                if (currentObject instanceof InternalCDOObject)
527
                {
528
                  // We have unset currentObject from parent. Arrange it for detaching
529
                  collectContainedIDs(((InternalCDOObject)currentObject), detach, true);
530
                }
531
              }
532
            }
533
          }
534
535
          CDOID resourceID = object.cdoRevision().getResourceID();
536
          if (resourceID != null && !resourceID.isNull())
537
          {
538
            if (!revertedIDs.contains(resourceID))
539
            {
540
              // resource is not reverted. Hence we need to attach resurrected data
541
              CDOResource resource = (CDOResource)activeTransaction.getObject(resourceID);
542
              object.cdoRevision().setResourceID(CDOID.NULL);
543
              int indexToInsert = findInListIndex(historicalObject, historicalObject.cdoResource().getContents(),
544
                  resource.getContents());
545
              resource.getContents().add(indexToInsert, object);
546
            }
547
          }
548
        }
549
      }
550
551
      // PHASE 3 collect object which are not contained into resource or container - they must be detached
552
      // target for detaching are objects, which was removed from container but still points to it
553
      for (Iterator<CDOID> iterator = detach.iterator(); iterator.hasNext();)
554
      {
555
        CDOID cdoid = iterator.next();
556
        InternalCDOObject object = (InternalCDOObject)activeTransaction.getObject(cdoid, true);
557
        deleteDeatachedObject(object, revertedIDs);
558
      }
559
    }
560
    finally
561
    {
562
      lock.unlock();
563
    }
564
  }
565
566
  /**
567
   * Analyze objects recursively and delete it if it is eligible for detaching. If id is from the reverted ID's - it is
568
   * not eligible for removing. If detaching object is not found in the container to which it points - it is eligible
569
   * for detaching
570
   */
571
  private void deleteDeatachedObject(CDOObject object, Set<CDOID> revertedIds)
572
  {
573
574
    if (!revertedIds.contains(object.cdoID()))
575
    {
576
      // Containing children must be removed silently, because they can be already attached to new parent
577
      if (object instanceof InternalCDOObject)
578
      {
579
        for (EReference containmentReference : object.eClass().getEAllContainments())
580
        {
581
          if (EMFUtil.isPersistent(containmentReference))
582
          {
583
            ((InternalCDOObject)object).cdoRevision().clear(containmentReference);
584
          }
585
        }
586
587
        // Object is removed
588
        EcoreUtil.remove(object);
589
        detach((InternalCDOObject)object);
590
      }
591
    }
592
  }
593
594
  private int findInListIndex(CDOObject historicalObject, EList<?> historicalList, EList<?> currentList)
595
  {
596
    int oldIndex = historicalList.indexOf(historicalObject);
597
    int indexToInsert = -1;
598
    for (int i = oldIndex - 1; i >= 0 && indexToInsert == -1; i--)
599
    {
600
      CDOObject cdoObject = (CDOObject)historicalList.get(i);
601
      for (int j = currentList.size(); j <= 0; j--)
602
      {
603
        if (((CDOObject)currentList.get(j)).cdoID().equals(cdoObject))
604
        {
605
          indexToInsert = j;
606
          break;
607
        }
608
      }
609
    }
610
611
    if (indexToInsert == -1)
612
    {
613
      // Inserting at the beginning
614
      indexToInsert = 0;
615
    }
616
    else if (indexToInsert > currentList.size())
617
    {
618
      indexToInsert = currentList.size();
619
    }
620
621
    return indexToInsert;
622
  }
623
624
  private void collectContainedIDs(InternalCDOObject object, Set<CDOID> containedIDs, boolean recursive)
625
  {
626
    for (EReference containmentReference : object.eClass().getEAllContainments())
627
    {
628
      if (containmentReference.isMany())
629
      {
630
        int size = object.eStore().size(object, containmentReference);
631
        for (int k = 0; k < size; k++)
632
        {
633
          Object object2 = object.eStore().get(object, containmentReference, k);
634
          if (object2 instanceof InternalCDOObject)
635
          {
636
            InternalCDOObject internalObject = (InternalCDOObject)object2;
637
            if (recursive && !containedIDs.contains(internalObject.cdoID()))
638
            {
639
              collectContainedIDs(internalObject, containedIDs, recursive);
640
            }
641
            containedIDs.add(internalObject.cdoID());
642
          }
643
        }
644
      }
645
      else
646
      {
647
        Object object2 = object.eStore().get(object, containmentReference, EStore.NO_INDEX);
648
        if (object2 instanceof InternalCDOObject)
649
        {
650
          InternalCDOObject internalObject = (InternalCDOObject)object2;
651
          if (recursive && !containedIDs.contains(internalObject.cdoID()))
652
          {
653
            collectContainedIDs(internalObject, containedIDs, recursive);
654
          }
655
          containedIDs.add(internalObject.cdoID());
656
        }
657
      }
658
659
    }
660
  }
661
662
  private InternalCDOObject resurrect(InternalCDORevision historicalRevision, InternalCDOTransaction transaction)
663
  {
664
    // need to find latest version
665
    CDORevisionManager revisionManager = transaction.getSession().getRevisionManager();
666
    CDOID id = historicalRevision.getID();
667
    InternalCDORevision latestRevision = historicalRevision;
668
669
    // searching latest revision to obtain version
670
    for (int i = historicalRevision.getVersion() + 1; true; i++)
671
    {
672
      revisionManager.getRevision(id, transaction, 0, 0, true);
673
      InternalCDORevision revisionByVersion = (InternalCDORevision)revisionManager.getRevisionByVersion(id, transaction
674
          .getBranch().getVersion(i), CDORevision.DEPTH_NONE, true);
675
      if (revisionByVersion != null)
676
      {
677
        latestRevision = revisionByVersion;
678
      }
679
      else
680
      {
681
        break;
682
      }
683
    }
684
685
    EClass eClass = historicalRevision.getEClass();
686
687
    InternalCDOObject object = (InternalCDOObject)EcoreUtil.create(eClass);
688
689
    InternalCDORevision createRevision = (InternalCDORevision)CDORevisionFactory.DEFAULT.createRevision(eClass);
690
    createRevision.setID(id);
691
    createRevision.setVersion(latestRevision.getVersion());
692
    createRevision.setBranchPoint(transaction);
693
    object.cdoInternalSetRevision(createRevision);
694
    object.cdoInternalSetView(transaction);
695
    object.cdoInternalSetID(createRevision.getID());
696
    object.cdoInternalSetState(CDOState.NEW);
697
698
    transaction.registerObject(object);
699
    transaction.registerNew(object);
700
701
    return object;
702
  }
403
703
404
  /**
704
  /**
405
   * @since 3.0
705
   * @since 3.0
Lines 701-707 Link Here
701
      // CDORevision originalRevision = revisionManager.getRevisionByVersion(id, branchVersion, -1, true);
1001
      // CDORevision originalRevision = revisionManager.getRevisionByVersion(id, branchVersion, -1, true);
702
      CDORevisionDelta revisionDelta = CDORevisionDeltaUtil.create(formerRevision, revision);
1002
      CDORevisionDelta revisionDelta = CDORevisionDeltaUtil.create(formerRevision, revision);
703
      transaction.registerRevisionDelta(revisionDelta);
1003
      transaction.registerRevisionDelta(revisionDelta);
704
      transaction.registerDirty(object, null);
1004
      transaction.registerDirty(object, (CDOFeatureDelta)null);
705
      changeState(object, CDOState.DIRTY);
1005
      changeState(object, CDOState.DIRTY);
706
1006
707
      // Add the object to the set of reattached objects
1007
      // Add the object to the set of reattached objects
Lines 710-715 Link Here
710
  }
1010
  }
711
1011
712
  /**
1012
  /**
1013
   * @author Egidijus Vaisnora
1014
   */
1015
  private final class RevertTransition implements
1016
      ITransition<CDOState, CDOEvent, InternalCDOObject, InternalCDORevision>
1017
  {
1018
1019
    public void execute(InternalCDOObject object, CDOState state, CDOEvent event, InternalCDORevision historicalRevision)
1020
    {
1021
1022
      InternalCDORevision originalRevision = object.cdoRevision();
1023
      InternalCDORevision originalRevisionModify = originalRevision.copy();
1024
1025
      EStructuralFeature[] allPersistentFeatures = CDOModelUtil
1026
          .getAllPersistentFeatures(historicalRevision.getEClass());
1027
      for (int j = 0; j < allPersistentFeatures.length; j++)
1028
      {
1029
1030
        ((CDORevisionImpl)originalRevisionModify).setValue(allPersistentFeatures[j],
1031
            historicalRevision.getValue(allPersistentFeatures[j]));
1032
      }
1033
      originalRevisionModify.setContainerID(historicalRevision.getContainerID());
1034
      originalRevisionModify.setContainingFeatureID(historicalRevision.getContainingFeatureID());
1035
      originalRevisionModify.setResourceID(historicalRevision.getResourceID());
1036
1037
      object.cdoInternalSetRevision(originalRevisionModify);
1038
1039
      // NEW objects are resurrected objects or really new
1040
      if (object.cdoState() != CDOState.NEW)
1041
      {
1042
        CDORevisionDelta delta = CDORevisionDeltaUtil.create(originalRevision, originalRevisionModify);
1043
        InternalCDOTransaction transaction = object.cdoView().toTransaction();
1044
        transaction.registerDirty(object, delta);
1045
        changeState(object, CDOState.DIRTY);
1046
      }
1047
    }
1048
1049
  }
1050
1051
  /**
713
   * @author Eike Stepper
1052
   * @author Eike Stepper
714
   */
1053
   */
715
  private static final class DetachTransition implements
1054
  private static final class DetachTransition implements
Lines 978-982 Link Here
978
 */
1317
 */
979
enum CDOEvent
1318
enum CDOEvent
980
{
1319
{
981
  PREPARE, ATTACH, DETACH, REATTACH, READ, WRITE, INVALIDATE, DETACH_REMOTE, COMMIT, ROLLBACK
1320
  PREPARE, ATTACH, DETACH, REATTACH, READ, WRITE, INVALIDATE, DETACH_REMOTE, COMMIT, ROLLBACK,
1321
1322
  /**
1323
   * Event for reverting object to historical state
1324
   */
1325
  REVERT
982
}
1326
}
(-)src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java (-1 / +47 lines)
Lines 263-268 Link Here
263
    return conflict != 0;
263
    return conflict != 0;
264
  }
264
  }
265
265
266
  /**
267
   * Historical cdo objects, taken from audit view. These objects will be used to restore CDOObjects in current
268
   * transaction. If CDOObject doesn't exist for given historical CDOID, it will initiate new CDO object creation with
269
   * old (historical) CDOID - object will be resurrected. Object, attached in current CDOObject but not found in
270
   * historical CDOObject, will be detached.
271
   * <p>
272
   * <strong>Note:</strong> Doesn't support revert for CDOObjects, which in current transaction have state
273
   * {@link CDOState#DIRTY DIRTY} and {@link CDOState#TRANSIENT TRANSIENT}
274
   * 
275
   * @since 3.0
276
   */
277
  public void revert(CDOObject... historicalObjects)
278
  {
279
    CDOStateMachine.INSTANCE.revert(this, historicalObjects);
280
  }
281
266
  public void setConflict(InternalCDOObject object)
282
  public void setConflict(InternalCDOObject object)
267
  {
283
  {
268
    ConflictEvent event = new ConflictEvent(object, conflict == 0);
284
    ConflictEvent event = new ConflictEvent(object, conflict == 0);
Lines 1401-1406 Link Here
1401
    lastSavepoint.getRevisionDeltas().putIfAbsent(revisionDelta.getID(), revisionDelta);
1417
    lastSavepoint.getRevisionDeltas().putIfAbsent(revisionDelta.getID(), revisionDelta);
1402
  }
1418
  }
1403
1419
1420
  public void registerDirty(InternalCDOObject object, CDORevisionDelta revisionDelta)
1421
  {
1422
    if (TRACER.isEnabled())
1423
    {
1424
      TRACER.format("Registering dirty object {0}", object);
1425
    }
1426
1427
    // rewriting old revision delta
1428
    ConcurrentMap<CDOID, CDORevisionDelta> revisionDeltas = lastSavepoint.getRevisionDeltas();
1429
    if (revisionDeltas.containsKey(object.cdoID()))
1430
    {
1431
      // recursively add feature deltas
1432
      if (revisionDelta != null)
1433
      {
1434
        List<CDOFeatureDelta> featureDeltas = revisionDelta.getFeatureDeltas();
1435
        for (int i = 0; i < featureDeltas.size(); i++)
1436
        {
1437
          registerFeatureDelta(object, featureDeltas.get(i));
1438
        }
1439
      }
1440
    }
1441
    else
1442
    {
1443
      revisionDeltas.put(object.cdoID(), revisionDelta);
1444
1445
      registerNew(lastSavepoint.getDirtyObjects(), object);
1446
    }
1447
1448
  }
1449
1404
  public void registerDirty(InternalCDOObject object, CDOFeatureDelta featureDelta)
1450
  public void registerDirty(InternalCDOObject object, CDOFeatureDelta featureDelta)
1405
  {
1451
  {
1406
    if (TRACER.isEnabled())
1452
    if (TRACER.isEnabled())
Lines 1654-1660 Link Here
1654
          CDORevision revision = object.cdoRevision().copy();
1700
          CDORevision revision = object.cdoRevision().copy();
1655
          merger.merge(object, delta);
1701
          merger.merge(object, delta);
1656
          registerRevisionDelta(delta);
1702
          registerRevisionDelta(delta);
1657
          registerDirty(object, null);
1703
          registerDirty(object, (CDOFeatureDelta)null);
1658
1704
1659
          if (delta.getVersion() < revision.getVersion())
1705
          if (delta.getVersion() < revision.getVersion())
1660
          {
1706
          {
(-)src/org/eclipse/emf/spi/cdo/InternalCDOTransaction.java (-2 / +10 lines)
Lines 75-80 Link Here
75
75
76
  public void registerNew(InternalCDOObject object);
76
  public void registerNew(InternalCDOObject object);
77
77
78
  /**
79
   * Registers object as dirty with given <code>revisionDelta</code>. If changes are registered, merges registered
80
   * changes with a new given revision delta
81
   * 
82
   * @since 3.0
83
   */
84
  public void registerDirty(InternalCDOObject object, CDORevisionDelta revisionDelta);
85
78
  public void registerDirty(InternalCDOObject object, CDOFeatureDelta featureDelta);
86
  public void registerDirty(InternalCDOObject object, CDOFeatureDelta featureDelta);
79
87
80
  public void registerFeatureDelta(InternalCDOObject object, CDOFeatureDelta featureDelta);
88
  public void registerFeatureDelta(InternalCDOObject object, CDOFeatureDelta featureDelta);
Lines 88-95 Link Here
88
  /**
96
  /**
89
   * @since 3.0
97
   * @since 3.0
90
   */
98
   */
91
  public CDOChangeSetData applyChangeSetData(CDOChangeSetData changeSetData,
99
  public CDOChangeSetData applyChangeSetData(CDOChangeSetData changeSetData, CDORevisionAvailabilityInfo ancestorInfo,
92
      CDORevisionAvailabilityInfo ancestorInfo, CDORevisionAvailabilityInfo targetInfo, CDORevisionAvailabilityInfo sourceInfo);
100
      CDORevisionAvailabilityInfo targetInfo, CDORevisionAvailabilityInfo sourceInfo);
93
101
94
  /**
102
  /**
95
   * @since 3.0
103
   * @since 3.0
(-)src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionManagerImpl.java (-4 / +4 lines)
Lines 208-215 Link Here
208
  public InternalCDORevision getRevisionByVersion(CDOID id, CDOBranchVersion branchVersion, int referenceChunk,
208
  public InternalCDORevision getRevisionByVersion(CDOID id, CDOBranchVersion branchVersion, int referenceChunk,
209
      boolean loadOnDemand)
209
      boolean loadOnDemand)
210
  {
210
  {
211
    checkArg(branchVersion.getVersion() >= CDOBranchVersion.FIRST_VERSION, "Invalid version: "
211
    checkArg(branchVersion.getVersion() >= CDOBranchVersion.FIRST_VERSION,
212
        + branchVersion.getVersion());
212
        "Invalid version: " + branchVersion.getVersion());
213
    acquireAtomicRequestLock(loadAndAddLock);
213
    acquireAtomicRequestLock(loadAndAddLock);
214
214
215
    try
215
    try
Lines 400-407 Link Here
400
        CDOBranchVersion target = pointer.getTarget();
400
        CDOBranchVersion target = pointer.getTarget();
401
        if (target instanceof InternalCDORevision)
401
        if (target instanceof InternalCDORevision)
402
        {
402
        {
403
          revision = new PointerCDORevision(pointer.getEClass(), pointer.getID(), pointer.getBranch(), pointer
403
          revision = new PointerCDORevision(pointer.getEClass(), pointer.getID(), pointer.getBranch(),
404
              .getRevised(), CDOBranchUtil.copyBranchVersion(target));
404
              pointer.getRevised(), CDOBranchUtil.copyBranchVersion(target));
405
        }
405
        }
406
      }
406
      }
407
407
(-)src/org/eclipse/emf/cdo/spi/common/revision/DetachedCDORevision.java (-1 / +18 lines)
Lines 27-37 Link Here
27
27
28
  private long timeStamp;
28
  private long timeStamp;
29
29
30
  private long revised;
31
30
  public DetachedCDORevision(EClass eClass, CDOID id, CDOBranch branch, int version, long timeStamp)
32
  public DetachedCDORevision(EClass eClass, CDOID id, CDOBranch branch, int version, long timeStamp)
31
  {
33
  {
34
    this(eClass, id, branch, version, timeStamp, UNSPECIFIED_DATE);
35
  }
36
37
  /**
38
   * @since 3.0.1
39
   */
40
  public DetachedCDORevision(EClass eClass, CDOID id, CDOBranch branch, int version, long timeStamp, long revised)
41
  {
32
    super(eClass, id, branch);
42
    super(eClass, id, branch);
33
    this.version = version;
43
    this.version = version;
34
    this.timeStamp = timeStamp;
44
    this.timeStamp = timeStamp;
45
    this.revised = revised;
35
  }
46
  }
36
47
37
  @Override
48
  @Override
Lines 49-55 Link Here
49
  @Override
60
  @Override
50
  public long getRevised()
61
  public long getRevised()
51
  {
62
  {
52
    return UNSPECIFIED_DATE;
63
    return revised;
53
  }
64
  }
54
65
55
  @Override
66
  @Override
Lines 57-60 Link Here
57
  {
68
  {
58
    return MessageFormat.format("DetachedCDORevision[{0}:{1}v{2}]", getID(), getBranch().getID(), version);
69
    return MessageFormat.format("DetachedCDORevision[{0}:{1}v{2}]", getID(), getBranch().getID(), version);
59
  }
70
  }
71
72
  @Override
73
  public void setRevised(long revised)
74
  {
75
    this.revised = revised;
76
  }
60
}
77
}
(-)src/org/eclipse/emf/cdo/spi/common/revision/RevisionInfo.java (-5 / +17 lines)
Lines 10-15 Link Here
10
 */
10
 */
11
package org.eclipse.emf.cdo.spi.common.revision;
11
package org.eclipse.emf.cdo.spi.common.revision;
12
12
13
import org.eclipse.emf.cdo.common.branch.CDOBranch;
13
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
14
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
14
import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
15
import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
15
import org.eclipse.emf.cdo.common.id.CDOID;
16
import org.eclipse.emf.cdo.common.id.CDOID;
Lines 192-198 Link Here
192
    result = (InternalCDORevision)in.readCDORevision();
193
    result = (InternalCDORevision)in.readCDORevision();
193
  }
194
  }
194
195
195
  protected void doWriteResult(CDODataOutput out, InternalCDORevision revision, int referenceChunk) throws IOException
196
  protected InternalCDORevision doReadResult(CDODataInput in) throws IOException
197
  {
198
    return doReadResult(in, getID(), requestedBranchPoint.getBranch());
199
  }
200
201
  /**
202
   * @since 3.0.1
203
   */
204
  public static void doWriteResult(CDODataOutput out, InternalCDORevision revision, int referenceChunk)
205
      throws IOException
196
  {
206
  {
197
    if (revision == null)
207
    if (revision == null)
198
    {
208
    {
Lines 221-226 Link Here
221
      out.writeByte(DETACHED_RESULT);
231
      out.writeByte(DETACHED_RESULT);
222
      out.writeCDOClassifierRef(detached.getEClass());
232
      out.writeCDOClassifierRef(detached.getEClass());
223
      out.writeLong(detached.getTimeStamp());
233
      out.writeLong(detached.getTimeStamp());
234
      out.writeLong(detached.getRevised());
224
      out.writeInt(detached.getVersion());
235
      out.writeInt(detached.getVersion());
225
    }
236
    }
226
    else
237
    else
Lines 230-236 Link Here
230
    }
241
    }
231
  }
242
  }
232
243
233
  protected InternalCDORevision doReadResult(CDODataInput in) throws IOException
244
  public static InternalCDORevision doReadResult(CDODataInput in, CDOID id, CDOBranch branch) throws IOException
234
  {
245
  {
235
    byte type = in.readByte();
246
    byte type = in.readByte();
236
    switch (type)
247
    switch (type)
Lines 242-257 Link Here
242
    {
253
    {
243
      EClassifier classifier = in.readCDOClassifierRefAndResolve();
254
      EClassifier classifier = in.readCDOClassifierRefAndResolve();
244
      long revised = in.readLong();
255
      long revised = in.readLong();
245
      InternalCDORevision target = doReadResult(in);
256
      InternalCDORevision target = doReadResult(in, id, branch);
246
      return new PointerCDORevision((EClass)classifier, id, requestedBranchPoint.getBranch(), revised, target);
257
      return new PointerCDORevision((EClass)classifier, id, branch, revised, target);
247
    }
258
    }
248
259
249
    case DETACHED_RESULT:
260
    case DETACHED_RESULT:
250
    {
261
    {
251
      EClassifier classifier = in.readCDOClassifierRefAndResolve();
262
      EClassifier classifier = in.readCDOClassifierRefAndResolve();
252
      long timeStamp = in.readLong();
263
      long timeStamp = in.readLong();
264
      long revised = in.readLong();
253
      int version = in.readInt();
265
      int version = in.readInt();
254
      return new DetachedCDORevision((EClass)classifier, id, requestedBranchPoint.getBranch(), version, timeStamp);
266
      return new DetachedCDORevision((EClass)classifier, id, branch, version, timeStamp, revised);
255
    }
267
    }
256
268
257
    case NORMAL_RESULT:
269
    case NORMAL_RESULT:
(-)src/org/eclipse/emf/cdo/internal/net4j/protocol/LoadRevisionByVersionRequest.java (-1 / +2 lines)
Lines 17-22 Link Here
17
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
17
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
18
import org.eclipse.emf.cdo.internal.net4j.bundle.OM;
18
import org.eclipse.emf.cdo.internal.net4j.bundle.OM;
19
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
19
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
20
import org.eclipse.emf.cdo.spi.common.revision.RevisionInfo;
20
21
21
import org.eclipse.net4j.util.om.trace.ContextTracer;
22
import org.eclipse.net4j.util.om.trace.ContextTracer;
22
23
Lines 71-77 Link Here
71
  @Override
72
  @Override
72
  protected InternalCDORevision confirming(CDODataInput in) throws IOException
73
  protected InternalCDORevision confirming(CDODataInput in) throws IOException
73
  {
74
  {
74
    return (InternalCDORevision)in.readCDORevision();
75
    return RevisionInfo.doReadResult(in, id, branchVersion.getBranch());
75
  }
76
  }
76
77
77
  @Override
78
  @Override
(-)src/org/eclipse/emf/cdo/server/internal/db/DBRevisionHandler.java (-2 / +2 lines)
Lines 21-28 Link Here
21
  {
21
  {
22
    if (revision.getVersion() < CDOBranchVersion.FIRST_VERSION - 1)
22
    if (revision.getVersion() < CDOBranchVersion.FIRST_VERSION - 1)
23
    {
23
    {
24
      revision = new DetachedCDORevision(revision.getEClass(), revision.getID(), revision.getBranch(), -revision
24
      revision = new DetachedCDORevision(revision.getEClass(), revision.getID(), revision.getBranch(),
25
          .getVersion(), revision.getTimeStamp());
25
          -revision.getVersion(), revision.getTimeStamp(), revision.getRevised());
26
    }
26
    }
27
27
28
    delegate.handleRevision(revision);
28
    delegate.handleRevision(revision);
(-)src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java (-1 / +9 lines)
Lines 206-212 Link Here
206
      int version = revision.getVersion();
206
      int version = revision.getVersion();
207
      if (version < CDOBranchVersion.FIRST_VERSION - 1)
207
      if (version < CDOBranchVersion.FIRST_VERSION - 1)
208
      {
208
      {
209
        return new DetachedCDORevision(eClass, id, revision.getBranch(), -version, revision.getTimeStamp());
209
        return new DetachedCDORevision(eClass, id, revision.getBranch(), -version, revision.getTimeStamp(),
210
            revision.getRevised());
210
      }
211
      }
211
212
212
      return revision;
213
      return revision;
Lines 240-245 Link Here
240
241
241
      // if audit support is present, just use the audit method
242
      // if audit support is present, just use the audit method
242
      success = ((IClassMappingAuditSupport)mapping).readRevisionByVersion(this, revision, listChunk);
243
      success = ((IClassMappingAuditSupport)mapping).readRevisionByVersion(this, revision, listChunk);
244
      if (success && revision.getVersion() < CDOBranchVersion.FIRST_VERSION)
245
      {
246
        // it is detached revision
247
        revision = new DetachedCDORevision(eClass, id, revision.getBranch(), -revision.getVersion(),
248
            revision.getTimeStamp(), revision.getRevised());
249
250
      }
243
    }
251
    }
244
    else
252
    else
245
    {
253
    {
(-)src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java (-2 / +3 lines)
Lines 15-20 Link Here
15
15
16
import org.eclipse.emf.cdo.common.branch.CDOBranch;
16
import org.eclipse.emf.cdo.common.branch.CDOBranch;
17
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
17
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
18
import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
18
import org.eclipse.emf.cdo.common.id.CDOID;
19
import org.eclipse.emf.cdo.common.id.CDOID;
19
import org.eclipse.emf.cdo.common.id.CDOIDUtil;
20
import org.eclipse.emf.cdo.common.id.CDOIDUtil;
20
import org.eclipse.emf.cdo.common.revision.CDORevision;
21
import org.eclipse.emf.cdo.common.revision.CDORevision;
Lines 153-159 Link Here
153
154
154
    builder = new StringBuilder(sqlSelectAttributesPrefix);
155
    builder = new StringBuilder(sqlSelectAttributesPrefix);
155
156
156
    builder.append(CDODBSchema.ATTRIBUTES_VERSION);
157
    builder.append("ABS(" + CDODBSchema.ATTRIBUTES_VERSION + ")");
157
    builder.append("=?)"); //$NON-NLS-1$
158
    builder.append("=?)"); //$NON-NLS-1$
158
159
159
    sqlSelectAttributesByVersion = builder.toString();
160
    sqlSelectAttributesByVersion = builder.toString();
Lines 293-299 Link Here
293
      boolean success = readValuesFromStatement(pstmt, revision, accessor);
294
      boolean success = readValuesFromStatement(pstmt, revision, accessor);
294
295
295
      // Read multival tables only if revision exists
296
      // Read multival tables only if revision exists
296
      if (success)
297
      if (success && revision.getVersion() >= CDOBranchVersion.FIRST_VERSION)
297
      {
298
      {
298
        readLists(accessor, revision, listChunk);
299
        readLists(accessor, revision, listChunk);
299
      }
300
      }
(-)src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingClassMapping.java (-1 / +1 lines)
Lines 327-333 Link Here
327
      boolean success = readValuesFromStatement(pstmt, revision, accessor);
327
      boolean success = readValuesFromStatement(pstmt, revision, accessor);
328
328
329
      // Read multival tables only if revision exists
329
      // Read multival tables only if revision exists
330
      if (success)
330
      if (success && revision.getVersion() >= CDOBranchVersion.FIRST_VERSION)
331
      {
331
      {
332
        readLists(accessor, revision, listChunk);
332
        readLists(accessor, revision, listChunk);
333
      }
333
      }
(-)src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateCommitContext.java (+1 lines)
Lines 62-67 Link Here
62
    {
62
    {
63
      newObjects.put(cdoRevision.getID(), cdoRevision);
63
      newObjects.put(cdoRevision.getID(), cdoRevision);
64
    }
64
    }
65
65
  }
66
  }
66
67
67
  public InternalCDORevision getDirtyObject(CDOID id)
68
  public InternalCDORevision getDirtyObject(CDOID id)
(-)src/org/eclipse/emf/cdo/server/internal/net4j/protocol/LoadRevisionByVersionIndication.java (-4 / +5 lines)
Lines 15-22 Link Here
15
import org.eclipse.emf.cdo.common.protocol.CDODataInput;
15
import org.eclipse.emf.cdo.common.protocol.CDODataInput;
16
import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
16
import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
17
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
17
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
18
import org.eclipse.emf.cdo.common.revision.CDORevision;
19
import org.eclipse.emf.cdo.server.internal.net4j.bundle.OM;
18
import org.eclipse.emf.cdo.server.internal.net4j.bundle.OM;
19
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
20
import org.eclipse.emf.cdo.spi.common.revision.RevisionInfo;
20
21
21
import org.eclipse.net4j.util.om.trace.ContextTracer;
22
import org.eclipse.net4j.util.om.trace.ContextTracer;
22
23
Lines 66-73 Link Here
66
  @Override
67
  @Override
67
  protected void responding(CDODataOutput out) throws IOException
68
  protected void responding(CDODataOutput out) throws IOException
68
  {
69
  {
69
    CDORevision revision = getRepository().getRevisionManager().getRevisionByVersion(id, branchVersion, referenceChunk,
70
    InternalCDORevision revision = getRepository().getRevisionManager().getRevisionByVersion(id, branchVersion,
70
        true);
71
        referenceChunk, true);
71
    out.writeCDORevision(revision, referenceChunk);
72
    RevisionInfo.doWriteResult(out, revision, referenceChunk);
72
  }
73
  }
73
}
74
}
(-)src/org/eclipse/emf/cdo/server/internal/objectivity/ObjectivityStoreAccessor.java (-1 / +1 lines)
Lines 887-893 Link Here
887
      }
887
      }
888
      EClass eClass = ObjySchema.getEClass(getStore(), objyObject.objyClass());
888
      EClass eClass = ObjySchema.getEClass(getStore(), objyObject.objyClass());
889
      return new DetachedCDORevision(eClass, id, branchPoint.getBranch(), -objyRevision.getVersion(),
889
      return new DetachedCDORevision(eClass, id, branchPoint.getBranch(), -objyRevision.getVersion(),
890
          objyRevision.getCreationTime());
890
          objyRevision.getCreationTime(), objyRevision.getRevisedTime());
891
    }
891
    }
892
892
893
    CDOBranchPoint branchPoint2 = revision.getBranch().getPoint(objyRevision.getCreationTime());
893
    CDOBranchPoint branchPoint2 = revision.getBranch().getPoint(objyRevision.getCreationTime());
(-)src/org/eclipse/emf/cdo/tests/AllConfigs.java (+2 lines)
Lines 144-149 Link Here
144
    testClasses.add(DynamicPackageTest.class);
144
    testClasses.add(DynamicPackageTest.class);
145
    testClasses.add(LegacyTest.class);
145
    testClasses.add(LegacyTest.class);
146
    testClasses.add(XRefTest.class);
146
    testClasses.add(XRefTest.class);
147
    testClasses.add(RevertTest.class);
148
    testClasses.add(DetachedCDORevisionConsistencyTest.class);
147
149
148
    // Specific for MEMStore
150
    // Specific for MEMStore
149
    testClasses.add(MEMStoreQueryTest.class);
151
    testClasses.add(MEMStoreQueryTest.class);
(-)src/org/eclipse/emf/cdo/tests/DetachedCDORevisionConsistencyTest.java (+322 lines)
Added Link Here
1
/**
2
 * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *    Eike Stepper - initial API and implementation
10
 */
11
package org.eclipse.emf.cdo.tests;
12
13
import org.eclipse.emf.cdo.CDOObject;
14
import org.eclipse.emf.cdo.common.id.CDOID;
15
import org.eclipse.emf.cdo.common.revision.CDORevision;
16
import org.eclipse.emf.cdo.common.revision.CDORevisionManager;
17
import org.eclipse.emf.cdo.eresource.CDOResource;
18
import org.eclipse.emf.cdo.net4j.CDOSession;
19
import org.eclipse.emf.cdo.spi.common.revision.DetachedCDORevision;
20
import org.eclipse.emf.cdo.spi.server.InternalRepository;
21
import org.eclipse.emf.cdo.tests.RevertTest.RevertEqualityHelper;
22
import org.eclipse.emf.cdo.tests.config.IRepositoryConfig;
23
import org.eclipse.emf.cdo.tests.model1.Category;
24
import org.eclipse.emf.cdo.tests.model1.Company;
25
import org.eclipse.emf.cdo.tests.model1.Customer;
26
import org.eclipse.emf.cdo.tests.model1.OrderDetail;
27
import org.eclipse.emf.cdo.tests.model1.Product1;
28
import org.eclipse.emf.cdo.tests.model1.PurchaseOrder;
29
import org.eclipse.emf.cdo.tests.model1.SalesOrder;
30
import org.eclipse.emf.cdo.tests.model1.Supplier;
31
import org.eclipse.emf.cdo.transaction.CDOTransaction;
32
import org.eclipse.emf.cdo.util.CDOUtil;
33
import org.eclipse.emf.cdo.util.CommitException;
34
import org.eclipse.emf.cdo.util.ObjectNotFoundException;
35
import org.eclipse.emf.cdo.view.CDOView;
36
37
import org.eclipse.emf.internal.cdo.transaction.CDOTransactionImpl;
38
39
import org.eclipse.emf.common.util.TreeIterator;
40
import org.eclipse.emf.ecore.EObject;
41
import org.eclipse.emf.ecore.util.EcoreUtil;
42
43
import java.util.ArrayList;
44
import java.util.Calendar;
45
import java.util.HashSet;
46
import java.util.Iterator;
47
import java.util.List;
48
import java.util.Set;
49
50
import junit.framework.Assert;
51
52
/**
53
 * Test checks if detached revision (holes) breaks server environment
54
 * 
55
 * @author Egidijus Vaisnora
56
 */
57
public class DetachedCDORevisionConsistencyTest extends AbstractCDOTest
58
{
59
  private static final String RESOURCE_NAME = "resource";
60
61
  private long timeStampOfInitialCommit;
62
63
  private long timeStampOfHoleCommit;
64
65
  private Set<CDOID> cdoid;
66
67
  @Override
68
  protected void doSetUp() throws Exception
69
  {
70
    super.doSetUp();
71
72
    // create model history
73
    CDOSession session = (CDOSession)openSession();
74
    CDOTransaction openTransaction = session.openTransaction();
75
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
76
77
    // creating initial commit
78
    Company createdCompany = getModel1Factory().createCompany();
79
    createdCompany.setName("CompanyTesting");
80
    createdCompany.setCity("City");
81
    createdCompany.setStreet("Street");
82
83
    Supplier createSupplier = getModel1Factory().createSupplier();
84
    createSupplier.setName("CompanySupplier");
85
    createSupplier.setCity("CitySupplier");
86
    createSupplier.setStreet("StreetSupplier");
87
    createdCompany.getSuppliers().add(createSupplier);
88
89
    Category category = getModel1Factory().createCategory();
90
    category.setName("Category");
91
    createdCompany.getCategories().add(category);
92
    resource.getContents().add(createdCompany);
93
94
    Customer customer = getModel1Factory().createCustomer();
95
    customer.setCity("city");
96
    customer.setName("name");
97
    customer.setStreet("street");
98
    createdCompany.getCustomers().add(customer);
99
100
    // product 1
101
    Product1 createProduct1 = getModel1Factory().createProduct1();
102
    createProduct1.setDescription("description");
103
    createProduct1.setName("product name");
104
    category.getProducts().add(createProduct1);
105
106
    // second product
107
    Product1 createProduct2 = getModel1Factory().createProduct1();
108
    createProduct2.setDescription("description");
109
    createProduct2.setName("product name");
110
    category.getProducts().add(createProduct2);
111
112
    // customer
113
    Customer createCustomer = getModel1Factory().createCustomer();
114
    createCustomer.setName("customer name");
115
    createdCompany.getCustomers().add(createCustomer);
116
117
    // purchase order
118
    OrderDetail createOrderDetail = getModel1Factory().createOrderDetail();
119
    createOrderDetail.setPrice(12f);
120
    createOrderDetail.setProduct(createProduct1);
121
122
    PurchaseOrder createPurchaseOrder = getModel1Factory().createPurchaseOrder();
123
    createPurchaseOrder.setDate(Calendar.getInstance().getTime());
124
    createPurchaseOrder.getOrderDetails().add(createOrderDetail);
125
    createdCompany.getPurchaseOrders().add(createPurchaseOrder);
126
127
    // sale order
128
    OrderDetail createOrderDetail2 = getModel1Factory().createOrderDetail();
129
    createOrderDetail.setPrice(13f);
130
    createOrderDetail.setProduct(createProduct2);
131
132
    SalesOrder createSaleOrder = getModel1Factory().createSalesOrder();
133
    createSaleOrder.setId(-1);
134
    createSaleOrder.setCustomer(createCustomer);
135
    createSaleOrder.getOrderDetails().add(createOrderDetail2);
136
    resource.getContents().add(createSaleOrder);
137
138
    timeStampOfInitialCommit = openTransaction.commit().getTimeStamp();
139
140
    // collect id's
141
    cdoid = new HashSet<CDOID>();
142
    for (TreeIterator<EObject> allContents = resource.getAllContents(); allContents.hasNext();)
143
    {
144
      CDOObject next = (CDOObject)allContents.next();
145
      cdoid.add(next.cdoID());
146
    }
147
148
    // making holes - detaching
149
    List<EObject> contents = new ArrayList<EObject>(resource.getContents());
150
    for (int i = 0; i < contents.size(); i++)
151
    {
152
      EcoreUtil.delete(contents.get(i), true);
153
    }
154
155
    timeStampOfHoleCommit = openTransaction.commit().getTimeStamp();
156
157
    session.close();
158
  }
159
160
  /**
161
   * Restart repository and check project loading is working
162
   * 
163
   * @throws Exception
164
   */
165
  public void testReloadingRevisions() throws Exception
166
  {
167
168
    List<Integer> detachedVersions = new ArrayList<Integer>();
169
    List<Long> versionTimestamps = new ArrayList<Long>();
170
    detachedVersions.add(2);
171
    versionTimestamps.add(timeStampOfInitialCommit);
172
    versionTimestamps.add(timeStampOfHoleCommit);
173
    clearServerRevisionCache();
174
175
    // load whole deleted resource
176
    CDOSession session = (CDOSession)openSession();
177
    CDOTransaction openTransaction = session.openTransaction();
178
    CDOResource resource = openTransaction.getResource(RESOURCE_NAME);
179
180
    // loading
181
    CDOUtil.load(resource, openTransaction);
182
183
    Assert.assertEquals(resource.getContents().size(), 0);
184
    session.close();
185
186
    // revert, create version 3
187
    clearServerRevisionCache();
188
    long restoredTimestamp = revertResource(RESOURCE_NAME, timeStampOfInitialCommit);
189
    versionTimestamps.add(restoredTimestamp);
190
191
    // assert
192
    clearServerRevisionCache();
193
    assertResources(RESOURCE_NAME, timeStampOfInitialCommit, restoredTimestamp, null);
194
195
    // revert to deleted, create version 4
196
    clearServerRevisionCache();
197
    long restoredHolesTimestamp = revertResource(RESOURCE_NAME, timeStampOfHoleCommit);
198
    detachedVersions.add(4);
199
    versionTimestamps.add(restoredHolesTimestamp);
200
201
    // assert
202
    clearServerRevisionCache();
203
    assertResources(RESOURCE_NAME, timeStampOfHoleCommit, restoredHolesTimestamp, cdoid);
204
205
    org.eclipse.emf.cdo.session.CDOSession openSession = openSession();
206
    CDORevisionManager revisionManager = openSession.getRevisionManager();
207
    for (int i = 0; i < versionTimestamps.size(); i++)
208
    {
209
      clearServerRevisionCache();
210
      int version = i + 1;
211
      boolean detachedVersion = detachedVersions.contains(version);
212
      for (Iterator<CDOID> it = cdoid.iterator(); it.hasNext();)
213
      {
214
        CDOID next = it.next();
215
216
        CDORevision revisionByVersion = revisionManager.getRevisionByVersion(next, openSession.getBranchManager()
217
            .getMainBranch().getVersion(version), CDORevision.DEPTH_NONE, true);
218
        assertRevisionTakenByVersion(revisionByVersion, detachedVersion);
219
220
        CDORevision revisionByTimestamp = revisionManager.getRevision(next, openSession.getBranchManager()
221
            .getMainBranch().getPoint(versionTimestamps.get(i)), CDORevision.DEPTH_NONE, 0, true);
222
        assertRevisionTakenByTimestamp(revisionByTimestamp, detachedVersion);
223
      }
224
225
    }
226
    openSession.close();
227
228
  }
229
230
  private void clearServerRevisionCache()
231
  {
232
    InternalRepository repository = getScenario().getRepositoryConfig()
233
        .getRepository(IRepositoryConfig.REPOSITORY_NAME);
234
    clearCache(repository.getRevisionManager());
235
  }
236
237
  private long revertResource(String resourceName, long timestamp) throws CommitException
238
  {
239
    CDOSession session = (CDOSession)openSession();
240
    CDOView openAudit = session.openView(timestamp);
241
    CDOResource historicalResource = openAudit.getResource(resourceName);
242
    List<CDOObject> tmpObjects = collectAllRevertDataFromResource(historicalResource);
243
244
    CDOTransaction openTransaction2 = session.openTransaction();
245
    ((CDOTransactionImpl)openTransaction2).revert(tmpObjects.toArray(new CDOObject[tmpObjects.size()]));
246
    long timestampCommit = openTransaction2.commit().getTimeStamp();
247
    session.close();
248
    return timestampCommit;
249
  }
250
251
  private List<CDOObject> collectAllRevertDataFromResource(CDOResource historicalResource)
252
  {
253
    List<CDOObject> tmpObjects = new ArrayList<CDOObject>();
254
    tmpObjects.add(historicalResource);
255
    for (TreeIterator<EObject> allContents = historicalResource.getAllContents(); allContents.hasNext();)
256
    {
257
      CDOObject next = (CDOObject)allContents.next();
258
      tmpObjects.add(next);
259
    }
260
261
    return tmpObjects;
262
  }
263
264
  private void assertResources(String resourceName, long timestamp1, long timestamp2, Set<CDOID> detached)
265
  {
266
    CDOSession session;
267
    session = (CDOSession)openSession();
268
    CDOView historyView1 = session.openView(timestamp1);
269
    CDOResource historyResource1 = historyView1.getResource(resourceName);
270
    CDOView historyView2 = session.openView(timestamp2);
271
    CDOResource currentResource2 = historyView2.getResource(resourceName);
272
273
    // assertTrue(EcoreUtil.equals(currentResource, historyResource));
274
    assertTrue(new RevertEqualityHelper().equals(currentResource2.getContents(), historyResource1.getContents()));
275
276
    if (detached != null)
277
    {
278
      for (Iterator<CDOID> iterator = detached.iterator(); iterator.hasNext();)
279
      {
280
        CDOID cdoid = iterator.next();
281
        try
282
        {
283
          historyView2.getObject(cdoid);
284
          fail();
285
        }
286
        catch (ObjectNotFoundException ex)
287
        {
288
          // Expected exception
289
        }
290
      }
291
    }
292
293
    session.close();
294
  }
295
296
  private void assertRevisionTakenByTimestamp(CDORevision revision, boolean detached)
297
  {
298
    if (detached)
299
    {
300
      Assert.assertNull(revision);
301
    }
302
    else
303
    {
304
      Assert.assertNotNull(revision);
305
    }
306
307
  }
308
309
  private void assertRevisionTakenByVersion(CDORevision revision, boolean detached)
310
  {
311
    if (detached)
312
    {
313
      Assert.assertTrue(revision instanceof DetachedCDORevision);
314
      // Assert.assertNull(revision);
315
    }
316
    else
317
    {
318
      Assert.assertNotNull(revision);
319
    }
320
321
  }
322
}
(-)src/org/eclipse/emf/cdo/tests/RevertTest.java (+804 lines)
Added Link Here
1
/**
2
 * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, Germany) and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *    Eike Stepper - initial API and implementation
10
 */
11
package org.eclipse.emf.cdo.tests;
12
13
import org.eclipse.emf.cdo.CDOObject;
14
import org.eclipse.emf.cdo.CDOState;
15
import org.eclipse.emf.cdo.common.id.CDOID;
16
import org.eclipse.emf.cdo.eresource.CDOResource;
17
import org.eclipse.emf.cdo.net4j.CDOSession;
18
import org.eclipse.emf.cdo.spi.server.InternalRepository;
19
import org.eclipse.emf.cdo.tests.bundle.OM;
20
import org.eclipse.emf.cdo.tests.config.IRepositoryConfig;
21
import org.eclipse.emf.cdo.tests.model1.Category;
22
import org.eclipse.emf.cdo.tests.model1.Company;
23
import org.eclipse.emf.cdo.tests.model1.Customer;
24
import org.eclipse.emf.cdo.tests.model1.OrderDetail;
25
import org.eclipse.emf.cdo.tests.model1.Product1;
26
import org.eclipse.emf.cdo.tests.model1.PurchaseOrder;
27
import org.eclipse.emf.cdo.tests.model1.SalesOrder;
28
import org.eclipse.emf.cdo.tests.model1.Supplier;
29
import org.eclipse.emf.cdo.transaction.CDOTransaction;
30
import org.eclipse.emf.cdo.util.CommitException;
31
import org.eclipse.emf.cdo.util.ObjectNotFoundException;
32
import org.eclipse.emf.cdo.view.CDOView;
33
34
import org.eclipse.emf.internal.cdo.CDOObjectImpl;
35
import org.eclipse.emf.internal.cdo.transaction.CDOTransactionImpl;
36
37
import org.eclipse.emf.common.util.EList;
38
import org.eclipse.emf.common.util.TreeIterator;
39
import org.eclipse.emf.ecore.EAttribute;
40
import org.eclipse.emf.ecore.EObject;
41
import org.eclipse.emf.ecore.util.EcoreUtil;
42
import org.eclipse.emf.ecore.util.EcoreUtil.EqualityHelper;
43
44
import java.util.ArrayList;
45
import java.util.Calendar;
46
import java.util.Collections;
47
import java.util.HashSet;
48
import java.util.Iterator;
49
import java.util.List;
50
import java.util.Set;
51
52
/**
53
 * Revert testing subject:
54
 * <ul>
55
 * <li>simple attribute values
56
 * <li>deleted object revert when is reverting non deleted parent along with deleted child
57
 * <li>deleted object revert when deleted object with all recursive content is selected to revert, but parent is not for
58
 * revert
59
 * <li>moved object revert
60
 * <li>roll-back for revert changes. Roll-back of revert changes locally is tested for failure, because TRANSIENT and
61
 * DIRTY are not supported yet
62
 * 
63
 * @author Egidijus Vaisnora
64
 */
65
public class RevertTest extends AbstractCDOTest
66
{
67
  private static final String RESOURCE_NAME = "resource";
68
69
  private static final String TESTING_COMPANY_NAME = "CompanyTesting";
70
71
  private static final String TESTING_COMPANY2_NAME = "CompanyTestingAnother";
72
73
  private static final int TESTING_SALESORDER_ID = -1;
74
75
  private long timeStampOfCommit;
76
77
  @Override
78
  protected void doSetUp() throws Exception
79
  {
80
    super.doSetUp();
81
82
    // create model history
83
    CDOSession session = (CDOSession)openSession();
84
    CDOTransaction openTransaction = session.openTransaction();
85
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
86
87
    // creating initial commit
88
    Company createdCompany = getModel1Factory().createCompany();
89
    createdCompany.setName(TESTING_COMPANY_NAME);
90
    createdCompany.setCity("City");
91
    createdCompany.setStreet("Street");
92
93
    Supplier createSupplier = getModel1Factory().createSupplier();
94
    createSupplier.setName("CompanySupplier");
95
    createSupplier.setCity("CitySupplier");
96
    createSupplier.setStreet("StreetSupplier");
97
    createdCompany.getSuppliers().add(createSupplier);
98
99
    Category category = getModel1Factory().createCategory();
100
    category.setName("Category");
101
    createdCompany.getCategories().add(category);
102
    resource.getContents().add(createdCompany);
103
104
    Category category2 = getModel1Factory().createCategory();
105
    category2.setName("Category2");
106
    createdCompany.getCategories().add(category2);
107
    resource.getContents().add(createdCompany);
108
109
    Customer customer = getModel1Factory().createCustomer();
110
    customer.setCity("city");
111
    customer.setName("name");
112
    customer.setStreet("street");
113
    createdCompany.getCustomers().add(customer);
114
115
    // product 1
116
    Product1 createProduct1 = getModel1Factory().createProduct1();
117
    createProduct1.setDescription("description");
118
    createProduct1.setName("product name");
119
    category.getProducts().add(createProduct1);
120
121
    // second product
122
    Product1 createProduct2 = getModel1Factory().createProduct1();
123
    createProduct2.setDescription("description");
124
    createProduct2.setName("product name");
125
    category.getProducts().add(createProduct2);
126
127
    // customer
128
    Customer createCustomer = getModel1Factory().createCustomer();
129
    createCustomer.setName("customer name");
130
    createdCompany.getCustomers().add(createCustomer);
131
132
    // purchase order
133
    OrderDetail createOrderDetail = getModel1Factory().createOrderDetail();
134
    createOrderDetail.setPrice(12f);
135
    createOrderDetail.setProduct(createProduct1);
136
137
    PurchaseOrder createPurchaseOrder = getModel1Factory().createPurchaseOrder();
138
    createPurchaseOrder.setDate(Calendar.getInstance().getTime());
139
    createPurchaseOrder.getOrderDetails().add(createOrderDetail);
140
    createdCompany.getPurchaseOrders().add(createPurchaseOrder);
141
142
    // sale order
143
    OrderDetail createOrderDetail2 = getModel1Factory().createOrderDetail();
144
    createOrderDetail.setPrice(13f);
145
    createOrderDetail.setProduct(createProduct2);
146
147
    SalesOrder createSaleOrder = getModel1Factory().createSalesOrder();
148
    createSaleOrder.setId(TESTING_SALESORDER_ID);
149
    createSaleOrder.setCustomer(createCustomer);
150
    createSaleOrder.getOrderDetails().add(createOrderDetail2);
151
    resource.getContents().add(createSaleOrder);
152
153
    Company createdCompany2 = getModel1Factory().createCompany();
154
    createdCompany2.setName(TESTING_COMPANY2_NAME);
155
    createdCompany2.setCity("City2");
156
    createdCompany2.setStreet("Street2");
157
    resource.getContents().add(createdCompany2);
158
159
    timeStampOfCommit = openTransaction.commit().getTimeStamp();
160
    session.close();
161
  }
162
163
  /**
164
   * Testing simple attribute value revert. Collecting values from given resource, changing EAttribute values and
165
   * committing. Reverting to the previous version and comparing models
166
   */
167
  public void testEAttributeValueRevert() throws CommitException
168
  {
169
    CDOSession session = (CDOSession)openSession();
170
    CDOTransaction openTransaction = session.openTransaction();
171
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
172
173
    // simple property modification
174
    for (TreeIterator<EObject> it = resource.getAllContents(); it.hasNext();)
175
    {
176
      EObject next = it.next();
177
      EList<EAttribute> eAllStructuralFeatures = next.eClass().getEAllAttributes();
178
      for (int i = 0; i < eAllStructuralFeatures.size(); i++)
179
      {
180
        EAttribute eAttribute = eAllStructuralFeatures.get(i);
181
        changeAttribute(next, eAttribute);
182
      }
183
    }
184
185
    openTransaction.commit();
186
    session.close();
187
188
    // revert session
189
    revertResource(RESOURCE_NAME, timeStampOfCommit);
190
191
    // asserting
192
    assertResources(RESOURCE_NAME, timeStampOfCommit, null);
193
  }
194
195
  /**
196
   * Test that object doesn't obtain new CDO version after revert, if it was not eligible for revert
197
   */
198
  public void testVoidReverse() throws CommitException
199
  {
200
    CDOSession session = (CDOSession)openSession();
201
    CDOTransaction openTransaction = session.openTransaction();
202
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
203
204
    // revert session
205
    revertResource(RESOURCE_NAME, timeStampOfCommit);
206
207
    // simple property modification
208
    for (TreeIterator<EObject> it = resource.getAllContents(); it.hasNext();)
209
    {
210
      EObject next = it.next();
211
      assertEquals(CDOState.CLEAN, ((CDOObject)next).cdoState());
212
    }
213
214
    session.close();
215
  }
216
217
  /**
218
   * Removes objects and reverts removed object from historical revision. Second attempt is to remove all root object
219
   * contents along with object
220
   */
221
  public void testRemovedObjectsRevertInResource() throws CommitException
222
  {
223
    // modifying model
224
    CDOSession session = (CDOSession)openSession();
225
    CDOTransaction openTransaction = session.openTransaction();
226
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
227
228
    Company found = findTestingCompany(resource, TESTING_COMPANY_NAME);
229
230
    EList<Category> categories = found.getCategories();
231
    List<Product1> products = new ArrayList<Product1>();
232
    for (int i = 0; i < categories.size(); i++)
233
    {
234
      products.addAll(categories.get(i).getProducts());
235
    }
236
237
    for (int i = 0; i < products.size(); i++)
238
    {
239
      EcoreUtil.delete(products.get(i), true);
240
    }
241
242
    openTransaction.commit();
243
    session.close();
244
245
    revertResource(RESOURCE_NAME, timeStampOfCommit);
246
    assertResources(RESOURCE_NAME, timeStampOfCommit, null);
247
248
    // remove all contents
249
    session = (CDOSession)openSession();
250
    openTransaction = session.openTransaction();
251
    CDOResource object = openTransaction.getResource(RESOURCE_NAME);
252
    List<EObject> eContents = new ArrayList<EObject>(object.eContents());
253
    for (Iterator<EObject> it = eContents.iterator(); it.hasNext();)
254
    {
255
      EObject next = it.next();
256
      EcoreUtil.delete(next, true);
257
    }
258
259
    openTransaction.commit();
260
    session.close();
261
262
    revertResource(RESOURCE_NAME, timeStampOfCommit);
263
    assertResources(RESOURCE_NAME, timeStampOfCommit, null);
264
  }
265
266
  /**
267
   * When historical object contains less references then reverting one, then extra references are removed from the
268
   * containment. After revert, removed such object doesn't have parent and must be "garbage collected"
269
   */
270
  public void testAdditinalObjectDeletingAfterRevert() throws CommitException
271
  {
272
    // modifying model
273
    CDOSession session = (CDOSession)openSession();
274
    CDOTransaction openTransaction = session.openTransaction();
275
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
276
277
    Company found = findTestingCompany(resource, TESTING_COMPANY_NAME);
278
279
    Category createCategory = getModel1Factory().createCategory();
280
    found.getCategories().add(createCategory);
281
282
    openTransaction.commit();
283
    CDOID deletedObject = ((CDOObjectImpl)createCategory).cdoID();
284
    session.close();
285
286
    revertResource(RESOURCE_NAME, timeStampOfCommit);
287
    assertResources(RESOURCE_NAME, timeStampOfCommit, Collections.singleton(deletedObject));
288
  }
289
290
  /**
291
   * Reverting object move. Consist of single object move. Second part makes move of child object of moved object
292
   */
293
  public void testObjectAndItsChildMoveRevert() throws CommitException
294
  {
295
    // TEST1 move of child
296
    CDOSession session = (CDOSession)openSession();
297
    CDOTransaction openTransaction = session.openTransaction();
298
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
299
300
    Company found = findTestingCompany(resource, TESTING_COMPANY_NAME);
301
302
    EList<Category> categories = found.getCategories();
303
304
    Category category = categories.get(0);
305
    Category category2 = categories.get(1);
306
307
    category2.getProducts().add(category.getProducts().remove(0));
308
309
    openTransaction.commit();
310
    session.close();
311
312
    revertResource(RESOURCE_NAME, timeStampOfCommit);
313
    assertResources(RESOURCE_NAME, timeStampOfCommit, null);
314
315
    // TEST2 move of moved child
316
    session = (CDOSession)openSession();
317
    openTransaction = session.openTransaction();
318
    resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
319
320
    Company found1 = null;
321
    Company found2 = null;
322
    EList<EObject> contents = resource.getContents();
323
    for (int i = 0; i < contents.size() && (found1 == null || found2 == null); i++)
324
    {
325
      EObject eObject = contents.get(i);
326
      if (eObject instanceof Company)
327
      {
328
        if (found1 == null)
329
        {
330
          found1 = (Company)eObject;
331
        }
332
        else
333
        {
334
          found2 = (Company)eObject;
335
        }
336
      }
337
    }
338
339
    EList<Category> categoriesFound1 = found1.getCategories();
340
    Category category1Found1 = categoriesFound1.get(0);
341
    Category category2Found1 = categoriesFound1.get(1);
342
343
    // move of category
344
    found2.getCategories().add(category1Found1);
345
346
    // move of product
347
    category2Found1.getProducts().add(category1Found1.getProducts().get(0));
348
349
    openTransaction.commit();
350
    session.close();
351
352
    revertResource(RESOURCE_NAME, timeStampOfCommit);
353
    assertResources(RESOURCE_NAME, timeStampOfCommit, null);
354
  }
355
356
  /**
357
   * Moving object child to another object, while old parent was removed
358
   */
359
  public void testObjectMoveWithRemoveRevert() throws CommitException
360
  {
361
    CDOSession session = (CDOSession)openSession();
362
    CDOTransaction openTransaction = session.openTransaction();
363
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
364
365
    Company found = findTestingCompany(resource, TESTING_COMPANY_NAME);
366
    Company found2 = findTestingCompany(resource, TESTING_COMPANY2_NAME);
367
    found2.getPurchaseOrders().add(found.getPurchaseOrders().remove(0));
368
369
    // delete parent of purchase order
370
    EcoreUtil.delete(found, true);
371
372
    openTransaction.commit();
373
    session.close();
374
375
    revertResource(RESOURCE_NAME, timeStampOfCommit);
376
    assertResources(RESOURCE_NAME, timeStampOfCommit, null);
377
  }
378
379
  /**
380
   * Removes objects and reverts removed object recursively. Parent of removed object is not reverted and after revert
381
   * must ensure to attache deleted object to parent
382
   */
383
  public void testRemovedObjectRecursiveRevert() throws CommitException
384
  {
385
    // modifying model
386
    CDOSession session = (CDOSession)openSession();
387
    CDOTransaction openTransaction = session.openTransaction();
388
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
389
390
    Company found = findTestingCompany(resource, TESTING_COMPANY_NAME);
391
    CDOID revertId = ((CDOObject)found).cdoID();
392
    SalesOrder findTestingSalesOrder = findTestingSalesOrder(resource);
393
    CDOID salesOrderId = ((CDOObject)findTestingSalesOrder).cdoID();
394
395
    EcoreUtil.delete(found, true);
396
397
    openTransaction.commit();
398
    session.close();
399
400
    /*
401
     * When deleting company, we delete customer along with modified salesOrder, which had reference pointing to
402
     * customer. Revert restores deleted objects - reverts customer reference to SalesOrder, but doesn't restore
403
     * SalesOrder reference to Customer. Therefore passing SalesOrder to revert too
404
     */
405
    revertObject(revertId, timeStampOfCommit, true, salesOrderId);
406
    assertResources(RESOURCE_NAME, timeStampOfCommit, null);
407
  }
408
409
  /**
410
   * Testing general revert roll-back. After revert, roll-back must clear changes made by revert.
411
   */
412
  public void testRevertRollback() throws CommitException
413
  {
414
    CDOSession session = (CDOSession)openSession();
415
    CDOTransaction openTransaction = session.openTransaction();
416
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
417
418
    editingModelForRollback(resource);
419
420
    long timeStampCommit = openTransaction.commit().getTimeStamp();
421
    session.close();
422
423
    session = (CDOSession)openSession();
424
    CDOView openAudit = session.openView(timeStampOfCommit);
425
    CDOResource historicalResource = openAudit.getResource(RESOURCE_NAME);
426
    List<CDOObject> tmpObjects = collectAllRevertDataFromResource(historicalResource);
427
428
    CDOTransactionImpl openTransaction2 = (CDOTransactionImpl)session.openTransaction();
429
    openTransaction2.revert(tmpObjects.toArray(new CDOObject[tmpObjects.size()]));
430
431
    openTransaction2.rollback();
432
    openTransaction2.commit();
433
    session.close();
434
435
    assertResources(RESOURCE_NAME, timeStampCommit, null);
436
  }
437
438
  /**
439
   * Testing case when revert need to restore state, where it doesn't contain objects. Revert to deletion
440
   */
441
  public void testHoleRevert() throws CommitException
442
  {
443
    CDOSession session = (CDOSession)openSession();
444
    CDOTransaction openTransaction = session.openTransaction();
445
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
446
447
    Set<CDOID> ids = new HashSet<CDOID>();
448
    for (Iterator<EObject> it = resource.getAllContents(); it.hasNext();)
449
    {
450
      ids.add(((CDOObject)it.next()).cdoID());
451
452
    }
453
454
    List<EObject> contents = new ArrayList<EObject>(resource.getContents());
455
    for (int i = 0; i < contents.size(); i++)
456
    {
457
      EcoreUtil.delete(contents.get(i));
458
    }
459
    long holesTimestamp = openTransaction.commit().getTimeStamp();
460
    session.close();
461
462
    revertResource(RESOURCE_NAME, timeStampOfCommit);
463
464
    revertResource(RESOURCE_NAME, holesTimestamp);
465
466
    assertResources(RESOURCE_NAME, holesTimestamp, ids);
467
  }
468
469
  /**
470
   * Testing case when revert need to restore state of deleted object, which was deleted somewhere between current and
471
   * revert time-stamps. Covers version calculation, when version is restoring for detached element
472
   */
473
  public void testVersionNumberCalculationOnRevert() throws CommitException
474
  {
475
    CDOSession session = (CDOSession)openSession();
476
    CDOTransaction openTransaction = session.openTransaction();
477
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
478
479
    List<EObject> contents = new ArrayList<EObject>(resource.getContents());
480
    for (int i = 0; i < contents.size(); i++)
481
    {
482
      EcoreUtil.delete(contents.get(i));
483
    }
484
    long holesTimestamp = openTransaction.commit().getTimeStamp();
485
    session.close();
486
487
    revertResource(RESOURCE_NAME, timeStampOfCommit);
488
    revertResource(RESOURCE_NAME, holesTimestamp);
489
490
    InternalRepository repository = getScenario().getRepositoryConfig()
491
        .getRepository(IRepositoryConfig.REPOSITORY_NAME);
492
    clearCache(repository.getRevisionManager());
493
494
    revertResource(RESOURCE_NAME, timeStampOfCommit);
495
    assertResources(RESOURCE_NAME, timeStampOfCommit, null);
496
497
  }
498
499
  /**
500
   * Complex situation - moved content from deleted object to newly created. Revert must restore deleted object, detach
501
   * object which was newly created ("garbage collected"), while containment of deleted object is moved back to restored
502
   * object
503
   */
504
  public void testObjectCreationMoveDeleteRevert() throws CommitException
505
  {
506
    CDOSession session = (CDOSession)openSession();
507
    CDOTransaction openTransaction = session.openTransaction();
508
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
509
    // apply editing
510
    Company found = findTestingCompany(resource, TESTING_COMPANY_NAME);
511
512
    Category createCategoryNew = getModel1Factory().createCategory();
513
    createCategoryNew.getProducts().addAll(found.getCategories().get(0).getProducts());
514
515
    Company found2 = findTestingCompany(resource, TESTING_COMPANY2_NAME);
516
    found2.getCategories().add(createCategoryNew);
517
518
    EcoreUtil.delete(found, true);
519
    found2.setName("ChangedCompanyName");
520
521
    openTransaction.commit();
522
    // removed id on revert
523
    CDOID removedId = ((CDOObject)createCategoryNew).cdoID();
524
    session.close();
525
526
    // getting back to the beginning
527
    revertResource(RESOURCE_NAME, timeStampOfCommit);
528
    assertResources(RESOURCE_NAME, timeStampOfCommit, Collections.singleton(removedId));
529
  }
530
531
  /**
532
   * If object was reverted after it was edited, changes must be applied from the revert. Currently this test is testing
533
   * for failure, because TRANSIENT and DIRTY are not supported yet
534
   */
535
  public void testEditedObjectRevertFailure() throws CommitException
536
  {
537
    CDOSession session = (CDOSession)openSession();
538
    CDOTransaction openTransaction = session.openTransaction();
539
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
540
541
    editingModelForRollback(resource);
542
543
    CDOView openAudit = session.openView(timeStampOfCommit);
544
    CDOResource historicalResource = openAudit.getResource(RESOURCE_NAME);
545
    List<CDOObject> tmpObjects = collectAllRevertDataFromResource(historicalResource);
546
547
    try
548
    {
549
      ((CDOTransactionImpl)openTransaction).revert(tmpObjects.toArray(new CDOObject[tmpObjects.size()]));
550
      fail();
551
    }
552
    catch (IllegalStateException ex)
553
    {
554
      // NOT supported yet
555
      OM.LOG.info("Not supported revert for objects with state: TRANSIENT, DIRTY", ex);
556
    }
557
558
    // openTransaction.commit();
559
    session.close();
560
561
    // assertResources(RESOURCE_NAME, timeStampOfCommit, null);
562
  }
563
564
  /**
565
   * Testing object revert till specified saving point. Expected behavior is to roll-back only changes made by revert,
566
   * but leave changes applied before revert. At current time it is testing for failure, because TRANSIENT and DIRTY are
567
   * not supported yet
568
   */
569
  public void testRevertRollbackToSavePointFailure() throws CommitException
570
  {
571
    CDOSession session = (CDOSession)openSession();
572
    CDOTransaction openTransaction = session.openTransaction();
573
    CDOResource resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
574
575
    // apply editing
576
    editingModelForRollback(resource);
577
    openTransaction.commit();
578
579
    // long timeStampOfComparingModel = openTransaction.getLastCommitTime();
580
    session.close();
581
582
    // getting back to the beginning
583
    revertResource(RESOURCE_NAME, timeStampOfCommit);
584
585
    // applying editing again
586
    session = (CDOSession)openSession();
587
    openTransaction = session.openTransaction();
588
    resource = openTransaction.getOrCreateResource(RESOURCE_NAME);
589
    editingModelForRollback(resource);
590
591
    // creating save point
592
    // CDOSavepoint setSavepoint = openTransaction.setSavepoint();
593
594
    // reverting, but not committing
595
    CDOView openAudit = session.openView(timeStampOfCommit);
596
    CDOResource historicalResource = openAudit.getResource(RESOURCE_NAME);
597
    List<CDOObject> tmpObjects = collectAllRevertDataFromResource(historicalResource);
598
    try
599
    {
600
      ((CDOTransactionImpl)openTransaction).revert(tmpObjects.toArray(new CDOObject[tmpObjects.size()]));
601
      fail();
602
    }
603
    catch (IllegalStateException ex)
604
    {
605
      // NOT supported yet
606
      OM.LOG.info("Not supported revert for objects with state: TRANSIENT, DIRTY", ex);
607
    }
608
609
    // roll-backing to save point
610
    // openTransaction.rollback(setSavepoint);
611
612
    // it must be equal
613
    // assertResources(RESOURCE_NAME, timeStampOfComparingModel, null);
614
  }
615
616
  private void editingModelForRollback(CDOResource resource) throws CommitException
617
  {
618
    Company found = findTestingCompany(resource, TESTING_COMPANY_NAME);
619
620
    Category createCategoryNew = getModel1Factory().createCategory();
621
    createCategoryNew.getProducts().addAll(found.getCategories().get(0).getProducts());
622
623
    Company found2 = findTestingCompany(resource, TESTING_COMPANY2_NAME);
624
    found2.getCategories().add(createCategoryNew);
625
626
    EcoreUtil.delete(found, true);
627
    found2.setName("ChangedCompanyName");
628
  }
629
630
  private Company findTestingCompany(CDOResource resource, String name)
631
  {
632
    Company found = null;
633
    EList<EObject> contents = resource.getContents();
634
    for (int i = 0; i < contents.size() && found == null; i++)
635
    {
636
      EObject eObject = contents.get(i);
637
      if (eObject instanceof Company && name.equals(((Company)eObject).getName()))
638
      {
639
        found = (Company)eObject;
640
      }
641
    }
642
643
    return found;
644
  }
645
646
  private SalesOrder findTestingSalesOrder(CDOResource resource)
647
  {
648
    SalesOrder found = null;
649
    EList<EObject> contents = resource.getContents();
650
    for (int i = 0; i < contents.size() && found == null; i++)
651
    {
652
      EObject eObject = contents.get(i);
653
      if (eObject instanceof SalesOrder && ((SalesOrder)eObject).getId() == TESTING_SALESORDER_ID)
654
      {
655
        found = (SalesOrder)eObject;
656
      }
657
    }
658
659
    return found;
660
  }
661
662
  private long revertResource(String resourceName, long timestamp) throws CommitException
663
  {
664
    CDOSession session = (CDOSession)openSession();
665
    CDOView openAudit = session.openView(timestamp);
666
    CDOResource historicalResource = openAudit.getResource(resourceName);
667
    List<CDOObject> tmpObjects = collectAllRevertDataFromResource(historicalResource);
668
669
    CDOTransaction openTransaction2 = session.openTransaction();
670
    ((CDOTransactionImpl)openTransaction2).revert(tmpObjects.toArray(new CDOObject[tmpObjects.size()]));
671
    long ret = 0;
672
    if (openTransaction2.isDirty())
673
    {
674
      ret = openTransaction2.commit().getTimeStamp();
675
    }
676
677
    session.close();
678
    return ret;
679
  }
680
681
  private List<CDOObject> collectAllRevertDataFromResource(CDOResource historicalResource)
682
  {
683
    List<CDOObject> tmpObjects = new ArrayList<CDOObject>();
684
    tmpObjects.add(historicalResource);
685
    for (TreeIterator<EObject> allContents = historicalResource.getAllContents(); allContents.hasNext();)
686
    {
687
      CDOObject next = (CDOObject)allContents.next();
688
      tmpObjects.add(next);
689
    }
690
691
    return tmpObjects;
692
  }
693
694
  private void assertResources(String resourceName, long timestamp, Set<CDOID> detached)
695
  {
696
    CDOSession session;
697
    session = (CDOSession)openSession();
698
    CDOView currentView = session.openView();
699
    CDOResource currentResource = currentView.getResource(resourceName);
700
    CDOView historyView = session.openView(timestamp);
701
    CDOResource historyResource = historyView.getResource(resourceName);
702
703
    // assertTrue(EcoreUtil.equals(currentResource, historyResource));
704
    assertTrue(new RevertEqualityHelper().equals(currentResource.getContents(), historyResource.getContents()));
705
706
    if (detached != null)
707
    {
708
      for (Iterator<CDOID> iterator = detached.iterator(); iterator.hasNext();)
709
      {
710
        CDOID cdoid = iterator.next();
711
        try
712
        {
713
          currentView.getObject(cdoid);
714
          fail();
715
        }
716
        catch (ObjectNotFoundException ex)
717
        {
718
          // Expected exception
719
        }
720
      }
721
    }
722
723
    session.close();
724
  }
725
726
  private void revertObject(CDOID objectId, long timestamp, boolean recursively, CDOID... additionalIds)
727
      throws CommitException
728
  {
729
    CDOSession session;
730
    session = (CDOSession)openSession();
731
    CDOView openAudit = session.openView(timestamp);
732
    CDOObject historicalObject = openAudit.getObject(objectId);
733
    List<CDOObject> tmpObjects = new ArrayList<CDOObject>();
734
    tmpObjects.add(historicalObject);
735
    if (recursively)
736
    {
737
      for (TreeIterator<EObject> allContents = historicalObject.eAllContents(); allContents.hasNext();)
738
      {
739
        CDOObject next = (CDOObject)allContents.next();
740
        tmpObjects.add(next);
741
      }
742
    }
743
744
    for (CDOID id : additionalIds)
745
    {
746
      CDOObject object = openAudit.getObject(id);
747
      tmpObjects.add(object);
748
    }
749
750
    CDOTransaction openTransaction2 = session.openTransaction();
751
    ((CDOTransactionImpl)openTransaction2).revert(tmpObjects.toArray(new CDOObject[tmpObjects.size()]));
752
    openTransaction2.commit();
753
    session.close();
754
  }
755
756
  private void changeAttribute(EObject next, EAttribute eAttribute)
757
  {
758
    Object value = next.eGet(eAttribute);
759
    if (eAttribute.getEType().getInstanceClass() == String.class)
760
    {
761
      next.eSet(eAttribute, String.valueOf(value) + String.valueOf(value));
762
    }
763
    else if (eAttribute.getEType().getInstanceClass() == Float.TYPE)
764
    {
765
      next.eSet(eAttribute, ((Float)value).floatValue() + 1);
766
    }
767
    else if (eAttribute.getEType().getInstanceClass() == Double.TYPE)
768
    {
769
      next.eSet(eAttribute, ((Double)value).doubleValue() + 1);
770
    }
771
    else if (eAttribute.getEType().getInstanceClass() == Integer.TYPE)
772
    {
773
      next.eSet(eAttribute, ((Integer)value).intValue() + 1);
774
    }
775
    else if (eAttribute.getEType().getInstanceClass() == Long.TYPE)
776
    {
777
      next.eSet(eAttribute, ((Long)value).longValue() + 1);
778
    }
779
    else if (eAttribute.getEType().getInstanceClass() == java.util.Date.class)
780
    {
781
      next.eSet(eAttribute, Calendar.getInstance().getTime());
782
    }
783
  }
784
785
  public static class RevertEqualityHelper extends EqualityHelper
786
  {
787
    private static final long serialVersionUID = -729066319986556429L;
788
789
    @Override
790
    public boolean equals(EObject eObject1, EObject eObject2)
791
    {
792
      boolean eq = super.equals(eObject1, eObject2);
793
      if (eq)
794
      {
795
        if (eObject1 instanceof CDOObject)
796
        {
797
          eq = ((CDOObject)eObject1).cdoID().equals(((CDOObject)eObject2).cdoID());
798
        }
799
      }
800
      return eq;
801
    }
802
  }
803
804
}

Return to bug 319409