From b6363cd52c2819c89aefdfcb2e791bb83439b9bf Mon Sep 17 00:00:00 2001 From: Dusan Balek Date: Wed, 12 Jul 2023 13:30:40 +0200 Subject: [PATCH 1/3] LSP: block workspaceSymbols until projects get opened and scannig is finished, notify client on scanning runs. --- .../java/lsp/server/protocol/Server.java | 76 +++++ .../server/protocol/WorkspaceServiceImpl.java | 298 +++++++++--------- java/java.lsp.server/vscode/package.json | 8 + java/java.lsp.server/vscode/src/extension.ts | 21 +- 4 files changed, 258 insertions(+), 145 deletions(-) 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 3cb748b10c5c..276e58005ef4 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 @@ -99,6 +99,7 @@ import org.eclipse.lsp4j.services.TextDocumentService; import org.eclipse.lsp4j.services.WorkspaceService; import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.editor.mimelookup.MimeRegistration; import org.netbeans.api.java.classpath.ClassPath; import org.netbeans.api.java.source.ClasspathInfo; import org.netbeans.api.java.source.JavaSource; @@ -124,6 +125,10 @@ import org.netbeans.modules.java.lsp.server.input.ShowMutliStepInputParams; import org.netbeans.modules.java.lsp.server.input.ShowInputBoxParams; import org.netbeans.modules.java.lsp.server.progress.OperationContext; +import org.netbeans.modules.parsing.spi.indexing.Context; +import org.netbeans.modules.parsing.spi.indexing.CustomIndexer; +import org.netbeans.modules.parsing.spi.indexing.CustomIndexerFactory; +import org.netbeans.modules.parsing.spi.indexing.Indexable; import org.netbeans.modules.progress.spi.InternalHandle; import org.netbeans.spi.project.ActionProgress; import org.netbeans.spi.project.ActionProvider; @@ -961,6 +966,7 @@ protected LanguageClient client() { ((LanguageClientAware) getTextDocumentService()).connect(client); ((LanguageClientAware) getWorkspaceService()).connect(client); ((LanguageClientAware) treeService).connect(client); + LSPServerTelemetryFactory.getDefault().connect(client); } @Override @@ -1185,4 +1191,74 @@ private static void hackNoReuseOfOutputsForAntProjects() { } } } + + public static class LSPServerTelemetryFactory extends CustomIndexerFactory implements LanguageClientAware { + + private static LSPServerTelemetryFactory INSTANCE; + private final CustomIndexer noOp = new CustomIndexer() { + @Override + protected void index(Iterable files, Context context) { + } + }; + private LanguageClient client; + + @MimeRegistration(mimeType="", service=CustomIndexerFactory.class) + public static LSPServerTelemetryFactory getDefault() { + if (INSTANCE == null) { + INSTANCE = new LSPServerTelemetryFactory(); + } + return INSTANCE; + } + + private LSPServerTelemetryFactory() { + } + + @Override + public synchronized void connect(LanguageClient client) { + this.client = client; + } + + @Override + public synchronized boolean scanStarted(Context context) { + if (client != null) { + client.telemetryEvent("nbls.scanStarted"); + } + return true; + } + + @Override + public synchronized void scanFinished(Context context) { + if (client != null) { + client.telemetryEvent("nbls.scanFinished"); + } + } + + @Override + public void filesDeleted(Iterable deleted, Context context) { + } + + @Override + public void filesDirty(Iterable dirty, Context context) { + } + + @Override + public String getIndexerName() { + return "LSPServerTelemetry"; + } + + @Override + public int getIndexVersion() { + return 1; + } + + @Override + public CustomIndexer createIndexer() { + return noOp; + } + + @Override + public boolean supportsEmbeddedIndexers() { + return false; + } + } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java index 80519251257e..dc9b090e59f4 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java @@ -124,7 +124,11 @@ import org.netbeans.modules.java.source.ui.JavaSymbolProvider; import org.netbeans.modules.java.source.ui.JavaTypeProvider; import org.netbeans.modules.java.source.usages.ClassIndexImpl; +import org.netbeans.modules.parsing.api.ParserManager; +import org.netbeans.modules.parsing.api.ResultIterator; +import org.netbeans.modules.parsing.api.UserTask; import org.netbeans.modules.parsing.lucene.support.Queries; +import org.netbeans.modules.parsing.spi.ParseException; import org.netbeans.spi.java.classpath.support.ClassPathSupport; import org.netbeans.spi.jumpto.type.SearchType; import org.netbeans.spi.project.ActionProgress; @@ -898,17 +902,11 @@ private boolean isTestGroup(SourceGroup sg) { @Override public CompletableFuture, List>> symbol(WorkspaceSymbolParams params) { - // shortcut: if the projects are not yet initialized, return empty: - final Project[] openedProjects = server.openedProjects().getNow(null); - if (openedProjects == null) { - return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList())); - } String query = params.getQuery(); if (query.isEmpty()) { //cannot query "all": return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList())); } - System.err.println("query=" + query); boolean exact = false; if (query.endsWith(" ")) { query = query.substring(0, query.length() - 1); @@ -924,166 +922,180 @@ public boolean cancel(boolean mayInterruptIfRunning) { return super.cancel(mayInterruptIfRunning); } }; - WORKER.post(() -> { + server.openedProjects().thenAccept(openedProjects -> { try { - List symbols = new ArrayList<>(); - SearchType searchType = getSearchType(queryFin, exactFin, false, null, null); + ParserManager.parseWhenScanFinished("text/x-java", new UserTask() { + @Override + public void run(ResultIterator resultIterator) throws Exception { + WORKER.post(() -> { + try { + List symbols = new ArrayList<>(); + SearchType searchType = getSearchType(queryFin, exactFin, false, null, null); - // CSL Part - Collection providers = Lookup.getDefault().lookupAll(IndexSearcher.class); - Set descriptors; - for (Project project : openedProjects) { - if (!providers.isEmpty()) { - for (IndexSearcher provider : providers) { - descriptors = provider.getSymbols(project, queryFin, Utils.searchType2QueryKind(searchType), null); - for (IndexSearcher.Descriptor desc : descriptors) { - FileObject fo = desc.getFileObject(); - org.netbeans.modules.csl.api.ElementHandle element = desc.getElement(); - if (fo != null) { - Position pos = Utils.createPosition(fo, desc.getOffset()); - WorkspaceSymbol symbol = new WorkspaceSymbol( - desc.getSimpleName(), - Utils.cslElementKind2SymbolKind(element.getKind()), - Either.forLeft(new Location(Utils.toUri(fo), new Range(pos, pos))), - desc.getContextName()); - symbols.add(symbol); + // CSL Part + Collection providers = Lookup.getDefault().lookupAll(IndexSearcher.class); + Set descriptors; + for (Project project : openedProjects) { + if (!providers.isEmpty()) { + for (IndexSearcher provider : providers) { + descriptors = provider.getSymbols(project, queryFin, Utils.searchType2QueryKind(searchType), null); + for (IndexSearcher.Descriptor desc : descriptors) { + FileObject fo = desc.getFileObject(); + org.netbeans.modules.csl.api.ElementHandle element = desc.getElement(); + if (fo != null) { + Position pos = Utils.createPosition(fo, desc.getOffset()); + WorkspaceSymbol symbol = new WorkspaceSymbol( + desc.getSimpleName(), + Utils.cslElementKind2SymbolKind(element.getKind()), + Either.forLeft(new Location(Utils.toUri(fo), new Range(pos, pos))), + desc.getContextName()); + symbols.add(symbol); + } + } + } + } } - } - } - } - } - // Java part - if (client.getNbCodeCapabilities().wantsJavaSupport()) { - JavaSymbolProvider.ResultHandler symbolHandler = new JavaSymbolProvider.ResultHandler() { - @Override - public void setHighlightText(String text) { - } + // Java part + if (client.getNbCodeCapabilities().wantsJavaSupport()) { + JavaSymbolProvider.ResultHandler symbolHandler = new JavaSymbolProvider.ResultHandler() { + @Override + public void setHighlightText(String text) { + } - private Map, List> type2Idents; + private Map, List> type2Idents; - @Override - public void runRoot(FileObject root, ClassIndexImpl ci, Exec exec) throws IOException, InterruptedException { - ClasspathInfo cpInfo = ClasspathInfo.create(root); - try { - type2Idents = new HashMap<>(); - exec.run(); - Map, List>> sources = new HashMap<>(); - for (Entry, List> e : type2Idents.entrySet()) { - FileObject sourceFile = SourceUtils.getFile(e.getKey(), cpInfo); - sources.computeIfAbsent(sourceFile, s -> new HashMap<>()) - .put(e.getKey(), e.getValue()); - } - if (!sources.isEmpty()) { - JavaSource.create(cpInfo, sources.keySet()) - .runUserActionTask(cc -> { - if (Phase.ELEMENTS_RESOLVED.compareTo(cc.toPhase(Phase.ELEMENTS_RESOLVED))> 0) { - return ; + @Override + public void runRoot(FileObject root, ClassIndexImpl ci, Exec exec) throws IOException, InterruptedException { + ClasspathInfo cpInfo = ClasspathInfo.create(root); + try { + type2Idents = new HashMap<>(); + exec.run(); + Map, List>> sources = new HashMap<>(); + for (Entry, List> e : type2Idents.entrySet()) { + FileObject sourceFile = SourceUtils.getFile(e.getKey(), cpInfo); + sources.computeIfAbsent(sourceFile, s -> new HashMap<>()) + .put(e.getKey(), e.getValue()); } - for (Entry, List> e : sources.get(cc.getFileObject()).entrySet()) { - TypeElement te = e.getKey().resolve(cc); + if (!sources.isEmpty()) { + JavaSource.create(cpInfo, sources.keySet()) + .runUserActionTask(cc -> { + if (Phase.ELEMENTS_RESOLVED.compareTo(cc.toPhase(Phase.ELEMENTS_RESOLVED))> 0) { + return ; + } + for (Entry, List> e : sources.get(cc.getFileObject()).entrySet()) { + TypeElement te = e.getKey().resolve(cc); - if (te == null) { - //cannot resolve - continue; - } + if (te == null) { + //cannot resolve + continue; + } - for (String ident : e.getValue()) { - if (ident.equals(getSimpleName(te, null, false))) { - TreePath path = cc.getTrees().getPath(te); + for (String ident : e.getValue()) { + if (ident.equals(getSimpleName(te, null, false))) { + TreePath path = cc.getTrees().getPath(te); - if (path != null) { - final String symbolName = te.getSimpleName().toString(); - final ElementKind kind = te.getKind(); - if (!kind.isClass() && !kind.isInterface()) { - WorkspaceSymbol symbol = new WorkspaceSymbol(symbolName, Utils.elementKind2SymbolKind(kind), Either.forLeft(tree2Location(cc, path)), te.getQualifiedName().toString()); - symbols.add(symbol); - } - } - } - for (Element ne : te.getEnclosedElements()) { - if (ident.equals(getSimpleName(ne, te, false))) { - TreePath path = cc.getTrees().getPath(ne); + if (path != null) { + final String symbolName = te.getSimpleName().toString(); + final ElementKind kind = te.getKind(); + if (!kind.isClass() && !kind.isInterface()) { + WorkspaceSymbol symbol = new WorkspaceSymbol(symbolName, Utils.elementKind2SymbolKind(kind), Either.forLeft(tree2Location(cc, path)), te.getQualifiedName().toString()); + symbols.add(symbol); + } + } + } + for (Element ne : te.getEnclosedElements()) { + if (ident.equals(getSimpleName(ne, te, false))) { + TreePath path = cc.getTrees().getPath(ne); - if (path != null) { - final Pair name = JavaSymbolProvider.getDisplayName(ne, te); - final String symbolName = name.first() + (name.second() != null ? name.second() : ""); - final ElementKind kind = ne.getKind(); - if (!kind.isClass() && !kind.isInterface()) { - WorkspaceSymbol symbol = new WorkspaceSymbol(symbolName, Utils.elementKind2SymbolKind(kind), Either.forLeft(tree2Location(cc, path)), te.getQualifiedName().toString()); - symbols.add(symbol); + if (path != null) { + final Pair name = JavaSymbolProvider.getDisplayName(ne, te); + final String symbolName = name.first() + (name.second() != null ? name.second() : ""); + final ElementKind kind = ne.getKind(); + if (!kind.isClass() && !kind.isInterface()) { + WorkspaceSymbol symbol = new WorkspaceSymbol(symbolName, Utils.elementKind2SymbolKind(kind), Either.forLeft(tree2Location(cc, path)), te.getQualifiedName().toString()); + symbols.add(symbol); + } + } + } + } } } - } - } - } + }, true); } - }, true); - } - //TODO: handle exceptions - } finally { - type2Idents = null; - } - } + //TODO: handle exceptions + } finally { + type2Idents = null; + } + } - @Override - public void handleResult(ElementHandle owner, String ident, boolean caseSensitive) { - type2Idents.computeIfAbsent(owner, s -> new ArrayList<>()).add(ident); - } - }; - JavaSymbolProvider.doComputeSymbols(searchType, queryFin, symbolHandler, true, cancel); - List, FileObject>> pairs = new ArrayList<>(); - JavaTypeProvider.ResultHandler, FileObject>> typeHandler = new JavaTypeProvider.ResultHandler, FileObject>>() { - private FileObject root; + @Override + public void handleResult(ElementHandle owner, String ident, boolean caseSensitive) { + type2Idents.computeIfAbsent(owner, s -> new ArrayList<>()).add(ident); + } + }; + JavaSymbolProvider.doComputeSymbols(searchType, queryFin, symbolHandler, true, cancel); + List, FileObject>> pairs = new ArrayList<>(); + JavaTypeProvider.ResultHandler, FileObject>> typeHandler = new JavaTypeProvider.ResultHandler, FileObject>>() { + private FileObject root; - @Override - public void setMessage(String msg) { - } + @Override + public void setMessage(String msg) { + } - @Override - public void setHighlightText(String text) { - } + @Override + public void setHighlightText(String text) { + } - @Override - public void pendingResult() { - } + @Override + public void pendingResult() { + } - @Override - public void runRoot(FileObject root, JavaTypeProvider.ResultHandler.Exec exec) throws IOException, InterruptedException { - this.root = root; - try { - exec.run(); - } finally { - this.root = null; - } - } + @Override + public void runRoot(FileObject root, JavaTypeProvider.ResultHandler.Exec exec) throws IOException, InterruptedException { + this.root = root; + try { + exec.run(); + } finally { + this.root = null; + } + } - @Override - public Pair, FileObject> create(JavaTypeProvider.CacheItem cacheItem, ElementHandle handle, String simpleName, String relativePath) { - return Pair.of(handle, this.root); - } + @Override + public Pair, FileObject> create(JavaTypeProvider.CacheItem cacheItem, ElementHandle handle, String simpleName, String relativePath) { + return Pair.of(handle, this.root); + } - @Override - public void addResult(List, FileObject>> types) { - pairs.addAll(types); - } - }; - JavaTypeProvider.doComputeTypes(searchType, queryFin, typeHandler, cancel); - for (Pair, FileObject> pair : pairs) { - ElementHandle handle = pair.first(); - String fqn = handle.getQualifiedName(); - int idx = fqn.lastIndexOf('.'); - String simpleName = idx < 0 ? fqn : fqn.substring(idx + 1); - String contextName = idx < 0 ? null : fqn.substring(0, idx); - String uri = URLEncoder.encode(pair.second().toURI().toString() + '?' + handle.getKind().name() + '#' + handle.getBinaryName(), StandardCharsets.UTF_8.toString()); - WorkspaceSymbol symbol = new WorkspaceSymbol(simpleName, Utils.elementKind2SymbolKind(handle.getKind()), Either.forRight(new WorkspaceSymbolLocation(SOURCE_FOR + uri)), contextName); - symbols.add(symbol); + @Override + public void addResult(List, FileObject>> types) { + pairs.addAll(types); + } + }; + JavaTypeProvider.doComputeTypes(searchType, queryFin, typeHandler, cancel); + for (Pair, FileObject> pair : pairs) { + ElementHandle handle = pair.first(); + String fqn = handle.getQualifiedName(); + int idx = fqn.lastIndexOf('.'); + String simpleName = idx < 0 ? fqn : fqn.substring(idx + 1); + String contextName = idx < 0 ? null : fqn.substring(0, idx); + String uri = URLEncoder.encode(pair.second().toURI().toString() + '?' + handle.getKind().name() + '#' + handle.getBinaryName(), StandardCharsets.UTF_8.toString()); + WorkspaceSymbol symbol = new WorkspaceSymbol(simpleName, Utils.elementKind2SymbolKind(handle.getKind()), Either.forRight(new WorkspaceSymbolLocation(SOURCE_FOR + uri)), contextName); + symbols.add(symbol); + } + } + result.complete(Either.forRight(symbols)); + } catch (Throwable t) { + result.completeExceptionally(t); + } + }); } - } - result.complete(Either.forRight(symbols)); - } catch (Throwable t) { - result.completeExceptionally(t); + }); + } catch (ParseException pe) { + result.completeExceptionally(pe); } + }).exceptionally(ex -> { + result.completeExceptionally(ex); + return null; }); return result; } diff --git a/java/java.lsp.server/vscode/package.json b/java/java.lsp.server/vscode/package.json index d7fef35353bd..16c9d24b61bc 100644 --- a/java/java.lsp.server/vscode/package.json +++ b/java/java.lsp.server/vscode/package.json @@ -584,6 +584,10 @@ "title": "Run All Tests", "category": "Test" }, + { + "command": "nbls.addEventListener", + "title": "Add event listener" + }, { "command": "nbls:Tools:org.netbeans.modules.cloud.oracle.actions.DownloadWalletAction", "title": "Add DB Connection" @@ -720,6 +724,10 @@ { "command": "java.workspace.configureRunSettings", "when": "false" + }, + { + "command": "nbls.addEventListener", + "when": "false" } ], "view/title": [ diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts index 8f130527aef9..838f7b783303 100644 --- a/java/java.lsp.server/vscode/src/extension.ts +++ b/java/java.lsp.server/vscode/src/extension.ts @@ -38,7 +38,8 @@ import { ErrorHandlerResult, CloseHandlerResult, SymbolInformation, - TextDocumentFilter + TextDocumentFilter, + TelemetryEventNotification } from 'vscode-languageclient'; import * as net from 'net'; @@ -63,6 +64,7 @@ import { PropertiesView } from './propertiesView/propertiesView'; const API_VERSION : string = "1.0"; const DATABASE: string = 'Database'; +const listeners = new Map(); let client: Promise; let testAdapter: NbTestAdapter | undefined; let nbProcess : ChildProcess | null = null; @@ -638,7 +640,14 @@ export function activate(context: ExtensionContext): VSNetBeansAPI { context.subscriptions.push(commands.registerCommand('nbls.startup.condition', async () => { return client; })); - + context.subscriptions.push(commands.registerCommand('nbls.addEventListener', (eventName, listener) => { + let ls = listeners.get(eventName); + if (!ls) { + ls = []; + listeners.set(eventName, ls); + } + ls.push(listener); + })); context.subscriptions.push(commands.registerCommand('nbls.node.properties.edit', async (node) => await PropertiesView.createOrShow(context, node))); @@ -1077,6 +1086,14 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex }); } }); + c.onNotification(TelemetryEventNotification.type, (param) => { + const ls = listeners.get(param); + if (ls) { + for (const listener of ls) { + commands.executeCommand(listener); + } + } + }); handleLog(log, 'Language Client: Ready'); setClient[0](c); commands.executeCommand('setContext', 'nbJavaLSReady', true); From 543596b9b451fec069733e5e3df0aa71eb6ca4fb Mon Sep 17 00:00:00 2001 From: Dusan Balek Date: Thu, 13 Jul 2023 12:54:20 +0200 Subject: [PATCH 2/3] Modified to work with multiple clients. --- .../java/lsp/server/protocol/Server.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) 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 276e58005ef4..d5ec64f55d2c 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 @@ -47,6 +47,7 @@ import com.google.gson.JsonObject; import java.util.prefs.Preferences; import java.util.LinkedHashSet; +import java.util.WeakHashMap; import java.util.concurrent.CompletionException; import org.eclipse.lsp4j.CallHierarchyRegistrationOptions; import org.eclipse.lsp4j.CodeActionKind; @@ -172,6 +173,7 @@ public static NbLspServer launchServer(Pair io, LspSe ((LanguageClientAware) server).connect(remote); msgProcessor.attachClient(server.client); Future runningServer = serverLauncher.startListening(); + LSPServerTelemetryFactory.getDefault().connect(server.client, runningServer); return new NbLspServer(server, runningServer); } @@ -966,7 +968,6 @@ protected LanguageClient client() { ((LanguageClientAware) getTextDocumentService()).connect(client); ((LanguageClientAware) getWorkspaceService()).connect(client); ((LanguageClientAware) treeService).connect(client); - LSPServerTelemetryFactory.getDefault().connect(client); } @Override @@ -1192,7 +1193,7 @@ private static void hackNoReuseOfOutputsForAntProjects() { } } - public static class LSPServerTelemetryFactory extends CustomIndexerFactory implements LanguageClientAware { + public static class LSPServerTelemetryFactory extends CustomIndexerFactory { private static LSPServerTelemetryFactory INSTANCE; private final CustomIndexer noOp = new CustomIndexer() { @@ -1200,7 +1201,7 @@ public static class LSPServerTelemetryFactory extends CustomIndexerFactory imple protected void index(Iterable files, Context context) { } }; - private LanguageClient client; + private WeakHashMap> clients = new WeakHashMap<>(); @MimeRegistration(mimeType="", service=CustomIndexerFactory.class) public static LSPServerTelemetryFactory getDefault() { @@ -1213,23 +1214,26 @@ public static LSPServerTelemetryFactory getDefault() { private LSPServerTelemetryFactory() { } - @Override - public synchronized void connect(LanguageClient client) { - this.client = client; + public synchronized void connect(LanguageClient client, Future future) { + clients.put(client, future); } @Override public synchronized boolean scanStarted(Context context) { - if (client != null) { - client.telemetryEvent("nbls.scanStarted"); + for (Map.Entry> entry : clients.entrySet()) { + if (!entry.getValue().isDone()) { + entry.getKey().telemetryEvent("nbls.scanStarted"); + } } return true; } @Override public synchronized void scanFinished(Context context) { - if (client != null) { - client.telemetryEvent("nbls.scanFinished"); + for (Map.Entry> entry : clients.entrySet()) { + if (!entry.getValue().isDone()) { + entry.getKey().telemetryEvent("nbls.scanFinished"); + } } } From 0346cfa45291566222dc9c3dde018d41c90c5046 Mon Sep 17 00:00:00 2001 From: Dusan Balek Date: Fri, 14 Jul 2023 09:56:15 +0200 Subject: [PATCH 3/3] Removing clients with closed connection. --- .../java/lsp/server/protocol/Server.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) 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 d5ec64f55d2c..9323fb43d38f 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 @@ -1196,12 +1196,13 @@ private static void hackNoReuseOfOutputsForAntProjects() { public static class LSPServerTelemetryFactory extends CustomIndexerFactory { private static LSPServerTelemetryFactory INSTANCE; + + private final WeakHashMap> clients = new WeakHashMap<>(); private final CustomIndexer noOp = new CustomIndexer() { @Override protected void index(Iterable files, Context context) { } }; - private WeakHashMap> clients = new WeakHashMap<>(); @MimeRegistration(mimeType="", service=CustomIndexerFactory.class) public static LSPServerTelemetryFactory getDefault() { @@ -1220,21 +1221,33 @@ public synchronized void connect(LanguageClient client, Future future) { @Override public synchronized boolean scanStarted(Context context) { + Set toRemove = new HashSet<>(); for (Map.Entry> entry : clients.entrySet()) { - if (!entry.getValue().isDone()) { + if (entry.getValue().isDone()) { + toRemove.add(entry.getKey()); + } else { entry.getKey().telemetryEvent("nbls.scanStarted"); } } + for (LanguageClient lc : toRemove) { + clients.remove(lc); + } return true; } @Override public synchronized void scanFinished(Context context) { + Set toRemove = new HashSet<>(); for (Map.Entry> entry : clients.entrySet()) { - if (!entry.getValue().isDone()) { + if (entry.getValue().isDone()) { + toRemove.add(entry.getKey()); + } else { entry.getKey().telemetryEvent("nbls.scanFinished"); } } + for (LanguageClient lc : toRemove) { + clients.remove(lc); + } } @Override