Beispiel #1
0
    /**
     * @return the result feature delta, or <code>null</code> to indicate an unresolved conflict.
     */
    protected CDOFeatureDelta changedInSourceAndTarget(
        CDOFeatureDelta targetFeatureDelta, CDOFeatureDelta sourceFeatureDelta) {
      EStructuralFeature feature = targetFeatureDelta.getFeature();
      if (feature.isMany()) {
        return changedInSourceAndTargetManyValued(feature, targetFeatureDelta, sourceFeatureDelta);
      }

      return changedInSourceAndTargetSingleValued(feature, targetFeatureDelta, sourceFeatureDelta);
    }
    protected boolean hasFeatureConflicts(
        CDORevisionDelta localDelta, List<CDORevisionDelta> remoteDeltas) {
      Set<EStructuralFeature> features = new HashSet<EStructuralFeature>();
      for (CDOFeatureDelta localFeatureDelta : localDelta.getFeatureDeltas()) {
        features.add(localFeatureDelta.getFeature());
      }

      for (CDORevisionDelta remoteDelta : remoteDeltas) {
        for (CDOFeatureDelta remoteFeatureDelta : remoteDelta.getFeatureDeltas()) {
          EStructuralFeature feature = remoteFeatureDelta.getFeature();
          if (features.contains(feature)) {
            return true;
          }
        }
      }

      return false;
    }
Beispiel #3
0
    /**
     * @return the result feature delta, or <code>null</code> to indicate an unresolved conflict.
     */
    protected CDOFeatureDelta changedInSourceAndTargetSingleValued(
        EStructuralFeature feature,
        CDOFeatureDelta targetFeatureDelta,
        CDOFeatureDelta sourceFeatureDelta) {
      if (targetFeatureDelta.isStructurallyEqual(sourceFeatureDelta)) {
        return targetFeatureDelta;
      }

      return null;
    }
Beispiel #4
0
      @Override
      protected CDOFeatureDelta changedInSourceAndTargetManyValued(
          EStructuralFeature feature,
          CDOFeatureDelta targetFeatureDelta,
          CDOFeatureDelta sourceFeatureDelta) {
        if (targetFeatureDelta instanceof CDOListFeatureDelta
            && sourceFeatureDelta instanceof CDOListFeatureDelta) {
          // Initialize work lists with virtual elements
          int originSize = ((CDOListFeatureDelta) sourceFeatureDelta.copy()).getOriginSize();
          BasicEList<Element> ancestorList = new BasicEList<Element>(originSize);
          PerSide<BasicEList<Element>> listPerSide = new PerSide<BasicEList<Element>>();

          initWorkLists(originSize, ancestorList, listPerSide);

          // Apply list changes to source and target work lists
          PerSide<List<CDOFeatureDelta>> changesPerSide =
              new PerSide<List<CDOFeatureDelta>>(
                  copyListChanges(sourceFeatureDelta), copyListChanges(targetFeatureDelta));
          Map<Object, List<Element>> additions = new HashMap<Object, List<Element>>();
          Map<CDOFeatureDelta, Element> allElements = new HashMap<CDOFeatureDelta, Element>();

          applyChangesToWorkList(Side.SOURCE, listPerSide, changesPerSide, allElements, additions);
          applyChangesToWorkList(Side.TARGET, listPerSide, changesPerSide, allElements, additions);

          // Pick changes from source and target sides into the merge result
          CDOListFeatureDelta result = new CDOListFeatureDeltaImpl(feature, originSize);
          List<CDOFeatureDelta> resultChanges = result.getListChanges();

          pickChangesIntoResult(
              Side.SOURCE,
              feature,
              ancestorList,
              changesPerSide,
              allElements,
              additions,
              resultChanges);
          pickChangesIntoResult(
              Side.TARGET,
              feature,
              ancestorList,
              changesPerSide,
              allElements,
              additions,
              resultChanges);

          return result;
        }

        return super.changedInSourceAndTargetManyValued(
            feature, targetFeatureDelta, sourceFeatureDelta);
      }
