fix threading issue with project listener registration by introducing a delegate in between the involved parties

This commit is contained in:
Martin Lippert
2019-02-12 12:59:56 +01:00
committed by BoykoAlex
parent d9905c40ce
commit fdeb1dd55c
4 changed files with 101 additions and 33 deletions

View File

@@ -81,16 +81,19 @@ public class SpringLiveHoverWatchdog {
@Override
public void deleted(IJavaProject project) {
logger.info("project deleted event: {}", project.getElementName());
refreshEnablement();
}
@Override
public void created(IJavaProject project) {
logger.info("project created event: {}", project.getElementName());
refreshEnablement();
}
@Override
public void changed(IJavaProject project) {
logger.info("project changed event: {}", project.getElementName());
refreshEnablement();
}
});

View File

@@ -79,19 +79,19 @@ public class SpringSymbolIndex {
private final Listener projectListener = new Listener() {
@Override
public void created(IJavaProject project) {
log.debug("project created event: {}", project.getElementName());
log.info("project created event: {}", project.getElementName());
initializeProject(project);
}
@Override
public void changed(IJavaProject project) {
log.debug("project changed event: {}", project.getElementName());
log.info("project changed event: {}", project.getElementName());
initializeProject(project);
}
@Override
public void deleted(IJavaProject project) {
log.debug("project deleted event: {}", project.getElementName());
log.info("project deleted event: {}", project.getElementName());
deleteProject(project);
}
};
@@ -146,6 +146,7 @@ public class SpringSymbolIndex {
if (getProjectObserver() != null) {
getProjectObserver().addListener(projectListener);
log.info("project listener registered");
}
}

View File

@@ -10,7 +10,9 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.jdt.ls;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@@ -33,20 +35,52 @@ public class JavaProjectsServiceWithFallback implements JavaProjectsService {
private Logger log = LoggerFactory.getLogger(JavaProjectsServiceWithFallback.class);
final private CompletableFuture<Disposable> mainServiceInitialized;
private final CompletableFuture<Disposable> mainServiceInitialized;
final private SimpleLanguageServer server;
private Supplier<JavaProjectsService> fallback;
final private InitializableJavaProjectsService main;
private final SimpleLanguageServer server;
private final Supplier<JavaProjectsService> fallback;
private final InitializableJavaProjectsService main;
private final Listener listenerDelegate;
private final List<Listener> listeners;
public JavaProjectsServiceWithFallback(SimpleLanguageServer server, InitializableJavaProjectsService main, Supplier<JavaProjectsService> fallback) {
Assert.isNotNull(fallback);
this.main = main;
this.fallback = Suppliers.memoize(fallback);
this.fallback = Suppliers.memoize(new Supplier<JavaProjectsService>() {
@Override
public JavaProjectsService get() {
JavaProjectsService fallbackService = fallback.get();
fallbackService.addListener(listenerDelegate);
return fallbackService;
}
});
this.server = server;
this.listeners = new ArrayList<>();
this.listenerDelegate = new Listener() {
@Override
public void deleted(IJavaProject project) {
notifyDelete(project);
}
@Override
public void created(IJavaProject project) {
notifyCreated(project);
}
@Override
public void changed(IJavaProject project) {
notifyChanged(project);
}
};
this.main.addListener(this.listenerDelegate);
this.mainServiceInitialized = this.server
.onInitialized(main.initialize())
.toFuture();
this.server.onShutdown(() -> {
try {
if (!mainServiceInitialized.isCompletedExceptionally()) {
@@ -62,6 +96,50 @@ public class JavaProjectsServiceWithFallback implements JavaProjectsService {
);
}
@Override
public void addListener(Listener listener) {
synchronized (listeners) {
listeners.add(listener);
log.info("added listener - now listeners registered: " + listeners.size());
}
}
@Override
public void removeListener(Listener listener) {
synchronized (listeners) {
listeners.remove(listener);
log.info("removed listener - now listeners registered: " + listeners.size());
}
}
private void notifyCreated(IJavaProject newProject) {
log.info("Project created: " + newProject.getLocationUri());
synchronized (listeners) {
for (Listener listener : listeners) {
listener.created(newProject);
}
}
}
private void notifyDelete(IJavaProject deleted) {
log.info("Project deleted: " + deleted.getLocationUri());
synchronized (listeners) {
for (Listener listener : listeners) {
listener.deleted(deleted);
}
}
}
private void notifyChanged(IJavaProject project) {
log.info("Project changed: " + project.getLocationUri());
synchronized (listeners) {
for (Listener listener : listeners) {
listener.changed(project);
}
}
}
@Override
public Optional<IJavaProject> find(TextDocumentIdentifier doc) {
if (mainServiceInitialized.isDone()) {
@@ -77,30 +155,6 @@ public class JavaProjectsServiceWithFallback implements JavaProjectsService {
return Optional.empty();
}
@Override
public void addListener(Listener listener) {
mainServiceInitialized.handle((success, failed) -> {
if (failed!=null) {
fallback.get().addListener(listener);
} else {
main.addListener(listener);
}
return null;
});
}
@Override
public void removeListener(Listener listener) {
mainServiceInitialized.handle((success, failed) -> {
if (failed!=null) {
fallback.get().removeListener(listener);
} else {
main.removeListener(listener);
}
return null;
});
}
@Override
public IJavadocProvider javadocProvider(String projectUri, CPE classpathEntry) {
if (mainServiceInitialized.isDone()) {

View File

@@ -67,6 +67,7 @@ public class JdtLsProjectCache implements InitializableJavaProjectsService {
public void addListener(Listener listener) {
synchronized (listeners) {
listeners.add(listener);
log.info("added listener - now listeners registered: " + listeners.size());
}
}
@@ -74,14 +75,23 @@ public class JdtLsProjectCache implements InitializableJavaProjectsService {
public void removeListener(Listener listener) {
synchronized (listeners) {
listeners.remove(listener);
log.info("removed listener - now listeners registered: " + listeners.size());
}
}
private void notifyCreated(JavaProject newProject) {
logEvent("Created", newProject);
synchronized (listeners) {
log.info("listeners registered: " + listeners.size());
for (Listener listener : listeners) {
listener.created(newProject);
try {
listener.created(newProject);
}
catch (Exception e) {
log.info("listener caused exception: " + e);
}
}
}
}