Refactoring delegating classpath
Separated file caching out of delegating classpath
This commit is contained in:
@@ -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<GradleProjectClasspath>(
|
||||
() -> new GradleProjectClasspath(gradle, projectDir),
|
||||
projectDataCache == null ? null : projectDataCache.resolve(DelegatingCachedClasspath.CLASSPATH_DATA_CACHE_FILE).toFile()
|
||||
fileBasedCache
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<T extends IClasspath> 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<ClasspathData> cachedData;
|
||||
private Callable<T> delegateCreator;
|
||||
private AtomicReference<T> cachedDelegate;
|
||||
|
||||
private ClasspathFileBasedCache fileCache;
|
||||
|
||||
final private File cacheFile;
|
||||
|
||||
public DelegatingCachedClasspath(Callable<T> delegateCreator, File cacheFile) {
|
||||
public DelegatingCachedClasspath(Callable<T> 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<T extends IClasspath> 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<T extends IClasspath> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user