Beispiel #5
0
      private List<CDOFeatureDelta> copyListChanges(CDOFeatureDelta featureDelta) {
        CDOListFeatureDelta listFeatureDelta = (CDOListFeatureDelta) featureDelta.copy();
        List<CDOFeatureDelta> copy = listFeatureDelta.getListChanges();

        if (!copy.isEmpty()) {
          CDOFeatureDelta.Type firstType = copy.get(0).getType();
          if (firstType == Type.CLEAR || firstType == Type.UNSET) {
            copy.remove(0);

            List<CDOFeatureDelta> expandedDeltas = expandClearDelta(listFeatureDelta);
            copy.addAll(0, expandedDeltas);
          }
        }

        return copy;
      }
Beispiel #6
0
      private void pickChangesIntoResult(
          Side side,
          EStructuralFeature feature,
          BasicEList<Element> ancestorList,
          PerSide<List<CDOFeatureDelta>> changesPerSide,
          Map<CDOFeatureDelta, Element> allElements,
          Map<Object, List<Element>> additions,
          List<CDOFeatureDelta> result) {
        List<CDOFeatureDelta> changes = changesPerSide.get(side);
        for (CDOFeatureDelta change : changes) {
          Type changeType = change.getType();
          switch (changeType) {
            case ADD:
              {
                CDOAddFeatureDeltaImpl addChange = (CDOAddFeatureDeltaImpl) change;
                result.add(addChange);

                int sideIndex = addChange.getIndex();
                int ancestorIndex = sideIndex;

                int ancestorEnd = ancestorList.size();
                if (ancestorIndex > ancestorEnd) {
                  // TODO Better way to adjust ancestor indexes?
                  ancestorIndex = ancestorEnd;
                  addChange.setIndex(ancestorIndex);
                }

                Element newElement = allElements.get(addChange);
                ancestorList.add(ancestorIndex, newElement);

                if (treatAsUnique(feature)) {
                  // Detect and remove corresponding AddDeltas from the other side
                  Object value = addChange.getValue();
                  List<Element> elementsToAdd = additions.get(value);
                  if (elementsToAdd != null) {
                    for (Element element : elementsToAdd) {
                      CDOAddFeatureDelta otherAdd = (CDOAddFeatureDelta) element.get(other(side));
                      if (otherAdd != null) {
                        element.set(other(side), null);

                        // Not taking an AddDelta has the same effect on indexes as a removal of the
                        // element
                        List<CDOFeatureDelta> otherChanges = changesPerSide.get(other(side));
                        int otherIndex = otherAdd.getIndex();
                        adjustAfterRemoval(otherChanges, otherIndex, addChange);
                      }
                    }
                  }
                }

                break;
              }

            case REMOVE:
              {
                CDORemoveFeatureDeltaImpl removeChange = (CDORemoveFeatureDeltaImpl) change;
                result.add(removeChange);

                Element removedElement = allElements.get(removeChange);
                int ancestorIndex = ancestorList.indexOf(removedElement);
                removeChange.setIndex(ancestorIndex);
                ancestorList.remove(ancestorIndex);

                // Detect and remove a potential duplicate RemoveDelta from the other side
                CDOFeatureDelta otherChange = removedElement.get(other(side));
                if (otherChange != null) {
                  Type otherChangeType = otherChange.getType();
                  switch (otherChangeType) {
                    case REMOVE:
                      {
                        CDORemoveFeatureDelta otherRemove = (CDORemoveFeatureDelta) otherChange;
                        removedElement.set(other(side), null);

                        // Not taking a RemoveDelta has the same effect on indexes as an addition of
                        // the element
                        List<CDOFeatureDelta> otherChanges = changesPerSide.get(other(side));
                        int otherIndex = otherRemove.getIndex();
                        adjustAfterAddition(otherChanges, otherIndex, otherRemove);
                        break;
                      }

                    case MOVE:
                      {
                        CDOMoveFeatureDelta otherMove = (CDOMoveFeatureDelta) otherChange;
                        removedElement.set(other(side), null);

                        // Not taking a MoveDelta has the same effect on indexes as a reverse move
                        // of the element
                        List<CDOFeatureDelta> otherChanges = changesPerSide.get(other(side));
                        int otherOldPosition = otherMove.getOldPosition();
                        int otherNewPosition = otherMove.getNewPosition();
                        adjustAfterMove(
                            otherChanges, otherOldPosition, otherNewPosition, otherMove);
                        break;
                      }

                    default:
                      throw new IllegalStateException("Unexpected change type: " + otherChangeType);
                  }
                }

                break;
              }

            case SET:
              {
                throw new IllegalStateException("Unhandled change type: " + changeType);
                // CDOSetFeatureDelta setChange = (CDOSetFeatureDelta)change;
                // break;
              }

            case MOVE:
              {
                CDOMoveFeatureDeltaImpl moveChange = (CDOMoveFeatureDeltaImpl) change;
                int sideOldPosition = moveChange.getOldPosition();
                int sideNewPosition = moveChange.getNewPosition();

                Element movedElement = allElements.get(moveChange);
                CDOFeatureDelta otherChange = movedElement.get(other(side));

                if (otherChange != null) {
                  Type otherChangeType = otherChange.getType();
                  switch (otherChangeType) {
                    case REMOVE:
                      {
                        // Prioritize the RemoveDelta of the other side, delete the MoveDelta from
                        // this side
                        adjustAfterMove(changes, sideOldPosition, sideNewPosition, moveChange);
                        movedElement.set(side, null);
                        return;
                      }

                    case MOVE:
                      {
                        CDOMoveFeatureDelta otherMove = (CDOMoveFeatureDelta) otherChange;
                        movedElement.set(other(side), null);

                        // Not taking a MoveDelta has the same effect on indexes as a reverse move
                        // of the element
                        List<CDOFeatureDelta> otherChanges = changesPerSide.get(other(side));
                        int otherOldPosition = otherMove.getOldPosition();
                        int otherNewPosition = otherMove.getNewPosition();
                        adjustAfterMove(
                            otherChanges, otherOldPosition, otherNewPosition, otherMove);
                        movedElement.set(other(side), null);
                        break;
                      }

                    default:
                      throw new IllegalStateException("Unexpected change type: " + otherChangeType);
                  }
                }

                int positionDelta = sideNewPosition - sideOldPosition;
                int ancestorOldPosition = ancestorList.indexOf(movedElement);
                int ancestorNewPosition = ancestorOldPosition + positionDelta;
                if (ancestorNewPosition < 0) {
                  ancestorNewPosition = 0;
                }

                int ancestorEnd = ancestorList.size() - 1;
                if (ancestorNewPosition > ancestorEnd) {
                  ancestorNewPosition = ancestorEnd;
                }

                moveChange.setOldPosition(ancestorOldPosition);
                moveChange.setNewPosition(ancestorNewPosition);
                result.add(moveChange);

                ancestorList.move(ancestorNewPosition, ancestorOldPosition);
                break;
              }

            case CLEAR:
            case UNSET:

            default:
              throw new IllegalStateException("Illegal change type: " + changeType);
          }
        }
      }
