Fix race condition in SpringIndexer initialization
This commit is contained in:
@@ -13,7 +13,10 @@ package org.springframework.ide.vscode.commons.languageserver.java;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.Sts4LanguageServer;
|
||||
import org.springframework.ide.vscode.commons.util.FileObserver;
|
||||
@@ -33,6 +36,8 @@ import com.google.common.cache.CacheBuilder;
|
||||
*/
|
||||
public abstract class AbstractJavaProjectCache<K, P extends IJavaProject> implements JavaProjectCache<K, P> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AbstractJavaProjectCache.class);
|
||||
|
||||
protected Sts4LanguageServer server;
|
||||
|
||||
private ListenerList<Listener> listeners = new ListenerList<>();
|
||||
@@ -47,15 +52,23 @@ public abstract class AbstractJavaProjectCache<K, P extends IJavaProject> implem
|
||||
public P project(K key) {
|
||||
if (key != null) {
|
||||
try {
|
||||
return cache.get(key, () -> {
|
||||
try {
|
||||
P project = createProject(key);
|
||||
attachListeners(key, project);
|
||||
return project;
|
||||
} catch (Throwable t) {
|
||||
throw new ExecutionException(t);
|
||||
AtomicReference<P> createdProject = new AtomicReference<P>(null);
|
||||
try {
|
||||
return cache.get(key, () -> {
|
||||
try {
|
||||
P project = createProject(key);
|
||||
createdProject.set(project);
|
||||
attachListeners(key, project);
|
||||
return project;
|
||||
} catch (Throwable t) {
|
||||
throw new ExecutionException(t);
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
if (createdProject.get()!=null) {
|
||||
notifyProjectCreated(createdProject.get());
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
Log.log(e);
|
||||
return null;
|
||||
@@ -84,6 +97,7 @@ public abstract class AbstractJavaProjectCache<K, P extends IJavaProject> implem
|
||||
|
||||
@Override
|
||||
public void addListener(Listener listener) {
|
||||
log.info("Add listener {} to {}", listener, this);
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@@ -93,14 +107,17 @@ public abstract class AbstractJavaProjectCache<K, P extends IJavaProject> implem
|
||||
}
|
||||
|
||||
final protected void notifyProjectCreated(P project) {
|
||||
log.info("project created {}", project);
|
||||
listeners.forEach(l -> l.created(project));
|
||||
}
|
||||
|
||||
final protected void notifyProjectChanged(P project) {
|
||||
log.info("project changed {}", project);
|
||||
listeners.forEach(l -> l.changed(project));
|
||||
}
|
||||
|
||||
final protected void notifyProjectDeleted(P project) {
|
||||
log.info("project deleted {}", project);
|
||||
listeners.forEach(l -> l.deleted(project));
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
package org.springframework.ide.vscode.commons.languageserver.java;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
|
||||
@@ -83,7 +83,7 @@ public class BootLanguageServerParams {
|
||||
public static LSFactory<BootLanguageServerParams> createDefault() {
|
||||
return (SimpleLanguageServer server) -> {
|
||||
// Initialize project finders, project caches and project observers
|
||||
JdtLsProjectCache jdtProjectCache = new JdtLsProjectCache(server, createFallbackProjectCache(server));
|
||||
JdtLsProjectCache jdtProjectCache = new JdtLsProjectCache(server, () -> createFallbackProjectCache(server));
|
||||
DefaultSpringPropertyIndexProvider indexProvider = new DefaultSpringPropertyIndexProvider(jdtProjectCache, jdtProjectCache);
|
||||
indexProvider.setProgressService(server.getProgressService());
|
||||
|
||||
|
||||
@@ -150,10 +150,7 @@ public class SpringIndexer {
|
||||
}
|
||||
}
|
||||
}, "Spring Annotation Index Update Worker");
|
||||
server.onInitialized(() -> {
|
||||
log.debug("onServerInitialized {}", this);
|
||||
updateWorker.start();
|
||||
});
|
||||
server.onInitialized(updateWorker::start);
|
||||
getWorkspaceService().onDidChangeWorkspaceFolders(evt -> {
|
||||
log.debug("workspace roots have changed event arrived - added: " + evt.getEvent().getAdded() + " - removed: " + evt.getEvent().getRemoved());
|
||||
refresh();
|
||||
|
||||
@@ -38,6 +38,8 @@ import org.springframework.ide.vscode.commons.util.CollectorUtil;
|
||||
import org.springframework.ide.vscode.commons.util.ExceptionUtil;
|
||||
import org.springframework.ide.vscode.commons.util.UriUtil;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import reactor.core.Disposable;
|
||||
@@ -45,17 +47,17 @@ import reactor.core.Disposable;
|
||||
public class JdtLsProjectCache implements JavaProjectsService {
|
||||
|
||||
private CompletableFuture<Void> initialized = new CompletableFuture<Void>();
|
||||
|
||||
|
||||
private SimpleLanguageServer server;
|
||||
private Map<String, JdtLsProject> table = new HashMap<String, JdtLsProject>();
|
||||
private Logger log = LoggerFactory.getLogger(JdtLsProjectCache.class);
|
||||
private List<Listener> listeners = new ArrayList<>();
|
||||
|
||||
private final JavaProjectsService fallback;
|
||||
private final Supplier<JavaProjectsService> fallback;
|
||||
|
||||
public JdtLsProjectCache(SimpleLanguageServer server, JavaProjectsService fallback) {
|
||||
public JdtLsProjectCache(SimpleLanguageServer server, Supplier<JavaProjectsService> fallback) {
|
||||
Assert.isNotNull(fallback);
|
||||
this.fallback = fallback;
|
||||
this.fallback = Suppliers.memoize(fallback);
|
||||
this.server = server;
|
||||
CompletableFuture<Disposable> disposable = new CompletableFuture<Disposable>();
|
||||
this.server.onInitialized(() -> {
|
||||
@@ -110,7 +112,7 @@ public class JdtLsProjectCache implements JavaProjectsService {
|
||||
public void addListener(Listener listener) {
|
||||
initialized.handle((success, failed) -> {
|
||||
if (failed!=null) {
|
||||
fallback.addListener(listener);
|
||||
fallback.get().addListener(listener);
|
||||
} else {
|
||||
synchronized (listeners) {
|
||||
listeners.add(listener);
|
||||
@@ -124,7 +126,7 @@ public class JdtLsProjectCache implements JavaProjectsService {
|
||||
public void removeListener(Listener listener) {
|
||||
initialized.handle((success, failed) -> {
|
||||
if (failed!=null) {
|
||||
fallback.removeListener(listener);
|
||||
fallback.get().removeListener(listener);
|
||||
} else {
|
||||
synchronized (listeners) {
|
||||
listeners.remove(listener);
|
||||
@@ -171,9 +173,13 @@ public class JdtLsProjectCache implements JavaProjectsService {
|
||||
|
||||
@Override
|
||||
public Optional<IJavaProject> find(TextDocumentIdentifier doc) {
|
||||
log.info("find {} ",doc.getUri());
|
||||
if (initialized.isDone()) {
|
||||
if (initialized.isCompletedExceptionally()) {
|
||||
return fallback.find(doc);
|
||||
log.info("find {} delegating to fallback", doc.getUri());
|
||||
Optional<IJavaProject> result = fallback.get().find(doc);
|
||||
log.info("find => {}", result);
|
||||
return result;
|
||||
}
|
||||
String uri = UriUtil.normalize(doc.getUri());
|
||||
|
||||
@@ -186,6 +192,7 @@ public class JdtLsProjectCache implements JavaProjectsService {
|
||||
}
|
||||
}
|
||||
}
|
||||
log.info("find => NOT INITIALIZED YET");
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user