From 7a6603f520f63417c923c5bf3de897a6ba9161cd Mon Sep 17 00:00:00 2001 From: aboyko Date: Mon, 5 Jun 2023 19:03:29 -0400 Subject: [PATCH] Adopt API removal in LSP4E --- .../eclipse/boot/dash/BootDashActivator.java | 11 +-- .../DefaultLiveProcessCommandExecutor.java | 70 +++++++++--------- .../LiveDataConnectionManagementActions.java | 20 ++--- .../LiveProcessCommandsExecutor.java | 12 +-- .../boot/ls/BootLanguageServerPlugin.java | 4 +- .../tooling/boot/ls/Startup.java | 3 +- .../commands/LiveProcessCommandElement.java | 23 +++--- ...iveProcessCommandsQuickAccessProvider.java | 32 ++++---- .../commands/SpringQuickAccessProvider.java | 19 +++-- .../eclipse/commons/LSP4ECommandExecutor.java | 25 ++----- .../dialogs/InProjectSymbolsProvider.java | 74 +++++++++---------- .../dialogs/InWorkspaceSymbolsProvider.java | 36 +++------ 12 files changed, 143 insertions(+), 186 deletions(-) diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/BootDashActivator.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/BootDashActivator.java index d44eea739..b0ac55a70 100644 --- a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/BootDashActivator.java +++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/BootDashActivator.java @@ -12,7 +12,6 @@ package org.springframework.ide.eclipse.boot.dash; import java.time.Duration; import java.util.Arrays; -import java.util.List; import java.util.Map; import org.eclipse.core.net.proxy.IProxyService; @@ -33,7 +32,6 @@ import org.springframework.ide.eclipse.boot.core.BootPropertyTester; import org.springframework.ide.eclipse.boot.dash.di.SimpleDIContext; import org.springframework.ide.eclipse.boot.dash.liveprocess.CommandInfo; import org.springframework.ide.eclipse.boot.dash.liveprocess.LiveProcessCommandsExecutor; -import org.springframework.ide.eclipse.boot.dash.liveprocess.LiveProcessCommandsExecutor.Server; import org.springframework.ide.eclipse.boot.dash.model.BootDashModelContext; import org.springframework.ide.eclipse.boot.dash.model.BootDashViewModel; import org.springframework.ide.eclipse.boot.dash.model.DefaultBootDashModelContext; @@ -45,7 +43,6 @@ import org.springframework.ide.eclipse.boot.dash.util.RunStateTracker.RunStateLi import org.springframework.ide.eclipse.boot.launch.BootLaunchConfigurationDelegate; import org.springsource.ide.eclipse.commons.livexp.util.Log; -import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; /** @@ -194,7 +191,7 @@ public class BootDashActivator extends AbstractUIPlugin { return InstanceScope.INSTANCE.getNode(PLUGIN_ID); } - private final RunStateListener RUN_STATE_LISTENER = new RunStateListener() { + private final RunStateListener RUN_STATE_LISTENER = new RunStateListener<>() { @Override public void stateChanged(ILaunchConfiguration owner) { @@ -211,9 +208,6 @@ public class BootDashActivator extends AbstractUIPlugin { for (IProcess p : l.getProcesses()) { String pid = p.getAttribute(IProcess.ATTR_PROCESS_ID); if (pid != null) { - List servers = LiveProcessCommandsExecutor.getDefault() - .getLanguageServers(); - CommandInfo cmd = new CommandInfo("sts/livedata/connect", Map.of("processKey", pid)); @@ -221,7 +215,8 @@ public class BootDashActivator extends AbstractUIPlugin { // "VirtualMachine.list()" call may not list the newly created process which means the process is gone and triggers disconnect. // If lifecycle management is enabled the ready state seem to be a great indicator of a boot process fully started. // TODO: explore health endpoint perhaps instead of ready state under Admin endpoint. - Flux.fromIterable(servers).flatMap(s -> Mono.delay(Duration.ofMillis(500)).then(s.executeCommand(cmd))).subscribe(); +// Flux.fromIterable(servers).flatMap(s -> Mono.delay(Duration.ofMillis(500)).then(s.executeCommand(cmd))).subscribe(); + Mono.delay(Duration.ofMillis(500)).then(LiveProcessCommandsExecutor.getDefault().executeCommand(cmd)).subscribe(); } } diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/liveprocess/DefaultLiveProcessCommandExecutor.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/liveprocess/DefaultLiveProcessCommandExecutor.java index c0c946cbe..5ee35b2b4 100644 --- a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/liveprocess/DefaultLiveProcessCommandExecutor.java +++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/liveprocess/DefaultLiveProcessCommandExecutor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2022 Pivotal Software, Inc. + * Copyright (c) 2019, 2023 Pivotal Software, 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 @@ -10,14 +10,17 @@ *******************************************************************************/ package org.springframework.ide.eclipse.boot.dash.liveprocess; +import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; -import org.eclipse.lsp4e.LanguageServiceAccessor; +import org.eclipse.lsp4e.LanguageServers; +import org.eclipse.lsp4e.LanguageServers.LanguageServerProjectExecutor; +import org.eclipse.lsp4e.LanguageServersRegistry; import org.eclipse.lsp4j.ExecuteCommandOptions; import org.eclipse.lsp4j.ExecuteCommandParams; -import org.eclipse.lsp4j.services.LanguageServer; import com.google.common.collect.ImmutableList; @@ -29,46 +32,43 @@ public final class DefaultLiveProcessCommandExecutor implements LiveProcessComma private static final String CMD_LIST_PROCESSES = "sts/livedata/listProcesses"; - private class DefaultServer implements Server { - private LanguageServer ls; - public DefaultServer(LanguageServer ls) { - this.ls = ls; - } - @Override - @SuppressWarnings("unchecked") - public Flux listCommands() { - return Mono.fromFuture(ls.getWorkspaceService().executeCommand(new ExecuteCommandParams( - CMD_LIST_PROCESSES, - ImmutableList.of() - ))) - .flatMapIterable(list -> (List)list) - .map(_cmdInfo -> { - Map map = (Map) _cmdInfo; - return new CommandInfo(map.get("action"), map); - }); - } - - @Override - public Mono executeCommand(CommandInfo cmd) { - return Mono.fromRunnable(() -> ls.getWorkspaceService().executeCommand(new ExecuteCommandParams( - cmd.command, - ImmutableList.of(cmd.info) - ))); - } + @SuppressWarnings("unchecked") + @Override + public Flux listCommands() { + List>> futures = getLanguageServers().computeAll(ls -> ls.getWorkspaceService().executeCommand(new ExecuteCommandParams( + CMD_LIST_PROCESSES, + ImmutableList.of() + )).thenApply(o -> { + if (o instanceof List) { + List list = (List) o; + return list.stream().map(_cmdInfo -> { + Map map = (Map) _cmdInfo; + return new CommandInfo(map.get("action"), map); + }).collect(Collectors.toList()); + } + return Collections.emptyList(); + })); + Flux f = Flux.fromIterable(futures).flatMap(fo -> Mono.fromFuture(fo).flatMapIterable(l -> l)); + return f; } @Override - public List getLanguageServers() { - return LanguageServiceAccessor.getActiveLanguageServers(cap -> { + public Mono executeCommand(CommandInfo cmd) { + return Mono.fromFuture(getLanguageServers().collectAll(ls -> ls.getWorkspaceService().executeCommand(new ExecuteCommandParams( + cmd.command, + ImmutableList.of(cmd.info) + ))).thenAccept(null)); + } + + private LanguageServerProjectExecutor getLanguageServers() { + return LanguageServers.forProject(null).withFilter(cap -> { ExecuteCommandOptions commandCap = cap.getExecuteCommandProvider(); if (commandCap!=null) { List supportedCommands = commandCap.getCommands(); return supportedCommands!=null && supportedCommands.contains(CMD_LIST_PROCESSES); } return false; - }) - .stream() - .map(DefaultServer::new) - .collect(Collectors.toList()); + }).withPreferredServer(LanguageServersRegistry.getInstance() + .getDefinition("org.eclipse.languageserver.languages.springboot")); } } \ No newline at end of file diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/liveprocess/LiveDataConnectionManagementActions.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/liveprocess/LiveDataConnectionManagementActions.java index 622833d54..0f8a8a702 100644 --- a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/liveprocess/LiveDataConnectionManagementActions.java +++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/liveprocess/LiveDataConnectionManagementActions.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Pivotal Software, Inc. + * Copyright (c) 2019, 2023 Pivotal Software, 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 @@ -20,7 +20,6 @@ import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.resource.ImageDescriptor; import org.springframework.ide.eclipse.boot.dash.BootDashActivator; -import org.springframework.ide.eclipse.boot.dash.liveprocess.LiveProcessCommandsExecutor.Server; import org.springframework.ide.eclipse.boot.dash.model.BootDashElement; import org.springframework.ide.eclipse.boot.dash.model.BootDashModel.ElementStateListener; import org.springframework.ide.eclipse.boot.dash.model.RunState; @@ -35,8 +34,6 @@ import org.springsource.ide.eclipse.commons.livexp.util.Log; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import reactor.core.publisher.Flux; - public class LiveDataConnectionManagementActions extends AbstractDisposable implements DynamicSubMenuSupplier { private static final IAction DUMMY_ACTION = new Action("No matching processes") { @@ -75,12 +72,10 @@ public class LiveDataConnectionManagementActions extends AbstractDisposable impl public class ExecuteCommandAction extends AbstractBootDashElementsAction { private String projectName; private String label; - private Server server; private CommandInfo commandInfo; - public ExecuteCommandAction(Server server, CommandInfo commandInfo) { + public ExecuteCommandAction(CommandInfo commandInfo) { super(params); - this.server = server; this.commandInfo = commandInfo; String command = commandInfo.command; int lastSlash = command.lastIndexOf("/"); @@ -113,7 +108,7 @@ public class LiveDataConnectionManagementActions extends AbstractDisposable impl @Override public void run() { try { - server.executeCommand(commandInfo).block(Duration.ofSeconds(2)); + liveProcessCmds.executeCommand(commandInfo).block(Duration.ofSeconds(2)); } catch (Exception e) { Log.log(e); } @@ -128,7 +123,7 @@ public class LiveDataConnectionManagementActions extends AbstractDisposable impl this.params = params; this.liveProcessCmds = params.getLiveProcessCmds(); ObservableSet selection = params.getSelection().getElements(); - this.isEnabled = addDisposableChild(new LiveExpression(false) { + this.isEnabled = addDisposableChild(new LiveExpression<>(false) { ElementStateListener elementStateListener = (BootDashElement e) -> { refresh(); @@ -178,12 +173,7 @@ public class LiveDataConnectionManagementActions extends AbstractDisposable impl }; } try { - List servers = liveProcessCmds.getLanguageServers(); - return Flux.fromIterable(servers) - .flatMap((Server server) -> - server.listCommands() - .map(cmdInfo -> new ExecuteCommandAction(server, cmdInfo)) - ) + return liveProcessCmds.listCommands().map(cmdInfo -> new ExecuteCommandAction(cmdInfo)) .filter(filter) .cast(IAction.class) .collect(Collectors.toList()) diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/liveprocess/LiveProcessCommandsExecutor.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/liveprocess/LiveProcessCommandsExecutor.java index 1f51d001f..16c6e1784 100644 --- a/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/liveprocess/LiveProcessCommandsExecutor.java +++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.dash/src/org/springframework/ide/eclipse/boot/dash/liveprocess/LiveProcessCommandsExecutor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Pivotal Software, Inc. + * Copyright (c) 2019, 2023 Pivotal Software, 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 @@ -10,21 +10,15 @@ *******************************************************************************/ package org.springframework.ide.eclipse.boot.dash.liveprocess; -import java.util.List; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; public interface LiveProcessCommandsExecutor { - interface Server { - Flux listCommands(); - Mono executeCommand(CommandInfo cmd); - } + Flux listCommands(); + Mono executeCommand(CommandInfo cmd); static LiveProcessCommandsExecutor getDefault() { return new DefaultLiveProcessCommandExecutor(); } - - List getLanguageServers(); } diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java index bd45246f0..e68b55c6b 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java @@ -32,8 +32,6 @@ import org.springframework.tooling.boot.ls.prefs.LiveInformationPreferencePage; */ public class BootLanguageServerPlugin extends AbstractUIPlugin { - public static String BOOT_LS_DEFINITION_ID = "org.eclipse.languageserver.languages.springboot"; - public static String PLUGIN_ID = "org.springframework.tooling.boot.ls"; private static final Object LSP4E_COMMAND_SYMBOL_IN_WORKSPACE = "org.eclipse.lsp4e.symbolinworkspace"; @@ -41,6 +39,8 @@ public class BootLanguageServerPlugin extends AbstractUIPlugin { // The shared instance private static BootLanguageServerPlugin plugin; + public static final String BOOT_LS_DEFINITION_ID = "org.eclipse.languageserver.languages.springboot"; + public BootLanguageServerPlugin() { // Empty } diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/Startup.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/Startup.java index 8af884260..d20e4fe7c 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/Startup.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/Startup.java @@ -25,7 +25,6 @@ import org.springframework.tooling.jdt.ls.commons.Logger; @SuppressWarnings("restriction") public class Startup implements IStartup { - private static final String BOOT_LS_DEFINITION_ID = "org.eclipse.languageserver.languages.springboot"; private boolean started; @Override @@ -41,7 +40,7 @@ public class Startup implements IStartup { if (!started && !springProjects.isEmpty()) { BootLanguageServerPlugin.getDefault().getLog().info("Starting Boot LS..."); LanguageServerDefinition serverDefinition = LanguageServersRegistry.getInstance() - .getDefinition(BOOT_LS_DEFINITION_ID); + .getDefinition(BootLanguageServerPlugin.BOOT_LS_DEFINITION_ID); try { LanguageServiceAccessor.startLanguageServer(serverDefinition); diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/LiveProcessCommandElement.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/LiveProcessCommandElement.java index 3348895a9..694f4d347 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/LiveProcessCommandElement.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/LiveProcessCommandElement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Pivotal, Inc. + * Copyright (c) 2019, 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 @@ -18,12 +18,12 @@ import java.util.Random; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.lsp4e.LanguageServiceAccessor; +import org.eclipse.lsp4e.LanguageServers; +import org.eclipse.lsp4e.LanguageServersRegistry; import org.eclipse.lsp4j.ExecuteCommandParams; -import org.eclipse.lsp4j.services.LanguageServer; import org.eclipse.ui.quickaccess.QuickAccessElement; +import org.springframework.tooling.boot.ls.BootLanguageServerPlugin; /** * @author Martin Lippert @@ -79,12 +79,6 @@ public class LiveProcessCommandElement extends QuickAccessElement { @Override public void execute() { - List<@NonNull LanguageServer> usedLanguageServers = LanguageServiceAccessor.getActiveLanguageServers(serverCapabilities -> true); - - if (usedLanguageServers.isEmpty()) { - return; - } - ExecuteCommandParams commandParams = new ExecuteCommandParams(); commandParams.setCommand(this.action); @@ -94,10 +88,15 @@ public class LiveProcessCommandElement extends QuickAccessElement { arguments.add(argumentMap); commandParams.setArguments(arguments); + + List> futures = LanguageServers + .forProject(null) + .excludeInactive() + .withPreferredServer(LanguageServersRegistry.getInstance().getDefinition(BootLanguageServerPlugin.BOOT_LS_DEFINITION_ID)) + .computeAll(ls -> ls.getWorkspaceService().executeCommand(commandParams)); try { - CompletableFuture.allOf(usedLanguageServers.stream().map(ls -> - ls.getWorkspaceService().executeCommand(commandParams)).toArray(CompletableFuture[]::new)).get(2, TimeUnit.SECONDS); + CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).get(2, TimeUnit.SECONDS); } catch (Exception e) { // TODO: better exception handling diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/LiveProcessCommandsQuickAccessProvider.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/LiveProcessCommandsQuickAccessProvider.java index ac850fd1a..e0fabe6f9 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/LiveProcessCommandsQuickAccessProvider.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/LiveProcessCommandsQuickAccessProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Pivotal, Inc. + * Copyright (c) 2019, 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 @@ -19,12 +19,15 @@ import java.util.concurrent.TimeUnit; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.lsp4e.LanguageServiceAccessor; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.lsp4e.LanguageServers; +import org.eclipse.lsp4e.LanguageServersRegistry; import org.eclipse.lsp4j.ExecuteCommandParams; import org.eclipse.lsp4j.services.LanguageServer; import org.eclipse.ui.quickaccess.IQuickAccessComputer; import org.eclipse.ui.quickaccess.IQuickAccessComputerExtension; import org.eclipse.ui.quickaccess.QuickAccessElement; +import org.springframework.tooling.boot.ls.BootLanguageServerPlugin; /** * @author Martin Lippert @@ -50,23 +53,24 @@ public class LiveProcessCommandsQuickAccessProvider implements IQuickAccessCompu @Override public QuickAccessElement[] computeElements(String query, IProgressMonitor monitor) { - this.usedLanguageServers = LanguageServiceAccessor.getActiveLanguageServers(serverCapabilities -> true); - - if (usedLanguageServers.isEmpty()) { - return new QuickAccessElement[0]; - } - ExecuteCommandParams commandParams = new ExecuteCommandParams(); commandParams.setCommand(LiveProcessCommandElement.COMMAND_LIST_PROCESSES); - List res = Collections.synchronizedList(new ArrayList<>()); + usedLanguageServers = new ArrayList<>(); + @NonNull + List<@NonNull CompletableFuture<@Nullable Void>> futures = LanguageServers + .forProject(null) + .excludeInactive() + .withPreferredServer(LanguageServersRegistry.getInstance().getDefinition(BootLanguageServerPlugin.BOOT_LS_DEFINITION_ID)) + .computeAll(ls -> { + usedLanguageServers.add(ls); + return ls.getWorkspaceService().executeCommand(commandParams).thenAcceptAsync(commandResult -> + createCommandItems(res, commandResult)); + }); try { - CompletableFuture.allOf(usedLanguageServers.stream().map(ls -> - ls.getWorkspaceService().executeCommand(commandParams).thenAcceptAsync(commandResult -> - createCommandItems(res, commandResult))).toArray(CompletableFuture[]::new)).get(2000, TimeUnit.MILLISECONDS); - } - catch (Exception e) { + CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).get(2000, TimeUnit.MILLISECONDS); + } catch (Exception e) { // TODO: better error handling e.printStackTrace(); } diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/SpringQuickAccessProvider.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/SpringQuickAccessProvider.java index 6c6cfd139..6de236694 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/SpringQuickAccessProvider.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/commands/SpringQuickAccessProvider.java @@ -17,9 +17,9 @@ import java.util.concurrent.TimeUnit; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.lsp4e.LanguageServiceAccessor; +import org.eclipse.lsp4e.LanguageServers; +import org.eclipse.lsp4e.LanguageServersRegistry; import org.eclipse.lsp4j.ExecuteCommandParams; -import org.eclipse.lsp4j.services.LanguageServer; import org.eclipse.ui.quickaccess.IQuickAccessComputer; import org.eclipse.ui.quickaccess.IQuickAccessComputerExtension; import org.eclipse.ui.quickaccess.QuickAccessElement; @@ -60,20 +60,19 @@ public class SpringQuickAccessProvider implements IQuickAccessComputer, IQuickAc @Override public void execute() { - List usedLanguageServers = LanguageServiceAccessor.getActiveLanguageServers(serverCapabilities -> true); - - if (usedLanguageServers.isEmpty()) { - return; - } - ExecuteCommandParams commandParams = new ExecuteCommandParams(); commandParams.setCommand(commandId); commandParams.setArguments(Collections.emptyList()); + + List> futures = LanguageServers + .forProject(null) + .excludeInactive() + .withPreferredServer(LanguageServersRegistry.getInstance().getDefinition(BootLanguageServerPlugin.BOOT_LS_DEFINITION_ID)) + .computeAll(ls -> ls.getWorkspaceService().executeCommand(commandParams)); try { - CompletableFuture.allOf(usedLanguageServers.stream().map(ls -> - ls.getWorkspaceService().executeCommand(commandParams)).toArray(CompletableFuture[]::new)).get(2, TimeUnit.SECONDS); + CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).get(2, TimeUnit.SECONDS); } catch (Exception e) { BootLanguageServerPlugin.getDefault().getLog().error(errorMsg, e); diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/LSP4ECommandExecutor.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/LSP4ECommandExecutor.java index bcb40e828..385fdd1f3 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/LSP4ECommandExecutor.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/LSP4ECommandExecutor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 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 @@ -11,15 +11,14 @@ package org.springframework.tooling.ls.eclipse.commons; import java.util.Arrays; -import java.util.List; +import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; -import org.eclipse.lsp4e.LanguageServiceAccessor; +import org.eclipse.lsp4e.LanguageServers; import org.eclipse.lsp4j.ExecuteCommandOptions; import org.eclipse.lsp4j.ExecuteCommandParams; import org.eclipse.lsp4j.ServerCapabilities; -import org.eclipse.lsp4j.services.LanguageServer; import org.springframework.tooling.jdt.ls.commons.classpath.ClientCommandExecutor; @SuppressWarnings("restriction") @@ -27,19 +26,11 @@ public class LSP4ECommandExecutor implements ClientCommandExecutor { @Override public Object executeClientCommand(String id, Object... params) throws Exception { - List commandHandlers = LanguageServiceAccessor.getActiveLanguageServers(handlesCommand(id)); - if (commandHandlers != null) { - if (commandHandlers.size() == 1) { - LanguageServer handler = commandHandlers.get(0); - return handler - .getWorkspaceService() - .executeCommand(new ExecuteCommandParams(id, Arrays.asList(params))) - .get(2, TimeUnit.SECONDS); - } else if (commandHandlers.size() > 1) { - throw new IllegalStateException("Multiple language servers have registered to handle command '"+id+"'"); - } - } - throw new UnsupportedOperationException("No language server has registered to handle command '"+id+"'"); + Optional res = LanguageServers.forProject(null).withFilter(handlesCommand(id)).computeFirst( + ls -> ls.getWorkspaceService().executeCommand(new ExecuteCommandParams(id, Arrays.asList(params)))) + .get(2, TimeUnit.SECONDS); + return res.orElseThrow(() -> new UnsupportedOperationException( + "No language server has registered to handle command '" + id + "'")); } private Predicate handlesCommand(String id) { diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/InProjectSymbolsProvider.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/InProjectSymbolsProvider.java index 07b133933..4aadd52f4 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/InProjectSymbolsProvider.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/InProjectSymbolsProvider.java @@ -11,6 +11,7 @@ package org.springframework.tooling.ls.eclipse.gotosymbol.dialogs; import java.time.Duration; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; @@ -18,13 +19,13 @@ import java.util.stream.Collectors; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.lsp4e.LSPEclipseUtils; -import org.eclipse.lsp4e.LanguageServiceAccessor; +import org.eclipse.lsp4e.LanguageServers; import org.eclipse.lsp4j.SymbolInformation; import org.eclipse.lsp4j.WorkspaceSymbol; import org.eclipse.lsp4j.WorkspaceSymbolParams; import org.eclipse.lsp4j.jsonrpc.messages.Either; -import org.eclipse.lsp4j.services.LanguageServer; import org.springframework.ide.vscode.commons.protocol.spring.Bean; import org.springframework.ide.vscode.commons.protocol.spring.BeansParams; import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexLanguageServer; @@ -41,16 +42,7 @@ import reactor.core.publisher.Mono; public class InProjectSymbolsProvider implements SymbolsProvider { public static InProjectSymbolsProvider createFor(LiveExpression project) { - LiveExpression> languageServers = project.apply(p -> { - return p == null - ? ImmutableList.of() - : LanguageServiceAccessor.getLanguageServers( - project.getValue(), - capabilities -> LSPEclipseUtils.hasCapability(capabilities.getWorkspaceSymbolProvider()), - true - ); - }); - return new InProjectSymbolsProvider(languageServers::getValue, project::getValue); + return new InProjectSymbolsProvider(project::getValue); } public static InProjectSymbolsProvider createFor(ExecutionEvent event) { @@ -64,11 +56,9 @@ public class InProjectSymbolsProvider implements SymbolsProvider { private static final Duration TIMEOUT = Duration.ofSeconds(2); private static final int MAX_RESULTS = 200; - private Supplier> languageServers; private Supplier project; - public InProjectSymbolsProvider(Supplier> languageServers, Supplier project) { - this.languageServers = languageServers; + public InProjectSymbolsProvider(Supplier project) { this.project = project; } @@ -99,10 +89,15 @@ public class InProjectSymbolsProvider implements SymbolsProvider { WorkspaceSymbolParams params = new WorkspaceSymbolParams(query); - List servers = this.languageServers.get(); + List, List>>> responses = LanguageServers + .forProject(project) + .withFilter(capabilities -> LSPEclipseUtils.hasCapability(capabilities.getWorkspaceSymbolProvider())) + .excludeInactive() + .computeAll(ls -> ls.getWorkspaceService().symbol(params)); + - Flux, List>> first = Flux.fromIterable(servers) - .flatMap(server -> Mono.fromFuture(server.getWorkspaceService().symbol(params))) + Flux, List>> first = Flux.fromIterable(responses) + .flatMap(Mono::fromFuture) .timeout(TIMEOUT); Flux symbols = first @@ -128,31 +123,34 @@ public class InProjectSymbolsProvider implements SymbolsProvider { GotoSymbolPlugin.getInstance().getLog().log(ExceptionUtil.status(e)); } - @SuppressWarnings("removal") private void dumpBeansModel(String projectName) { - List activeLanguageServers = LanguageServiceAccessor.getActiveLanguageServers(null); + IProject p = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); - for (LanguageServer languageServer : activeLanguageServers) { - if (languageServer instanceof SpringIndexLanguageServer) { - SpringIndexLanguageServer springServer = (SpringIndexLanguageServer) languageServer; + BeansParams beansParams = new BeansParams(); + beansParams.setProjectName(projectName); - BeansParams beansParams = new BeansParams(); - beansParams.setProjectName(projectName); - - CompletableFuture> beansFuture = springServer.beans(beansParams); - - try { - List beans = beansFuture.get(); - - for (Bean bean : beans) { - System.out.println(bean); + List>> executors = LanguageServers + .forProject(p) + .withFilter(capabilities -> LSPEclipseUtils.hasCapability(capabilities.getWorkspaceSymbolProvider())) + .excludeInactive() + .computeAll(ls -> { + if (ls instanceof SpringIndexLanguageServer) { + return ((SpringIndexLanguageServer) ls).beans(beansParams); } + return CompletableFuture.completedFuture(Collections.emptyList()); + }); + + for (CompletableFuture> beansFuture : executors) { + try { + List beans = beansFuture.get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (java.util.concurrent.ExecutionException e) { - e.printStackTrace(); - } + for (Bean bean : beans) { + System.out.println(bean); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (java.util.concurrent.ExecutionException e) { + e.printStackTrace(); } } diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/InWorkspaceSymbolsProvider.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/InWorkspaceSymbolsProvider.java index 1b723ca3a..c08d8fce0 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/InWorkspaceSymbolsProvider.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/InWorkspaceSymbolsProvider.java @@ -12,6 +12,7 @@ package org.springframework.tooling.ls.eclipse.gotosymbol.dialogs; import java.time.Duration; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -22,13 +23,13 @@ import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.lsp4e.LSPEclipseUtils; -import org.eclipse.lsp4e.LanguageServiceAccessor; +import org.eclipse.lsp4e.LanguageServers; +import org.eclipse.lsp4e.LanguageServers.LanguageServerProjectExecutor; import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.lsp4j.SymbolInformation; import org.eclipse.lsp4j.WorkspaceSymbol; import org.eclipse.lsp4j.WorkspaceSymbolParams; import org.eclipse.lsp4j.jsonrpc.messages.Either; -import org.eclipse.lsp4j.services.LanguageServer; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.handlers.HandlerUtil; import org.springframework.tooling.ls.eclipse.gotosymbol.GotoSymbolPlugin; @@ -45,32 +46,21 @@ public class InWorkspaceSymbolsProvider implements SymbolsProvider { private static final Predicate WS_SYMBOL_CAP = capabilities -> LSPEclipseUtils.hasCapability(capabilities.getWorkspaceSymbolProvider()); public static InWorkspaceSymbolsProvider createFor(Supplier _project) { - return new InWorkspaceSymbolsProvider(() -> { - IProject project = _project.get(); - if (project!=null) { - return LanguageServiceAccessor.getLanguageServers(project, - WS_SYMBOL_CAP, true); - } else { - return LanguageServiceAccessor.getActiveLanguageServers(WS_SYMBOL_CAP); - } - }); + LanguageServerProjectExecutor lss = LanguageServers.forProject(_project.get()).withFilter(WS_SYMBOL_CAP).excludeInactive(); + return new InWorkspaceSymbolsProvider(lss); } public static InWorkspaceSymbolsProvider createFor(IProject project) { - List languageServers = LanguageServiceAccessor.getLanguageServers(project, - capabilities -> LSPEclipseUtils.hasCapability(capabilities.getWorkspaceSymbolProvider()), true); - if (!languageServers.isEmpty()) { - return new InWorkspaceSymbolsProvider(() -> languageServers); - } - return null; + LanguageServerProjectExecutor lss = LanguageServers.forProject(project).withFilter(capabilities -> LSPEclipseUtils.hasCapability(capabilities.getWorkspaceSymbolProvider())).excludeInactive(); + return new InWorkspaceSymbolsProvider(lss); } private static final Duration TIMEOUT = Duration.ofSeconds(2); private static final int MAX_RESULTS = 200; - private Supplier> languageServers; + private LanguageServers languageServers; - public InWorkspaceSymbolsProvider(Supplier> languageServers) { + public InWorkspaceSymbolsProvider(LanguageServers languageServers) { this.languageServers = languageServers; } @@ -91,12 +81,10 @@ public class InWorkspaceSymbolsProvider implements SymbolsProvider { //However it will also add complexity to the code that consumes this and at this time we only // really use this with a single language server anyways. WorkspaceSymbolParams params = new WorkspaceSymbolParams(query); - - List servers = this.languageServers.get(); - Flux, List>> first = Flux.fromIterable(servers) - .flatMap(server -> Mono.fromFuture(server.getWorkspaceService().symbol(params))) - .timeout(TIMEOUT); + List, List>>> responses = languageServers.computeAll(ls -> ls.getWorkspaceService().symbol(params)); + + Flux, List>> first = Flux.fromIterable(responses).flatMap(Mono::fromFuture).timeout(TIMEOUT); Flux symbols = first .doOnError(e -> log(e))