Beispiel #7
0
      private void applyChangesToWorkList(
          Side side,
          PerSide<BasicEList<Element>> listPerSide,
          PerSide<List<CDOFeatureDelta>> changesPerSide,
          Map<CDOFeatureDelta, Element> allElements,
          Map<Object, List<Element>> additions) {
        BasicEList<Element> list = listPerSide.get(side);
        List<CDOFeatureDelta> changes = changesPerSide.get(side);
        for (CDOFeatureDelta change : changes) {
          Type changeType = change.getType();
          switch (changeType) {
            case ADD:
              {
                CDOAddFeatureDelta addChange = (CDOAddFeatureDelta) change;

                Element element = new Element(-1);
                element.set(side, addChange);
                allElements.put(addChange, element);

                list.add(addChange.getIndex(), element);
                rememberAddition(addChange.getValue(), element, additions);
                break;
              }

            case REMOVE:
              {
                CDORemoveFeatureDelta removeChange = (CDORemoveFeatureDelta) change;

                Element element = list.remove(removeChange.getIndex());
                element.set(side, removeChange);
                allElements.put(removeChange, element);
                break;
              }

            case SET:
              {
                CDOSetFeatureDelta setChange = (CDOSetFeatureDelta) change;

                Element newElement = new Element(-1);
                newElement.set(side, setChange);
                rememberAddition(setChange.getValue(), newElement, additions);

                Element oldElement = list.set(setChange.getIndex(), newElement);
                oldElement.set(side, setChange);
                allElements.put(setChange, oldElement);
                break;
              }

            case MOVE:
              {
                CDOMoveFeatureDelta moveChange = (CDOMoveFeatureDelta) change;

                Element element =
                    list.move(moveChange.getNewPosition(), moveChange.getOldPosition());
                element.set(side, moveChange);
                allElements.put(moveChange, element);
                break;
              }

            case CLEAR:
            case UNSET:
              // These deltas should have been replaced by multiple REMOVE deltas in
              // copyListChanges()
              throw new IllegalStateException("Unhandled change type: " + changeType);

            default:
              throw new IllegalStateException("Illegal change type: " + changeType);
          }
        }
      }
