diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/AbstractProgressTask.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/AbstractProgressTask.java index 8a397cba8..07ff764ea 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/AbstractProgressTask.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/AbstractProgressTask.java @@ -18,12 +18,14 @@ package org.springframework.ide.vscode.commons.languageserver; */ public abstract class AbstractProgressTask { + private static long progress_counter = 0; + protected final String taskId; protected final ProgressService service; public AbstractProgressTask(String taskId, ProgressService service) { - this.taskId = taskId; + this.taskId = taskId + "-" + (progress_counter++); this.service = service; } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java index b635b09b0..e3bd3ce31 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java @@ -38,6 +38,7 @@ import org.eclipse.lsp4j.services.WorkspaceService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.util.Assert; +import org.springframework.ide.vscode.commons.util.AsyncRunner; import org.springframework.ide.vscode.commons.util.FileObserver; import com.google.common.collect.ImmutableList; @@ -55,6 +56,7 @@ public class SimpleWorkspaceService implements WorkspaceService { private ExecuteCommandHandler executeCommandHandler; private WorkspaceSymbolHandler workspaceSymbolHandler; private SimpleServerFileObserver fileObserver; + private AsyncRunner asyncRunner; private ListenerList workspaceFolderListeners = new ListenerList<>(); @@ -62,12 +64,13 @@ public class SimpleWorkspaceService implements WorkspaceService { public SimpleWorkspaceService(SimpleLanguageServer server) { this.fileObserver = new SimpleServerFileObserver(server); this.messageWorkerThreadPool = Executors.newCachedThreadPool(); + this.asyncRunner = server.getAsync(); } @Override public CompletableFuture, List>> symbol(WorkspaceSymbolParams params) { log.info("request for workspace symbols arrived: " + params.getQuery()); - + return CompletableFutures.computeAsync(messageWorkerThreadPool, cancelToken -> { WorkspaceSymbolHandler workspaceSymbolHandler = this.workspaceSymbolHandler; @@ -86,36 +89,38 @@ public class SimpleWorkspaceService implements WorkspaceService { @Override public void didChangeConfiguration(DidChangeConfigurationParams params) { - configurationListeners.fire(new Settings((JsonElement) params.getSettings())); + asyncRunner.execute(() -> configurationListeners.fire(new Settings((JsonElement) params.getSettings()))); } @Override public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) { - try { - Map> collect = - params.getChanges().stream().filter(event -> event.getUri() != null).collect(Collectors.groupingBy(FileEvent::getType)); - - for (FileChangeType type : collect.keySet()) { - String[] docURIs = collect.get(type).stream().map(event -> event.getUri()).toArray(String[]::new); - - switch (type) { - case Created: - fileObserver.notifyFilesCreated(docURIs); - break; - case Changed: - fileObserver.notifyFilesChanged(docURIs); - break; - case Deleted: - fileObserver.notifyFilesDeleted(docURIs); - break; - default: - log.warn("Uknown file change type '" + type + "' for files: " + docURIs); - break; + asyncRunner.execute(() -> { + try { + Map> collect = + params.getChanges().stream().filter(event -> event.getUri() != null).collect(Collectors.groupingBy(FileEvent::getType)); + + for (FileChangeType type : collect.keySet()) { + String[] docURIs = collect.get(type).stream().map(event -> event.getUri()).toArray(String[]::new); + + switch (type) { + case Created: + fileObserver.notifyFilesCreated(docURIs); + break; + case Changed: + fileObserver.notifyFilesChanged(docURIs); + break; + case Deleted: + fileObserver.notifyFilesDeleted(docURIs); + break; + default: + log.warn("Uknown file change type '" + type + "' for files: " + docURIs); + break; + } } + } catch (Throwable t) { + log.warn("problem occurred while dispatching file event", t); } - } catch (Throwable t) { - log.warn("problem occurred while dispatching file event", t); - } + }); } @Override @@ -131,7 +136,7 @@ public class SimpleWorkspaceService implements WorkspaceService { changed = true; } if (changed) { - workspaceFolderListeners.fire(params); + asyncRunner.execute(() -> workspaceFolderListeners.fire(params)); } } diff --git a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java index afacf4d5d..15ab14e88 100644 --- a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java +++ b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java @@ -498,6 +498,7 @@ public class LanguageServerHarness { public synchronized void changeFile(String uri) { FileEvent fileEvent = new FileEvent(uri, FileChangeType.Changed); getServer().getWorkspaceService().didChangeWatchedFiles(new DidChangeWatchedFilesParams(Arrays.asList(fileEvent))); + getServer().getAsync().waitForAll(); } public synchronized void createFile(String uri) { @@ -959,6 +960,7 @@ public class LanguageServerHarness { public void changeConfiguration(Settings settings) { getServer().getWorkspaceService().didChangeConfiguration(new DidChangeConfigurationParams(settings.getRawSettings())); + getServer().getAsync().waitForAll(); } public SimpleLanguageServer getServer() { diff --git a/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerInitializerTest.java b/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerInitializerTest.java index 6e9cc13c6..8f484a88f 100644 --- a/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerInitializerTest.java +++ b/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerInitializerTest.java @@ -23,7 +23,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -import org.eclipse.lsp4j.DidChangeConfigurationParams; import org.eclipse.lsp4j.InitializeResult; import org.eclipse.lsp4j.TextDocumentSyncKind; import org.junit.jupiter.api.Test; @@ -31,6 +30,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFClientParams; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.ClientParamsProvider; +import org.springframework.ide.vscode.commons.languageserver.util.Settings; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness; import org.springframework.ide.vscode.manifest.yaml.bootiful.ManifestLanguageServerTest; @@ -108,12 +108,7 @@ public class ManifestYamlLanguageServerInitializerTest { assertEquals(Arrays.asList("test.io"), serverInitializer.getCfTargets()); // This tests a change in workspace (e.g. boot dash) that results in two more targets created. - DidChangeConfigurationParams params = new DidChangeConfigurationParams(); - - JsonParser parser = new JsonParser(); - params.setSettings(parser.parse(new InputStreamReader(getClass().getResourceAsStream("/cf-targets1.json")))); - - server.getWorkspaceService().didChangeConfiguration(params); + harness.changeConfiguration(new Settings(JsonParser.parseReader(new InputStreamReader(getClass().getResourceAsStream("/cf-targets1.json"))))); assertEquals(3, getAllParams(serverInitializer.getParamsProvider()).size()); // End result should have the initial target as well as the two additional targets obtained on workspace change diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java index 8fbd40441..8330acab9 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java @@ -504,7 +504,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex { } CompletableFuture future = CompletableFuture.allOf((CompletableFuture[]) futures.toArray(new CompletableFuture[futures.size()])); - future = future.thenAcceptAsync(v -> server.getClient().indexUpdated()).thenAccept(v -> listeners.fire(v)); + future = future.thenAccept(v -> server.getClient().indexUpdated()).thenAccept(v -> listeners.fire(v)); return future; } } @@ -565,7 +565,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex { } } CompletableFuture future = CompletableFuture.allOf((CompletableFuture[]) futures.toArray(new CompletableFuture[futures.size()])); - future = future.thenAcceptAsync(v -> server.getClient().indexUpdated()).thenAccept(v -> listeners.fire(v)); + future = future.thenAccept(v -> server.getClient().indexUpdated()).thenAccept(v -> listeners.fire(v)); return future; } } @@ -640,7 +640,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex { } CompletableFuture future = CompletableFuture.allOf((CompletableFuture[]) futures.toArray(new CompletableFuture[futures.size()])); - future = future.thenAcceptAsync(v -> server.getClient().indexUpdated()).thenAccept(v -> listeners.fire(v)); + future = future.thenAccept(v -> server.getClient().indexUpdated()).thenAccept(v -> listeners.fire(v)); return future; } catch (Exception e) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java index 66b140684..07731cbc6 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java @@ -80,21 +80,22 @@ public class SpringPropertiesIndexManager extends ListenerManager settings = new HashMap<>(); settings.put("boot-java", bootJavaObj); - harness.getServer().getWorkspaceService().didChangeConfiguration(new DidChangeConfigurationParams(new Gson().toJsonTree(settings))); + harness.changeConfiguration(new Settings(new Gson().toJsonTree(settings))); project = projects.mavenProject("test-xml-hyperlinks"); @@ -206,7 +207,7 @@ public class XmlBeansHyperlinkTest { Map settings = new HashMap<>(); settings.put("boot-java", bootJavaObj); - harness.getServer().getWorkspaceService().didChangeConfiguration(new DidChangeConfigurationParams(new Gson().toJsonTree(settings))); + harness.changeConfiguration(new Settings(new Gson().toJsonTree(settings))); CompletableFuture initProject = indexer.waitOperation(); initProject.get(DEFAULT_INDEX_WAIT_TIME, TimeUnit.SECONDS); @@ -241,7 +242,8 @@ public class XmlBeansHyperlinkTest { Map settings = new HashMap<>(); settings.put("boot-java", bootJavaObj); - harness.getServer().getWorkspaceService().didChangeConfiguration(new DidChangeConfigurationParams(new Gson().toJsonTree(settings))); + harness.changeConfiguration(new Settings(new Gson().toJsonTree(settings))); + CompletableFuture initProject = indexer.waitOperation(); initProject.get(DEFAULT_INDEX_WAIT_TIME, TimeUnit.SECONDS); @@ -280,7 +282,7 @@ public class XmlBeansHyperlinkTest { Map settings = new HashMap<>(); settings.put("boot-java", bootJavaObj); - harness.getServer().getWorkspaceService().didChangeConfiguration(new DidChangeConfigurationParams(new Gson().toJsonTree(settings))); + harness.changeConfiguration(new Settings(new Gson().toJsonTree(settings))); CompletableFuture initProject = indexer.waitOperation(); initProject.get(DEFAULT_INDEX_WAIT_TIME, TimeUnit.SECONDS); @@ -309,7 +311,7 @@ public class XmlBeansHyperlinkTest { Map settings = new HashMap<>(); settings.put("boot-java", bootJavaObj); - harness.getServer().getWorkspaceService().didChangeConfiguration(new DidChangeConfigurationParams(new Gson().toJsonTree(settings))); + harness.changeConfiguration(new Settings(new Gson().toJsonTree(settings))); CompletableFuture initProject = indexer.waitOperation(); initProject.get(DEFAULT_INDEX_WAIT_TIME, TimeUnit.SECONDS); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/XMLSpelExpressionValidationTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/XMLSpelExpressionValidationTest.java index 2f00b892f..9f9b65021 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/XMLSpelExpressionValidationTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/XMLSpelExpressionValidationTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2020, 2021 Pivotal, Inc. + * Copyright (c) 2020, 2023 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 @@ -21,7 +21,6 @@ import java.util.List; import java.util.Map; import org.apache.commons.io.IOUtils; -import org.eclipse.lsp4j.DidChangeConfigurationParams; import org.eclipse.lsp4j.DidCloseTextDocumentParams; import org.eclipse.lsp4j.DidOpenTextDocumentParams; import org.eclipse.lsp4j.TextDocumentIdentifier; @@ -40,6 +39,7 @@ import org.springframework.ide.vscode.boot.xml.SpringXMLReconcileEngine; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem; +import org.springframework.ide.vscode.commons.languageserver.util.Settings; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject; import org.springframework.ide.vscode.commons.util.text.LanguageId; @@ -88,7 +88,7 @@ public class XMLSpelExpressionValidationTest { Map settings = new HashMap<>(); settings.put("boot-java", bootJavaObj); - harness.getServer().getWorkspaceService().didChangeConfiguration(new DidChangeConfigurationParams(new Gson().toJsonTree(settings))); + harness.changeConfiguration(new Settings(new Gson().toJsonTree(settings))); project = projects.mavenProject("test-xml-validations"); harness.useProject(project);