blob: 11e7e21deee66f9f71766f6cddec3e78e9db09ab [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 CEA LIST.
*
* 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:
* CEA LIST - Initial API and implementation
*******************************************************************************/
package org.eclipse.papyrus.requirements.reqif.util;
import java.util.HashMap;
import java.util.List;
import org.eclipse.emf.ecore.EAttribute;
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.util.FeatureMap;
import org.eclipse.emf.ecore.util.FeatureMapUtil;
public class EqualityHelperWithoutContainment extends HashMap<EObject, EObject>
{
private static final long serialVersionUID = 1L;
/**
* Returns whether <code>eObject1</code> and <code>eObject2</code> are {@link EqualityHelper equal}
* in the context of this helper instance.
* @return whether <code>eObject1</code> and <code>eObject2</code> are equal.
* @since 2.1.0
*/
public boolean equals(EObject eObject1, EObject eObject2)
{
// If the first object is null, the second object must be null.
//
if (eObject1 == null)
{
return eObject2 == null;
}
// We know the first object isn't null, so if the second one is, it can't be equal.
//
if (eObject2 == null)
{
return false;
}
// Both eObject1 and eObject2 are not null.
// If eObject1 has been compared already...
//
Object eObject1MappedValue = get(eObject1);
if (eObject1MappedValue != null)
{
// Then eObject2 must be that previous match.
//
return eObject1MappedValue == eObject2;
}
// If eObject2 has been compared already...
//
Object eObject2MappedValue = get(eObject2);
if (eObject2MappedValue != null)
{
// Then eObject1 must be that match.
//
return eObject2MappedValue == eObject1;
}
// Neither eObject1 nor eObject2 have been compared yet.
// If eObject1 and eObject2 are the same instance...
//
if (eObject1 == eObject2)
{
// Match them and return true.
//
put(eObject1, eObject2);
put(eObject2, eObject1);
return true;
}
// If eObject1 is a proxy...
//
if (eObject1.eIsProxy())
{
// Then the other object must be a proxy with the same URI.
//
if (((InternalEObject)eObject1).eProxyURI().equals(((InternalEObject)eObject2).eProxyURI()))
{
put(eObject1, eObject2);
put(eObject2, eObject1);
return true;
}
else
{
return false;
}
}
// If eObject1 isn't a proxy but eObject2 is, they can't be equal.
//
else if (eObject2.eIsProxy())
{
return false;
}
// If they don't have the same class, they can't be equal.
//
EClass eClass = eObject1.eClass();
if (eClass != eObject2.eClass())
{
return false;
}
// Assume from now on that they match.
//
put(eObject1, eObject2);
put(eObject2, eObject1);
// Check all the values.
//
for (int i = 0, size = eClass.getFeatureCount(); i < size; ++i)
{
// Ignore derived features.
//
EStructuralFeature feature = eClass.getEStructuralFeature(i);
if (!feature.isDerived())
{
if( feature instanceof EReference){
if(! ((EReference)feature).isContainment()){
if (!haveEqualFeature(eObject1, eObject2, feature))
{
remove(eObject1);
remove(eObject2);
return false;
}
}
}
else{
if (!haveEqualFeature(eObject1, eObject2, feature))
{
remove(eObject1);
remove(eObject2);
return false;
}
}
}
}
// There's no reason they aren't equal, so they are.
//
return true;
}
/**
* Returns whether <code>list1</code> and <code>list2</code> contain
* {@link #equals(EObject, EObject) equal} {@link EObject}s at the same index.
* It is assumed that list1 and list2 only contain EObjects.
* @return whether <code>list1</code> and <code>list2</code> contain equal objects.
* @since 2.1.0
*/
public boolean equals(List<EObject> list1, List<EObject> list2)
{
int size = list1.size();
if (size != list2.size())
{
return false;
}
for (int i = 0; i < size; i++)
{
EObject eObject1 = list1.get(i);
EObject eObject2 = list2.get(i);
if (!equals(eObject1, eObject2))
{
return false;
}
}
return true;
}
/**
* Returns whether the two objects have {@link EqualityHelper equal}
* {@link EObject#eIsSet(EStructuralFeature) isSet} states and {@link EObject#eGet(EStructuralFeature) value}s for the feature.
* @return whether the two objects have equal isSet states and values for the feature.
* @since 2.2.0
* @see #equals(EObject, EObject)
* @see #equals(List, List)
*/
protected boolean haveEqualFeature(EObject eObject1, EObject eObject2, EStructuralFeature feature)
{
// If the set states are the same, and the values of the feature are the structurally equal, they are equal.
//
final boolean isSet1 = eObject1.eIsSet(feature);
final boolean isSet2 = eObject2.eIsSet(feature);
if (isSet1 && isSet2)
{
return
feature instanceof EReference ?
haveEqualReference(eObject1, eObject2, (EReference)feature) :
haveEqualAttribute(eObject1, eObject2, (EAttribute)feature);
}
else
{
return isSet1 == isSet2;
}
}
/**
* Returns whether the two objects have {@link EqualityHelper equal} {@link EObject#eGet(EStructuralFeature) value}s for the reference.
* @return whether the two objects have equal values for the reference.
* @since 2.1.0
* @see #equals(EObject, EObject)
* @see #equals(List, List)
*/
@SuppressWarnings("unchecked")
protected boolean haveEqualReference(EObject eObject1, EObject eObject2, EReference reference)
{
Object value1 = eObject1.eGet(reference);
Object value2 = eObject2.eGet(reference);
return
reference.isMany() ?
equals((List<EObject>)value1, (List<EObject>)value2) :
equals((EObject)value1, (EObject)value2);
}
/**
* Returns whether the two objects have {@link EqualityHelper equal} {@link EObject#eGet(EStructuralFeature) value}s for the attribute.
* @return whether the two objects have equal values for the attribute.
* @since 2.1.0
* @see #equalFeatureMaps(FeatureMap, FeatureMap)
*/
protected boolean haveEqualAttribute(EObject eObject1, EObject eObject2, EAttribute attribute)
{
Object value1 = eObject1.eGet(attribute);
Object value2 = eObject2.eGet(attribute);
// If the first value is null, the second value must be null.
//
if (value1 == null)
{
return value2 == null;
}
// Since the first value isn't null, if the second one is, they aren't equal.
//
if (value2 == null)
{
return false;
}
// If this is a feature map...
//
if (FeatureMapUtil.isFeatureMap(attribute))
{
// The feature maps must be equal.
//
FeatureMap featureMap1 = (FeatureMap)value1;
FeatureMap featureMap2 = (FeatureMap)value2;
return equalFeatureMaps(featureMap1, featureMap2);
}
else
{
// The values must be Java equal.
//
return equalValues(value1, value2);
}
}
/**
* Returns whether value1 and value2 are structurally equal.
* The default implementation only checks for Java equality.
* @param value1 the first non-null value.
* @param value2 the second potentially null value.
* @return whether value1 and value2 are structurally equal.
* @since 2.10
*/
protected boolean equalValues(Object value1, Object value2)
{
return value1.equals(value2);
}
/**
* Returns whether the two feature maps are {@link EqualityHelper equal}.
* @return whether the two feature maps are equal.
* @since 2.1.0
*/
protected boolean equalFeatureMaps(FeatureMap featureMap1, FeatureMap featureMap2)
{
// If they don't have the same size, the feature maps aren't equal.
//
int size = featureMap1.size();
if (size != featureMap2.size())
{
return false;
}
// Compare entries in order.
//
for (int i = 0; i < size; i++)
{
// If entries don't have the same feature, the feature maps aren't equal.
//
EStructuralFeature feature = featureMap1.getEStructuralFeature(i);
if (feature != featureMap2.getEStructuralFeature(i))
{
return false;
}
Object value1 = featureMap1.getValue(i);
Object value2 = featureMap2.getValue(i);
if (!equalFeatureMapValues(value1, value2, feature))
{
return false;
}
}
// There is no reason they aren't equals.
//
return true;
}
/**
* Returns whether the two values of a feature map are {@link EqualityHelper equal}.
* @return whether the two values of a feature map are equal.
* @since 2.2.0
*/
protected boolean equalFeatureMapValues(Object value1, Object value2, EStructuralFeature feature)
{
if (feature instanceof EReference)
{
// If the referenced EObjects aren't equal, the feature maps aren't equal.
//
return equals((EObject)value1, (EObject)value2);
}
else
{
// If the values aren't Java equal, the feature maps aren't equal.
//
return value1 == null ? value2 == null : equalValues(value1, value2);
}
}
} // EqualityHelper