cache for symbol index
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.boot.java.utils;
|
||||
|
||||
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
|
||||
|
||||
public class CachedSymbol {
|
||||
|
||||
private final String docURI;
|
||||
private final long lastModified;
|
||||
private final EnhancedSymbolInformation enhancedSymbol;
|
||||
|
||||
public CachedSymbol(String docURI, long lastModified, EnhancedSymbolInformation enhancedSymbol) {
|
||||
this.docURI = docURI;
|
||||
this.lastModified = lastModified;
|
||||
this.enhancedSymbol = enhancedSymbol;
|
||||
}
|
||||
|
||||
public EnhancedSymbolInformation getEnhancedSymbol() {
|
||||
return enhancedSymbol;
|
||||
}
|
||||
|
||||
public String getDocURI() {
|
||||
return docURI;
|
||||
}
|
||||
|
||||
public long getLastModified() {
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,7 +21,10 @@ public interface SpringIndexer {
|
||||
boolean isInterestedIn(String docURI);
|
||||
|
||||
void initializeProject(IJavaProject project) throws Exception;
|
||||
void updateFile(IJavaProject project, String docURI, String content) throws Exception;
|
||||
void removeProject(IJavaProject project) throws Exception;
|
||||
|
||||
void updateFile(IJavaProject project, String docURI, long lastModified, String content) throws Exception;
|
||||
void removeFile(IJavaProject project, String docURI) throws Exception;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -20,6 +22,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.jdt.core.dom.AST;
|
||||
import org.eclipse.jdt.core.dom.ASTParser;
|
||||
@@ -55,10 +58,12 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
|
||||
private final SymbolHandler symbolHandler;
|
||||
private final AnnotationHierarchyAwareLookup<SymbolProvider> symbolProviders;
|
||||
private final SymbolCache cache;
|
||||
|
||||
public SpringIndexerJava(SymbolHandler symbolHandler, AnnotationHierarchyAwareLookup<SymbolProvider> symbolProviders) {
|
||||
public SpringIndexerJava(SymbolHandler symbolHandler, AnnotationHierarchyAwareLookup<SymbolProvider> symbolProviders, SymbolCache cache) {
|
||||
this.symbolHandler = symbolHandler;
|
||||
this.symbolProviders = symbolProviders;
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,53 +78,37 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
|
||||
@Override
|
||||
public void initializeProject(IJavaProject project) throws Exception {
|
||||
List<String> files = Files.walk(Paths.get(project.getLocationUri()))
|
||||
.filter(path -> path.getFileName().toString().endsWith(".java"))
|
||||
.filter(Files::isRegularFile)
|
||||
.map(path -> path.toAbsolutePath().toString())
|
||||
.collect(Collectors.toList());
|
||||
String[] files = this.getFiles(project);
|
||||
|
||||
log.info("scan java files for symbols for project: " + project.getElementName() + " - no. of files: " + files.size());
|
||||
log.info("scan java files for symbols for project: " + project.getElementName() + " - no. of files: " + files.length);
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
scanProject(project, (String[]) files.toArray(new String[files.size()]));
|
||||
scanFiles(project, files);
|
||||
long endTime = System.currentTimeMillis();
|
||||
|
||||
log.info("scan java files for symbols for project: " + project.getElementName() + " took ms: " + (endTime - startTime));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFile(IJavaProject project, String docURI, String content) throws Exception {
|
||||
String[] classpathEntries = getClasspathEntries(project);
|
||||
scanFile(project, docURI, content, classpathEntries);
|
||||
public void removeProject(IJavaProject project) throws Exception {
|
||||
SymbolCacheKey cacheKey = getCacheKey(project);
|
||||
this.cache.remove(cacheKey);
|
||||
}
|
||||
|
||||
|
||||
private void scanProject(IJavaProject project, String[] files) {
|
||||
try {
|
||||
ASTParser parser = ASTParser.newParser(AST.JLS11);
|
||||
String[] classpathEntries = getClasspathEntries(project);
|
||||
|
||||
scanFiles(project, parser, files, classpathEntries);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error parsing all Java source files from project: " + project.getElementName(), e);
|
||||
}
|
||||
@Override
|
||||
public void updateFile(IJavaProject project, String docURI, long lastModified, String content) throws Exception {
|
||||
scanFile(project, docURI, lastModified, content);
|
||||
}
|
||||
|
||||
private void scanFile(IJavaProject project, String docURI, String content, String[] classpathEntries) throws Exception {
|
||||
ASTParser parser = ASTParser.newParser(AST.JLS11);
|
||||
Map<String, String> options = JavaCore.getOptions();
|
||||
JavaCore.setComplianceOptions(JavaCore.VERSION_11, options);
|
||||
parser.setCompilerOptions(options);
|
||||
parser.setKind(ASTParser.K_COMPILATION_UNIT);
|
||||
parser.setStatementsRecovery(true);
|
||||
parser.setBindingsRecovery(true);
|
||||
parser.setResolveBindings(true);
|
||||
parser.setIgnoreMethodBodies(false);
|
||||
@Override
|
||||
public void removeFile(IJavaProject project, String docURI) throws Exception {
|
||||
SymbolCacheKey cacheKey = getCacheKey(project);
|
||||
String file = new File(new URI(docURI)).getAbsolutePath();
|
||||
this.cache.removeFile(cacheKey, file);
|
||||
}
|
||||
|
||||
String[] sourceEntries = new String[] {};
|
||||
parser.setEnvironment(classpathEntries, sourceEntries, null, false);
|
||||
private void scanFile(IJavaProject project, String docURI, long lastModified, String content) throws Exception {
|
||||
ASTParser parser = createParser(project);
|
||||
|
||||
String unitName = docURI.substring(docURI.lastIndexOf("/"));
|
||||
parser.setUnitName(unitName);
|
||||
@@ -128,44 +117,64 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
|
||||
|
||||
if (cu != null) {
|
||||
List<CachedSymbol> generatedSymbols = new ArrayList<CachedSymbol>();
|
||||
|
||||
AtomicReference<TextDocument> docRef = new AtomicReference<>();
|
||||
scanAST(project, cu, docURI, docRef, content);
|
||||
scanAST(project, cu, docURI, lastModified, docRef, content, generatedSymbols);
|
||||
|
||||
SymbolCacheKey cacheKey = getCacheKey(project);
|
||||
String file = new File(new URI(docURI)).getAbsolutePath();
|
||||
this.cache.update(cacheKey, file, lastModified, generatedSymbols);
|
||||
|
||||
for (CachedSymbol symbol : generatedSymbols) {
|
||||
symbolHandler.addSymbol(project, symbol.getDocURI(), symbol.getEnhancedSymbol());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void scanFiles(IJavaProject project, ASTParser parser, String[] javaFiles, String[] classpathEntries) throws Exception {
|
||||
private void scanFiles(IJavaProject project, String[] javaFiles) throws Exception {
|
||||
SymbolCacheKey cacheKey = getCacheKey(project);
|
||||
CachedSymbol[] symbols = this.cache.retrieve(cacheKey, javaFiles);
|
||||
|
||||
Map<String, String> options = JavaCore.getOptions();
|
||||
JavaCore.setComplianceOptions(JavaCore.VERSION_11, options);
|
||||
parser.setCompilerOptions(options);
|
||||
parser.setKind(ASTParser.K_COMPILATION_UNIT);
|
||||
parser.setStatementsRecovery(true);
|
||||
parser.setBindingsRecovery(true);
|
||||
parser.setResolveBindings(true);
|
||||
parser.setIgnoreMethodBodies(false);
|
||||
if (symbols == null) {
|
||||
List<CachedSymbol> generatedSymbols = new ArrayList<CachedSymbol>();
|
||||
|
||||
String[] sourceEntries = new String[] {};
|
||||
parser.setEnvironment(classpathEntries, sourceEntries, null, false);
|
||||
ASTParser parser = createParser(project);
|
||||
|
||||
FileASTRequestor requestor = new FileASTRequestor() {
|
||||
@Override
|
||||
public void acceptAST(String sourceFilePath, CompilationUnit cu) {
|
||||
String docURI = UriUtil.toUri(new File(sourceFilePath)).toString();
|
||||
AtomicReference<TextDocument> docRef = new AtomicReference<>();
|
||||
scanAST(project, cu, docURI, docRef, null);
|
||||
FileASTRequestor requestor = new FileASTRequestor() {
|
||||
@Override
|
||||
public void acceptAST(String sourceFilePath, CompilationUnit cu) {
|
||||
File file = new File(sourceFilePath);
|
||||
String docURI = UriUtil.toUri(file).toString();
|
||||
long lastModified = file.lastModified();
|
||||
|
||||
AtomicReference<TextDocument> docRef = new AtomicReference<>();
|
||||
scanAST(project, cu, docURI, lastModified, docRef, null, generatedSymbols);
|
||||
}
|
||||
};
|
||||
|
||||
parser.createASTs(javaFiles, null, new String[0], requestor, null);
|
||||
this.cache.store(cacheKey, javaFiles, generatedSymbols);
|
||||
}
|
||||
else {
|
||||
log.info("scan java files used cached data: " + project.getElementName() + " - no. of cached symbols retrieved: " + symbols.length);
|
||||
}
|
||||
|
||||
if (symbols != null) {
|
||||
for (int i = 0; i < symbols.length; i++) {
|
||||
CachedSymbol symbol = symbols[i];
|
||||
symbolHandler.addSymbol(project, symbol.getDocURI(), symbol.getEnhancedSymbol());
|
||||
}
|
||||
};
|
||||
|
||||
parser.createASTs(javaFiles, null, new String[0], requestor, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void scanAST(final IJavaProject project, final CompilationUnit cu, final String docURI, AtomicReference<TextDocument> docRef, final String content) {
|
||||
private void scanAST(final IJavaProject project, final CompilationUnit cu, final String docURI, long lastModified, AtomicReference<TextDocument> docRef, final String content, List<CachedSymbol> generatedSymbols) {
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
@Override
|
||||
public boolean visit(TypeDeclaration node) {
|
||||
try {
|
||||
extractSymbolInformation(project, node, docURI, docRef, content);
|
||||
extractSymbolInformation(project, node, docURI, docRef, content, lastModified, generatedSymbols);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error extracting symbol information in project '" + project.getElementName() + "' - for docURI '" + docURI + "' - on node: " + node.toString(), e);
|
||||
@@ -176,7 +185,7 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
@Override
|
||||
public boolean visit(MethodDeclaration node) {
|
||||
try {
|
||||
extractSymbolInformation(project, node, docURI, docRef, content);
|
||||
extractSymbolInformation(project, node, docURI, docRef, content, lastModified, generatedSymbols);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error extracting symbol information in project '" + project.getElementName() + "' - for docURI '" + docURI + "' - on node: " + node.toString(), e);
|
||||
@@ -187,7 +196,7 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
@Override
|
||||
public boolean visit(SingleMemberAnnotation node) {
|
||||
try {
|
||||
extractSymbolInformation(project, node, docURI, docRef, content);
|
||||
extractSymbolInformation(project, node, docURI, docRef, content, lastModified, generatedSymbols);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error extracting symbol information in project '" + project.getElementName() + "' - for docURI '" + docURI + "' - on node: " + node.toString(), e);
|
||||
@@ -199,7 +208,7 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
@Override
|
||||
public boolean visit(NormalAnnotation node) {
|
||||
try {
|
||||
extractSymbolInformation(project, node, docURI, docRef, content);
|
||||
extractSymbolInformation(project, node, docURI, docRef, content, lastModified, generatedSymbols);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error extracting symbol information in project '" + project.getElementName() + "' - for docURI '" + docURI + "' - on node: " + node.toString(), e);
|
||||
@@ -211,7 +220,7 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
@Override
|
||||
public boolean visit(MarkerAnnotation node) {
|
||||
try {
|
||||
extractSymbolInformation(project, node, docURI, docRef, content);
|
||||
extractSymbolInformation(project, node, docURI, docRef, content, lastModified, generatedSymbols);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error extracting symbol information in project '" + project.getElementName() + "' - for docURI '" + docURI + "' - on node: " + node.toString(), e);
|
||||
@@ -222,7 +231,8 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
});
|
||||
}
|
||||
|
||||
private void extractSymbolInformation(IJavaProject project, TypeDeclaration typeDeclaration, String docURI, AtomicReference<TextDocument> docRef, String content) throws Exception {
|
||||
private void extractSymbolInformation(IJavaProject project, TypeDeclaration typeDeclaration, String docURI, AtomicReference<TextDocument> docRef, String content,
|
||||
long lastModified, List<CachedSymbol> generatedSymbols) throws Exception {
|
||||
Collection<SymbolProvider> providers = symbolProviders.getAll();
|
||||
if (!providers.isEmpty()) {
|
||||
TextDocument doc = DocumentUtils.getTempTextDocument(docURI, docRef, content);
|
||||
@@ -230,14 +240,15 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
Collection<EnhancedSymbolInformation> sbls = provider.getSymbols(typeDeclaration, doc);
|
||||
if (sbls != null) {
|
||||
sbls.forEach(enhancedSymbol -> {
|
||||
symbolHandler.addSymbol(project, docURI, enhancedSymbol);
|
||||
generatedSymbols.add(new CachedSymbol(docURI, lastModified, enhancedSymbol));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void extractSymbolInformation(IJavaProject project, MethodDeclaration methodDeclaration, String docURI, AtomicReference<TextDocument> docRef, String content) throws Exception {
|
||||
private void extractSymbolInformation(IJavaProject project, MethodDeclaration methodDeclaration, String docURI, AtomicReference<TextDocument> docRef, String content,
|
||||
long lastModified, List<CachedSymbol> generatedSymbols) throws Exception {
|
||||
Collection<SymbolProvider> providers = symbolProviders.getAll();
|
||||
if (!providers.isEmpty()) {
|
||||
TextDocument doc = DocumentUtils.getTempTextDocument(docURI, docRef, content);
|
||||
@@ -245,14 +256,15 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
Collection<EnhancedSymbolInformation> sbls = provider.getSymbols(methodDeclaration, doc);
|
||||
if (sbls != null) {
|
||||
sbls.forEach(enhancedSymbol -> {
|
||||
symbolHandler.addSymbol(project, docURI, enhancedSymbol);
|
||||
generatedSymbols.add(new CachedSymbol(docURI, lastModified, enhancedSymbol));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void extractSymbolInformation(IJavaProject project, Annotation node, String docURI, AtomicReference<TextDocument> docRef, String content) throws Exception {
|
||||
private void extractSymbolInformation(IJavaProject project, Annotation node, String docURI, AtomicReference<TextDocument> docRef, String content,
|
||||
long lastModified, List<CachedSymbol> generatedSymbols) throws Exception {
|
||||
ITypeBinding typeBinding = node.resolveTypeBinding();
|
||||
|
||||
if (typeBinding != null) {
|
||||
@@ -264,14 +276,15 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
Collection<EnhancedSymbolInformation> sbls = provider.getSymbols(node, typeBinding, metaAnnotations, doc);
|
||||
if (sbls != null) {
|
||||
sbls.forEach(enhancedSymbol -> {
|
||||
symbolHandler.addSymbol(project, docURI, enhancedSymbol);
|
||||
generatedSymbols.add(new CachedSymbol(docURI, lastModified, enhancedSymbol));
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SymbolInformation symbol = provideDefaultSymbol(project, node, docURI, docRef, content);
|
||||
if (symbol != null) {
|
||||
symbolHandler.addSymbol(project, docURI, new EnhancedSymbolInformation(symbol, null));
|
||||
EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, null);
|
||||
generatedSymbols.add(new CachedSymbol(docURI, lastModified, enhancedSymbol));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -295,6 +308,24 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
return null;
|
||||
}
|
||||
|
||||
private ASTParser createParser(IJavaProject project) throws Exception {
|
||||
String[] classpathEntries = getClasspathEntries(project);
|
||||
|
||||
ASTParser parser = ASTParser.newParser(AST.JLS11);
|
||||
Map<String, String> options = JavaCore.getOptions();
|
||||
JavaCore.setComplianceOptions(JavaCore.VERSION_11, options);
|
||||
parser.setCompilerOptions(options);
|
||||
parser.setKind(ASTParser.K_COMPILATION_UNIT);
|
||||
parser.setStatementsRecovery(true);
|
||||
parser.setBindingsRecovery(true);
|
||||
parser.setResolveBindings(true);
|
||||
parser.setIgnoreMethodBodies(false);
|
||||
|
||||
String[] sourceEntries = new String[] {};
|
||||
parser.setEnvironment(classpathEntries, sourceEntries, null, false);
|
||||
return parser;
|
||||
}
|
||||
|
||||
private String[] getClasspathEntries(IJavaProject project) throws Exception {
|
||||
IClasspath classpath = project.getClasspath();
|
||||
Stream<File> classpathEntries = IClasspathUtil.getAllBinaryRoots(classpath).stream();
|
||||
@@ -304,4 +335,24 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
private String[] getFiles(IJavaProject project) throws Exception {
|
||||
return Files.walk(Paths.get(project.getLocationUri()))
|
||||
.filter(path -> path.getFileName().toString().endsWith(".java"))
|
||||
.filter(Files::isRegularFile)
|
||||
.map(path -> path.toAbsolutePath().toString())
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
private SymbolCacheKey getCacheKey(IJavaProject project) {
|
||||
IClasspath classpath = project.getClasspath();
|
||||
Stream<File> classpathEntries = IClasspathUtil.getAllBinaryRoots(classpath).stream();
|
||||
|
||||
String classpathIdentifier = classpathEntries
|
||||
.filter(file -> file.exists())
|
||||
.map(file -> file.getAbsolutePath() + "#" + file.lastModified())
|
||||
.collect(Collectors.joining(","));
|
||||
|
||||
return new SymbolCacheKey(project.getElementName() + "-java-", DigestUtils.md5Hex(classpathIdentifier).toUpperCase());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.eclipse.lsp4xml.dom.DOMDocument;
|
||||
@@ -37,10 +36,12 @@ public class SpringIndexerXML implements SpringIndexer {
|
||||
|
||||
private final SymbolHandler symbolHandler;
|
||||
private final Map<String, SpringIndexerXMLNamespaceHandler> namespaceHandler;
|
||||
private final SymbolCache cache;
|
||||
|
||||
public SpringIndexerXML(SymbolHandler handler, Map<String, SpringIndexerXMLNamespaceHandler> namespaceHandler) {
|
||||
public SpringIndexerXML(SymbolHandler handler, Map<String, SpringIndexerXMLNamespaceHandler> namespaceHandler, SymbolCache cache) {
|
||||
this.symbolHandler = handler;
|
||||
this.namespaceHandler = namespaceHandler;
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,30 +56,30 @@ public class SpringIndexerXML implements SpringIndexer {
|
||||
|
||||
@Override
|
||||
public void initializeProject(IJavaProject project) throws Exception {
|
||||
List<String> files = Files.walk(Paths.get(project.getLocationUri()))
|
||||
.filter(path -> path.getFileName().toString().endsWith(".xml"))
|
||||
.filter(Files::isRegularFile)
|
||||
.map(path -> path.toAbsolutePath().toString())
|
||||
.collect(Collectors.toList());
|
||||
String[] files = this.getFiles(project);
|
||||
|
||||
log.info("scan xml files for symbols for project: " + project.getElementName() + " - no. of files: " + files.size());
|
||||
log.info("scan xml files for symbols for project: " + project.getElementName() + " - no. of files: " + files.length);
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
scanProject(project, (String[]) files.toArray(new String[files.size()]));
|
||||
for (String file : files) {
|
||||
scanFile(project, file);
|
||||
}
|
||||
long endTime = System.currentTimeMillis();
|
||||
|
||||
log.info("scan xml files for symbols for project: " + project.getElementName() + " took ms: " + (endTime - startTime));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFile(IJavaProject project, String docURI, String content) throws Exception {
|
||||
public void removeProject(IJavaProject project) throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFile(IJavaProject project, String docURI, long lastModified, String content) throws Exception {
|
||||
scanFile(project, content, docURI);
|
||||
}
|
||||
|
||||
private void scanProject(IJavaProject project, String[] files) {
|
||||
for (String file : files) {
|
||||
scanFile(project, file);
|
||||
}
|
||||
@Override
|
||||
public void removeFile(IJavaProject project, String docURI) throws Exception {
|
||||
}
|
||||
|
||||
private void scanFile(IJavaProject project, String fileName) {
|
||||
@@ -86,6 +87,7 @@ public class SpringIndexerXML implements SpringIndexer {
|
||||
|
||||
try {
|
||||
File file = new File(fileName);
|
||||
long lastModified = file.lastModified();
|
||||
|
||||
String docURI = UriUtil.toUri(file).toString();
|
||||
String fileContent = FileUtils.readFileToString(file);
|
||||
@@ -132,4 +134,13 @@ public class SpringIndexerXML implements SpringIndexer {
|
||||
|
||||
|
||||
}
|
||||
|
||||
private String[] getFiles(IJavaProject project) throws Exception {
|
||||
return Files.walk(Paths.get(project.getLocationUri()))
|
||||
.filter(path -> path.getFileName().toString().endsWith(".xml"))
|
||||
.filter(Files::isRegularFile)
|
||||
.map(path -> path.toAbsolutePath().toString())
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
public class SpringSymbolIndex {
|
||||
|
||||
private static final String QUERY_PARAM_LOCATION_PREFIX = "locationPrefix:";
|
||||
|
||||
private static final int MAX_NUMBER_OF_SYMBOLS_IN_RESPONSE = 50;
|
||||
|
||||
private final SimpleLanguageServer server;
|
||||
@@ -73,6 +72,7 @@ public class SpringSymbolIndex {
|
||||
|
||||
private final ExecutorService updateQueue;
|
||||
private SpringIndexer[] indexer;
|
||||
private SymbolCache cache;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SpringSymbolIndex.class);
|
||||
|
||||
@@ -124,6 +124,19 @@ public class SpringSymbolIndex {
|
||||
this.addonInformationByDoc = new ConcurrentHashMap<>();
|
||||
this.addonInformationByProject = new ConcurrentHashMap<>();
|
||||
|
||||
if ("true".equals(System.getProperty("boot.ls.symbolCache.enabled", "true"))) {
|
||||
try {
|
||||
this.cache = new SymbolCacheOnDisc();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("symbol cache directory could not be created, no cache enabled");
|
||||
}
|
||||
}
|
||||
|
||||
if (this.cache == null) {
|
||||
this.cache = new SymbolCacheVoid();
|
||||
}
|
||||
|
||||
SymbolHandler handler = new SymbolHandler() {
|
||||
@Override
|
||||
public void addSymbol(IJavaProject project, String docURI, EnhancedSymbolInformation enhancedSymbol) {
|
||||
@@ -133,8 +146,8 @@ public class SpringSymbolIndex {
|
||||
|
||||
Map<String, SpringIndexerXMLNamespaceHandler> namespaceHandler = new HashMap<>();
|
||||
namespaceHandler.put("http://www.springframework.org/schema/beans", new SpringIndexerXMLNamespaceHandlerBeans());
|
||||
springIndexerXML = new SpringIndexerXML(handler, namespaceHandler);
|
||||
springIndexerJava = new SpringIndexerJava(handler, specificProviders);
|
||||
springIndexerXML = new SpringIndexerXML(handler, namespaceHandler, this.cache);
|
||||
springIndexerJava = new SpringIndexerJava(handler, specificProviders, this.cache);
|
||||
|
||||
this.indexer = new SpringIndexer[] {springIndexerJava};
|
||||
|
||||
@@ -248,7 +261,7 @@ public class SpringSymbolIndex {
|
||||
log.debug("Project with NULL name is being removed");
|
||||
return CompletableFuture.completedFuture(null);
|
||||
} else {
|
||||
DeleteProject initializeItem = new DeleteProject(project);
|
||||
DeleteProject initializeItem = new DeleteProject(project, this.indexer);
|
||||
return CompletableFuture.runAsync(initializeItem, this.updateQueue);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
@@ -267,8 +280,11 @@ public class SpringSymbolIndex {
|
||||
|
||||
if (maybeProject.isPresent()) {
|
||||
try {
|
||||
String content = FileUtils.readFileToString(new File(new URI(docURI)));
|
||||
UpdateItem updateItem = new UpdateItem(maybeProject.get(), docURI, content, indexer);
|
||||
File file = new File(new URI(docURI));
|
||||
long lastModified = file.lastModified();
|
||||
String content = FileUtils.readFileToString(file);
|
||||
|
||||
UpdateItem updateItem = new UpdateItem(maybeProject.get(), docURI, lastModified, content, indexer);
|
||||
futures.add(CompletableFuture.runAsync(updateItem, this.updateQueue));
|
||||
}
|
||||
catch (Exception e) {
|
||||
@@ -292,11 +308,14 @@ public class SpringSymbolIndex {
|
||||
Optional<IJavaProject> maybeProject = projectFinder.find(new TextDocumentIdentifier(docURI));
|
||||
if (maybeProject.isPresent()) {
|
||||
try {
|
||||
File file = new File(new URI(docURI));
|
||||
long lastModified = file.lastModified();
|
||||
|
||||
if (content == null) {
|
||||
content = FileUtils.readFileToString(new File(new URI(docURI)));
|
||||
content = FileUtils.readFileToString(file);
|
||||
}
|
||||
|
||||
UpdateItem updateItem = new UpdateItem(maybeProject.get(), docURI, content, indexer);
|
||||
UpdateItem updateItem = new UpdateItem(maybeProject.get(), docURI, lastModified, content, indexer);
|
||||
futures.add(CompletableFuture.runAsync(updateItem, this.updateQueue));
|
||||
}
|
||||
catch (Exception e) {
|
||||
@@ -314,7 +333,7 @@ public class SpringSymbolIndex {
|
||||
try {
|
||||
Optional<IJavaProject> maybeProject = projectFinder.find(new TextDocumentIdentifier(deletedDocURI));
|
||||
if (maybeProject.isPresent()) {
|
||||
DeleteItem deleteItem = new DeleteItem(maybeProject.get(), deletedDocURI);
|
||||
DeleteItem deleteItem = new DeleteItem(maybeProject.get(), deletedDocURI, this.indexer);
|
||||
return CompletableFuture.runAsync(deleteItem, this.updateQueue);
|
||||
}
|
||||
}
|
||||
@@ -459,10 +478,12 @@ public class SpringSymbolIndex {
|
||||
private final String content;
|
||||
private final IJavaProject project;
|
||||
private final SpringIndexer indexer;
|
||||
private final long lastModified;
|
||||
|
||||
public UpdateItem(IJavaProject project, String docURI, String content, SpringIndexer indexer) {
|
||||
public UpdateItem(IJavaProject project, String docURI, long lastModified, String content, SpringIndexer indexer) {
|
||||
this.project = project;
|
||||
this.docURI = docURI;
|
||||
this.lastModified = lastModified;
|
||||
this.content = content;
|
||||
this.indexer = indexer;
|
||||
}
|
||||
@@ -471,7 +492,7 @@ public class SpringSymbolIndex {
|
||||
public void run() {
|
||||
try {
|
||||
removeSymbolsByDoc(project, docURI);
|
||||
indexer.updateFile(project, docURI, content);
|
||||
indexer.updateFile(project, docURI, lastModified, content);
|
||||
} catch (Exception e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
@@ -481,17 +502,22 @@ public class SpringSymbolIndex {
|
||||
private class DeleteItem implements Runnable {
|
||||
|
||||
private final String docURI;
|
||||
private IJavaProject project;
|
||||
private final IJavaProject project;
|
||||
private final SpringIndexer[] indexer;
|
||||
|
||||
public DeleteItem(IJavaProject project, String docURI) {
|
||||
public DeleteItem(IJavaProject project, String docURI, SpringIndexer[] indexer) {
|
||||
this.project = project;
|
||||
this.docURI = docURI;
|
||||
this.indexer = indexer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
removeSymbolsByDoc(project, docURI);
|
||||
for (SpringIndexer index : this.indexer) {
|
||||
index.removeFile(project, docURI);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
@@ -501,9 +527,11 @@ public class SpringSymbolIndex {
|
||||
private class DeleteProject implements Runnable {
|
||||
|
||||
private final IJavaProject project;
|
||||
private final SpringIndexer[] indexer;
|
||||
|
||||
public DeleteProject(IJavaProject project) {
|
||||
public DeleteProject(IJavaProject project, SpringIndexer[] indexer) {
|
||||
this.project = project;
|
||||
this.indexer = indexer;
|
||||
log.debug("{} created ", this);
|
||||
}
|
||||
|
||||
@@ -512,6 +540,9 @@ public class SpringSymbolIndex {
|
||||
log.debug("{} starting...", this);
|
||||
try {
|
||||
removeSymbolsByProject(project);
|
||||
for (SpringIndexer index : this.indexer) {
|
||||
index.removeProject(project);
|
||||
}
|
||||
log.debug("{} completed", this);
|
||||
} catch (Throwable e) {
|
||||
log.error("{} threw exception", this, e);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.boot.java.utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public interface SymbolCache {
|
||||
|
||||
void store(SymbolCacheKey cacheKey, String[] files, List<CachedSymbol> generatedSymbols);
|
||||
CachedSymbol[] retrieve(SymbolCacheKey cacheKey, String[] files);
|
||||
|
||||
void update(SymbolCacheKey cacheKey, String file, long lastModified, List<CachedSymbol> generatedSymbols);
|
||||
|
||||
void remove(SymbolCacheKey cacheKey);
|
||||
void removeFile(SymbolCacheKey symbolCacheKey, String file);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.boot.java.utils;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class SymbolCacheKey {
|
||||
|
||||
private static final String SEPARATOR = "-";
|
||||
|
||||
private final String primaryIdentifier;
|
||||
private final String version;
|
||||
|
||||
public SymbolCacheKey(String primaryIdentifier, String version) {
|
||||
this.primaryIdentifier = primaryIdentifier;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getPrimaryIdentifier() {
|
||||
return primaryIdentifier;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return primaryIdentifier + SEPARATOR + version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((primaryIdentifier == null) ? 0 : primaryIdentifier.hashCode());
|
||||
result = prime * result + ((version == null) ? 0 : version.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
|
||||
SymbolCacheKey other = (SymbolCacheKey) obj;
|
||||
return this.toString().equals(other.toString());
|
||||
}
|
||||
|
||||
public static SymbolCacheKey parse(String fileName) {
|
||||
if (fileName != null && fileName.length() > 0) {
|
||||
int separatorIndex = fileName.lastIndexOf(SEPARATOR);
|
||||
if (separatorIndex > 0) {
|
||||
String primary = fileName.substring(0, separatorIndex);
|
||||
String version = fileName.substring(separatorIndex + 1);
|
||||
|
||||
int fileextensionIndex = version.lastIndexOf(".");
|
||||
if (fileextensionIndex > 0) {
|
||||
version = version.substring(0, fileextensionIndex);
|
||||
}
|
||||
|
||||
return new SymbolCacheKey(primary, version);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.boot.java.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation;
|
||||
import org.springframework.ide.vscode.commons.util.UriUtil;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class SymbolCacheOnDisc implements SymbolCache {
|
||||
|
||||
private final File cacheDirectory;
|
||||
private final Map<SymbolCacheKey, CacheStore> stores;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SymbolCacheOnDisc.class);
|
||||
|
||||
public SymbolCacheOnDisc() throws Exception {
|
||||
this(new File(System.getProperty("user.home") + File.separatorChar + ".sts4" + File.separatorChar + ".symbolCache"));
|
||||
}
|
||||
|
||||
public SymbolCacheOnDisc(File cacheDirectory) throws Exception {
|
||||
this.cacheDirectory = cacheDirectory;
|
||||
this.stores = new ConcurrentHashMap<>();
|
||||
|
||||
if (!this.cacheDirectory.exists()) {
|
||||
this.cacheDirectory.mkdirs();
|
||||
}
|
||||
|
||||
if (!this.cacheDirectory.exists()) {
|
||||
throw new Exception("symbol cache directory could not be created:");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(SymbolCacheKey cacheKey, String[] files, List<CachedSymbol> generatedSymbols) {
|
||||
SortedMap<String, Long> timestampedFiles = new TreeMap<>();
|
||||
|
||||
timestampedFiles = Arrays.stream(files)
|
||||
.filter(file -> new File(file).exists())
|
||||
.collect(Collectors.toMap(file -> file, file -> new File(file).lastModified(), (v1,v2) -> { throw new RuntimeException(String.format("Duplicate key for values %s and %s", v1, v2));}, TreeMap::new));
|
||||
|
||||
save(cacheKey, generatedSymbols, timestampedFiles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachedSymbol[] retrieve(SymbolCacheKey cacheKey, String[] files) {
|
||||
try {
|
||||
File cacheStore = new File(cacheDirectory, cacheKey.toString() + ".json");
|
||||
if (cacheStore.exists()) {
|
||||
Gson gson = createGson();
|
||||
JsonReader reader = new JsonReader(new FileReader(cacheStore));
|
||||
CacheStore store = gson.fromJson(reader, CacheStore.class);
|
||||
|
||||
SortedMap<String, Long> timestampedFiles = Arrays.stream(files)
|
||||
.filter(file -> new File(file).exists())
|
||||
.collect(Collectors.toMap(file -> file, file -> new File(file).lastModified(), (v1,v2) -> { throw new RuntimeException(String.format("Duplicate key for values %s and %s", v1, v2));}, TreeMap::new));
|
||||
|
||||
if (isFileMatch(timestampedFiles, store.getTimestampedFiles())) {
|
||||
this.stores.put(cacheKey, store);
|
||||
|
||||
List<CachedSymbol> symbols = store.getSymbols();
|
||||
return (CachedSymbol[]) symbols.toArray(new CachedSymbol[symbols.size()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error reading cached symbols", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFile(SymbolCacheKey cacheKey, String file) {
|
||||
CacheStore cacheStore = this.stores.get(cacheKey);
|
||||
if (cacheStore != null) {
|
||||
String docURI = UriUtil.toUri(new File(file)).toString();
|
||||
|
||||
SortedMap<String, Long> timestampedFiles = new TreeMap<>(cacheStore.getTimestampedFiles());
|
||||
timestampedFiles.remove(file);
|
||||
|
||||
List<CachedSymbol> cachedSymbols = cacheStore.getSymbols().stream()
|
||||
.filter(cachedSymbol -> !cachedSymbol.getDocURI().equals(docURI))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
save(cacheKey, cachedSymbols, timestampedFiles);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SymbolCacheKey cacheKey) {
|
||||
File cacheStore = new File(cacheDirectory, cacheKey.toString() + ".json");
|
||||
if (cacheStore.exists()) {
|
||||
cacheStore.delete();
|
||||
this.stores.remove(cacheKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(SymbolCacheKey cacheKey, String file, long lastModified, List<CachedSymbol> generatedSymbols) {
|
||||
CacheStore cacheStore = this.stores.get(cacheKey);
|
||||
|
||||
if (cacheStore != null) {
|
||||
String docURI = UriUtil.toUri(new File(file)).toString();
|
||||
|
||||
SortedMap<String, Long> timestampedFiles = new TreeMap<>(cacheStore.getTimestampedFiles());
|
||||
timestampedFiles.put(file, lastModified);
|
||||
|
||||
List<CachedSymbol> cachedSymbols = cacheStore.getSymbols().stream()
|
||||
.filter(cachedSymbol -> !cachedSymbol.getDocURI().equals(docURI))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
cachedSymbols.addAll(generatedSymbols);
|
||||
|
||||
save(cacheKey, cachedSymbols, timestampedFiles);
|
||||
}
|
||||
}
|
||||
|
||||
private void save(SymbolCacheKey cacheKey, List<CachedSymbol> generatedSymbols,
|
||||
SortedMap<String, Long> timestampedFiles) {
|
||||
CacheStore store = new CacheStore(cacheKey.toString(), timestampedFiles, generatedSymbols);
|
||||
this.stores.put(cacheKey, store);
|
||||
|
||||
try (FileWriter writer = new FileWriter(new File(cacheDirectory, cacheKey.toString() + ".json")))
|
||||
{
|
||||
Gson gson = createGson();
|
||||
gson.toJson(store, writer);
|
||||
|
||||
cleanupCacheFiles(cacheKey);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("cannot write symbol cache", e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFileMatch(SortedMap<String, Long> files1, SortedMap<String, Long> files2) {
|
||||
if (files1.size() != files2.size()) return false;
|
||||
|
||||
for (String file : files1.keySet()) {
|
||||
if (!files2.containsKey(file)) return false;
|
||||
if (!files1.get(file).equals(files2.get(file))) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void cleanupCacheFiles(SymbolCacheKey cacheKey) {
|
||||
File[] cacheFiles = this.cacheDirectory.listFiles();
|
||||
|
||||
for (int i = 0; i < cacheFiles.length; i++) {
|
||||
String fileName = cacheFiles[i].getName();
|
||||
SymbolCacheKey key = SymbolCacheKey.parse(fileName);
|
||||
|
||||
if (key != null && !key.equals(cacheKey)
|
||||
&& key.getPrimaryIdentifier().equals(cacheKey.getPrimaryIdentifier())) {
|
||||
cacheFiles[i].delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Gson createGson() {
|
||||
return new GsonBuilder().registerTypeAdapter(SymbolAddOnInformation.class, new SymbolAddOnInformationAdapter()).create();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* internal storage structure
|
||||
*/
|
||||
private static class CacheStore {
|
||||
|
||||
private final String cacheKey;
|
||||
private final SortedMap<String, Long> timestampedFiles;
|
||||
private final List<CachedSymbol> symbols;
|
||||
|
||||
public CacheStore(String cacheKey, SortedMap<String, Long> timestampedFiles, List<CachedSymbol> symbols) {
|
||||
super();
|
||||
this.cacheKey = cacheKey;
|
||||
this.timestampedFiles = timestampedFiles;
|
||||
this.symbols = symbols;
|
||||
}
|
||||
|
||||
public String getCacheKey() {
|
||||
return cacheKey;
|
||||
}
|
||||
|
||||
public List<CachedSymbol> getSymbols() {
|
||||
return symbols;
|
||||
}
|
||||
|
||||
public SortedMap<String, Long> getTimestampedFiles() {
|
||||
return timestampedFiles;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* gson adapter to store subtype information for symbol addon informations
|
||||
*/
|
||||
private static class SymbolAddOnInformationAdapter implements JsonSerializer<SymbolAddOnInformation>, JsonDeserializer<SymbolAddOnInformation> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(SymbolAddOnInformation addonInfo, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject result = new JsonObject();
|
||||
result.add("type", new JsonPrimitive(addonInfo.getClass().getName()));
|
||||
result.add("data", context.serialize(addonInfo));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolAddOnInformation deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObject parsedObject = json.getAsJsonObject();
|
||||
String className = parsedObject.get("type").getAsString();
|
||||
JsonElement element = parsedObject.get("data");
|
||||
|
||||
try {
|
||||
return context.deserialize(element, Class.forName(className));
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
throw new JsonParseException("cannot parse data from unknown SymbolAddOnInformation subtype: " + type, cnfe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.boot.java.utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class SymbolCacheVoid implements SymbolCache {
|
||||
|
||||
@Override
|
||||
public void store(SymbolCacheKey cacheKey, String[] files, List<CachedSymbol> generatedSymbols) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachedSymbol[] retrieve(SymbolCacheKey cacheKey, String[] files) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(SymbolCacheKey cacheKey, String file, long lastModified, List<CachedSymbol> generatedSymbols) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SymbolCacheKey cacheKey) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFile(SymbolCacheKey symbolCacheKey, String file) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.boot.java.utils.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SymbolCacheKey;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class SymbolCacheKeyTest {
|
||||
|
||||
@Test
|
||||
public void testCacheKey() {
|
||||
SymbolCacheKey key = new SymbolCacheKey("primary", "version");
|
||||
|
||||
assertEquals("primary", key.getPrimaryIdentifier());
|
||||
assertEquals("version", key.getVersion());
|
||||
assertEquals("primary-version", key.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheKeyParsingFromFileName() {
|
||||
SymbolCacheKey key = SymbolCacheKey.parse("primary-version.json");
|
||||
assertEquals("primary", key.getPrimaryIdentifier());
|
||||
assertEquals("version", key.getVersion());
|
||||
|
||||
key = SymbolCacheKey.parse("primary-name-with-separator-123ABC.json");
|
||||
assertEquals("primary-name-with-separator", key.getPrimaryIdentifier());
|
||||
assertEquals("123ABC", key.getVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheKeyParsingWithoutFileExtension() {
|
||||
SymbolCacheKey key = SymbolCacheKey.parse("primary-version");
|
||||
assertEquals("primary", key.getPrimaryIdentifier());
|
||||
assertEquals("version", key.getVersion());
|
||||
|
||||
key = SymbolCacheKey.parse("primary-name-with-separator-123ABC");
|
||||
assertEquals("primary-name-with-separator", key.getPrimaryIdentifier());
|
||||
assertEquals("123ABC", key.getVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCacheKeyEquals() {
|
||||
SymbolCacheKey key1 = new SymbolCacheKey("primary", "1");
|
||||
SymbolCacheKey key2 = new SymbolCacheKey("primary", "1");
|
||||
|
||||
SymbolCacheKey key3 = new SymbolCacheKey("primary", "2");
|
||||
SymbolCacheKey key4 = new SymbolCacheKey("secondary", "1");
|
||||
|
||||
assertEquals(key1, key1);
|
||||
assertEquals(key2, key2);
|
||||
assertEquals(key3, key3);
|
||||
assertEquals(key4, key4);
|
||||
|
||||
assertEquals(key1, key2);
|
||||
|
||||
assertNotEquals(key1, key3);
|
||||
assertNotEquals(key2, key3);
|
||||
assertNotEquals(key3, key4);
|
||||
assertNotEquals(key1, key4);
|
||||
assertNotEquals(key4, key1);
|
||||
assertNotEquals(key4, key2);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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.boot.java.utils.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
import org.eclipse.lsp4j.SymbolKind;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation;
|
||||
import org.springframework.ide.vscode.boot.java.requestmapping.WebfluxElementsInformation;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CachedSymbol;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SymbolCacheKey;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SymbolCacheOnDisc;
|
||||
import org.springframework.ide.vscode.commons.util.UriUtil;
|
||||
|
||||
public class SymbolCacheOnDiscTest {
|
||||
|
||||
private Path tempDir;
|
||||
private SymbolCacheOnDisc cache;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
tempDir = Files.createTempDirectory("cachetest");
|
||||
cache = new SymbolCacheOnDisc(tempDir.toFile());
|
||||
}
|
||||
|
||||
@After
|
||||
public void deleteTempDir() throws Exception {
|
||||
FileUtils.deleteDirectory(tempDir.toFile());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyCache() throws Exception {
|
||||
CachedSymbol[] result = cache.retrieve(new SymbolCacheKey("something", "0"), new String[0]);
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleValidCache() throws Exception {
|
||||
Path file1 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile1");
|
||||
Path file2 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile2");
|
||||
Path file3 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile3");
|
||||
|
||||
Files.createFile(file1);
|
||||
Files.createFile(file2);
|
||||
Files.createFile(file3);
|
||||
|
||||
FileTime timeFile1 = Files.getLastModifiedTime(file1);
|
||||
String[] files = {file1.toString(), file2.toString(), file3.toString()};
|
||||
|
||||
List<CachedSymbol> generatedSymbols = new ArrayList<>();
|
||||
SymbolInformation symbol = new SymbolInformation("symbol1", SymbolKind.Field, new Location("docURI", new Range(new Position(3, 10), new Position(3, 20))));
|
||||
EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, null);
|
||||
generatedSymbols.add(new CachedSymbol("", timeFile1.toMillis(), enhancedSymbol));
|
||||
|
||||
cache.store(new SymbolCacheKey("somekey", "1"), files, generatedSymbols);
|
||||
|
||||
CachedSymbol[] cachedSymbols = cache.retrieve(new SymbolCacheKey("somekey", "1"), files);
|
||||
assertNotNull(cachedSymbols);
|
||||
assertEquals(1, cachedSymbols.length);
|
||||
|
||||
assertEquals("symbol1", cachedSymbols[0].getEnhancedSymbol().getSymbol().getName());
|
||||
assertEquals(SymbolKind.Field, cachedSymbols[0].getEnhancedSymbol().getSymbol().getKind());
|
||||
assertEquals(new Location("docURI", new Range(new Position(3, 10), new Position(3, 20))), cachedSymbols[0].getEnhancedSymbol().getSymbol().getLocation());
|
||||
assertNull(cachedSymbols[0].getEnhancedSymbol().getAdditionalInformation());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentCacheKey() throws Exception {
|
||||
Path file1 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile1");
|
||||
Path file2 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile2");
|
||||
Path file3 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile3");
|
||||
|
||||
Files.createFile(file1);
|
||||
Files.createFile(file2);
|
||||
Files.createFile(file3);
|
||||
|
||||
FileTime timeFile1 = Files.getLastModifiedTime(file1);
|
||||
String[] files = {file1.toString(), file2.toString(), file3.toString()};
|
||||
|
||||
List<CachedSymbol> generatedSymbols = new ArrayList<>();
|
||||
SymbolInformation symbol = new SymbolInformation("symbol1", SymbolKind.Field, new Location("docURI", new Range(new Position(3, 10), new Position(3, 20))));
|
||||
EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, null);
|
||||
generatedSymbols.add(new CachedSymbol("", timeFile1.toMillis(), enhancedSymbol));
|
||||
|
||||
cache.store(new SymbolCacheKey("somekey", "1"), files, generatedSymbols);
|
||||
|
||||
CachedSymbol[] cachedSymbols = cache.retrieve(new SymbolCacheKey("otherkey", "1"), files);
|
||||
assertNull(cachedSymbols);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileTouched() throws Exception {
|
||||
Path file1 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile1");
|
||||
Path file2 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile2");
|
||||
Path file3 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile3");
|
||||
|
||||
Files.createFile(file1);
|
||||
Files.createFile(file2);
|
||||
Files.createFile(file3);
|
||||
|
||||
FileTime timeFile1 = Files.getLastModifiedTime(file1);
|
||||
String[] files = {file1.toString(), file2.toString(), file3.toString()};
|
||||
|
||||
List<CachedSymbol> generatedSymbols = new ArrayList<>();
|
||||
SymbolInformation symbol = new SymbolInformation("symbol1", SymbolKind.Field, new Location("docURI", new Range(new Position(3, 10), new Position(3, 20))));
|
||||
EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, null);
|
||||
generatedSymbols.add(new CachedSymbol("", timeFile1.toMillis(), enhancedSymbol));
|
||||
|
||||
cache.store(new SymbolCacheKey("somekey", "1"), files, generatedSymbols);
|
||||
|
||||
assertTrue(file1.toFile().setLastModified(timeFile1.toMillis() + 1000));
|
||||
|
||||
CachedSymbol[] cachedSymbols = cache.retrieve(new SymbolCacheKey("somekey", "1"), files);
|
||||
assertNull(cachedSymbols);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoreFiles() throws Exception {
|
||||
Path file1 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile1");
|
||||
Path file2 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile2");
|
||||
Path file3 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile3");
|
||||
|
||||
Files.createFile(file1);
|
||||
Files.createFile(file2);
|
||||
Files.createFile(file3);
|
||||
|
||||
String[] files = {file1.toString(), file2.toString()};
|
||||
cache.store(new SymbolCacheKey("somekey", "1"), files, new ArrayList<>());
|
||||
|
||||
String[] moreFiles = {file1.toString(), file2.toString(), file3.toString()};
|
||||
CachedSymbol[] cachedSymbols = cache.retrieve(new SymbolCacheKey("somekey", "1"), moreFiles);
|
||||
assertNull(cachedSymbols);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFewerFiles() throws Exception {
|
||||
Path file1 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile1");
|
||||
Path file2 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile2");
|
||||
Path file3 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile3");
|
||||
|
||||
Files.createFile(file1);
|
||||
Files.createFile(file2);
|
||||
Files.createFile(file3);
|
||||
|
||||
String[] files = {file1.toString(), file2.toString(), file3.toString()};
|
||||
cache.store(new SymbolCacheKey("somekey", "1"), files, new ArrayList<>());
|
||||
|
||||
String[] fewerFiles = {file1.toString(), file2.toString()};
|
||||
CachedSymbol[] cachedSymbols = cache.retrieve(new SymbolCacheKey("somekey", "1"), fewerFiles);
|
||||
assertNull(cachedSymbols);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteOldCacheFileIfNewOneIsStored() throws Exception {
|
||||
SymbolCacheKey key1 = new SymbolCacheKey("somekey", "1");
|
||||
cache.store(key1, new String[0], new ArrayList<>());
|
||||
assertTrue(Files.exists(tempDir.resolve(Paths.get(key1.toString() + ".json"))));
|
||||
|
||||
SymbolCacheKey key2 = new SymbolCacheKey("somekey", "2");
|
||||
cache.store(key2, new String[0], new ArrayList<>());
|
||||
assertTrue(Files.exists(tempDir.resolve(Paths.get(key2.toString() + ".json"))));
|
||||
assertFalse(Files.exists(tempDir.resolve(Paths.get(key1.toString() + ".json"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnhancedInformationSubclasses() throws Exception {
|
||||
Path file1 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile1");
|
||||
Files.createFile(file1);
|
||||
|
||||
FileTime timeFile1 = Files.getLastModifiedTime(file1);
|
||||
String[] files = {file1.toString()};
|
||||
String doc1URI = UriUtil.toUri(file1.toFile()).toString();
|
||||
|
||||
List<CachedSymbol> generatedSymbols = new ArrayList<>();
|
||||
|
||||
SymbolInformation symbol = new SymbolInformation("symbol1", SymbolKind.Field, new Location(doc1URI, new Range(new Position(3, 10), new Position(3, 20))));
|
||||
WebfluxElementsInformation addon = new WebfluxElementsInformation(new Range(new Position(4, 4), new Position(5, 5)), new Range(new Position(6, 6), new Position(7, 7)));
|
||||
EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, new SymbolAddOnInformation[] {addon});
|
||||
|
||||
generatedSymbols.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol));
|
||||
|
||||
cache.store(new SymbolCacheKey("somekey", "1"), files, generatedSymbols);
|
||||
|
||||
CachedSymbol[] cachedSymbols = cache.retrieve(new SymbolCacheKey("somekey", "1"), files);
|
||||
assertNotNull(cachedSymbols);
|
||||
assertEquals(1, cachedSymbols.length);
|
||||
|
||||
assertEquals("symbol1", cachedSymbols[0].getEnhancedSymbol().getSymbol().getName());
|
||||
assertEquals(SymbolKind.Field, cachedSymbols[0].getEnhancedSymbol().getSymbol().getKind());
|
||||
assertEquals(new Location(doc1URI, new Range(new Position(3, 10), new Position(3, 20))), cachedSymbols[0].getEnhancedSymbol().getSymbol().getLocation());
|
||||
|
||||
SymbolAddOnInformation[] retrievedAddOns = cachedSymbols[0].getEnhancedSymbol().getAdditionalInformation();
|
||||
assertNotNull(retrievedAddOns);
|
||||
assertEquals(1, retrievedAddOns.length);
|
||||
assertTrue(retrievedAddOns[0] instanceof WebfluxElementsInformation);
|
||||
|
||||
Range[] ranges = ((WebfluxElementsInformation)retrievedAddOns[0]).getRanges();
|
||||
assertEquals(2, ranges.length);
|
||||
assertEquals(new Range(new Position(4, 4), new Position(5, 5)), ranges[0]);
|
||||
assertEquals(new Range(new Position(6, 6), new Position(7, 7)), ranges[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSymbolAddedToExistingFile() throws Exception {
|
||||
Path file1 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile1");
|
||||
|
||||
Files.createFile(file1);
|
||||
|
||||
FileTime timeFile1 = Files.getLastModifiedTime(file1);
|
||||
String[] files = {file1.toAbsolutePath().toString()};
|
||||
|
||||
String doc1URI = UriUtil.toUri(file1.toFile()).toString();
|
||||
|
||||
List<CachedSymbol> generatedSymbols1 = new ArrayList<>();
|
||||
SymbolInformation symbol1 = new SymbolInformation("symbol1", SymbolKind.Field, new Location("docURI", new Range(new Position(3, 10), new Position(3, 20))));
|
||||
EnhancedSymbolInformation enhancedSymbol1 = new EnhancedSymbolInformation(symbol1, null);
|
||||
generatedSymbols1.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1));
|
||||
|
||||
cache.store(new SymbolCacheKey("somekey", "1"), files, generatedSymbols1);
|
||||
|
||||
List<CachedSymbol> generatedSymbols2 = new ArrayList<>();
|
||||
symbol1 = new SymbolInformation("symbol1", SymbolKind.Field, new Location(doc1URI, new Range(new Position(3, 10), new Position(3, 20))));
|
||||
enhancedSymbol1 = new EnhancedSymbolInformation(symbol1, null);
|
||||
|
||||
SymbolInformation symbol2 = new SymbolInformation("symbol2", SymbolKind.Interface, new Location(doc1URI, new Range(new Position(5, 5), new Position(5, 10))));
|
||||
EnhancedSymbolInformation enhancedSymbol2 = new EnhancedSymbolInformation(symbol2, null);
|
||||
|
||||
generatedSymbols2.add(new CachedSymbol(doc1URI, timeFile1.toMillis() + 2000, enhancedSymbol1));
|
||||
generatedSymbols2.add(new CachedSymbol(doc1URI, timeFile1.toMillis() + 2000, enhancedSymbol2));
|
||||
|
||||
assertTrue(file1.toFile().setLastModified(timeFile1.toMillis() + 2000));
|
||||
cache.update(new SymbolCacheKey("somekey", "1"), file1.toAbsolutePath().toString(), timeFile1.toMillis() + 2000, generatedSymbols2);
|
||||
|
||||
CachedSymbol[] cachedSymbols = cache.retrieve(new SymbolCacheKey("somekey", "1"), files);
|
||||
assertNotNull(cachedSymbols);
|
||||
assertEquals(2, cachedSymbols.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSymbolRemovedFromExistingFile() throws Exception {
|
||||
Path file1 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile1");
|
||||
|
||||
Files.createFile(file1);
|
||||
|
||||
FileTime timeFile1 = Files.getLastModifiedTime(file1);
|
||||
String[] files = {file1.toAbsolutePath().toString()};
|
||||
|
||||
String doc1URI = UriUtil.toUri(file1.toFile()).toString();
|
||||
|
||||
List<CachedSymbol> generatedSymbols1 = new ArrayList<>();
|
||||
SymbolInformation symbol1 = new SymbolInformation("symbol1", SymbolKind.Field, new Location("docURI", new Range(new Position(3, 10), new Position(3, 20))));
|
||||
EnhancedSymbolInformation enhancedSymbol1 = new EnhancedSymbolInformation(symbol1, null);
|
||||
generatedSymbols1.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1));
|
||||
|
||||
cache.store(new SymbolCacheKey("somekey", "1"), files, generatedSymbols1);
|
||||
|
||||
List<CachedSymbol> generatedSymbols2 = new ArrayList<>();
|
||||
assertTrue(file1.toFile().setLastModified(timeFile1.toMillis() + 2000));
|
||||
|
||||
cache.update(new SymbolCacheKey("somekey", "1"), file1.toAbsolutePath().toString(), timeFile1.toMillis() + 2000, generatedSymbols2);
|
||||
|
||||
CachedSymbol[] cachedSymbols = cache.retrieve(new SymbolCacheKey("somekey", "1"), files);
|
||||
assertNotNull(cachedSymbols);
|
||||
assertEquals(0, cachedSymbols.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSymbolAddedToNewFile() throws Exception {
|
||||
Path file1 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile1");
|
||||
Path file2 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile2");
|
||||
|
||||
Files.createFile(file1);
|
||||
Files.createFile(file2);
|
||||
|
||||
FileTime timeFile1 = Files.getLastModifiedTime(file1);
|
||||
FileTime timeFile2 = Files.getLastModifiedTime(file2);
|
||||
String[] files = {file1.toString()};
|
||||
|
||||
String doc1URI = UriUtil.toUri(file1.toFile()).toString();
|
||||
String doc2URI = UriUtil.toUri(file2.toFile()).toString();
|
||||
|
||||
List<CachedSymbol> generatedSymbols1 = new ArrayList<>();
|
||||
SymbolInformation symbol1 = new SymbolInformation("symbol1", SymbolKind.Field, new Location(doc1URI, new Range(new Position(3, 10), new Position(3, 20))));
|
||||
EnhancedSymbolInformation enhancedSymbol1 = new EnhancedSymbolInformation(symbol1, null);
|
||||
generatedSymbols1.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1));
|
||||
|
||||
cache.store(new SymbolCacheKey("somekey", "1"), files, generatedSymbols1);
|
||||
|
||||
List<CachedSymbol> generatedSymbols2 = new ArrayList<>();
|
||||
SymbolInformation symbol2 = new SymbolInformation("symbol2", SymbolKind.Interface, new Location(doc2URI, new Range(new Position(5, 5), new Position(5, 10))));
|
||||
EnhancedSymbolInformation enhancedSymbol2 = new EnhancedSymbolInformation(symbol2, null);
|
||||
|
||||
generatedSymbols2.add(new CachedSymbol(doc2URI, timeFile2.toMillis(), enhancedSymbol2));
|
||||
|
||||
cache.update(new SymbolCacheKey("somekey", "1"), file2.toString(), timeFile2.toMillis(), generatedSymbols2);
|
||||
|
||||
CachedSymbol[] cachedSymbols = cache.retrieve(new SymbolCacheKey("somekey", "1"), new String[] {file1.toString(), file2.toString()});
|
||||
assertNotNull(cachedSymbols);
|
||||
assertEquals(2, cachedSymbols.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProjectDeleted() throws Exception {
|
||||
SymbolCacheKey key1 = new SymbolCacheKey("somekey", "1");
|
||||
cache.store(key1, new String[0], new ArrayList<>());
|
||||
assertTrue(Files.exists(tempDir.resolve(Paths.get(key1.toString() + ".json"))));
|
||||
|
||||
cache.remove(key1);
|
||||
assertFalse(Files.exists(tempDir.resolve(Paths.get(key1.toString() + ".json"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileDeleted() throws Exception {
|
||||
Path file1 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile1");
|
||||
Path file2 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile2");
|
||||
|
||||
Files.createFile(file1);
|
||||
Files.createFile(file2);
|
||||
|
||||
FileTime timeFile1 = Files.getLastModifiedTime(file1);
|
||||
FileTime timeFile2 = Files.getLastModifiedTime(file2);
|
||||
String[] files = {file1.toAbsolutePath().toString(), file2.toAbsolutePath().toString()};
|
||||
|
||||
String doc1URI = UriUtil.toUri(file1.toFile()).toString();
|
||||
String doc2URI = UriUtil.toUri(file2.toFile()).toString();
|
||||
|
||||
List<CachedSymbol> generatedSymbols = new ArrayList<>();
|
||||
|
||||
SymbolInformation symbol1 = new SymbolInformation("symbol1", SymbolKind.Field, new Location(doc1URI, new Range(new Position(3, 10), new Position(3, 20))));
|
||||
EnhancedSymbolInformation enhancedSymbol1 = new EnhancedSymbolInformation(symbol1, null);
|
||||
|
||||
SymbolInformation symbol2 = new SymbolInformation("symbol2", SymbolKind.Field, new Location(doc2URI, new Range(new Position(5, 10), new Position(5, 20))));
|
||||
EnhancedSymbolInformation enhancedSymbol2 = new EnhancedSymbolInformation(symbol2, null);
|
||||
|
||||
generatedSymbols.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1));
|
||||
generatedSymbols.add(new CachedSymbol(doc2URI, timeFile2.toMillis(), enhancedSymbol2));
|
||||
|
||||
cache.store(new SymbolCacheKey("somekey", "1"), files, generatedSymbols);
|
||||
cache.removeFile(new SymbolCacheKey("somekey", "1"), file1.toAbsolutePath().toString());
|
||||
|
||||
files = new String[] {file2.toAbsolutePath().toString()};
|
||||
CachedSymbol[] cachedSymbols = cache.retrieve(new SymbolCacheKey("somekey", "1"), files);
|
||||
assertNotNull(cachedSymbols);
|
||||
assertEquals(1, cachedSymbols.length);
|
||||
|
||||
assertEquals("symbol2", cachedSymbols[0].getEnhancedSymbol().getSymbol().getName());
|
||||
assertEquals(SymbolKind.Field, cachedSymbols[0].getEnhancedSymbol().getSymbol().getKind());
|
||||
assertEquals(new Location(doc2URI, new Range(new Position(5, 10), new Position(5, 20))), cachedSymbols[0].getEnhancedSymbol().getSymbol().getLocation());
|
||||
assertNull(cachedSymbols[0].getEnhancedSymbol().getAdditionalInformation());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user