/* * Copyright (c) 2006 Eclipse.org * * 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: * Dmitry Stadnik - initial API and implementation */ package org.eclipse.gmf.internal.bridge.resolver; import java.lang.ref.WeakReference; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EReference; /** * @author dstadnik */ public class ContainmentClosure { private WeakReference<EClass> rootRef = new WeakReference<EClass>(null); // : EClass private WeakReference<EPackage> scopeRef = new WeakReference<EPackage>(null); // : EPackage private WeakReference<Set<EClass>> closureRef = new WeakReference<Set<EClass>>(null); // : Set : EClass public ContainmentClosure() { } /** * Checks whether type is contained within the containment closure of the root type. */ public synchronized boolean contains(EClass root, EClass type, EPackage scope) { assert root != null; assert type != null; assert scope != null; Set<EClass> closure = closureRef.get(); if (rootRef.get() != root || scopeRef.get() != scope || closure == null) { closure = build(root, scope); rootRef = new WeakReference<EClass>(root); scopeRef = new WeakReference<EPackage>(scope); closureRef = new WeakReference<Set<EClass>>(closure); } return closure.contains(type); } private static Set<EClass> build(EClass type, EPackage scope) { assert type != null; Set<EClass> closure = new HashSet<EClass>(); Set<EClass> roots = new HashSet<EClass>(); // types that should be investigated roots.add(type); while (!roots.isEmpty()) { Set<EClass> localRoots = roots; roots = new HashSet<EClass>(); for (Iterator<EClass> it = localRoots.iterator(); it.hasNext();) { EClass root = it.next(); for (Iterator<EReference> it1 = root.getEAllContainments().iterator(); it1.hasNext();) { EClass refType = it1.next().getEReferenceType(); if (closure.contains(refType)) { continue; // do not traverse loops } closure.add(refType); roots.add(refType); Collection<EClass> subtypes = getSubtypes(refType, scope); if (subtypes != null) { for (Iterator<EClass> it2 = subtypes.iterator(); it2.hasNext();) { EClass subtype = it2.next(); if (closure.contains(subtype)) { continue; // do not traverse loops } closure.add(subtype); roots.add(subtype); } } } } } return closure; } private static Collection<EClass> getSubtypes(EClass type, EPackage scope) { Collection<EClass> subtypes = null; for (Iterator<EObject> it = scope.eAllContents(); it.hasNext();) { EObject next = it.next(); if (next instanceof EClass) { EClass nextType = (EClass) next; if (type != nextType && type.isSuperTypeOf(nextType)) { if (subtypes == null) { subtypes = new HashSet<EClass>(); } subtypes.add(nextType); } } } return subtypes; } }