From d648e60e2f1e0e38c95fe2f0db460fa7e53678b9 Mon Sep 17 00:00:00 2001 From: Svata Dedic Date: Wed, 29 Mar 2023 22:39:01 +0200 Subject: [PATCH 1/2] DAP and LSP use a common Lookup. --- .../java/lsp/server/debugging/Debugger.java | 26 ++++++++++++------- .../server/debugging/NbProtocolServer.java | 1 + .../java/lsp/server/protocol/NbLspServer.java | 2 +- .../java/lsp/server/protocol/Server.java | 24 ++++++++++++++--- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/Debugger.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/Debugger.java index 606f1b6078fc..9d8ba9300d0e 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/Debugger.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/Debugger.java @@ -20,7 +20,6 @@ import java.io.InputStream; import java.io.OutputStream; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.eclipse.lsp4j.debug.launch.DSPLauncher; @@ -33,7 +32,6 @@ import org.netbeans.modules.java.lsp.server.LspSession; import org.netbeans.modules.java.lsp.server.progress.OperationContext; -import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.Pair; import org.openide.util.lookup.AbstractLookup; @@ -55,7 +53,7 @@ public static NbProtocolServer startDebugger(Pair io, NbProtocolServer server = new NbProtocolServer(context); Launcher serverLauncher = DSPLauncher.createServerLauncher( - server, io.first(), io.second(), null, ConsumeWithLookup::new); + server, io.first(), io.second(), null, (d) -> new ConsumeWithLookup(d, session)); context.setClient(serverLauncher.getRemoteProxy()); Future runningServer = serverLauncher.startListening(); server.setRunningFuture(runningServer); @@ -64,22 +62,32 @@ public static NbProtocolServer startDebugger(Pair io, private static class ConsumeWithLookup implements MessageConsumer { private final MessageConsumer delegate; + private final LspSession lspSession; private OperationContext topContext; + private Lookup debugSessionLookup; - public ConsumeWithLookup(MessageConsumer delegate) { + public ConsumeWithLookup(MessageConsumer delegate, LspSession session) { this.delegate = delegate; + this.lspSession = session; } @Override public void consume(Message message) throws MessageIssueException, JsonRpcException { InstanceContent ic = new InstanceContent(); - ProxyLookup ll = new ProxyLookup(new AbstractLookup(ic), Lookup.getDefault()); - // HACK: piggyback on LSP's client. + Lookup ll = debugSessionLookup; + final OperationContext ctx; + if (ll == null) { + ll = new ProxyLookup(new AbstractLookup(ic), lspSession.getLookup()); + synchronized (this) { + if (debugSessionLookup == null) { + debugSessionLookup = ll; + } + } + // HACK: piggyback on LSP's client. + } if (topContext == null) { - topContext = OperationContext.find(null); + topContext = OperationContext.find(lspSession.getLookup()); } - final OperationContext ctx; - if (topContext != null) { ctx = topContext.operationContext(); ctx.disableCancels(); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java index d4ffca260074..eee80d166353 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java @@ -97,6 +97,7 @@ import org.netbeans.spi.debugger.ui.DebuggingView; import org.netbeans.spi.debugger.ui.DebuggingView.DVFrame; import org.netbeans.spi.debugger.ui.DebuggingView.DVThread; +import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.RequestProcessor; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbLspServer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbLspServer.java index f50d437bff9d..15f4b691cda5 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbLspServer.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbLspServer.java @@ -43,7 +43,7 @@ public final class NbLspServer implements LspSession.ScheduledServer { @Override public Lookup getServerLookup() { - return impl.getSessionLookup(); + return impl.getSessionOnlyLookup(); } public TextDocumentService getTextDocumentService() { diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java index 411948f195d4..d10758d91388 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java @@ -158,7 +158,7 @@ public static boolean isClientResponseThread(NbCodeLanguageClient client) { } public static NbLspServer launchServer(Pair io, LspSession session) { - LanguageServerImpl server = new LanguageServerImpl(); + LanguageServerImpl server = new LanguageServerImpl(session); ConsumeWithLookup msgProcessor = new ConsumeWithLookup(server.getSessionLookup()); Launcher serverLauncher = createLauncher(server, io, msgProcessor::attachLookup); NbCodeLanguageClient remote = serverLauncher.getRemoteProxy(); @@ -357,8 +357,9 @@ public static class LanguageServerImpl implements LanguageServer, LanguageClient private final TextDocumentServiceImpl textDocumentService = new TextDocumentServiceImpl(this); private final WorkspaceServiceImpl workspaceService = new WorkspaceServiceImpl(this); private final InstanceContent sessionServices = new InstanceContent(); + private final AbstractLookup sessionOnly = new AbstractLookup(sessionServices); private final Lookup sessionLookup = new ProxyLookup( - new AbstractLookup(sessionServices), + sessionOnly, Lookup.getDefault() ); @@ -401,9 +402,24 @@ public static class LanguageServerImpl implements LanguageServer, LanguageClient private final List acceptedWorkspaceFolders = new ArrayList<>(); private final OpenedDocuments openedDocuments = new OpenedDocuments(); + + private final LspSession lspSession; + + LanguageServerImpl(LspSession session) { + this.lspSession = session; + } - Lookup getSessionLookup() { - return sessionLookup; + private Lookup getSessionLookup() { + return lspSession.getLookup(); + } + + /** + * Returns a Lookup specific for this LSP server's session. Does not include the default Lookup contents, + * it is suitable for composing into a ProxyLookup with other parts + the default one. + * @return + */ + Lookup getSessionOnlyLookup() { + return sessionOnly; } /** From 8a59dc3a051253e27c8eef48ab039ba060d0cba4 Mon Sep 17 00:00:00 2001 From: Svata Dedic Date: Thu, 30 Mar 2023 09:08:16 +0200 Subject: [PATCH 2/2] Test that default Lookup is included just once. --- .../java/lsp/server/protocol/ServerTest.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java index 5b620cb2f035..9f62b26e51b7 100644 --- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java +++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java @@ -41,6 +41,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; @@ -188,6 +189,7 @@ import org.netbeans.spi.project.ProjectFactory; import org.netbeans.spi.project.ProjectState; import org.netbeans.spi.project.ui.ProjectOpenedHook; +import org.openide.DialogDisplayer; import org.openide.cookies.EditorCookie; import org.openide.cookies.LineCookie; import org.openide.filesystems.FileObject; @@ -219,6 +221,40 @@ public ServerTest(String name) { super(name); } + private static final String COMMAND_EXTRACT_LOOKUP = "test.lookup.extract"; // NOI8N + + static volatile ServerLookupExtractionCommand extractCommand = null; + + @ServiceProvider(service = CodeActionsProvider.class) + public static class ServerLookupExtractionCommand extends CodeActionsProvider { + volatile Lookup serverLookup; + volatile Lookup commandLookup; + + public ServerLookupExtractionCommand() { + extractCommand = this; + } + + @Override + public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + return Collections.emptyList(); + } + + @Override + public Set getCommands() { + // this is called during server's initialization. + serverLookup = Lookup.getDefault(); + return Collections.singleton(COMMAND_EXTRACT_LOOKUP); + } + + @Override + public CompletableFuture processCommand(NbCodeLanguageClient client, String command, List arguments) { + if (COMMAND_EXTRACT_LOOKUP.equals(command)) { + commandLookup = Lookup.getDefault(); + return CompletableFuture.completedFuture(true); + } + return null; + } + } @Override protected void setUp() throws Exception { System.setProperty("java.awt.headless", Boolean.TRUE.toString()); @@ -4362,6 +4398,7 @@ public CompletableFuture> showQuickPick(ShowQuickPickParams } private Launcher createClientLauncherWithLogging(LanguageClient client, InputStream input, OutputStream output) { + System.err.println("Creating a client for testcase: " + getName()); Launcher.Builder builder = new LSPLauncher.Builder() .setLocalService(client) .setExceptionHandler((t) -> { @@ -5551,6 +5588,29 @@ public void testDeclarativeHints() throws Exception { assertEquals(Arrays.asList("Method:length() : int"), actualItems); } + /** + * Checks that the default Lookup contents is present just once in Lookup.getDefault() during server invocation in general, + * and specifically during command invocation. + */ + public void testDefaultLookupJustOnce() throws Exception { + Launcher serverLauncher = createClientLauncherWithLogging(new LspClient(), client.getInputStream(), client.getOutputStream()); + serverLauncher.startListening(); + LanguageServer server = serverLauncher.getRemoteProxy(); + CompletableFuture o = server.getWorkspaceService().executeCommand(new ExecuteCommandParams(COMMAND_EXTRACT_LOOKUP, Collections.emptyList())); + o.get(); + Collection mm1 = extractCommand.serverLookup.lookupAll(NbCodeLanguageClient.class); + Collection mm2 = extractCommand.commandLookup.lookupAll(NbCodeLanguageClient.class); + + assertEquals(1, mm1.size()); + assertEquals(1, mm2.size()); + + Collection mm3 = extractCommand.serverLookup.lookupAll(DialogDisplayer.class); + Collection mm4 = extractCommand.commandLookup.lookupAll(DialogDisplayer.class); + + assertEquals(1, mm3.size()); + assertEquals(1, mm4.size()); + } + static { System.setProperty("SourcePath.no.source.filter", "true"); JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true;