/** * <copyright> * * Copyright (c) 2010-2016 Thales Global Services S.A.S. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Thales Global Services S.A.S. - initial API and implementation * * </copyright> */ package org.eclipse.emf.diffmerge.impl.policies; import java.util.List; import java.util.Set; import org.eclipse.emf.diffmerge.api.IComparison; import org.eclipse.emf.diffmerge.api.IMatch; import org.eclipse.emf.diffmerge.api.IMergePolicy; import org.eclipse.emf.diffmerge.api.Role; import org.eclipse.emf.diffmerge.api.scopes.IFeaturedModelScope; import org.eclipse.emf.diffmerge.util.ModelImplUtil; import org.eclipse.emf.diffmerge.util.structures.FHashSet; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.util.FeatureMapUtil; /** * A default merge policy. * Conformity to references of multiplicity [1] is enforced by default. * @author Olivier Constant */ public class DefaultMergePolicy implements IMergePolicy { /** * @see org.eclipse.emf.diffmerge.api.IMergePolicy#bindPresenceToOwnership(org.eclipse.emf.diffmerge.api.scopes.IFeaturedModelScope) */ public boolean bindPresenceToOwnership(IFeaturedModelScope scope_p) { return true; } /** * @see org.eclipse.emf.diffmerge.api.IMergePolicy#copyExtrinsicIDs(org.eclipse.emf.diffmerge.api.scopes.IFeaturedModelScope, org.eclipse.emf.diffmerge.api.scopes.IFeaturedModelScope) */ public boolean copyExtrinsicIDs(IFeaturedModelScope sourceScope_p, IFeaturedModelScope targetScope_p) { return true; } /** * @see org.eclipse.emf.diffmerge.api.IMergePolicy#copyFeature(org.eclipse.emf.ecore.EStructuralFeature, org.eclipse.emf.diffmerge.api.scopes.IFeaturedModelScope) */ public boolean copyFeature(EStructuralFeature feature_p, IFeaturedModelScope scope_p) { return !feature_p.isDerived() && feature_p.isChangeable() && !FeatureMapUtil.isFeatureMap(feature_p); } /** * @see org.eclipse.emf.diffmerge.api.IMergePolicy#copyOutOfScopeCrossReferences(org.eclipse.emf.diffmerge.api.scopes.IFeaturedModelScope, org.eclipse.emf.diffmerge.api.scopes.IFeaturedModelScope) */ public boolean copyOutOfScopeCrossReferences( IFeaturedModelScope sourceScope_p, IFeaturedModelScope targetScope_p) { return true; } /** * @see org.eclipse.emf.diffmerge.api.IMergePolicy#getAdditionGroup(EObject, IFeaturedModelScope) */ public Set<EObject> getAdditionGroup(EObject element_p, IFeaturedModelScope scope_p) { Set<EObject> result = new FHashSet<EObject>(); for (EReference reference : element_p.eClass().getEAllReferences()) { if (!reference.isDerived() && !reference.isContainer() && (!reference.isContainment() || !bindPresenceToOwnership(scope_p)) && isMandatoryForAddition(reference)) result.addAll(scope_p.get(element_p, reference)); } return result; } /** * @see org.eclipse.emf.diffmerge.api.IMergePolicy#getDeletionGroup(EObject, IFeaturedModelScope) */ public Set<EObject> getDeletionGroup(EObject element_p, IFeaturedModelScope scope_p) { Set<EObject> result = new FHashSet<EObject>(); for (EReference reference : element_p.eClass().getEAllReferences()) { if (!reference.isDerived() && !reference.isContainer() && (!reference.isContainment() || !bindPresenceToOwnership(scope_p)) && isMandatoryForDeletion(reference)) result.addAll(scope_p.get(element_p, reference)); } return result; } /** * @see org.eclipse.emf.diffmerge.api.IMergePolicy#getDesiredValuePosition(org.eclipse.emf.diffmerge.api.IComparison, org.eclipse.emf.diffmerge.api.Role, org.eclipse.emf.diffmerge.api.IMatch, org.eclipse.emf.ecore.EReference, org.eclipse.emf.ecore.EObject) */ public int getDesiredValuePosition(IComparison comparison_p, Role destination_p, IMatch source_p, EReference reference_p, EObject sourceValue_p) { EObject sourceHolder = source_p.get(destination_p.opposite()); EObject destinationHolder = source_p.get(destination_p); if (sourceHolder != null && destinationHolder != null && sourceValue_p != null) { List<EObject> sourceValues = comparison_p.getScope(destination_p.opposite()).get( sourceHolder, reference_p); List<EObject> destinationValues = comparison_p.getScope(destination_p).get( destinationHolder, reference_p); // Priority is given to the successor int start = sourceValues.indexOf(sourceValue_p) + 1; for (int i = start; i < sourceValues.size(); i++) { EObject nextSourceElement = sourceValues.get(i); IMatch nextMatch = comparison_p.getMapping().getMatchFor( nextSourceElement, destination_p.opposite()); if (nextMatch != null) { // Should be true since scope must be complete EObject nextDestinationElement = nextMatch.get(destination_p); if (nextDestinationElement != null) { int nextDestinationIndex = destinationValues.indexOf(nextDestinationElement); if (nextDestinationIndex >= 0) return nextDestinationIndex; } } } } return -1; } /** * Return a new intrinsic ID for the given element, if applicable * @param element_p a non-null element * @param scope_p a non-null scope to which the element is being added by copy * @return a potentially null string */ protected String getNewIntrinsicID(EObject element_p, IFeaturedModelScope scope_p) { return null; } /** * @see org.eclipse.emf.diffmerge.api.IMergePolicy#isMandatoryForAddition(org.eclipse.emf.ecore.EReference) */ public boolean isMandatoryForAddition(EReference reference_p) { return isSingleMandatory(reference_p); } /** * @see org.eclipse.emf.diffmerge.api.IMergePolicy#isMandatoryForDeletion(org.eclipse.emf.ecore.EReference) */ public boolean isMandatoryForDeletion(EReference reference_p) { EReference opposite = reference_p.getEOpposite(); return opposite != null && isSingleMandatory(opposite); } /** * Return whether the given reference is of multiplicity [1] * @param reference_p a non-null reference */ protected boolean isSingleMandatory(EReference reference_p) { return !reference_p.isMany() && reference_p.getLowerBound() > 0; } /** * Return whether the given newly-added element must be given a new intrinsic ID. * This method has an impact only if getNewIntrinsicID does not return null. * @param element_p a non-null element * @param scope_p a non-null scope to which the element is being added by copy */ protected boolean requiresNewIntrinsicID(EObject element_p, IFeaturedModelScope scope_p) { // By default, intrinsic IDs are copied like other attributes return false; } /** * @see org.eclipse.emf.diffmerge.api.IMergePolicy#setIntrinsicID(org.eclipse.emf.ecore.EObject, org.eclipse.emf.diffmerge.api.scopes.IFeaturedModelScope, org.eclipse.emf.ecore.EObject, org.eclipse.emf.diffmerge.api.scopes.IFeaturedModelScope) */ public void setIntrinsicID(EObject source_p, IFeaturedModelScope sourceScope_p, EObject target_p, IFeaturedModelScope targetScope_p) { // By default (requiresNewIntrinsicID == false), intrinsic IDs are copied like other attributes if (requiresNewIntrinsicID(target_p, targetScope_p)) { String newID = getNewIntrinsicID(target_p, targetScope_p); ModelImplUtil.setIntrinsicID(target_p, newID); } } }