Beispiel #8
0
    @Override
    protected Object changedInSourceAndTarget(
        CDORevisionDelta targetDelta, CDORevisionDelta sourceDelta) {
      InternalCDORevisionDelta result = new CDORevisionDeltaImpl(targetDelta, false);
      ChangedInSourceAndTargetConflict conflict = null;

      Map<EStructuralFeature, CDOFeatureDelta> targetMap =
          ((InternalCDORevisionDelta) targetDelta).getFeatureDeltaMap();
      Map<EStructuralFeature, CDOFeatureDelta> sourceMap =
          ((InternalCDORevisionDelta) sourceDelta).getFeatureDeltaMap();

      for (CDOFeatureDelta targetFeatureDelta : targetMap.values()) {
        EStructuralFeature feature = targetFeatureDelta.getFeature();
        CDOFeatureDelta sourceFeatureDelta = sourceMap.get(feature);

        if (sourceFeatureDelta == null) {
          CDOFeatureDelta featureDelta = changedInTarget(targetFeatureDelta);
          if (featureDelta != null) {
            result.addFeatureDelta(featureDelta, null);
          }
        } else {
          CDOFeatureDelta featureDelta =
              changedInSourceAndTarget(targetFeatureDelta, sourceFeatureDelta);
          if (featureDelta != null) {
            result.addFeatureDelta(featureDelta, null);
          } else {
            if (conflict == null) {
              ResolutionPreference resolutionPreference = getResolutionPreference();
              switch (resolutionPreference) {
                case SOURCE_OVER_TARGET:
                  // TODO: implement
                  // DefaultCDOMerger.PerFeature.changedInSourceAndTarget(targetDelta, sourceDelta)
                  throw new UnsupportedOperationException();

                case TARGET_OVER_SOURCE:
                  // TODO: implement
                  // DefaultCDOMerger.PerFeature.changedInSourceAndTarget(targetDelta, sourceDelta)
                  throw new UnsupportedOperationException();

                case NONE:
                  conflict =
                      new ChangedInSourceAndTargetConflict(
                          new CDORevisionDeltaImpl(targetDelta, false),
                          new CDORevisionDeltaImpl(sourceDelta, false));
                  break;

                default:
                  throw new IllegalStateException(
                      "Illegal resolution preference: " + resolutionPreference);
              }
            }

            ((InternalCDORevisionDelta) conflict.getTargetDelta())
                .addFeatureDelta(targetFeatureDelta, null);
            ((InternalCDORevisionDelta) conflict.getSourceDelta())
                .addFeatureDelta(sourceFeatureDelta, null);
          }
        }
      }

      for (CDOFeatureDelta sourceFeatureDelta : sourceMap.values()) {
        EStructuralFeature feature = sourceFeatureDelta.getFeature();
        CDOFeatureDelta targetFeatureDelta = targetMap.get(feature);

        if (targetFeatureDelta == null) {
          CDOFeatureDelta featureDelta = changedInSource(sourceFeatureDelta);
          if (featureDelta != null) {
            result.addFeatureDelta(featureDelta, null);
          }
        }
      }

      if (result.isEmpty()) {
        return conflict;
      }

      if (conflict != null) {
        return Pair.create(result, conflict);
      }

      return result;
    }