All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.stjs.generator.DependencyCollection Maven / Gradle / Ivy

There is a newer version: 3.3.2.2
Show newest version
/**
 *  Copyright 2011 Alexandru Craciun, Eyal Kaspi
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.stjs.generator;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import com.google.common.collect.ImmutableList;

import edu.umd.cs.findbugs.annotations.SuppressWarnings;

/**
 * This class is used to arrange the list of all dependencies coming from the root classes, such that classes depend on
 * other classes found in the dependency list before they appear. This can be used for example to build the include list
 * of the scripts for a given html page. As in Java cyclic dependency is possible the list may be incorrect.
 * 
 * @author acraciun
 */
public class DependencyCollection {
	private final List roots;

	public static final Comparator> DEPENDENCY_COMPARATOR = new Comparator>() {

		/**
		 * -1: if "b" or any child type of "b" (at any level) extends from "a" or any of "a"'s child type 
* 1: the other way around
* 0: if none of the cases * * @param a * @param b * @return * @throws if * there is a situation where the method cannot decide weather it should return -1 or 1 */ @Override public int compare(Class a, Class b) { return tryCompare(a, b, true); } private int tryCompare(Class a, Class b, boolean checkInverse) { if (a.equals(b)) { return 0; } int direct = getAssignationDirection(a, b); if (!checkInverse) { return direct; } // check both directions to see if there is any contradiction int inverse = tryCompare(b, a, false); if (direct == -1 && inverse == -1) { throw new IllegalArgumentException("Cannot decide the dependency order between the types:" + a + " and " + b); } if (direct != 0) { return direct; } return -inverse; } /** * @return -1 of a (or any of the a declared classes is assignable from b), or 0 otherwise */ private int getAssignationDirection(Class a, Class b) { int direct = 0; if (isAssignableFromTypeOrChildTypes(a, b)) { direct = -1; } else { for (Class child : a.getDeclaredClasses()) { if (isAssignableFromTypeOrChildTypes(child, b)) { direct = -1; break; } } } return direct; } private boolean isAssignableFromTypeOrChildTypes(Class a, Class b) { if (a.isAssignableFrom(b)) { return true; } for (Class child : b.getDeclaredClasses()) { if (isAssignableFromTypeOrChildTypes(a, child)) { return true; } } return false; } }; public DependencyCollection(List roots) { this.roots = ImmutableList.copyOf(roots); } public DependencyCollection(ClassWithJavascript root) { this.roots = ImmutableList.of(root); } private int compareDeps(int withIndex, List deps, Comparator comparator) { for (int j = 0; j < deps.size(); ++j) { if (withIndex != j) { int cmp = comparator.compare(deps.get(withIndex), deps.get(j)); if (cmp > 0) { return cmp; } } } return -1; } public List orderAllDependencies(ClassLoader classLoader) { List deps = new ArrayList(); Set visited = new HashSet(); for (ClassWithJavascript root : roots) { visit(visited, new LinkedHashSet(), deps, root); } Comparator comparator = new ClassWithJavascriptComparator(classLoader); List orderedDeps = new ArrayList(); while (!deps.isEmpty()) { // add to orderedDeps only the classes that have no "extends" dependency to any of the other from the // remaining list. // i.e. the result of the comparison is <= 0 for (int i = 0; i < deps.size(); ++i) { if (compareDeps(i, deps, comparator) <= 0) { orderedDeps.add(deps.remove(i)); i--; } } } return orderedDeps; } /** * use topological sort to find the order of processing cells */ private void visit(Set visited, Set path, List deps, ClassWithJavascript cj) { if (path.contains(cj)) { // cyclic dependency here return; } if (!visited.contains(cj)) { visited.add(cj); path.add(cj); for (ClassWithJavascript dep : cj.getDirectDependencies()) { visit(visited, path, deps, dep); path.remove(dep); } deps.add(cj); } } @SuppressWarnings( value = "SE_COMPARATOR_SHOULD_BE_SERIALIZABLE", justification = "This comparator will not be used with Serializable lists") private static class ClassWithJavascriptComparator implements Comparator { private final ClassLoader classLoader; public ClassWithJavascriptComparator(ClassLoader classLoader) { this.classLoader = classLoader; } @Override public int compare(ClassWithJavascript o1, ClassWithJavascript o2) { try { Class c1 = classLoader.loadClass(o1.getClassName()); Class c2 = classLoader.loadClass(o2.getClassName()); return DEPENDENCY_COMPARATOR.compare(c1, c2); } catch (ClassNotFoundException e) { throw new STJSRuntimeException(e); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy