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

com.google.gwt.dev.cfg.LibraryGroup Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * Copyright 2013 Google Inc.
 *
 * 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 com.google.gwt.dev.cfg;

import com.google.gwt.dev.cfg.Libraries.IncompatibleLibraryVersionException;
import com.google.gwt.dev.javac.CompilationUnit;
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.PermutationResult;
import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.util.PersistenceBackedObject;
import com.google.gwt.thirdparty.guava.common.base.Function;
import com.google.gwt.thirdparty.guava.common.base.Predicates;
import com.google.gwt.thirdparty.guava.common.collect.HashMultimap;
import com.google.gwt.thirdparty.guava.common.collect.Iterables;
import com.google.gwt.thirdparty.guava.common.collect.LinkedHashMultimap;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import com.google.gwt.thirdparty.guava.common.collect.Maps;
import com.google.gwt.thirdparty.guava.common.collect.Multimap;
import com.google.gwt.thirdparty.guava.common.collect.Sets;

import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * A convenience wrapper around a set of libraries.
* * Indexes library contents to enable single step retrieval of resources by name.
* * Analyzes the library dependency tree to provide link ordering and property and rebound type * change analysis for partial generator execution.
* * Combines library resource lists for easy iteration over the complete set. */ public class LibraryGroup { /** * An exception that indicates that some library was referenced as a dependency but was not * provided to the compiler. */ public static class UnresolvedLibraryException extends InternalCompilerException { public UnresolvedLibraryException(String message) { super(message); } } /** * Factory function that constructs and returns a library group from a list of libraries. */ public static LibraryGroup fromLibraries( List libraries, boolean verifyLibraryReferences) { LibraryGroup libraryGroup = new LibraryGroup(); for (Library library : libraries) { libraryGroup.libraries.add(library); } libraryGroup.buildLibraryIndexes(verifyLibraryReferences); return libraryGroup; } /** * Factory function that constructs and returns a library group from a list of zip library paths. */ public static LibraryGroup fromZipPaths(List zipLibraryPaths) throws IncompatibleLibraryVersionException { List zipLibraries = Lists.newArrayList(); for (String zipLibraryPath : zipLibraryPaths) { zipLibraries.add(new ZipLibrary(zipLibraryPath)); } return fromLibraries(zipLibraries, true); } private Set compilationUnitTypeNames; private List libraries = Lists.newArrayList(); private Map librariesByBuildResourcePath; private Map librariesByClassFilePath; private Map librariesByCompilationUnitTypeName; private Map librariesByName; private Map librariesByPublicResourcePath; private List> permutationResultHandles; private Set reboundTypeNames; private List rootLibraries; private Set superSourceCompilationUnitTypeNames; private LibraryGroup() { // Private to force class construction via one of the public factory functions. } /** * Returns whether a build resource is is available at the given path. */ public boolean containsBuildResource(String buildResourcePath) { return getLibrariesByBuildResourcePath().containsKey(buildResourcePath); } /** * Create and return a library group of just the given libraries referenced by name. Useful for * taking an overly broad library group of all libraries in a dependency tree and trimming it down * to a restricted set of strict top level dependencies. */ public LibraryGroup createSubgroup(List libraryNames) { return fromLibraries(getLibraries(libraryNames), false); } /** * Walks the parts of the library dependency graph that have not run the given generator * referenced by name and accumulates and returns a map from binding property name to newly legal * values that were declared in those libraries. */ public Multimap gatherNewBindingPropertyValuesForGenerator(String generatorName) { Multimap newBindingPropertyValuesByName = LinkedHashMultimap.create(); for (Library libraryPendingGeneratorRun : gatherLibrariesForGenerator(generatorName, true)) { newBindingPropertyValuesByName.putAll( libraryPendingGeneratorRun.getNewBindingPropertyValuesByName()); } return newBindingPropertyValuesByName; } /** * Walks the parts of the library dependency graph that have not run the given generator * referenced by name and accumulates and returns a map from configuration property name to newly * set values that were declared in those libraries. */ public Multimap gatherNewConfigurationPropertyValuesForGenerator( String generatorName) { Multimap newConfigurationPropertyValuesByName = LinkedHashMultimap.create(); for (Library libraryPendingGeneratorRun : gatherLibrariesForGenerator(generatorName, true)) { newConfigurationPropertyValuesByName.putAll( libraryPendingGeneratorRun.getNewConfigurationPropertyValuesByName()); } return newConfigurationPropertyValuesByName; } /** * Walks the parts of the library dependency graph that have not run the given generator * referenced by name and accumulates and returns a set of newly rebound type names. */ public Set gatherNewReboundTypeNamesForGenerator(String generatorName) { Set newReboundTypeNames = Sets.newHashSet(); for (Library libraryPendingGeneratorRun : gatherLibrariesForGenerator(generatorName, true)) { newReboundTypeNames.addAll(libraryPendingGeneratorRun.getReboundTypeNames()); } return newReboundTypeNames; } /** * Walks the parts of the library dependency graph that have already run the given generator * referenced by name and accumulates and returns the set of old rebound type names. */ public Set gatherOldReboundTypeNamesForGenerator(String generatorName) { Set oldReboundTypeNames = Sets.newHashSet(); for (Library processedLibrary : gatherLibrariesForGenerator(generatorName, false)) { oldReboundTypeNames.addAll(processedLibrary.getReboundTypeNames()); } return oldReboundTypeNames; } /** * Returns the resource referenced by name if present or null; */ public Resource getBuildResourceByPath(String buildResourcePath) { if (!getLibrariesByBuildResourcePath().containsKey(buildResourcePath)) { return null; } Library library = getLibrariesByBuildResourcePath().get(buildResourcePath); return library.getBuildResourceByPath(buildResourcePath); } /** * Returns the set of all build resource paths. */ public Set getBuildResourcePaths() { return getLibrariesByBuildResourcePath().keySet(); } /** * Opens and returns an input stream for the given class file path if present or null. */ public InputStream getClassFileStream(String classFilePath) { Set classFilePaths = getLibrariesByClassFilePath().keySet(); if (!classFilePaths.contains(Libraries.computeClassFileName(classFilePath))) { return null; } Library library = getLibrariesByClassFilePath().get(Libraries.computeClassFileName(classFilePath)); return library.getClassFileStream(classFilePath); } /** * Returns the compilation unit for the given compilation unit type name if present or null. */ public CompilationUnit getCompilationUnitByTypeName(String typeName) { if (!getLibrariesByCompilationUnitTypeName().containsKey(typeName)) { return null; } Library library = getLibrariesByCompilationUnitTypeName().get(typeName); return library.getCompilationUnitByTypeName(typeName); } /** * Returns the set of all compilation unit type names. */ public Set getCompilationUnitTypeNames() { if (compilationUnitTypeNames == null) { compilationUnitTypeNames = Sets.newLinkedHashSet(); for (Library library : libraries) { compilationUnitTypeNames.addAll(library.getCompilationUnitTypeNames()); } compilationUnitTypeNames = Collections.unmodifiableSet(compilationUnitTypeNames); } return compilationUnitTypeNames; } /** * Returns the list of all permutation result handles (one per library) in library link order. */ public List> getPermutationResultHandlesInLinkOrder() { if (permutationResultHandles == null) { permutationResultHandles = Lists.newArrayList(); for (Library library : libraries) { permutationResultHandles.add(library.getPermutationResultHandle()); } permutationResultHandles = Collections.unmodifiableList(permutationResultHandles); } return permutationResultHandles; } /** * Returns the resource referenced by name if present or null; */ public Resource getPublicResourceByPath(String path) { if (!getLibrariesByPublicResourcePath().containsKey(path)) { return null; } Library library = getLibrariesByPublicResourcePath().get(path); return library.getPublicResourceByPath(path); } /** * Returns the set of all public resource paths. */ public Set getPublicResourcePaths() { return getLibrariesByPublicResourcePath().keySet(); } /** * Returns the set of names of types which are the subject of GWT.create() calls in source code in * any of the contained libraries. */ public Set getReboundTypeNames() { if (reboundTypeNames == null) { reboundTypeNames = Sets.newLinkedHashSet(); for (Library library : libraries) { reboundTypeNames.addAll(library.getReboundTypeNames()); } reboundTypeNames = Collections.unmodifiableSet(reboundTypeNames); } return reboundTypeNames; } /** * Returns the set of compilation unit type names for all contained super source compilation * units. */ public Set getSuperSourceCompilationUnitTypeNames() { if (superSourceCompilationUnitTypeNames == null) { superSourceCompilationUnitTypeNames = Sets.newLinkedHashSet(); for (Library library : libraries) { superSourceCompilationUnitTypeNames.addAll( library.getSuperSourceCompilationUnitTypeNames()); } superSourceCompilationUnitTypeNames = Collections.unmodifiableSet(superSourceCompilationUnitTypeNames); } return superSourceCompilationUnitTypeNames; } // VisibleForTesting List getLibraries() { return libraries; } // VisibleForTesting List getLibraries(Collection libraryNames) { return Lists.newArrayList( Maps.filterKeys(librariesByName, Predicates.in(libraryNames)).values()); } private Iterable asLibraries(Set libraryNames) { return Iterables.transform(libraryNames, new Function() { @Override public Library apply(String libraryName) { return librariesByName.get(libraryName); } }); } private void buildLibraryIndexes(boolean verifyLibraryReferences) { librariesByName = Maps.newLinkedHashMap(); for (Library library : libraries) { librariesByName.put(library.getLibraryName(), library); } Multimap parentLibrariesByChildLibrary = HashMultimap.create(); Multimap childLibrariesByParentLibrary = HashMultimap.create(); for (Library parentLibrary : libraries) { for (String childLibraryName : parentLibrary.getDependencyLibraryNames()) { Library childLibrary = librariesByName.get(childLibraryName); boolean libraryIsMissing = childLibrary == null; if (libraryIsMissing && verifyLibraryReferences) { throw new UnresolvedLibraryException("Library " + parentLibrary.getLibraryName() + " references library " + childLibraryName + " but it is not available."); } parentLibrariesByChildLibrary.put(childLibrary, parentLibrary); childLibrariesByParentLibrary.put(parentLibrary, childLibrary); } } rootLibraries = Lists.newArrayList(); for (Library library : libraries) { boolean libraryHasParents = parentLibrariesByChildLibrary.containsKey(library); if (libraryHasParents) { continue; } rootLibraries.add(library); } List librariesInLinkOrder = Lists.newArrayList(); Set maybeLeafLibraries = Sets.newLinkedHashSet(libraries); while (!maybeLeafLibraries.isEmpty()) { List leafLibraries = Lists.newArrayList(); for (Library maybeLeafLibrary : maybeLeafLibraries) { if (childLibrariesByParentLibrary.get(maybeLeafLibrary).isEmpty()) { leafLibraries.add(maybeLeafLibrary); } } librariesInLinkOrder.addAll(leafLibraries); maybeLeafLibraries.clear(); for (Library leafLibrary : leafLibraries) { Collection parentLibraries = parentLibrariesByChildLibrary.removeAll(leafLibrary); maybeLeafLibraries.addAll(parentLibraries); for (Library parentLibrary : parentLibraries) { childLibrariesByParentLibrary.remove(parentLibrary, leafLibrary); } } } libraries = librariesInLinkOrder; } /** * Walks the library dependency graph and collects a list of libraries that either have or have * not run the given generator depending on the given gatherNotProcessed boolean. */ private List gatherLibrariesForGenerator(String generatorName, boolean generatorWasRun) { Set exploredLibraries = Sets.newHashSet(); LinkedList unexploredLibraries = Lists.newLinkedList(); List librariesForGenerator = Lists.newArrayList(); unexploredLibraries.addAll(rootLibraries); while (!unexploredLibraries.isEmpty()) { Library library = unexploredLibraries.removeFirst(); exploredLibraries.add(library); boolean alreadyProcessed = library.getRanGeneratorNames().contains(generatorName); if (generatorWasRun && alreadyProcessed) { continue; } librariesForGenerator.add(library); for (Library dependencyLibrary : asLibraries(library.getDependencyLibraryNames())) { if (exploredLibraries.contains(dependencyLibrary)) { continue; } unexploredLibraries.add(dependencyLibrary); } } return librariesForGenerator; } private Map getLibrariesByBuildResourcePath() { if (librariesByBuildResourcePath == null) { librariesByBuildResourcePath = Maps.newLinkedHashMap(); for (Library library : libraries) { Set buildResourcePaths = library.getBuildResourcePaths(); for (String buildResourcePath : buildResourcePaths) { librariesByBuildResourcePath.put(buildResourcePath, library); } } librariesByBuildResourcePath = Collections.unmodifiableMap(librariesByBuildResourcePath); } return librariesByBuildResourcePath; } private Map getLibrariesByClassFilePath() { if (librariesByClassFilePath == null) { librariesByClassFilePath = Maps.newLinkedHashMap(); // Record regular class files first. for (Library library : libraries) { Set classFilePaths = library.getClassFilePaths(); for (String classFilePath : classFilePaths) { librariesByClassFilePath.put(classFilePath, library); } } // Overwrite with superSource class files, so they have higher priority. for (Library library : libraries) { Set superSourceClassFilePaths = library.getSuperSourceClassFilePaths(); for (String superSourceClassFilePath : superSourceClassFilePaths) { librariesByClassFilePath.put(superSourceClassFilePath, library); } } librariesByClassFilePath = Collections.unmodifiableMap(librariesByClassFilePath); } return librariesByClassFilePath; } private Map getLibrariesByCompilationUnitTypeName() { if (librariesByCompilationUnitTypeName == null) { librariesByCompilationUnitTypeName = Maps.newLinkedHashMap(); // Record regular compilation units first. for (Library library : libraries) { for (String compilationUnitTypeName : library.getCompilationUnitTypeNames()) { librariesByCompilationUnitTypeName.put(compilationUnitTypeName, library); } } // Overwrite with superSource compilation units, so they have higher priority. for (Library library : libraries) { for (String superSourceCompilationUnitTypeName : library.getSuperSourceCompilationUnitTypeNames()) { librariesByCompilationUnitTypeName.put(superSourceCompilationUnitTypeName, library); } } librariesByCompilationUnitTypeName = Collections.unmodifiableMap(librariesByCompilationUnitTypeName); } return librariesByCompilationUnitTypeName; } private Map getLibrariesByPublicResourcePath() { if (librariesByPublicResourcePath == null) { librariesByPublicResourcePath = Maps.newLinkedHashMap(); for (Library library : libraries) { Set publicResourcePaths = library.getPublicResourcePaths(); for (String publicResourcePath : publicResourcePaths) { librariesByPublicResourcePath.put(publicResourcePath, library); } } librariesByPublicResourcePath = Collections.unmodifiableMap(librariesByPublicResourcePath); } return librariesByPublicResourcePath; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy