blob: 721a3b0d14919e3ac03559513042cca223212aca [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2018 SAP AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* SAP AG - initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.examples.impactanalyzer.instanceScope;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EPackage;
public class AllSubclassesFinder {
private static final Logger logger = Logger.getLogger(AllSubclassesFinder.class.getName());
private final EPackage.Registry registry;
private static AllSubclassesFinder instance;
/**
* remembers which packages from the {@link #registry} have already been
* cached in {@link #oppositeCache}.
*/
private Set<EPackage> cachedPackages;
/**
* Caches the subclasses of all classes held by the Ecore package registry
*/
private Map<EClass, Set<EClass>> subclasses = new HashMap<EClass, Set<EClass>>();
public static AllSubclassesFinder getInstance() {
if (instance == null) {
instance = new AllSubclassesFinder();
}
return instance;
}
protected AllSubclassesFinder() {
this(EPackage.Registry.INSTANCE);
}
public AllSubclassesFinder(EPackage.Registry registry) {
this.registry = registry;
cachedPackages = new HashSet<EPackage>();
}
private void cachePackage(EPackage ePackage) {
for (EClassifier c : ePackage.getEClassifiers()) {
if (c instanceof EClass) {
cacheSubclassRelations((EClass) c);
}
}
}
private void cacheSubclassRelations(EClass c) {
for (EClass sup : c.getESuperTypes()) {
cacheSubclassForSuperclass(c, sup);
}
}
private void cacheSubclassForSuperclass(EClass sub, EClass sup) {
Set<EClass> subclassesOfSup = subclasses.get(sup);
if (subclassesOfSup == null) {
subclassesOfSup = new HashSet<EClass>();
subclasses.put(sup, subclassesOfSup);
}
subclassesOfSup.add(sub);
for (EClass supsup : sup.getESuperTypes()) {
cacheSubclassForSuperclass(sub, supsup);
}
}
public Collection<EClass> getAllSubclasses(EClass c) {
updateOppositeCache();
Collection<EClass> result = subclasses.get(c);
if (result == null) {
result = Collections.emptySet();
} else {
result = Collections.unmodifiableCollection(result);
}
return result;
}
private void updateOppositeCache() {
Set<String> registryKeys = new HashSet<String>(registry.keySet()); // avoid concurrent modifications
for (String packageUri : registryKeys) {
try {
EPackage ePackage = registry.getEPackage(packageUri);
if (!cachedPackages.contains(ePackage)) {
cachedPackages.add(ePackage);
cachePackage(ePackage);
}
} catch (Throwable e) {
// TODO problem resolving the packageUri into an EPackage; could be
// that the package class doesn't exist in generated form;
// ignore those for now (although it should somehow be possible
// to instantiate this package dynamically)
logger.warning("couldn't resolve Ecore package with URI " + packageUri + ": " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
}