From f7978ba94bb7df83ee0c9dc6e944e0dae2dd940d Mon Sep 17 00:00:00 2001 From: nsingh Date: Wed, 24 Jan 2018 16:12:30 -0800 Subject: [PATCH] Avoid caching maven projects in the maven classpath. Instead extract all the required information into classpath data and cache that instead. --- .../gradle/GradleProjectClasspath.java | 6 + .../commons/jandex/JandexClasspath.java | 19 +-- .../java/DelegatingCachedClasspath.java | 52 ++------ .../ide/vscode/commons/java/IClasspath.java | 6 + .../maven/java/MavenProjectClasspath.java | 119 +++++++++++++----- .../java/classpathfile/FileClasspath.java | 5 + 6 files changed, 123 insertions(+), 84 deletions(-) diff --git a/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectClasspath.java b/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectClasspath.java index cbffe7b47..3559c42a8 100644 --- a/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectClasspath.java +++ b/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleProjectClasspath.java @@ -25,6 +25,7 @@ import org.gradle.tooling.model.build.BuildEnvironment; import org.gradle.tooling.model.eclipse.EclipseProject; import org.springframework.ide.vscode.commons.jandex.JandexClasspath; import org.springframework.ide.vscode.commons.jandex.JandexIndex; +import org.springframework.ide.vscode.commons.java.ClasspathData; import org.springframework.ide.vscode.commons.java.IClasspath; import org.springframework.ide.vscode.commons.java.IJavadocProvider; import org.springframework.ide.vscode.commons.java.parser.ParserJavadocProvider; @@ -241,5 +242,10 @@ public class GradleProjectClasspath extends JandexClasspath { return ImmutableList.copyOf(project.getSourceDirectories().stream() .map(dir -> dir.getDirectory().toPath().toString()).collect(Collectors.toList())); } + + @Override + public ClasspathData createClasspathData() throws Exception { + return ClasspathData.from(getName(), getClasspathEntries(), getClasspathResources(), getOutputFolder()); + } } diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java index 78b5878c9..cbca86b7a 100644 --- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/jandex/JandexClasspath.java @@ -57,12 +57,17 @@ public abstract class JandexClasspath implements IClasspath { Log.log(e); } return new JandexIndex(classpathEntries.map(p -> p.toFile()).collect(Collectors.toList()), jarFile -> findIndexFile(jarFile), classpathResource -> { - switch (providerType) { - case JAVA_PARSER: - return createParserJavadocProvider(classpathResource); - default: - return createHtmlJavdocProvider(classpathResource); + try { + switch (providerType) { + case JAVA_PARSER: + return createParserJavadocProvider(classpathResource); + default: + return createHtmlJavdocProvider(classpathResource); + } + } catch (Exception e) { + Log.log(e); } + return null; }, getBaseIndices()); } @@ -103,8 +108,8 @@ public abstract class JandexClasspath implements IClasspath { return javaIndex.get().findClasspathResourceForType(fqName); } - abstract protected IJavadocProvider createParserJavadocProvider(File classpathResource); + abstract protected IJavadocProvider createParserJavadocProvider(File classpathResource) throws Exception; - abstract protected IJavadocProvider createHtmlJavdocProvider(File classpathResource); + abstract protected IJavadocProvider createHtmlJavdocProvider(File classpathResource) throws Exception; } diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/DelegatingCachedClasspath.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/DelegatingCachedClasspath.java index 788d5d3a7..cd5cb8ad0 100644 --- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/DelegatingCachedClasspath.java +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/DelegatingCachedClasspath.java @@ -19,7 +19,6 @@ import java.nio.file.Path; import java.util.Collections; import java.util.LinkedHashSet; import java.util.Optional; -import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; @@ -55,45 +54,11 @@ import reactor.util.function.Tuple2; public class DelegatingCachedClasspath implements IClasspath { public static final String CLASSPATH_DATA_CACHE_FILE = "classpath-data.json"; - private static final ClasspathData EMPTY_CLASSPATH_DATA = new ClasspathData(null, Collections.emptySet(), - Collections.emptySet(), null); private static final String OUTPUT_FOLDER_PROPERTY = "outputFolder"; private static final String CLASSPATH_RESOURCES_PROPERTY = "classpathResources"; private static final String CLASSPATH_ENTRIES_PROPERTY = "classpathEntries"; private static final String NAME_PROPERTY = "name"; - - protected static class ClasspathData { - - final public String name; - final public Set classpathEntries; - final public Set classpathResources; - final public Path outputFolder; - - public ClasspathData(String name, Set classpathEntries, Set classpathResources, Path outputFolder) { - this.name = name; - this.classpathEntries = classpathEntries; - this.classpathResources = classpathResources; - this.outputFolder = outputFolder; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ClasspathData) { - ClasspathData other = (ClasspathData) obj; - try { - return Objects.equal(name, other.name) - && Objects.equal(classpathEntries, other.classpathEntries) - && Objects.equal(classpathResources, other.classpathResources) - && Objects.equal(outputFolder, outputFolder); - } catch (Throwable t) { - Log.log(t); - } - } - return false; - } - - } private AtomicReference cachedData; private Callable delegateCreator; @@ -245,16 +210,17 @@ public class DelegatingCachedClasspath implements IClasspa return t == null ? Flux.empty() : t.allSubtypesOf(type); } - protected ClasspathData createClasspathData() throws Exception { + @Override + public ClasspathData createClasspathData() throws Exception { T newDelegate = delegateCreator.call(); cachedDelegate.set(newDelegate); - if (newDelegate == null) { - return EMPTY_CLASSPATH_DATA; - } else { - LinkedHashSet classpathEntries = new LinkedHashSet<>(newDelegate.getClasspathEntries()); - return new ClasspathData(newDelegate.getName(), classpathEntries, - new LinkedHashSet<>(newDelegate.getClasspathResources()), newDelegate.getOutputFolder()); - } + if (newDelegate != null) { + ClasspathData data = newDelegate.createClasspathData(); + if (data != null) { + return data; + } + } + return EMPTY_CLASSPATH_DATA; } @Override diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IClasspath.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IClasspath.java index b750729c3..ec58a40c4 100644 --- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IClasspath.java +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/IClasspath.java @@ -12,6 +12,7 @@ package org.springframework.ide.vscode.commons.java; import java.io.File; import java.nio.file.Path; +import java.util.Collections; import java.util.Optional; import java.util.function.Predicate; @@ -60,5 +61,10 @@ public interface IClasspath { ImmutableList getSourceFolders(); Optional findClasspathResourceContainer(String fqName); + + ClasspathData createClasspathData() throws Exception; + + public static final ClasspathData EMPTY_CLASSPATH_DATA = new ClasspathData(null, Collections.emptySet(), + Collections.emptySet(), null); } diff --git a/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectClasspath.java b/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectClasspath.java index a76868e46..76c57ee43 100644 --- a/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectClasspath.java +++ b/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenProjectClasspath.java @@ -16,17 +16,19 @@ import java.net.URL; import java.nio.file.Path; import java.util.Arrays; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; -import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.DirectoryScanner; import org.springframework.ide.vscode.commons.jandex.JandexClasspath; import org.springframework.ide.vscode.commons.jandex.JandexIndex; +import org.springframework.ide.vscode.commons.java.ClasspathData; import org.springframework.ide.vscode.commons.java.IJavadocProvider; import org.springframework.ide.vscode.commons.java.parser.ParserJavadocProvider; import org.springframework.ide.vscode.commons.javadoc.HtmlJavadocProvider; @@ -48,13 +50,13 @@ public class MavenProjectClasspath extends JandexClasspath { private MavenCore maven; private File pom; - private MavenProject project; + private MavenClasspathData cachedData; - MavenProjectClasspath(MavenCore maven, File pom) throws MavenException { + MavenProjectClasspath(MavenCore maven, File pom) throws Exception { super(); this.maven = maven; this.pom = pom; - this.project = createMavenProject(); + this.cachedData = createClasspathData(); } @Override @@ -85,24 +87,28 @@ public class MavenProjectClasspath extends JandexClasspath { } public String getName() { - return project == null ? null : project.getArtifact().getArtifactId(); + return cachedData != null ? cachedData.name : null; + } + + private ImmutableList resolveClasspathEntries(MavenProject project) throws Exception { +// return Stream.concat(maven.resolveDependencies(project, null).stream().map(artifact -> { +// return artifact.getFile().toPath(); +// }), projectResolvedOutput()); + ImmutableList classpathEntries = ImmutableList.copyOf(Stream.concat(projectDependencies(project).stream().map(a -> a.getFile().toPath()), + projectOutput(project).stream().map(f -> f.toPath())).collect(Collectors.toList())); + return classpathEntries; } @Override public ImmutableList getClasspathEntries() throws Exception { -// return Stream.concat(maven.resolveDependencies(project, null).stream().map(artifact -> { -// return artifact.getFile().toPath(); -// }), projectResolvedOutput()); - ImmutableList classpathEntries = ImmutableList.copyOf(Stream.concat(projectDependencies().stream().map(a -> a.getFile().toPath()), - projectOutput().stream().map(f -> f.toPath())).collect(Collectors.toList())); - return classpathEntries; + return cachedData != null ? ImmutableList.copyOf(cachedData.classpathEntries) : ImmutableList.of(); } - private Set projectDependencies() { + private Set projectDependencies(MavenProject project) { return project == null ? Collections.emptySet() : project.getArtifacts(); } - private List projectOutput() { + private List projectOutput(MavenProject project) { if (project == null) { return Collections.emptyList(); } else { @@ -110,16 +116,15 @@ public class MavenProjectClasspath extends JandexClasspath { } } - public Path getOutputFolder() { + private Path resolveOutputFolder(MavenProject project) { return project == null ? null : new File(project.getBuild().getOutputDirectory()).toPath(); } - private Optional getArtifactFromJarFile(File file) throws MavenException { - return project.getArtifacts().stream().filter(a -> file.equals(a.getFile())).findFirst(); + public Path getOutputFolder() { + return cachedData != null ? cachedData.outputFolder : null; } - @Override - public ImmutableList getClasspathResources() { + private ImmutableList resolveClasspathResources(MavenProject project) { if (project == null) { return ImmutableList.of(); } @@ -137,6 +142,11 @@ public class MavenProjectClasspath extends JandexClasspath { return Arrays.stream(scanner.getIncludedFiles()); }).toArray(String[]::new)); } + + @Override + public ImmutableList getClasspathResources() { + return cachedData != null ? ImmutableList.copyOf(cachedData.classpathResources) : ImmutableList.of(); + } /* * Roaster lib is experiment to generate javadoc from source. Commented out for now since roaster lib is taken out @@ -174,20 +184,21 @@ public class MavenProjectClasspath extends JandexClasspath { // } // } + @Override protected IJavadocProvider createParserJavadocProvider(File classpathResource) { - if (project == null) { + if (cachedData == null) { return null; } if (classpathResource.isDirectory()) { - if (classpathResource.toString().startsWith(project.getBuild().getOutputDirectory())) { + if (classpathResource.toString().startsWith(cachedData.outputDirectory)) { return new ParserJavadocProvider(type -> { return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER - .sourceUrl(new File(project.getBuild().getSourceDirectory()).toURI().toURL(), type); + .sourceUrl(new File(cachedData.sourceDirectory).toURI().toURL(), type); }); - } else if (classpathResource.toString().startsWith(project.getBuild().getTestOutputDirectory())) { + } else if (classpathResource.toString().startsWith(cachedData.testOutputDirectory)) { return new ParserJavadocProvider(type -> { return SourceUrlProviderFromSourceContainer.SOURCE_FOLDER_URL_SUPPLIER - .sourceUrl(new File(project.getBuild().getTestSourceDirectory()).toURI().toURL(), type); + .sourceUrl(new File(cachedData.testSourceDirectory).toURI().toURL(), type); }); } else { throw new IllegalArgumentException("Cannot find source folder for " + classpathResource); @@ -196,8 +207,8 @@ public class MavenProjectClasspath extends JandexClasspath { // Assume it's a JAR file return new ParserJavadocProvider(type -> { try { - Artifact artifact = getArtifactFromJarFile(classpathResource).get(); - URL sourceContainer = maven.getSources(artifact, project.getRemoteArtifactRepositories()).getFile().toURI().toURL(); + Artifact artifact = cachedData.artifacts.stream().filter(a -> classpathResource.equals(a.getFile())).findFirst().get(); + URL sourceContainer = maven.getSources(artifact, cachedData.remoteArtifactRepositories).getFile().toURI().toURL(); return SourceUrlProviderFromSourceContainer.JAR_SOURCE_URL_PROVIDER.sourceUrl(sourceContainer, type); } catch (MavenException e) { @@ -210,20 +221,21 @@ public class MavenProjectClasspath extends JandexClasspath { } } + @Override protected IJavadocProvider createHtmlJavdocProvider(File classpathResource) { - if (project == null) { + if (cachedData == null) { return null; } if (classpathResource.isDirectory()) { - if (classpathResource.toString().startsWith(project.getBuild().getOutputDirectory())) { + if (classpathResource.toString().startsWith(cachedData.outputDirectory)) { return new HtmlJavadocProvider(type -> { return SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER - .sourceUrl(new File(project.getModel().getReporting().getOutputDirectory(), "apidocs").toURI().toURL(), type); + .sourceUrl(new File(cachedData.reportingOutputDirectory, "apidocs").toURI().toURL(), type); }); - } else if (classpathResource.toString().startsWith(project.getBuild().getTestOutputDirectory())) { + } else if (classpathResource.toString().startsWith(cachedData.testOutputDirectory)) { return new ParserJavadocProvider(type -> { return SourceUrlProviderFromSourceContainer.JAVADOC_FOLDER_URL_SUPPLIER - .sourceUrl(new File(project.getModel().getReporting().getOutputDirectory(), "apidocs").toURI().toURL(), type); + .sourceUrl(new File(cachedData.reportingOutputDirectory, "apidocs").toURI().toURL(), type); }); } else { throw new IllegalArgumentException("Cannot find source folder for " + classpathResource); @@ -232,8 +244,8 @@ public class MavenProjectClasspath extends JandexClasspath { // Assume it's a JAR file return new HtmlJavadocProvider(type -> { try { - Artifact artifact = getArtifactFromJarFile(classpathResource).get(); - URL sourceContainer = maven.getJavadoc(artifact, project.getRemoteArtifactRepositories()).getFile().toURI().toURL(); + Artifact artifact = cachedData.artifacts.stream().filter(a -> classpathResource.equals(a.getFile())).findFirst().get(); + URL sourceContainer = maven.getJavadoc(artifact, cachedData.remoteArtifactRepositories).getFile().toURI().toURL(); return SourceUrlProviderFromSourceContainer.JAR_JAVADOC_URL_PROVIDER.sourceUrl(sourceContainer, type); } catch (MavenException e) { @@ -252,7 +264,7 @@ public class MavenProjectClasspath extends JandexClasspath { MavenProjectClasspath other = (MavenProjectClasspath) obj; try { if (pom.equals(other.pom) - && Objects.equal(project, other.project)) { + && Objects.equal(cachedData, other.cachedData)) { return super.equals(obj); } } catch (Throwable t) { @@ -264,7 +276,46 @@ public class MavenProjectClasspath extends JandexClasspath { @Override public ImmutableList getSourceFolders() { - return ImmutableList.of(project.getBuild().getSourceDirectory()); + return cachedData != null ? ImmutableList.of(cachedData.sourceDirectory) : ImmutableList.of(); } + @Override + public MavenClasspathData createClasspathData() throws Exception { + MavenProject project = createMavenProject(); + + ImmutableList entries = resolveClasspathEntries(project); + String name = project.getArtifact().getArtifactId(); + ImmutableList resources = resolveClasspathResources(project); + Path outputFolder = resolveOutputFolder(project); + + MavenClasspathData data = new MavenClasspathData(name, new LinkedHashSet<>(entries), + new LinkedHashSet<>(resources), outputFolder); + + data.outputDirectory = project.getBuild().getOutputDirectory(); + data.reportingOutputDirectory = project.getModel().getReporting().getOutputDirectory(); + data.testOutputDirectory = project.getBuild().getTestOutputDirectory(); + data.testSourceDirectory = project.getBuild().getTestSourceDirectory(); + data.artifacts = project.getArtifacts(); + data.remoteArtifactRepositories = project.getRemoteArtifactRepositories(); + data.sourceDirectory = project.getBuild().getSourceDirectory(); + return data; + } + + class MavenClasspathData extends ClasspathData { + + private String testSourceDirectory; + private List remoteArtifactRepositories; + private Set artifacts; + private String testOutputDirectory; + private String reportingOutputDirectory; + private String outputDirectory; + private String sourceDirectory; + + + public MavenClasspathData(String name, Set classpathEntries, Set classpathResources, + Path outputFolder) { + super(name, classpathEntries, classpathResources, outputFolder); + } + + } } diff --git a/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/classpathfile/FileClasspath.java b/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/classpathfile/FileClasspath.java index 1888f5cbb..fc313c0b2 100644 --- a/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/classpathfile/FileClasspath.java +++ b/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/classpathfile/FileClasspath.java @@ -18,6 +18,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.springframework.ide.vscode.commons.java.ClasspathData; import org.springframework.ide.vscode.commons.java.IClasspath; import org.springframework.ide.vscode.commons.java.IType; import org.springframework.ide.vscode.commons.maven.MavenCore; @@ -99,4 +100,8 @@ public class FileClasspath implements IClasspath { return Optional.empty(); } + @Override + public ClasspathData createClasspathData() throws Exception { + return ClasspathData.from(getName(), getClasspathEntries(), getClasspathResources(), getOutputFolder()); + } }