diff --git a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/SpringProjectUtil.java b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/SpringProjectUtil.java index 5cde37cae..12b7bcfa1 100644 --- a/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/SpringProjectUtil.java +++ b/headless-services/commons/commons-java/src/main/java/org/springframework/ide/vscode/commons/java/SpringProjectUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2020 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 @@ -20,18 +20,22 @@ public class SpringProjectUtil { public static final Logger log = LoggerFactory.getLogger(SpringProjectUtil.class); public static boolean isSpringProject(IJavaProject jp) { - return hasSpecificLibraryOnClasspath(jp, "spring-core"); + return hasSpecificLibraryOnClasspath(jp, "spring-core", true); } public static boolean isBootProject(IJavaProject jp) { - return hasSpecificLibraryOnClasspath(jp, "spring-boot"); + return hasSpecificLibraryOnClasspath(jp, "spring-boot", true); } - private static boolean hasSpecificLibraryOnClasspath(IJavaProject jp, String libraryNamePrefix) { + public static boolean hasBootActuators(IJavaProject jp) { + return hasSpecificLibraryOnClasspath(jp, "spring-boot-actuator-", true); + } + + private static boolean hasSpecificLibraryOnClasspath(IJavaProject jp, String libraryNamePrefix, boolean onlyLibs) { try { IClasspath cp = jp.getClasspath(); if (cp!=null) { - return IClasspathUtil.getBinaryRoots(cp, (cpe) -> !cpe.isSystem()).stream().anyMatch(cpe -> isEntry(cpe, libraryNamePrefix)); + return IClasspathUtil.getBinaryRoots(cp, (cpe) -> !cpe.isSystem()).stream().anyMatch(cpe -> isEntry(cpe, libraryNamePrefix, onlyLibs)); } } catch (Exception e) { log.error("Failed to determine whether '" + jp.getElementName() + "' is Spring Boot project", e); @@ -39,8 +43,8 @@ public class SpringProjectUtil { return false; } - private static boolean isEntry(File cpe, String libNamePrefix) { + private static boolean isEntry(File cpe, String libNamePrefix, boolean onlyLibs) { String name = cpe.getName(); - return name.endsWith(".jar") && name.startsWith(libNamePrefix); + return name.startsWith(libNamePrefix) && (!onlyLibs || name.endsWith(".jar")); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java index 8f3760097..9c98f8fe3 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2019 Pivotal, Inc. + * Copyright (c) 2017, 2020 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 @@ -39,9 +39,8 @@ import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyA import org.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessLiveData; import org.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessLiveDataProvider; import org.springframework.ide.vscode.boot.java.utils.ASTUtils; -import org.springframework.ide.vscode.commons.java.IClasspath; -import org.springframework.ide.vscode.commons.java.IClasspathUtil; import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.java.SpringProjectUtil; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler; import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService; @@ -292,7 +291,7 @@ public class BootJavaHoverProvider implements HoverHandler { } //Only reaching here if we didn't get a hover. - if (!hasActuatorDependency(project)) { + if (!SpringProjectUtil.hasBootActuators(project)) { DocumentRegion region = ASTUtils.nameRegion(doc, annotation); if (region.containsOffset(offset)) { return liveHoverWarning(project); @@ -328,21 +327,6 @@ public class BootJavaHoverProvider implements HoverHandler { return new Hover(ImmutableList.of(Either.forLeft(hoverText))); } - private boolean hasActuatorDependency(IJavaProject project) { - try { - IClasspath classpath = project.getClasspath(); - if (classpath != null) { - return IClasspathUtil.getBinaryRoots(classpath, (cpe) -> !cpe.isSystem()).stream().anyMatch(cpe -> { - String name = cpe.getName(); - return name.startsWith("spring-boot-actuator-"); - }); - } - } catch (Exception e) { - logger.error("error identifying actuator dependency on project '" + project.getElementName() + "'", e); - } - return false; - } - private Optional getProject(IDocument doc) { return this.projectFinder.find(new TextDocumentIdentifier(doc.getUri())); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessConnectorLocal.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessConnectorLocal.java index 5e85894a6..b81775086 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessConnectorLocal.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessConnectorLocal.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Pivotal, Inc. + * Copyright (c) 2019, 2020 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 @@ -12,18 +12,20 @@ package org.springframework.ide.vscode.boot.java.livehover.v2; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.java.SpringProjectUtil; import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver; import com.sun.tools.attach.VirtualMachine; @@ -41,7 +43,7 @@ public class SpringProcessConnectorLocal { private static final String LOCAL_CONNECTOR_ADDRESS = "com.sun.management.jmxremote.localConnectorAddress"; - private final Collection projects; + private final Map projects; private final Set processes; private final SpringProcessConnectorService processConnectorService; @@ -49,7 +51,7 @@ public class SpringProcessConnectorLocal { private boolean projectsChanged; public SpringProcessConnectorLocal(SpringProcessConnectorService processConnector, ProjectObserver projectObserver) { - this.projects = Collections.synchronizedCollection(new HashSet<>()); + this.projects = new ConcurrentHashMap<>(); this.processes = Collections.synchronizedSet(new HashSet<>()); this.projectsChanged = false; @@ -58,7 +60,8 @@ public class SpringProcessConnectorLocal { projectObserver.addListener(new ProjectObserver.Listener() { @Override public void created(IJavaProject project) { - projects.add(project.getElementName()); + boolean hasActuators = SpringProjectUtil.hasBootActuators(project); + projects.put(project.getElementName(), hasActuators); projectsChanged = true; } @Override @@ -157,7 +160,7 @@ public class SpringProcessConnectorLocal { List> futures = new ArrayList<>(); for (SpringProcessDescriptor process : processes) { - futures.add(process.updateStatus(projects::contains)); + futures.add(process.updateStatus(projects::containsKey, projects::get)); } CompletableFuture allStatusUpdates = CompletableFuture.allOf((CompletableFuture[]) futures.toArray(new CompletableFuture[futures.size()])); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessDescriptor.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessDescriptor.java index 4311fc845..60b7047cf 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessDescriptor.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/v2/SpringProcessDescriptor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Pivotal, Inc. + * Copyright (c) 2019, 2020 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 @@ -109,21 +109,21 @@ public class SpringProcessDescriptor { return true; } - public CompletableFuture updateStatus(Predicate projectIsKnown) { + public CompletableFuture updateStatus(Predicate projectIsKnown, Predicate projectHasActuators) { return CompletableFuture.supplyAsync(() -> { - this.status = checkStatus(projectIsKnown); + this.status = checkStatus(projectIsKnown, projectHasActuators); return null; }); } - private SpringProcessStatus checkStatus(Predicate projectIsKnown) { + private SpringProcessStatus checkStatus(Predicate projectIsKnown, Predicate projectHasActuators) { VirtualMachine vm = null; try { vm = VirtualMachine.attach(this.getVm()); if (shouldIgnore(this.getVm(), vm)) { return SpringProcessStatus.IGNORE; } - if (shouldAutoConnect(this.getVm(), vm, projectIsKnown)) { + if (shouldAutoConnect(this.getVm(), vm, projectIsKnown, projectHasActuators)) { return SpringProcessStatus.AUTO_CONNECT; } @@ -168,7 +168,7 @@ public class SpringProcessDescriptor { return false; } - private boolean shouldAutoConnect(VirtualMachineDescriptor vmDescriptor, VirtualMachine vm, Predicate projectIsKnown) { + private boolean shouldAutoConnect(VirtualMachineDescriptor vmDescriptor, VirtualMachine vm, Predicate projectIsKnown, Predicate projectHasActuators) { try { Properties systemProperties = vm.getSystemProperties(); @@ -176,7 +176,8 @@ public class SpringProcessDescriptor { if (projectName instanceof String) { log.info("Spring boot process found: " + projectName); this.projectName = (String) projectName; - return projectIsKnown.test((String) projectName); + + return projectIsKnown.test((String) projectName) && projectHasActuators.test((String)projectName); } } catch (Exception e) {