11diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspServerTelemetryManager.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspServerTelemetryManager.java
2- index d82646afb1..7f4c88acd1 100644
2+ index d82646afb1..5018896480 100644
33--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspServerTelemetryManager.java
44+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspServerTelemetryManager.java
55@@ -21,6 +21,7 @@ package org.netbeans.modules.java.lsp.server.protocol;
@@ -10,16 +10,16 @@ index d82646afb1..7f4c88acd1 100644
1010 import java.math.BigInteger;
1111 import java.nio.charset.StandardCharsets;
1212 import java.security.MessageDigest;
13- @@ -28,25 +29,30 @@ import java.security.NoSuchAlgorithmException;
13+ @@ -28,25 +29,36 @@ import java.security.NoSuchAlgorithmException;
1414 import java.util.ArrayList;
1515 import java.util.Collection;
1616 import java.util.Collections;
1717- import java.util.HashSet;
1818+ import java.util.Iterator;
1919 import java.util.List;
2020 import java.util.Map;
21- - import java.util.Set;
2221+ import java.util.NavigableMap;
22+ import java.util.Set;
2323+ import java.util.TreeMap;
2424 import java.util.WeakHashMap;
2525+ import java.util.concurrent.CompletableFuture;
@@ -33,19 +33,24 @@ index d82646afb1..7f4c88acd1 100644
3333 import org.eclipse.lsp4j.ConfigurationParams;
3434 import org.eclipse.lsp4j.MessageType;
3535 import org.eclipse.lsp4j.services.LanguageClient;
36+ + import org.netbeans.api.annotations.common.NonNull;
3637+ import org.netbeans.api.java.platform.JavaPlatform;
38+ + import org.netbeans.api.java.project.JavaProjectConstants;
3739 import org.netbeans.api.java.queries.CompilerOptionsQuery;
3840 import org.netbeans.api.java.queries.CompilerOptionsQuery.Result;
3941 import org.netbeans.api.project.Project;
4042 import org.netbeans.api.project.ProjectManager;
43+ + import org.netbeans.api.project.ProjectUtils;
44+ + import org.netbeans.api.project.SourceGroup;
4145 import org.netbeans.api.project.ui.ProjectProblems;
4246+ import org.netbeans.modules.java.platform.implspi.JavaPlatformProvider;
4347 import org.openide.filesystems.FileObject;
4448- import org.openide.util.Exceptions;
49+ + import org.openide.filesystems.FileUtil;
4550 import org.openide.util.Lookup;
4651
4752 /**
48- @@ -55,130 +61,205 @@ import org.openide.util.Lookup;
53+ @@ -55,130 +67,261 @@ import org.openide.util.Lookup;
4954 */
5055 public class LspServerTelemetryManager {
5156
@@ -86,15 +91,15 @@ index d82646afb1..7f4c88acd1 100644
8691+
8792+ private static final LspServerTelemetryManager instance = new LspServerTelemetryManager();
8893+ }
89-
94+ +
9095+ private final WeakHashMap<LanguageClient, WeakReference<Future<Void>>> clients = new WeakHashMap<>();
9196+ private volatile boolean telemetryEnabled = false;
9297+ private long lspServerIntializationTime;
9398+
9499+ public boolean isTelemetryEnabled() {
95100+ return telemetryEnabled;
96101+ }
97- +
102+
98103+ public void connect(LanguageClient client, Future<Void> future) {
99104 synchronized (clients) {
100105- for (Map.Entry<LanguageClient, Future<Void>> entry : clients.entrySet()) {
@@ -168,50 +173,28 @@ index d82646afb1..7f4c88acd1 100644
168173 }
169174
170175- public void sendWorkspaceInfo(LanguageClient client, List<FileObject> workspaceClientFolders, Collection<Project> prjs, long timeToOpenPrjs) {
176+ - JsonObject properties = new JsonObject();
177+ - JsonArray prjProps = new JsonArray();
171178+ private boolean isInvalidClient(WeakReference<Future<Void>> closeListener) {
172179+ Future<Void> close = closeListener == null ? null : closeListener.get();
173180+ return close == null || close.isDone();
174181+ }
175- +
176- + public CompletableFuture<Void> sendWorkspaceInfo(LanguageClient client, List<FileObject> workspaceClientFolders, Collection<Project> projects, long timeToOpenProjects) {
177- JsonObject properties = new JsonObject();
178- - JsonArray prjProps = new JsonArray();
179- + List<CompletableFuture<JsonObject>> createProjectFutures = new ArrayList<>();
180182
181183- Map<String, Project> mp = prjs.stream()
182184- .collect(Collectors.toMap(project -> project.getProjectDirectory().getPath(), project -> project));
185+ + public CompletableFuture<Void> sendWorkspaceInfo(LanguageClient client, List<FileObject> workspaceClientFolders, Collection<Project> projects, long timeToOpenProjects) {
186+ + JsonObject properties = new JsonObject();
187+
183188+ NavigableMap<String, Project> mp = projects.stream()
184189+ .collect(Collectors.toMap(project -> project.getProjectDirectory().getPath(), project -> project, (p1, p2) -> p1, TreeMap<String, Project>::new));
185-
190+ + List<CompletableFuture<JsonObject>> createProjectFutures = new ArrayList<>();
186191 for (FileObject workspaceFolder : workspaceClientFolders) {
187192 try {
188193- JsonObject obj = new JsonObject();
189194+ boolean noProjectFound = true;
190195 String prjPath = workspaceFolder.getPath();
191196- String prjId = this.getPrjId(prjPath);
192197- obj.addProperty("id", prjId);
193- -
194- - // In future if different JDK is used for different project then this can be updated
195- - obj.addProperty("javaVersion", System.getProperty("java.version"));
196- -
197- - if (mp.containsKey(prjPath)) {
198- - Project prj = mp.get(prjPath);
199- -
200- - ProjectManager.Result r = ProjectManager.getDefault().isProject2(prj.getProjectDirectory());
201- - String projectType = r.getProjectType();
202- - obj.addProperty("buildTool", (projectType.contains("maven") ? "MavenProject" : "GradleProject"));
203- -
204- - obj.addProperty("openedWithProblems", ProjectProblems.isBroken(prj));
205- -
206- - boolean isPreviewFlagEnabled = this.isEnablePreivew(prj.getProjectDirectory(), projectType);
207- - obj.addProperty("enablePreview", isPreviewFlagEnabled);
208- - } else {
209- - obj.addProperty("buildTool", this.STANDALONE_PRJ);
210- - obj.addProperty("javaVersion", System.getProperty("java.version"));
211- - obj.addProperty("openedWithProblems", false);
212- -
213- - boolean isPreviewFlagEnabled = this.isEnablePreivew(workspaceFolder, this.STANDALONE_PRJ);
214- - obj.addProperty("enablePreview", isPreviewFlagEnabled);
215198+ String prjPathWithSlash = null;
216199+ for (Map.Entry<String, Project> p : mp.tailMap(prjPath, true).entrySet()) {
217200+ String projectPath = p.getKey();
@@ -221,20 +204,15 @@ index d82646afb1..7f4c88acd1 100644
221204+ noProjectFound = false;
222205+ break;
223206+ }
224- + prjPathWithSlash = prjPath + '/';
207+ + prjPathWithSlash = prjPath + '/';
225208+ }
226209+ if (projectPath.startsWith(prjPathWithSlash)) {
227210+ createProjectFutures.add(createProjectInfo(p.getKey(), p.getValue(), workspaceFolder, client));
228211+ noProjectFound = false;
229212+ continue;
230213+ }
231214+ break;
232- }
233- -
234- - prjProps.add(obj);
235- -
236- - } catch (NoSuchAlgorithmException ex) {
237- - Exceptions.printStackTrace(ex);
215+ + }
238216+ if (noProjectFound) {
239217+ // No project found
240218+ createProjectFutures.add(createProjectInfo(prjPath, null, workspaceFolder, client));
@@ -243,10 +221,11 @@ index d82646afb1..7f4c88acd1 100644
243221+ LOG.log(Level.INFO, "NoSuchAlgorithmException while creating workspaceInfo event: {0}", e.getMessage());
244222+ } catch (Exception e) {
245223+ LOG.log(Level.INFO, "Exception while creating workspaceInfo event: {0}", e.getMessage());
246- }
247- }
248-
249- - properties.add("prjsInfo", prjProps);
224+ + }
225+ + }
226+
227+ - // In future if different JDK is used for different project then this can be updated
228+ - obj.addProperty("javaVersion", System.getProperty("java.version"));
250229+ return CompletableFuture.allOf(createProjectFutures.toArray(new CompletableFuture[0]))
251230+ .thenApply((ignored) -> {
252231+ JsonArray prjProps = new JsonArray();
@@ -255,16 +234,37 @@ index d82646afb1..7f4c88acd1 100644
255234+ })
256235+ .thenAccept((prjProps) -> {
257236+ properties.add("projectInfo", prjProps);
237+
238+ - if (mp.containsKey(prjPath)) {
239+ - Project prj = mp.get(prjPath);
258240+ properties.addProperty("projInitTimeTaken", timeToOpenProjects);
259241+ properties.addProperty("numProjects", workspaceClientFolders.size());
260242+ properties.addProperty("lspInitTimeTaken", System.currentTimeMillis() - this.lspServerIntializationTime);
243+
244+ - ProjectManager.Result r = ProjectManager.getDefault().isProject2(prj.getProjectDirectory());
245+ - String projectType = r.getProjectType();
246+ - obj.addProperty("buildTool", (projectType.contains("maven") ? "MavenProject" : "GradleProject"));
247+ -
248+ - obj.addProperty("openedWithProblems", ProjectProblems.isBroken(prj));
249+ -
250+ - boolean isPreviewFlagEnabled = this.isEnablePreivew(prj.getProjectDirectory(), projectType);
251+ - obj.addProperty("enablePreview", isPreviewFlagEnabled);
252+ - } else {
253+ - obj.addProperty("buildTool", this.STANDALONE_PRJ);
254+ - obj.addProperty("javaVersion", System.getProperty("java.version"));
255+ - obj.addProperty("openedWithProblems", false);
256+ -
257+ - boolean isPreviewFlagEnabled = this.isEnablePreivew(workspaceFolder, this.STANDALONE_PRJ);
258+ - obj.addProperty("enablePreview", isPreviewFlagEnabled);
259+ - }
260+ -
261+ - prjProps.add(obj);
261262+ this.sendTelemetry(client, new TelemetryEvent(MessageType.Info.toString(), LspServerTelemetryManager.WORKSPACE_INFO_EVT, properties));
262263+ });
263264+ }
264265
265- - properties.addProperty("timeToOpenPrjs", timeToOpenPrjs);
266- - properties.addProperty("numOfPrjsOpened", workspaceClientFolders.size());
267- - properties.addProperty("lspServerInitializationTime", System.currentTimeMillis() - this.lspServerIntiailizationTime);
266+ - } catch (NoSuchAlgorithmException ex) {
267+ - Exceptions.printStackTrace(ex);
268268+ private CompletableFuture<JsonObject> createProjectInfo(String prjPath, Project prj, FileObject workspaceFolder, LanguageClient client) throws NoSuchAlgorithmException {
269269+ JsonObject obj = new JsonObject();
270270+ String prjId = getPrjId(prjPath);
@@ -283,28 +283,35 @@ index d82646afb1..7f4c88acd1 100644
283283+ } catch (RuntimeException e) {
284284+ LOG.log(Level.INFO, "Exception while checking project problems for workspaceInfo event: {0}", e.getMessage());
285285+ projectHasProblems = true;
286- + }
286+ }
287287+ obj.addProperty("isOpenedWithProblems", projectHasProblems);
288- + }
288+ }
289289+ String javaVersion = getProjectJavaVersion();
290290+ obj.addProperty("javaVersion", javaVersion);
291- + obj.addProperty("buildTool", projectType.name());
292- + return isPreviewEnabled(projectDirectory, projectType , client).thenApply(isPreviewFlagEnabled -> {
291+ + if (projectType != null) obj.addProperty("buildTool", projectType.name());
292+ + return isPreviewEnabled(projectDirectory, prj , client).thenApply(isPreviewFlagEnabled -> {
293293+ obj.addProperty("isPreviewEnabled", isPreviewFlagEnabled);
294294+ return obj;
295295+ });
296296+ }
297297
298+ - properties.add("prjsInfo", prjProps);
299+ -
300+ - properties.addProperty("timeToOpenPrjs", timeToOpenPrjs);
301+ - properties.addProperty("numOfPrjsOpened", workspaceClientFolders.size());
302+ - properties.addProperty("lspServerInitializationTime", System.currentTimeMillis() - this.lspServerIntiailizationTime);
303+ -
298304- this.sendTelemetry(client, new TelemetryEvent(MessageType.Info.toString(), this.WORKSPACE_INFO_EVT, properties));
299- + public CompletableFuture<Boolean> isPreviewEnabled(FileObject source, ProjectType prjType ) {
300- + return isPreviewEnabled(source, prjType , null);
305+ + public CompletableFuture<Boolean> isPreviewEnabled(FileObject source, Project prj ) {
306+ + return isPreviewEnabled(source, prj , null);
301307 }
302308-
303309- private boolean isEnablePreivew(FileObject source, String prjType) {
304310- if (prjType.equals(this.STANDALONE_PRJ)) {
305311- NbCodeLanguageClient client = Lookup.getDefault().lookup(NbCodeLanguageClient.class);
306312+
307- + public CompletableFuture<Boolean> isPreviewEnabled(FileObject source, ProjectType prjType, LanguageClient languageClient) {
313+ + public CompletableFuture<Boolean> isPreviewEnabled(FileObject source, Project prj, LanguageClient languageClient) {
314+ + ProjectType prjType = prj == null ? ProjectType.standalone : getProjectType(prj);
308315+ if (prjType == ProjectType.standalone) {
309316+ NbCodeLanguageClient client = languageClient instanceof NbCodeLanguageClient ? (NbCodeLanguageClient) languageClient : null;
310317 if (client == null) {
@@ -320,25 +327,76 @@ index d82646afb1..7f4c88acd1 100644
320327- client.configuration(new ConfigurationParams(Collections.singletonList(conf))).thenAccept(c -> {
321328- String config = ((JsonPrimitive) ((List<Object>) c).get(0)).getAsString();
322329- isEnablePreviewSet.set(config.contains(this.ENABLE_PREVIEW));
323- - });
324- -
325- - return isEnablePreviewSet.get();
326330+ conf.setSection(client.getNbCodeCapabilities().getConfigurationPrefix() + "runConfig.vmOptions");
327331+ return client.configuration(new ConfigurationParams(Collections.singletonList(conf)))
328332+ .thenApply(c -> {
329333+ return c != null && !c.isEmpty()
330334+ && ((JsonPrimitive) c.get(0)).getAsString().contains(ENABLE_PREVIEW);
331- + });
335+ });
336+
337+ - return isEnablePreviewSet.get();
332338 }
333- -
339+
340+ + boolean previewEnabled;
341+ + previewEnabled = source != null && isPreviewEnabledForSource(source);
342+ + if (!previewEnabled && prjType == ProjectType.gradle) {
343+ + assert prj != null;
344+ + FileObject prjRoot = prj.getProjectDirectory();
345+ + String relativePath = prjRoot == null ? null : FileUtil.getRelativePath(prjRoot, source);
346+ + if (relativePath == null || relativePath.isEmpty()) {
347+ + // The source is not inside the project root, and,
348+ + // so the project contents need to be checked for preview-enabled
349+ + previewEnabled = previewEnabled || isPreviewEnabledForAnyProjectSourceRoot(prj);
350+ + previewEnabled = previewEnabled || isPreviewEnabledForAnyContainedProjects(prj);
351+ + }
352+ + }
353+ +
354+ + return CompletableFuture.completedFuture(previewEnabled);
355+ + }
356+ +
357+ + private boolean isPreviewEnabledForAnyContainedProjects(@NonNull Project project) {
358+ + Set<Project> subProjects = ProjectUtils.getContainedProjects(project, false);
359+ + if (subProjects != null) {
360+ + for (Project subProject : subProjects) {
361+ + if (isPreviewEnabledForAnyProjectSourceRoot(subProject)) {
362+ + return true;
363+ + }
364+ + }
365+ + for (Project subProject : subProjects) {
366+ + if (isPreviewEnabledForAnyContainedProjects(subProject)) {
367+ + return true;
368+ + }
369+ + }
370+ + }
371+ + return false;
372+ + }
373+ +
374+ + private boolean isPreviewEnabledForAnyProjectSourceRoot(@NonNull Project project) {
375+ + SourceGroup[] sources = ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
376+ + if (sources == null || sources.length == 0) {
377+ + FileObject root = project.getProjectDirectory();
378+ + if (root != null && isPreviewEnabledForSource(root)) {
379+ + return true;
380+ + }
381+ + } else {
382+ + for (SourceGroup s : sources) {
383+ + FileObject root = s.getRootFolder();
384+ + if (root != null && isPreviewEnabledForSource(root)) {
385+ + return true;
386+ + }
387+ + }
388+ + }
389+ + return false;
390+ + }
334391+
392+ + private boolean isPreviewEnabledForSource(@NonNull FileObject source) {
335393 Result result = CompilerOptionsQuery.getOptions(source);
336394- return result.getArguments().contains(this.ENABLE_PREVIEW);
337- + return CompletableFuture.completedFuture( result.getArguments().contains(ENABLE_PREVIEW) );
395+ + return result.getArguments().contains(ENABLE_PREVIEW);
338396 }
339397
340398 private String getPrjId(String prjPath) throws NoSuchAlgorithmException {
341- @@ -187,15 +268,50 @@ public class LspServerTelemetryManager {
399+ @@ -187,15 +330,54 @@ public class LspServerTelemetryManager {
342400
343401 BigInteger number = new BigInteger(1, hash);
344402
@@ -387,9 +445,13 @@ index d82646afb1..7f4c88acd1 100644
387445+ }
388446+
389447+ public ProjectType getProjectType(Project prj) {
390- + ProjectManager.Result r = ProjectManager.getDefault().isProject2(prj.getProjectDirectory());
448+ + FileObject prjDir = prj.getProjectDirectory();
449+ + ProjectManager.Result r = prjDir == null ? null : ProjectManager.getDefault().isProject2(prjDir);
391450+ String projectType = r == null ? null : r.getProjectType();
392- + return projectType != null && projectType.contains(ProjectType.maven.name()) ? ProjectType.maven : ProjectType.gradle;
451+ + return projectType == null ? null
452+ + : projectType.contains(ProjectType.maven.name()) ? ProjectType.maven
453+ + : projectType.contains(ProjectType.gradle.name()) ? ProjectType.gradle
454+ + : null;
393455+ }
394456 }
395457diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientCapabilities.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientCapabilities.java
0 commit comments