blob: 5a1ed0af458255fa628f3175030cea974e2bb84c [file] [log] [blame]
/**
* Copyright (c) 2010, 2011 Mia-Software 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:
* Gabriel Barbier (Mia-Software) - initial API and implementation
* Fabien Giquel (Mia-Software) - Bug 339720 : MoDisco Discoverers (infra + techno) API clean
* Nicolas Bros (Mia-Software) - Bug 335003 - [Discoverer] : Existing Discoverers Refactoring based on new framework
*/
package org.eclipse.modisco.usecase.modelfilter.dependencies.ui.internal.editor;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.modisco.java.Package;
import org.eclipse.modisco.java.Type;
public class GetUsedPackages {
final Set<Package> getUsedPackages(final Package contextPackage) {
Set<Package> result = new HashSet<Package>();
/*
* calculate used packages from owned elements 1. owned types 2. owned packages
*/
GetUsedTypes typesFinder = new GetUsedTypes();
for (Type ownedType : contextPackage.getOwnedElements()) {
for (Type usedType : typesFinder.getUsedTypes(ownedType)) {
result.add(getContainerPackage(usedType));
}
}
for (Package ownedPackage : contextPackage.getOwnedPackages()) {
result.addAll(getUsedPackages(ownedPackage));
}
/*
* We should filter used packages to keep only first common parent package. We should also
* remove all children packages.
*/
Iterator<Package> iter = result.iterator();
while (iter.hasNext()) {
Package used = iter.next();
if (isParentPackage(contextPackage, used)) {
iter.remove();
}
}
// heavy filter, only if it contains an empty package (no type inside)
if (contextPackage.getOwnedElements().isEmpty()) {
result = filterUsedPackages(result);
}
/*
* there is sometimes a null element in collection we have to find where it comes from. But
* in case of, we will remove null value every time
*/
result.remove(null);
return result;
}
private final Package getContainerPackage(final EObject source) {
Package result = null;
if (source != null) {
if (source.eContainer() instanceof Package) {
result = (Package) source.eContainer();
} else {
result = getContainerPackage(source.eContainer());
}
}
return result;
}
/**
* We should filter used packages to keep only first common parent package. example: initial
* list of used packages = a.b.c, a.b.d, e.f, e.g
*
* final list of used packages = a.b, e
*
* @param usedPackages
* @return a collection of common packages
*/
private final Set<Package> filterUsedPackages(final Set<Package> usedPackages) {
Set<Package> result = new HashSet<Package>();
for (Package usedPackage : usedPackages) {
Package common = this.getFirstCommonPackage(usedPackage, usedPackages);
result.add(common);
}
return result;
}
/**
* This is a particular algorithm, even if we look at a parent package which is common to all
* packages provided as parameters, we consider that packages which have no common hierarchy
* don't have to be compared. For example, if we have two packages a.b and c.d, then result will
* be a.b But if we have three packages a.b, a.c and d.e, then result will be a
*
* @param usedPackage
* @param usedPackages
* @return the package which is common of both packages, usedPackage otherwise
*/
private final Package getFirstCommonPackage(final Package usedPackage,
final Set<Package> usedPackages) {
Package common = usedPackage;
if (usedPackages.contains(usedPackage)) {
Set<Package> subset = new HashSet<Package>(usedPackages);
subset.remove(usedPackage);
common = this.getFirstCommonPackage(usedPackage, subset);
} else {
for (Package otherPackage : usedPackages) {
Package commonTemp = this.getFirstCommonPackage(usedPackage, otherPackage);
if (commonTemp != null) {
if (common == null) {
common = commonTemp;
} else if (isParentPackage(commonTemp, common)) {
common = commonTemp;
} // else, common is a parent package of commonTemp.
} // else, compared packages have no common hierarchy of packages
}
}
return common;
}
/**
*
* @param usedPackage
* @param otherPackage
* @return the package which is common of both packages, null otherwise
*/
private final Package getFirstCommonPackage(final Package usedPackage,
final Package otherPackage) {
Package common = null;
Package current = usedPackage;
while ((common == null) && (current != null)) {
if (isParentPackage(current, otherPackage)) {
common = current;
} else {
current = current.getPackage();
}
}
return common;
}
/**
* @param parent
* @param otherPackage
* @return true if current is in parent hierarchy of otherPackage, false otherwise
*/
private boolean isParentPackage(final Package parent, final Package otherPackage) {
boolean result = false;
if ((parent != null) && (otherPackage != null)) {
if (parent == otherPackage) {
result = true;
} else {
result = isParentPackage(parent, otherPackage.getPackage());
}
}
return result;
}
}