blob: 80ed950f098291936947c0cd54144c986eabd0a8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2019 THALES GLOBAL SERVICES.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.common.tools.api.util;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import com.google.common.base.Objects;
/**
* An helper to check EObject equality.</br>
* It extends and override EcoreUtil.EqualityHelper so that equals methods ignore EAttribute that are ID=true.
*
* @author mchauvin
*/
public final class EqualityHelper extends org.eclipse.emf.ecore.util.EcoreUtil.EqualityHelper {
private static final String ENABLE_URI_FRAGMENT_OPTIMIZATION_SYSTEM_PROPERTY = "org.eclipse.sirius.common.enableUriFragmentOptimization"; //$NON-NLS-1$
private static boolean enableUriFragmentCache;
private static final Map<EObject, Record> E_URI_FRAGMENT_CACHE = new ConcurrentHashMap<>();
@Override
protected boolean haveEqualAttribute(EObject eObject1, EObject eObject2, EAttribute attribute) {
boolean isID = attribute.isID();
return isID || super.haveEqualAttribute(eObject1, eObject2, attribute);
}
/**
* Check if a Collection of EObjects contains an EObject, based on their resource and URI fragment.
*
* @param collection
* the collection to watch
* @param eObj
* the EObject to find
* @return <code>true</code> if the collection contains the object, <code>false</code> otherwise
*/
public static boolean contains(final Collection<? extends EObject> collection, final EObject eObj) {
for (final EObject object : collection) {
if (EqualityHelper.areEquals(object, eObj)) {
return true;
}
}
return false;
}
/**
* Remove from a Collection, an EObject, based on their resource and URI fragment.
*
* @param collection
* the collection
* @param eObj
* the EObject to remove
*/
public static void remove(final Collection<? extends EObject> collection, final EObject eObj) {
final Iterator<? extends EObject> iterator = collection.iterator();
while (iterator.hasNext()) {
final EObject next = iterator.next();
if (EqualityHelper.areEquals(next, eObj)) {
iterator.remove();
}
}
}
/**
* Check if two EObject are the same, based on their resource and URI fragment.
*
* @param eObj1
* the first EObject to compare
* @param eObj2
* the second EObject to compare
* @return <code>true</code> if they are equals, <code>false</code> otherwise. If the two objects are both
* <code>null</code> return <code>true</code>, otherwise if only one of them is null, return
* <code>false</code>
*/
public static boolean areEquals(EObject eObj1, EObject eObj2) {
if (Objects.equal(eObj1, eObj2)) {
return true;
}
return haveSameURIFragment(eObj1, eObj2);
}
private static boolean haveSameURIFragment(EObject eObj1, EObject eObj2) {
boolean result = false;
if (sameType(eObj1, eObj2)) {
EObject container1 = eObj1.eContainer();
EObject container2 = eObj2.eContainer();
if (container1 instanceof InternalEObject && container2 instanceof InternalEObject) {
String eObj1Frag = getUriFragment((InternalEObject) container1, eObj1.eContainingFeature(), eObj1);
String eObj2Frag = getUriFragment((InternalEObject) container2, eObj2.eContainingFeature(), eObj2);
if (eObj1Frag != null && eObj2Frag != null && eObj1Frag.equals(eObj2Frag)) {
result = haveSameURIFragment(container1, container2);
}
} else if (container1 == null && container2 == null) {
Resource res1 = eObj1.eResource();
Resource res2 = eObj2.eResource();
if (res1 != null && res2 != null) {
URI uriRes1 = res1.getURI();
URI uriRes2 = res2.getURI();
if ((uriRes1.isPlatformPlugin() && uriRes2.isPlatformPlugin()) || (uriRes1.isPlatformResource() && uriRes2.isPlatformResource())) {
result = uriRes1.equals(uriRes2);
}
}
} else {
/*
* one of the containers is null.. no chance both objects are sharing the same URI.
*/
}
}
return result;
}
private static String getUriFragment(InternalEObject container, EStructuralFeature eContainingFeature, EObject eObj) {
String uriFragment;
if (enableUriFragmentCache) {
Record record = E_URI_FRAGMENT_CACHE.get(eObj);
if (record != null && record.matches(container, eContainingFeature)) {
uriFragment = E_URI_FRAGMENT_CACHE.get(eObj).getUriFragment();
} else {
uriFragment = container.eURIFragmentSegment(eContainingFeature, eObj);
E_URI_FRAGMENT_CACHE.put(eObj, new Record(uriFragment, container, eContainingFeature));
}
} else {
uriFragment = container.eURIFragmentSegment(eContainingFeature, eObj);
}
return uriFragment;
}
private static boolean sameType(EObject eObj1, EObject eObj2) {
return eObj1 != null && eObj2 != null && eObj1.getClass() == eObj2.getClass();
}
/**
* Enable or disable the ability to cache the computed values. The cache is cleared when this method is called to
* disable the cache.
*
* This method does nothing if the optimization has been disabled with the system property
* "org.eclipse.sirius.common.enableUriFragmentOptimization" set to false.
*
* @param enable
* <code>true</code> to allow this helper to put the computed values in a cache, <code>false</code>
* otherwise.
*/
public static synchronized void setUriFragmentCacheEnabled(boolean enable) {
if (!Boolean.valueOf(System.getProperty(ENABLE_URI_FRAGMENT_OPTIMIZATION_SYSTEM_PROPERTY, "true"))) { //$NON-NLS-1$
return;
}
enableUriFragmentCache = enable;
if (!enable) {
E_URI_FRAGMENT_CACHE.clear();
}
}
private static class Record {
private final String uriFragment;
private final EObject eContainer;
private final EStructuralFeature containingFeature;
Record(String uriFragment, EObject container, EStructuralFeature containingFeature) {
this.uriFragment = uriFragment;
this.eContainer = container;
this.containingFeature = containingFeature;
}
/**
* Compare the given container and feature to the recorded ones.
*
* @param container
* a potential container.
* @param feature
* a potential containing feature.
* @return <code>true</code> if the given container and feature are the same instances than the one referenced
* by the current Record, <code>false</code> otherwise.
*/
public boolean matches(EObject container, EStructuralFeature feature) {
return this.eContainer == container && this.containingFeature == feature;
}
public String getUriFragment() {
return uriFragment;
}
}
}