Skip to content

Commit

Permalink
Optimized the parsing of projects from the IdeaProject.
Browse files Browse the repository at this point in the history
  • Loading branch information
kelemen committed Oct 18, 2012
1 parent ec193fc commit abcda21
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 97 deletions.
12 changes: 11 additions & 1 deletion src/org/netbeans/gradle/project/CollectionUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,17 @@ public static <E> List<E> copyNullSafeList(Collection<? extends E> list) {
if (list == null) throw new NullPointerException("list");

List<E> result = Collections.unmodifiableList(new ArrayList<E>(list));
for (E element: list) {
for (E element: result) {
if (element == null) throw new NullPointerException("element");
}
return result;
}

public static <E> ArrayList<E> copyNullSafeMutableList(Collection<? extends E> list) {
if (list == null) throw new NullPointerException("list");

ArrayList<E> result = new ArrayList<E>(list);
for (E element: result) {
if (element == null) throw new NullPointerException("element");
}
return result;
Expand Down
80 changes: 23 additions & 57 deletions src/org/netbeans/gradle/project/model/GradleModelLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand Down Expand Up @@ -152,7 +150,6 @@ public static NbGradleModel createEmptyModel(FileObject projectDir) throws IOExc
File projectDirAsFile = FileUtil.toFile(projectDir);
String name = projectDir.getNameExt();
NbGradleModule.Properties properties = new NbGradleModule.Properties(
true,
name,
projectDirAsFile,
createDefaultOutput(projectDirAsFile),
Expand Down Expand Up @@ -211,10 +208,9 @@ private static IdeaModule tryFindMainModule(FileObject projectDir, IdeaProject i
return null;
}

private static DependenciesResult getDependencies(
private static Map<NbDependencyType, NbDependencyGroup> getDependencies(
IdeaModule module, Map<String, NbGradleModule> parsedModules) {

boolean circular = false;
DependencyBuilder dependencies = new DependencyBuilder();

for (IdeaDependency dependency: module.getDependencies()) {
Expand All @@ -241,12 +237,6 @@ else if ("RUNTIME".equalsIgnoreCase(scope)) {
dependencies.addModuleDependency(
dependencyType,
new NbModuleDependency(parsedDependency, true));
if (parsedDependency.getProperties().hasCircularDependencies()) {
circular = true;
}
}
else {
circular = true;
}
}
else if (dependency instanceof ExternalDependency) {
Expand Down Expand Up @@ -274,7 +264,7 @@ else if (dependency instanceof ExternalDependency) {
dependencyMap.put(type, group);
}
}
return new DependenciesResult(circular, dependencyMap);
return dependencyMap;
}

private static boolean isResourcePath(IdeaSourceDirectory srcDir) {
Expand Down Expand Up @@ -361,16 +351,10 @@ private static NbGradleModule tryParseModule(IdeaModule module,
Map<String, NbGradleModule> parsedModules) {
String uniqueName = module.getGradleProject().getPath();

if (parsedModules.containsKey(uniqueName)) {
NbGradleModule parsedModule = parsedModules.get(uniqueName);
if (parsedModule == null) {
LOGGER.log(Level.WARNING, "Circular or missing dependency: {0}", uniqueName);
}
NbGradleModule parsedModule = parsedModules.get(uniqueName);
if (parsedModule != null) {
return parsedModule;
}
parsedModules.put(uniqueName, null);

DependenciesResult dependencies = getDependencies(module, parsedModules);

Map<NbSourceType, NbSourceGroup> sources = getSources(module);

Expand All @@ -389,32 +373,32 @@ private static NbGradleModule tryParseModule(IdeaModule module,
taskNames.add(new NbGradleTask(qualifiedName, description.trim()));
}

List<NbGradleModule> children = new LinkedList<NbGradleModule>();
NbGradleModule.Properties properties = new NbGradleModule.Properties(
uniqueName,
moduleDir,
createDefaultOutput(moduleDir),
taskNames);
List<File> listedDirs = lookupListedDirs(sources);

NbGradleModuleBuilder moduleBuilder = new NbGradleModuleBuilder(properties, sources, listedDirs);
NbGradleModule result = moduleBuilder.getReadOnlyView();
parsedModules.put(uniqueName, result);

// Recursion is only allowed from this point to avoid infinite
// recursion.

moduleBuilder.addDependencies(getDependencies(module, parsedModules));

for (IdeaModule child: getChildModules(module)) {
NbGradleModule parsedChild = tryParseModule(child, parsedModules);
if (parsedChild == null) {
LOGGER.log(Level.WARNING, "Failed to parse a child module: {0}", child.getName());
}
else {
children.add(parsedChild);
moduleBuilder.addChild(parsedChild);
}
}

NbGradleModule.Properties properties = new NbGradleModule.Properties(
dependencies.hasCircular(),
uniqueName,
moduleDir,
createDefaultOutput(moduleDir),
taskNames);

List<File> listedDirs = lookupListedDirs(sources);
NbGradleModule result = new NbGradleModule(
properties,
sources,
listedDirs,
dependencies.getDependencies(),
children);
parsedModules.put(uniqueName, result);
return result;
}

Expand All @@ -436,37 +420,19 @@ private static NbGradleModel parseFromIdeaModel(
throw new IOException("Unable to parse the main project from the model.");
}

Map<String, NbGradleModule> loadedModules = new HashMap<String, NbGradleModule>(parsedModules);
for (IdeaModule module: ideaModel.getModules()) {
String uniqueName = module.getGradleProject().getPath();
// We have to remove the modules containing circular depencies,
// otherwise we would risk not having every module in the
// dependency graph.
Iterator<Map.Entry<String, NbGradleModule>> parsedModulesItr
= parsedModules.entrySet().iterator();
while (parsedModulesItr.hasNext()) {
Entry<String, NbGradleModule> parsedModule = parsedModulesItr.next();
if (parsedModule.getValue().getProperties().hasCircularDependencies()) {
parsedModulesItr.remove();
}
}

NbGradleModule parsedModule = parsedModules.get(uniqueName);
if (parsedModule == null) {
NbGradleModule subModule = tryParseModule(module, parsedModules);
if (subModule != null) {
loadedModules.put(uniqueName, subModule);
}
}
else {
loadedModules.put(uniqueName, parsedModule);
tryParseModule(module, parsedModules);
}
}

NbGradleModel mainModel = new NbGradleModel(projectDir, parsedMainModule);
FileObject settings = mainModel.getSettingsFile();

for (NbGradleModule module: loadedModules.values()) {
for (NbGradleModule module: parsedModules.values()) {
if (module != null && module != parsedMainModule) {
FileObject moduleDir = FileUtil.toFileObject(module.getModuleDir());
if (moduleDir != null) {
Expand Down
46 changes: 7 additions & 39 deletions src/org/netbeans/gradle/project/model/NbGradleModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import org.netbeans.gradle.project.CollectionUtils;

public final class NbGradleModule {
private final Properties properties;
Expand All @@ -18,38 +16,24 @@ public final class NbGradleModule {
private final List<NbGradleModule> children;
private final List<File> listedDirs;

public NbGradleModule(
// Should only be called by NbGradleModuleBuilder
NbGradleModule(
Properties properties,
Map<NbSourceType, NbSourceGroup> sources,
List<File> listedDirs,
Map<NbDependencyType, NbDependencyGroup> dependencies,
Collection<NbGradleModule> children) {
List<NbGradleModule> children) {

if (properties == null) throw new NullPointerException("properties");
if (dependencies == null) throw new NullPointerException("dependencies");
if (listedDirs == null) throw new NullPointerException("listedDirs");
if (children == null) throw new NullPointerException("children");

this.properties = properties;
this.sources = asImmutable(NbSourceType.class, sources);
this.listedDirs = CollectionUtils.copyNullSafeList(listedDirs);
this.dependencies = asImmutable(NbDependencyType.class, dependencies);
this.children = CollectionUtils.copyNullSafeList(children);
}

private static <K extends Enum<K>, V> Map<K, V> asImmutable(
Class<K> keyType,
Map<K, V> map) {

Map<K, V> clonedMap = new EnumMap<K, V>(keyType);
clonedMap.putAll(map);

for (Map.Entry<K, V> entry: clonedMap.entrySet()) {
if (entry.getKey() == null) throw new NullPointerException("entry.key");
if (entry.getValue() == null) throw new NullPointerException("entry.value for " + entry.getKey());
}

return Collections.unmodifiableMap(clonedMap);
this.sources = Collections.unmodifiableMap(sources);
this.listedDirs = Collections.unmodifiableList(listedDirs);
this.dependencies = Collections.unmodifiableMap(dependencies);
this.children = Collections.unmodifiableList(children);
}

public Properties getProperties() {
Expand Down Expand Up @@ -101,7 +85,6 @@ public List<NbGradleModule> getChildren() {
public static final class Properties {
private static final Collator STR_CMP = Collator.getInstance();

private final boolean circularDependencies;
private final File moduleDir;
private final NbOutput output;
private final String uniqueName;
Expand All @@ -110,7 +93,6 @@ public static final class Properties {
private final List<String> nameParts;

public Properties(
boolean circularDependencies,
String uniqueName,
File moduleDir,
NbOutput output,
Expand All @@ -120,7 +102,6 @@ public Properties(
if (output == null) throw new NullPointerException("output");
if (tasks == null) throw new NullPointerException("tasks");

this.circularDependencies = circularDependencies;
this.uniqueName = uniqueName;
this.moduleDir = moduleDir;
this.output = output;
Expand All @@ -142,19 +123,6 @@ public int compare(NbGradleTask o1, NbGradleTask o2) {
}
}

/**
* Checks whether the associated {@code NbGradleModule} contains all the
* dependencies or not. This property had to be introduced to support
* circular dependencies. That is, when there are circular dependencies
* we are not able to pass all dependencies to each
* {@code NbGradleModule} (the first {@code NbGradleModule} created in
* the circle will surely not have all the dependencies due to the
* immutable nature of this class).
*/
public boolean hasCircularDependencies() {
return circularDependencies;
}

public NbOutput getOutput() {
return output;
}
Expand Down
68 changes: 68 additions & 0 deletions src/org/netbeans/gradle/project/model/NbGradleModuleBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.netbeans.gradle.project.model;

import java.io.File;
import java.util.EnumMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.netbeans.gradle.project.CollectionUtils;

public final class NbGradleModuleBuilder {
// We need this class because in case of circular dependencies we are
// not able to create an immutable NbGradleModule instance.

private final Map<NbDependencyType, NbDependencyGroup> dependencies;
private final List<NbGradleModule> children;
private final NbGradleModule view;

public NbGradleModuleBuilder(
NbGradleModule.Properties properties,
Map<NbSourceType, NbSourceGroup> sources,
List<File> listedDirs) {

if (properties == null) throw new NullPointerException("properties");
if (sources == null) throw new NullPointerException("sources");
if (listedDirs == null) throw new NullPointerException("listedDirs");

this.dependencies = new EnumMap<NbDependencyType, NbDependencyGroup>(NbDependencyType.class);
this.children = new LinkedList<NbGradleModule>();
this.view = new NbGradleModule(properties,
copyNullSafeMutableMap(NbSourceType.class, sources),
CollectionUtils.copyNullSafeMutableList(listedDirs),
dependencies,
children);
}

private static <K extends Enum<K>, V> Map<K, V> copyNullSafeMutableMap(
Class<K> keyType,
Map<K, V> map) {

Map<K, V> clonedMap = new EnumMap<K, V>(keyType);
clonedMap.putAll(map);

for (Map.Entry<K, V> entry: clonedMap.entrySet()) {
if (entry.getKey() == null) throw new NullPointerException("entry.key");
if (entry.getValue() == null) throw new NullPointerException("entry.value for " + entry.getKey());
}

return clonedMap;
}

public void addDependencies(Map<NbDependencyType, NbDependencyGroup> dependencies) {
for (Map.Entry<?, ?> entry: dependencies.entrySet()) {
if (entry.getKey() == null) throw new NullPointerException("entry.key");
if (entry.getValue() == null) throw new NullPointerException("entry.value for " + entry.getKey());
}

this.dependencies.putAll(dependencies);
}

public void addChild(NbGradleModule child) {
if (child == null) throw new NullPointerException("child");
this.children.add(child);
}

public NbGradleModule getReadOnlyView() {
return view;
}
}

0 comments on commit abcda21

Please sign in to comment.