/**
* <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.diffdata.impl;
import java.util.Collection;
import java.util.List;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.diffmerge.api.IComparison;
import org.eclipse.emf.diffmerge.api.IDiffPolicy;
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.diff.IReferenceValuePresence;
import org.eclipse.emf.diffmerge.api.scopes.IEditableModelScope;
import org.eclipse.emf.diffmerge.diffdata.DiffdataPackage;
import org.eclipse.emf.diffmerge.diffdata.EComparison;
import org.eclipse.emf.diffmerge.diffdata.EMatch;
import org.eclipse.emf.diffmerge.diffdata.EReferenceValuePresence;
import org.eclipse.emf.diffmerge.impl.helpers.BidirectionalComparisonCopier;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
/**
* <!-- begin-user-doc -->
* An implementation of the model object '<em><b>EReference Value Presence</b></em>'.
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
* </p>
* <ul>
* <li>{@link org.eclipse.emf.diffmerge.diffdata.impl.EReferenceValuePresenceImpl#getValue <em>Value</em>}</li>
* <li>{@link org.eclipse.emf.diffmerge.diffdata.impl.EReferenceValuePresenceImpl#getValueMatch <em>Value Match</em>}</li>
* </ul>
* </p>
*
* @generated
*/
public class EReferenceValuePresenceImpl extends EValuePresenceImpl implements
EReferenceValuePresence {
/**
* The cached value of the '{@link #getValue() <em>Value</em>}' reference.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getValue()
* @generated
* @ordered
*/
protected EObject value;
/**
* The cached value of the '{@link #getValueMatch() <em>Value Match</em>}' reference.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getValueMatch()
* @generated
* @ordered
*/
protected EMatch valueMatch;
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected EReferenceValuePresenceImpl() {
super();
}
/**
* Constructor
* @param comparison_p the non-null comparison to which this difference belongs
* @param elementMatch_p the non-null match for the element holding the value
* @param reference_p the non-null reference holding the value
* @param value_p the value element, which is non-null unless valueMatch_p is not null
* @param valueMatch_p the optional match corresponding to the value held
* @param presenceRole_p the role in which the value is held: TARGET or REFERENCE
* @param isOrder_p whether the value presence is solely due to ordering
* @generated NOT
*/
public EReferenceValuePresenceImpl(EComparison comparison_p,
EMatch elementMatch_p, EReference reference_p, EObject value_p,
EMatch valueMatch_p, Role presenceRole_p, boolean isOrder_p) {
super(comparison_p, elementMatch_p, reference_p, presenceRole_p, isOrder_p);
assert valueMatch_p != null || value_p != null;
valueMatch = valueMatch_p;
value = (value_p != null)? value_p: valueMatch_p.get(presenceRole_p);
assert value != null;
((IMatch.Editable) elementMatch).addRelatedDifference(this);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
protected EClass eStaticClass() {
return DiffdataPackage.Literals.EREFERENCE_VALUE_PRESENCE;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public EObject getValue() {
if (value != null && value.eIsProxy()) {
InternalEObject oldValue = (InternalEObject) value;
value = eResolveProxy(oldValue);
if (value != oldValue) {
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.RESOLVE,
DiffdataPackage.EREFERENCE_VALUE_PRESENCE__VALUE, oldValue,
value));
}
}
return value;
}
/**
* @see org.eclipse.emf.diffmerge.diffdata.impl.EValuePresenceImpl#getFeature()
* @generated NOT
*/
@Override
public EReference getFeature() {
return (EReference) super.getFeature();
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public EObject basicGetValue() {
return value;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public EMatch getValueMatch() {
if (valueMatch != null && valueMatch.eIsProxy()) {
InternalEObject oldValueMatch = (InternalEObject) valueMatch;
valueMatch = (EMatch) eResolveProxy(oldValueMatch);
if (valueMatch != oldValueMatch) {
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.RESOLVE,
DiffdataPackage.EREFERENCE_VALUE_PRESENCE__VALUE_MATCH,
oldValueMatch, valueMatch));
}
}
return valueMatch;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public EMatch basicGetValueMatch() {
return valueMatch;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public Object eGet(int featureID, boolean resolve, boolean coreType) {
switch (featureID) {
case DiffdataPackage.EREFERENCE_VALUE_PRESENCE__VALUE:
if (resolve)
return getValue();
return basicGetValue();
case DiffdataPackage.EREFERENCE_VALUE_PRESENCE__VALUE_MATCH:
if (resolve)
return getValueMatch();
return basicGetValueMatch();
}
return super.eGet(featureID, resolve, coreType);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public boolean eIsSet(int featureID) {
switch (featureID) {
case DiffdataPackage.EREFERENCE_VALUE_PRESENCE__VALUE:
return value != null;
case DiffdataPackage.EREFERENCE_VALUE_PRESENCE__VALUE_MATCH:
return valueMatch != null;
}
return super.eIsSet(featureID);
}
/**
* @see org.eclipse.emf.diffmerge.api.diff.IReferenceValuePresence#getOpposite()
* @generated NOT
*/
public IReferenceValuePresence getOpposite() {
IReferenceValuePresence result = null;
EReference opposite = getFeature().getEOpposite();
if (opposite != null) {
IMatch valueMatch = getValueMatch();
if (valueMatch != null) {
result = valueMatch.getReferenceValueDifference(opposite,
getElementMatch().get(getPresenceRole()));
}
}
return result;
}
/**
* @see org.eclipse.emf.diffmerge.diffdata.impl.EValuePresenceImpl#getSymmetrical()
* @generated NOT
*/
@Override
public IReferenceValuePresence getSymmetrical() {
IReferenceValuePresence result = null;
if (!getFeature().isMany()) {
Collection<IReferenceValuePresence> candidates = getElementMatch()
.getReferenceDifferences(getFeature());
assert candidates.size() <= 2; // Because !isMany()
for (IReferenceValuePresence candidate : candidates) {
if (candidate.getPresenceRole() == getAbsenceRole()) {
result = candidate;
break;
}
}
} else if (isOrder()) {
result = (IReferenceValuePresence) getElementMatch()
.getOrderDifference(getFeature(), getAbsenceRole());
}
return result;
}
/**
* @see org.eclipse.emf.diffmerge.api.diff.IReferenceValuePresence#getSymmetricalOwnership()
* @generated NOT
*/
public IReferenceValuePresence getSymmetricalOwnership() {
IReferenceValuePresence result = null;
IMatch valueMatch = getValueMatch();
if (valueMatch != null)
result = valueMatch.getOwnershipDifference(getAbsenceRole());
return result;
}
/**
* Return whether this difference has an opposite with stronger constraints
* @generated NOT
*/
protected boolean hasStrongerOpposite() {
boolean result = false;
EStructuralFeature ownfeature = getFeature();
if (ownfeature instanceof EReference) {
EReference ref = (EReference) ownfeature;
if (ref.isMany()) {
EReference opposite = ref.getEOpposite();
result = opposite != null && !opposite.isMany();
}
}
return result;
}
/**
* @see org.eclipse.emf.diffmerge.api.diff.IReferenceValuePresence#isOppositeOf(org.eclipse.emf.diffmerge.api.diff.IReferenceValuePresence)
* @generated NOT
*/
public boolean isOppositeOf(IReferenceValuePresence peer_p) {
return getPresenceRole() == peer_p.getPresenceRole()
&& getFeature().getEOpposite() == peer_p.getFeature()
&& getElementMatch() == peer_p.getValueMatch()
&& getValueMatch() == peer_p.getElementMatch();
}
/**
* @see org.eclipse.emf.diffmerge.api.diff.IReferenceValuePresence#isOutOfScope()
* @generated NOT
*/
public boolean isOutOfScope() {
return getValueMatch() == null;
}
/**
* @see org.eclipse.emf.diffmerge.api.diff.IElementRelativeDifference#isUnrelatedToContainmentTree()
* @generated NOT
*/
public boolean isUnrelatedToContainmentTree() {
return !getFeature().isContainment() || isOrder();
}
/**
* @see org.eclipse.emf.diffmerge.api.diff.IReferenceValuePresence#isSymmetricalOwnershipTo(org.eclipse.emf.diffmerge.api.diff.IReferenceValuePresence)
* @generated NOT
*/
public boolean isSymmetricalOwnershipTo(IReferenceValuePresence peer_p) {
return getAbsenceRole() == peer_p.getPresenceRole()
&& getFeature().isContainment() && peer_p.getFeature().isContainment()
&& getValueMatch() != null && getValueMatch() == peer_p.getValueMatch();
}
/**
* @see org.eclipse.emf.diffmerge.diffdata.impl.EValuePresenceImpl#mergeOrder()
* @generated NOT
*/
@Override
protected void mergeOrder() {
EObject sourceHolder = getHolder();
EObject destinationHolder = getMatchOfHolder();
EReference reference = getFeature();
assert sourceHolder != null && destinationHolder != null; // Otherwise order change would not have been detected
assert getFeature() != null; // Order merge does not cover root containment at this time
IEditableModelScope absenceScope = getAbsenceScope();
IMergePolicy mergePolicy = getComparison().getLastMergePolicy();
Role destination = getAbsenceRole();
IMatch holderMatch = getElementMatch();
IComparison owningComparison = getComparison();
List<EObject> sourceValues = getPresenceScope().get(sourceHolder,
reference);
for (int i = sourceValues.size() - 1; i >= 0; i--) {
EObject sourceValue = sourceValues.get(i);
IMatch valueMatch = owningComparison.getMapping().getMatchFor(sourceValue,
destination.opposite());
boolean coverValue = valueMatch != null ||
getFeature() != null &&
getComparison().getLastDiffPolicy().coverOutOfScopeValue(sourceValue, getFeature());
if (coverValue) {
EObject destinationValue = valueMatch != null?
valueMatch.get(destination): sourceValue;
if (destinationValue != null) {
int index = mergePolicy.getDesiredValuePosition(owningComparison,
destination, holderMatch, reference, sourceValue);
if (index >= 0) {
List<EObject> updatedDestinationValues = absenceScope
.get(destinationHolder, reference);
int oldIndex = updatedDestinationValues.indexOf(destinationValue);
absenceScope.move(destinationHolder, reference, index, oldIndex);
}
}
}
}
}
/**
* @see org.eclipse.emf.diffmerge.diffdata.impl.EValuePresenceImpl#mergeValueAddition()
* @generated NOT
*/
@Override
protected void mergeValueAddition() {
IEditableModelScope absenceScope = getAbsenceScope();
EObject destinationHolder = getMatchOfHolder();
IMatch valueMatch = getValueMatch();
EObject destinationValue;
boolean cloned;
if (valueMatch == null) {
// Out of scope
destinationValue = getValue(); // Keep as-is
cloned = false;
} else if (valueMatch.isPartial()) {
// Within scope, value not present in absence scope
destinationValue = getComparison().getMapping().completeMatch(valueMatch);
cloned = true;
} else {
// Within scope, value present in absence scope
destinationValue = valueMatch.get(getAbsenceRole());
cloned = false;
}
// Assertions are assumed to be enforced by diff dependency handling
assert destinationHolder != null && destinationValue != null;
boolean actuallyAdded = absenceScope.add(destinationHolder, getFeature(),
destinationValue);
// Order handling
IDiffPolicy diffPolicy = getComparison().getLastDiffPolicy();
IMergePolicy mergePolicy = getComparison().getLastMergePolicy();
if (diffPolicy != null && actuallyAdded
&& diffPolicy.considerOrdered(getFeature())) {
// Move added value if required
int index = mergePolicy.getDesiredValuePosition(getComparison(),
getAbsenceRole(), getElementMatch(), getFeature(), getValue());
if (index >= 0)
absenceScope.move(destinationHolder, getFeature(), index, -1);
}
// ID enforcement
if (cloned && actuallyAdded)
BidirectionalComparisonCopier.handleIDCopy(getValue(),
getPresenceScope(), destinationValue, getAbsenceScope(), mergePolicy);
}
/**
* @see org.eclipse.emf.diffmerge.diffdata.impl.EValuePresenceImpl#mergeValueRemoval()
* @generated NOT
*/
@Override
protected final void mergeValueRemoval() {
if (isOutOfScope()) {
// Out of scope
getPresenceScope().remove(getHolder(), getFeature(), getValue());
} else {
// Within scope
mergeValueRemovalWithinScope();
}
}
/**
* Remove the in-presence-scope value from the presence scope.
* Precondition: !isOutOfScope()
* @generated NOT
*/
protected void mergeValueRemovalWithinScope() {
IEditableModelScope presenceScope = getPresenceScope();
if (getSymmetrical() == null
&& !(hasStrongerOpposite() && !getValueMatch().isPartial())) {
EObject valueElement = getValue();
if (getFeature() != null)
presenceScope.remove(getHolder(), getFeature(), valueElement);
else
presenceScope.remove(valueElement);
if (getFeature() == null || getFeature().isContainment()) {
// Value has been removed from its containment: delete element
for (EStructuralFeature.Setting setting : getComparison().getMapping()
.getCrossReferences(valueElement, getPresenceRole())) {
presenceScope.remove(setting.getEObject(),
(EReference) setting.getEStructuralFeature(), valueElement);
}
if (!getComparison().getLastMergePolicy()
.bindPresenceToOwnership(presenceScope)) {
// Re-integrate direct children in scope
for (EObject child : presenceScope.getContents(valueElement)) {
presenceScope.add(child);
}
}
}
}
// Otherwise, we know this difference will be merged implicitly because of dependencies
// since a required difference implies this difference
}
} //EReferenceValuePresenceImpl