From b76e3b8e1e5ff340af8b4fbdcf26a2df21341f17 Mon Sep 17 00:00:00 2001 From: nsingh Date: Thu, 1 Feb 2018 15:56:02 -0800 Subject: [PATCH] Refactoring delegating classpath Separated file caching out of delegating classpath --- .../commons/gradle/GradleJavaProject.java | 6 +- .../commons/java/ClasspathFileBasedCache.java | 107 ++++++++++++++++++ .../java/DelegatingCachedClasspath.java | 98 ++-------------- .../commons/maven/java/MavenJavaProject.java | 6 +- .../commons/maven/MavenProjectCacheTest.java | 6 +- 5 files changed, 132 insertions(+), 91 deletions(-) create mode 100644 headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/ClasspathFileBasedCache.java diff --git a/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleJavaProject.java b/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleJavaProject.java index 669bb8e35..ac7f98169 100644 --- a/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleJavaProject.java +++ b/headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleJavaProject.java @@ -14,6 +14,7 @@ import java.io.File; import java.nio.file.Path; import org.springframework.ide.vscode.commons.java.AbstractJavaProject; +import org.springframework.ide.vscode.commons.java.ClasspathFileBasedCache; import org.springframework.ide.vscode.commons.java.DelegatingCachedClasspath; import org.springframework.ide.vscode.commons.util.Log; @@ -31,9 +32,12 @@ public class GradleJavaProject extends AbstractJavaProject { public GradleJavaProject(GradleCore gradle, File projectDir, Path projectDataCache) { super(projectDataCache); this.projectDir = projectDir; + File file = projectDataCache == null ? null + : projectDataCache.resolve(ClasspathFileBasedCache.CLASSPATH_DATA_CACHE_FILE).toFile(); + ClasspathFileBasedCache fileBasedCache = new ClasspathFileBasedCache(file); this.classpath = new DelegatingCachedClasspath( () -> new GradleProjectClasspath(gradle, projectDir), - projectDataCache == null ? null : projectDataCache.resolve(DelegatingCachedClasspath.CLASSPATH_DATA_CACHE_FILE).toFile() + fileBasedCache ); } diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/ClasspathFileBasedCache.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/ClasspathFileBasedCache.java new file mode 100644 index 000000000..91992010e --- /dev/null +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/ClasspathFileBasedCache.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2017, 2018 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.java; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Collections; +import java.util.stream.Collectors; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.json.JSONTokener; +import org.springframework.ide.vscode.commons.util.Log; + +public class ClasspathFileBasedCache { + public static final String CLASSPATH_DATA_CACHE_FILE = "classpath-data.json"; + + 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"; + final private File file; + + public ClasspathFileBasedCache(File file) { + super(); + this.file = file; + } + + public synchronized void persist(ClasspathData data) { + if (file != null && data != null) { + FileWriter writer = null; + try { + Files.createDirectories(file.getParentFile().toPath()); + JSONObject json = new JSONObject(); + json.put(NAME_PROPERTY, data.name); + json.put(CLASSPATH_ENTRIES_PROPERTY, data.classpathEntries.stream().map(e -> e.toString()).collect(Collectors.toList())); + json.put(CLASSPATH_RESOURCES_PROPERTY, data.classpathResources); + json.put(OUTPUT_FOLDER_PROPERTY, data.outputFolder); + writer = new FileWriter(file); + json.write(writer); + } catch (IOException e) { + Log.log(e); + } finally { + if (writer != null) { + try { + writer.close(); + } catch (IOException e) { + Log.log(e); + } + } + } + } + } + + public boolean isCached() { + return file != null && file.exists(); + } + + public synchronized ClasspathData load() { + + if (file != null && file.exists()) { + try { + JSONObject json = new JSONObject(new JSONTokener(new FileInputStream(file))); + String name = json.getString(NAME_PROPERTY); + JSONArray classpathEntriesJson = json.optJSONArray(CLASSPATH_ENTRIES_PROPERTY); + JSONArray classpathResourcesJson = json.optJSONArray(CLASSPATH_RESOURCES_PROPERTY); + String outputFolderStr = json.optString(OUTPUT_FOLDER_PROPERTY); + + return new ClasspathData( + name, + classpathEntriesJson == null ? Collections.emptySet() : classpathEntriesJson.toList().stream() + .filter(o -> o instanceof String) + .map(o -> (String) o) + .map(s -> new File(s).toPath()) + .collect(Collectors.toSet()), + classpathResourcesJson == null ? Collections.emptySet() : classpathResourcesJson.toList().stream() + .filter(o -> o instanceof String) + .map(o -> (String) o) + .collect(Collectors.toSet()), + outputFolderStr == null ? null : new File(outputFolderStr).toPath() + ); + } catch (Throwable e) { + Log.log(e); + } + } + return ClasspathData.EMPTY_CLASSPATH_DATA; + } + + + public void delete() { + if (file != null && file.exists()) { + file.delete(); + } + } + +} 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 7ba840d22..14c26b426 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 @@ -11,22 +11,12 @@ package org.springframework.ide.vscode.commons.java; import java.io.File; -import java.io.FileInputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Collections; import java.util.Optional; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; -import java.util.stream.Collectors; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.json.JSONTokener; -import org.springframework.ide.vscode.commons.util.Log; import com.google.common.base.Objects; import com.google.common.collect.ImmutableList; @@ -52,26 +42,24 @@ import reactor.util.function.Tuple2; */ public class DelegatingCachedClasspath implements IClasspath { - public static final String CLASSPATH_DATA_CACHE_FILE = "classpath-data.json"; - - 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"; - private AtomicReference cachedData; private Callable delegateCreator; private AtomicReference cachedDelegate; + + private ClasspathFileBasedCache fileCache; - final private File cacheFile; - public DelegatingCachedClasspath(Callable delegateCreator, File cacheFile) { + public DelegatingCachedClasspath(Callable delegateCreator, ClasspathFileBasedCache fileCache) { super(); - this.cacheFile = cacheFile; + this.fileCache = fileCache; this.cachedDelegate = new AtomicReference<>(null); - this.cachedData = new AtomicReference<>(init()); + this.cachedData = new AtomicReference<>(loadFileBasedCache(fileCache)); this.delegateCreator = delegateCreator; } + + private ClasspathData loadFileBasedCache(ClasspathFileBasedCache fileCache) { + return fileCache != null ? fileCache.load() : ClasspathData.EMPTY_CLASSPATH_DATA; + } public T delegate() { return cachedDelegate.get(); @@ -98,67 +86,7 @@ public class DelegatingCachedClasspath implements IClasspa } public boolean isCached() { - return cacheFile != null && cacheFile.exists(); - } - - private synchronized ClasspathData loadCachedData() { - if (cacheFile != null && cacheFile.exists()) { - try { - JSONObject json = new JSONObject(new JSONTokener(new FileInputStream(cacheFile))); - String name = json.getString(NAME_PROPERTY); - JSONArray classpathEntriesJson = json.optJSONArray(CLASSPATH_ENTRIES_PROPERTY); - JSONArray classpathResourcesJson = json.optJSONArray(CLASSPATH_RESOURCES_PROPERTY); - String outputFolderStr = json.optString(OUTPUT_FOLDER_PROPERTY); - - return new ClasspathData( - name, - classpathEntriesJson == null ? Collections.emptySet() : classpathEntriesJson.toList().stream() - .filter(o -> o instanceof String) - .map(o -> (String) o) - .map(s -> new File(s).toPath()) - .collect(Collectors.toSet()), - classpathResourcesJson == null ? Collections.emptySet() : classpathResourcesJson.toList().stream() - .filter(o -> o instanceof String) - .map(o -> (String) o) - .collect(Collectors.toSet()), - outputFolderStr == null ? null : new File(outputFolderStr).toPath() - ); - } catch (Throwable e) { - Log.log(e); - } - } - return null; - } - - private ClasspathData init() { - ClasspathData data = loadCachedData(); - return data == null ? new ClasspathData(null, Collections.emptySet(), Collections.emptySet(), null) : data; - } - - private synchronized void persistCachedData(ClasspathData data) { - if (cacheFile != null && data != null) { - FileWriter writer = null; - try { - Files.createDirectories(cacheFile.getParentFile().toPath()); - JSONObject json = new JSONObject(); - json.put(NAME_PROPERTY, data.name); - json.put(CLASSPATH_ENTRIES_PROPERTY, data.classpathEntries.stream().map(e -> e.toString()).collect(Collectors.toList())); - json.put(CLASSPATH_RESOURCES_PROPERTY, data.classpathResources); - json.put(OUTPUT_FOLDER_PROPERTY, data.outputFolder); - writer = new FileWriter(cacheFile); - json.write(writer); - } catch (IOException e) { - Log.log(e); - } finally { - if (writer != null) { - try { - writer.close(); - } catch (IOException e) { - Log.log(e); - } - } - } - } + return fileCache.isCached(); } public boolean update() throws Exception { @@ -166,15 +94,13 @@ public class DelegatingCachedClasspath implements IClasspa final ClasspathData newData = createClasspathData(); if (!Objects.equal(cachedData.get(), newData)) { cachedData.set(newData); - persistCachedData(newData); + fileCache.persist(newData); return true; } return false; } catch (Exception e) { cachedData.set(new ClasspathData(null, Collections.emptySet(), Collections.emptySet(), null)); - if (cacheFile != null && cacheFile.exists()) { - cacheFile.delete(); - } + fileCache.delete(); throw e; } } diff --git a/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenJavaProject.java b/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenJavaProject.java index bf9a645f9..ccad4991b 100644 --- a/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenJavaProject.java +++ b/headless-services/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/MavenJavaProject.java @@ -14,6 +14,7 @@ import java.io.File; import java.nio.file.Path; import org.springframework.ide.vscode.commons.java.AbstractJavaProject; +import org.springframework.ide.vscode.commons.java.ClasspathFileBasedCache; import org.springframework.ide.vscode.commons.java.DelegatingCachedClasspath; import org.springframework.ide.vscode.commons.maven.MavenCore; import org.springframework.ide.vscode.commons.util.Log; @@ -32,9 +33,12 @@ public class MavenJavaProject extends AbstractJavaProject { public MavenJavaProject(MavenCore maven, File pom, Path projectDataCache) { super(projectDataCache); this.pom = pom; + File file = projectDataCache == null ? null + : projectDataCache.resolve(ClasspathFileBasedCache.CLASSPATH_DATA_CACHE_FILE).toFile(); + ClasspathFileBasedCache fileBasedCache = new ClasspathFileBasedCache(file); this.classpath = new DelegatingCachedClasspath<>( () -> new MavenProjectClasspath(maven, pom), - projectDataCache == null ? null : projectDataCache.resolve(DelegatingCachedClasspath.CLASSPATH_DATA_CACHE_FILE).toFile() + fileBasedCache ); } diff --git a/headless-services/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/MavenProjectCacheTest.java b/headless-services/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/MavenProjectCacheTest.java index f264b086f..b2031ebb1 100644 --- a/headless-services/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/MavenProjectCacheTest.java +++ b/headless-services/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/MavenProjectCacheTest.java @@ -42,7 +42,7 @@ import org.junit.Before; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import org.springframework.ide.vscode.commons.java.DelegatingCachedClasspath; +import org.springframework.ide.vscode.commons.java.ClasspathFileBasedCache; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.DiagnosticService; import org.springframework.ide.vscode.commons.languageserver.ProgressService; @@ -156,7 +156,7 @@ public class MavenProjectCacheTest { Path cacheFolder = testProjectPath.resolve(IJavaProject.PROJECT_CACHE_FOLDER); - final File classpathCacheFile = cacheFolder.resolve(DelegatingCachedClasspath.CLASSPATH_DATA_CACHE_FILE) + final File classpathCacheFile = cacheFolder.resolve(ClasspathFileBasedCache.CLASSPATH_DATA_CACHE_FILE) .toFile(); AtomicBoolean progressDone = new AtomicBoolean(); @@ -254,6 +254,6 @@ public class MavenProjectCacheTest { progressDone.set(false); verify(diagnosticService, times(1)).diagnosticEvent(any(ShowMessageException.class)); assertTrue(project.getClasspath().getClasspathEntries().isEmpty()); - assertFalse(cacheFolder.resolve(DelegatingCachedClasspath.CLASSPATH_DATA_CACHE_FILE).toFile().exists()); + assertFalse(cacheFolder.resolve(ClasspathFileBasedCache.CLASSPATH_DATA_CACHE_FILE).toFile().exists()); } } \ No newline at end of file