// This product is provided under the terms of EPL (Eclipse Public License) // version 1.0. // // The full license text can be read from: http://www.eclipse.org/org/documents/epl-v10.php package org.dtangler.core.dependencies; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public class Dependencies { private class ParentInfo { private Map<Scope, Set<Dependable>> allParents = new HashMap<Scope, Set<Dependable>>(); void addParent(Dependable parent) { Scope scope = parent.getScope(); Set<Dependable> parents = this.allParents.get(scope); if (parents == null) { parents = new HashSet<Dependable>(); allParents.put(scope, parents); } parents.add(parent); } Set<Dependable> getParents(Scope scope) { Set<Dependable> parents = this.allParents.get(scope); return parents != null ? parents : Collections .<Dependable> emptySet(); } } private final Map<Scope, Set<Dependable>> allItems = new HashMap<Scope, Set<Dependable>>(); private final Map<Dependable, Map<Dependable, Integer>> dependencies = new HashMap<Dependable, Map<Dependable, Integer>>(); private final Map<Dependable, Set<Dependable>> allChilds = new HashMap<Dependable, Set<Dependable>>(); private final Map<Dependable, ParentInfo> parents = new HashMap<Dependable, ParentInfo>(); // scopeGraphCache is needed to speed up analysis private final Map<Scope, DependencyGraph> scopeGraphCache = new HashMap<Scope, DependencyGraph>(); private Scope defaultScope; public enum DependencyFilter { none, itemsContributingToTheParentDependencyWeight; } public List<Scope> getAvailableScopes() { List<Scope> sortedScopes = new ArrayList<Scope>(allItems.keySet()); Collections.sort(sortedScopes, new ScopeComparator()); return sortedScopes; } public Scope getChildScope(Scope scope) { List<Scope> scopes = getAvailableScopes(); int index = scopes.indexOf(scope); if (index < 0 || index == scopes.size() - 1) return null; return scopes.get(index + 1); } public Scope getParentScope(Scope scope) { List<Scope> scopes = getAvailableScopes(); int index = scopes.indexOf(scope); if (index <= 0) return null; return scopes.get(index - 1); } public void setDefaultScope(Scope scope) { defaultScope = scope; } public Scope getDefaultScope() { if (defaultScope != null) return defaultScope; List<Scope> scopes = getAvailableScopes(); if (scopes != null && scopes.size() > 0) { for (Scope scope : scopes) { if (scope == null) continue; defaultScope = scope; return defaultScope; } } return null; } public DependencyGraph getDependencyGraph() { return getDependencyGraph(getDefaultScope()); } public DependencyGraph getDependencyGraph(Scope scope) { DependencyGraph graph = scopeGraphCache.get(scope); if (graph == null) { graph = createGraph(scope, getItems(scope), null, DependencyFilter.none); scopeGraphCache.put(scope, graph); } return graph; } public DependencyGraph getDependencyGraph(Scope scope, Set<Dependable> parents, DependencyFilter dependencyFilter) { return createGraph(scope, getItems(scope, parents), parents, dependencyFilter); } private Set<Dependable> getItems(Scope graphScope, Set<Dependable> selectedParents) { Set<Dependable> items = new HashSet<Dependable>(); for (Dependable item : getItems(graphScope)) { for (Dependable parent : selectedParents) { if (getParents(item, parent.getScope()).contains(parent)) { items.add(item); break; } } } return items; } private DependencyGraph createGraph(Scope graphScope, Set<Dependable> items, Set<Dependable> selectedParents, DependencyFilter dependencyFilter) { DependencyGraph graph = null; if (dependencyFilter == DependencyFilter.itemsContributingToTheParentDependencyWeight) { graph = new DependencyGraph(graphScope); } else { graph = new DependencyGraph(graphScope, items); } for (Dependable item : items) { addDependencies(graph, item, graphScope, selectedParents, dependencyFilter); } return graph; } private void addDependencyToGraph(DependencyGraph graph, Dependable dependant, Dependable dependee, Set<Dependable> selectedParents, DependencyFilter dependencyFilter) { if (dependencyFilter == DependencyFilter.itemsContributingToTheParentDependencyWeight) { Scope parentGraphScope = null; for (Dependable parent : selectedParents) { parentGraphScope = parent.getScope(); break; } if (dependant == null || dependee == null || dependant.equals(dependee) || selectedParents == null || parentGraphScope == null) return; Set<Dependable> parentsOfDependant = getParents(dependant, parentGraphScope); if (parentsOfDependant == null) return; for (Dependable parentOfDependee : getParents(dependee, parentGraphScope)) { if (parentOfDependee != null && selectedParents.contains(parentOfDependee)) { for (Dependable parentOfDependant : parentsOfDependant) { if (!selectedParents.contains(parentOfDependant)) continue; if (!parentOfDependee.equals(parentOfDependant)) { if (!graph.getAllItems().contains(dependant)) graph.addItem(dependant); if (!graph.getAllItems().contains(dependee)) graph.addItem(dependee); graph.addDependency(dependant, dependee); return; } } } } } else { graph.addDependency(dependant, dependee); } } private Set<Dependable> getItems(Scope scope) { Set<Dependable> result = allItems.get(scope); return result != null ? result : Collections.<Dependable> emptySet(); } private void addDependencies(DependencyGraph graph, Dependable item, Scope graphScope, Set<Dependable> selectedParents, DependencyFilter dependencyFilter) { addDirectDependencies(graph, item, graphScope, selectedParents, dependencyFilter); addChildDependencies(graph, item, item, graphScope, selectedParents, dependencyFilter); } private void addDirectDependencies(DependencyGraph graph, Dependable item, Scope graphScope, Set<Dependable> selectedParents, DependencyFilter dependencyFilter) { Map<Dependable, Integer> directDependenciesMap = dependencies.get(item); if (directDependenciesMap != null) { Set<Dependable> directDependencies = directDependenciesMap.keySet(); for (Dependable dep : directDependencies) { addDependencies(graph, item, graphScope, directDependenciesMap, dep, selectedParents, dependencyFilter); } } } private void addDependencies(DependencyGraph graph, Dependable item, Scope scope, Map<Dependable, Integer> directDependenciesMap, Dependable dep, Set<Dependable> selectedParents, DependencyFilter dependencyFilter) { if (dep.getScope().equals(scope)) { Integer weight = directDependenciesMap.get(dep); while (weight > 0) { addDependencyToGraph(graph, item, dep, selectedParents, dependencyFilter); weight--; } } } private void addChildDependencies(DependencyGraph graph, Dependable dependant, Dependable item, Scope graphScope, Set<Dependable> selectedParents, DependencyFilter dependencyFilter) { for (Dependable child : getChilds(item)) { addChildDependencies(graph, dependant, child, graphScope, selectedParents, dependencyFilter); Map<Dependable, Integer> childDependenciesMap = dependencies .get(child); if (childDependenciesMap == null) continue; Set<Dependable> childDeps = childDependenciesMap.keySet(); for (Dependable dep : childDeps) { for (Dependable parent : getParents(dep, graphScope)) addDependencyToGraph(graph, dependant, parent, selectedParents, dependencyFilter); } } } public Set<Dependable> getAllItems() { Set<Dependable> items = new HashSet<Dependable>(); for (Scope scope : getAvailableScopes()) { items.addAll(allItems.get(scope)); } return items; } public Set<Dependable> getParents(Dependable item, Scope scope) { ParentInfo parentInfo = parents.get(item); return parentInfo != null ? parentInfo.getParents(scope) : Collections .<Dependable> emptySet(); } public Scope getParentScope(Dependable item) { List<Scope> scopes = getAvailableScopes(); if (item.getScope().index() > 0) { return scopes.get(item.getScope().index() - 1); } return null; } public List<Scope> getParentScopes(Dependable item) { List<Scope> parentScopes = getAvailableScopes(); parentScopes = parentScopes.subList(0, item.getScope().index()); return parentScopes; } public Set<Dependable> getParentsFromAllScopes(Dependable item) { List<Scope> parentScopes = getParentScopes(item); Set<Dependable> parents = new HashSet<Dependable>(); for (Scope scope : parentScopes) { parents.addAll(getParents(item, scope)); } return parents; } public Set<Dependable> getChilds(Dependable item) { Set<Dependable> result = allChilds.get(item); return result != null ? result : Collections.<Dependable> emptySet(); } public void addDependencies(Dependable dependant, Map<? extends Dependable, Integer> newDependees) { addItem(dependant); for (Dependable dependee : newDependees.keySet()) { addItem(dependee); } Map<Dependable, Integer> dependees = dependencies.get(dependant); if (dependees == null) { dependees = new HashMap<Dependable, Integer>(); dependencies.put(dependant, dependees); } dependees.putAll(newDependees); scopeGraphCache.clear(); } public void addChild(Dependable parent, Dependable child) { addItem(parent); if (parent.equals(child)) return; // guard for ownership relation on self addItem(child); Set<Dependable> childs = allChilds.get(parent); if (childs == null) { childs = new HashSet<Dependable>(); allChilds.put(parent, childs); } childs.add(child); setParent(parent, child); scopeGraphCache.clear(); } private void setParent(Dependable newParent, Dependable child) { ParentInfo parentInfo = parents.get(child); if (parentInfo == null) { parentInfo = new ParentInfo(); parents.put(child, parentInfo); } parentInfo.addParent(newParent); setParentToChildsOf(child, newParent); } private void setParentToChildsOf(Dependable item, Dependable newParent) { for (Dependable child : getChilds(item)) { if (child.equals(newParent)) continue;// guard for cyclic ownership relations setParent(newParent, child); } } private void addItem(Dependable item) { Scope scope = item.getScope(); Set<Dependable> items = allItems.get(scope); if (items == null) { items = new HashSet<Dependable>(); allItems.put(scope, items); } items.add(item); } }