PT #151888326: let the update document task wait for the initial annotation index to be ready and changed the update mechanics towards an async queue

This commit is contained in:
Martin Lippert
2017-10-12 13:10:10 +02:00
parent ee069226f9
commit 4d32d4849e
3 changed files with 97 additions and 7 deletions

View File

@@ -17,7 +17,6 @@ import java.util.concurrent.CompletableFuture;
import org.eclipse.lsp4j.CompletionItemKind;
import org.eclipse.lsp4j.InitializeParams;
import org.eclipse.lsp4j.InitializeResult;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.springframework.ide.vscode.boot.java.beans.BeansSymbolProvider;
import org.springframework.ide.vscode.boot.java.beans.ComponentSymbolProvider;
import org.springframework.ide.vscode.boot.java.handlers.BootJavaCodeLensEngine;
@@ -162,7 +161,9 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
@Override
public CompletableFuture<Object> shutdown() {
liveHoverWatchdog.shutdown();
this.liveHoverWatchdog.shutdown();
this.indexer.shutdown();
return super.shutdown();
}

View File

@@ -19,10 +19,12 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -63,6 +65,9 @@ public class SpringIndexer {
private CompletableFuture<Void> initializeTask;
private final Thread updateWorker;
private final BlockingQueue<UpdateItem> updateQueue;
public SpringIndexer(SimpleLanguageServer server, JavaProjectFinder projectFinder, Map<String, SymbolProvider> specificProviders) {
this.server = server;
this.projectFinder = projectFinder;
@@ -70,9 +75,26 @@ public class SpringIndexer {
this.symbols = Collections.synchronizedList(new ArrayList<>());
this.symbolsByDoc = new ConcurrentHashMap<>();
this.updateQueue = new LinkedBlockingQueue<>();
this.updateWorker = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
UpdateItem updateItem = updateQueue.take();
scanFile(updateItem.getDocURI(), updateItem.getContent(), updateItem.getClasspathEntries());
updateItem.getFuture().complete(null);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}, "Spring Annotation Index Update Worker");
}
public void initialize(final Path workspaceRoot) {
public CompletableFuture<Void> initialize(final Path workspaceRoot) {
synchronized(this) {
if (this.initializeTask == null) {
this.initializeTask = CompletableFuture.runAsync(new Runnable() {
@@ -81,31 +103,59 @@ public class SpringIndexer {
System.out.println("start initial scan...");
scanFiles(workspaceRoot.toFile());
System.out.println("initial scan done...!!!");
updateWorker.start();
}
});
}
return this.initializeTask;
}
}
public void updateDocument(String docURI, String content) {
if (docURI.endsWith(".java")) {
public void shutdown() {
try {
if (this.initializeTask != null) {
initializeTask.cancel(true);
}
if (updateWorker.isAlive()) {
updateWorker.interrupt();
}
}
catch (Exception e) {
e.printStackTrace();
}
}
public CompletableFuture<Void> updateDocument(String docURI, String content) {
if (docURI.endsWith(".java") && initializeTask != null) {
try {
initializeTask.get();
IJavaProject project = projectFinder.find(new File(new URI(docURI)));
if (project != null) {
String[] classpathEntries = getClasspathEntries(project);
scanFile(docURI, content, classpathEntries);
CompletableFuture<Void> future = new CompletableFuture<>();
UpdateItem updateItem = new UpdateItem(docURI, content, classpathEntries, future);
updateQueue.put(updateItem);
return future;
}
}
catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
public List<? extends SymbolInformation> getAllSymbols(String query) {
if (initializeTask != null) {
try {
initializeTask.get();
if (query != null && query.length() > 0) {
return searchMatchingSymbols(this.symbols, query);
} else {
@@ -362,4 +412,39 @@ public class SpringIndexer {
.map(path -> path.toAbsolutePath().toString()).toArray(String[]::new);
}
/**
* inner class to capture items for the update worker
*/
private static class UpdateItem {
private final String docURI;
private final String content;
private final String[] classpathEntries;
private final CompletableFuture<Void> future;
public UpdateItem(String docURI, String content, String[] classpathEntries, CompletableFuture<Void> future) {
this.docURI = docURI;
this.content = content;
this.classpathEntries = classpathEntries;
this.future = future;
}
public String getDocURI() {
return docURI;
}
public String getContent() {
return content;
}
public String[] getClasspathEntries() {
return classpathEntries;
}
public CompletableFuture<Void> getFuture() {
return future;
}
}
}

View File

@@ -20,6 +20,8 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.FileUtils;
import org.eclipse.lsp4j.SymbolInformation;
@@ -158,7 +160,9 @@ public class SpringIndexerTest {
// update document and update index
String changedDocURI = "file://" + directory.getAbsolutePath() + "/src/main/java/org/test/SimpleMappingClass.java";
String newContent = FileUtils.readFileToString(new File(new URI(changedDocURI))).replace("mapping1", "mapping1-CHANGED");
indexer.updateDocument(changedDocURI, newContent);
CompletableFuture<Void> updateFuture = indexer.updateDocument(changedDocURI, newContent);
updateFuture.get(5, TimeUnit.SECONDS);
// check for updated index per document
List<? extends SymbolInformation> symbols = indexer.getSymbols(changedDocURI);