From 34728a702fed1cf80fea38516d2b09391d8230a8 Mon Sep 17 00:00:00 2001 From: BoykoAlex Date: Mon, 9 Jul 2018 19:28:31 -0400 Subject: [PATCH 1/3] Avoid calling editor.markBufferRange(...) with custom options --- .../atom-spring-boot/lib/boot-sts-adapter.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/atom-extensions/atom-spring-boot/lib/boot-sts-adapter.ts b/atom-extensions/atom-spring-boot/lib/boot-sts-adapter.ts index d028a686f..37f036a5e 100644 --- a/atom-extensions/atom-spring-boot/lib/boot-sts-adapter.ts +++ b/atom-extensions/atom-spring-boot/lib/boot-sts-adapter.ts @@ -1,11 +1,16 @@ import {StsAdapter, HighlightParams} from '@pivotal-tools/atom-languageclient-commons'; import {Convert} from 'atom-languageclient'; import { Range } from 'vscode-languageserver-protocol'; -import {TextEditor} from 'atom'; +import {TextEditor, DecorationOptions } from 'atom'; -const BOOT_DATA_MARKER_TYPE: any = 'BootApp-Hint'; const BOOT_HINT_GUTTER_NAME = 'boot-hint-gutter'; +const DECORATION_OPTIONS: DecorationOptions = { + type: 'highlight', + class: 'boot-hint', + gutterName: BOOT_HINT_GUTTER_NAME +}; + export class BootStsAdapter extends StsAdapter { constructor() { @@ -17,7 +22,7 @@ export class BootStsAdapter extends StsAdapter { } private markHintsForEditor(editor: TextEditor, ranges: Range[]) { - editor.findMarkers(BOOT_DATA_MARKER_TYPE).forEach(m => m.destroy()); + editor.getDecorations(DECORATION_OPTIONS).map(decoration => decoration.getMarker()).forEach(m => m.destroy()); if (Array.isArray(ranges)) { ranges.forEach(range => this.createHintMarker(editor, range)); } @@ -33,13 +38,10 @@ export class BootStsAdapter extends StsAdapter { private createHintMarker(editor: TextEditor, range: Range) { // Create marker model - const marker = editor.markBufferRange(Convert.lsRangeToAtomRange(range), BOOT_DATA_MARKER_TYPE); + const marker = editor.markBufferRange(Convert.lsRangeToAtomRange(range)); // Marker around the text in the editor - editor.decorateMarker(marker, { - type: 'highlight', - class: 'boot-hint' - }); + editor.decorateMarker(marker, DECORATION_OPTIONS); // Marker in the diagnostic gutter let gutter = editor.gutterWithName(BOOT_HINT_GUTTER_NAME); @@ -53,4 +55,5 @@ export class BootStsAdapter extends StsAdapter { iconElement.setAttribute('class', 'gutter-boot-hint'); gutter.decorateMarker(marker, {item: iconElement}); } + } \ No newline at end of file From 20ff5f406a50ac1c73f45ca8f41c77f9c75b5252 Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Tue, 10 Jul 2018 12:06:30 +0200 Subject: [PATCH 2/3] adopting new LSP4E API to avoid restaring old language servers --- .../eclipse/gotosymbol/dialogs/InWorkspaceSymbolsProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 331b65e72..3dd28f924 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 @@ -100,7 +100,7 @@ public class InWorkspaceSymbolsProvider implements SymbolsProvider { public static InWorkspaceSymbolsProvider createFor(IProject project) { List languageServers = LanguageServiceAccessor.getLanguageServers(project, - capabilities -> Boolean.TRUE.equals(capabilities.getWorkspaceSymbolProvider())); + capabilities -> Boolean.TRUE.equals(capabilities.getWorkspaceSymbolProvider()), true); if (!languageServers.isEmpty()) { return new InWorkspaceSymbolsProvider(languageServers); } From d7fc10794cd929d2c791c05ba5c61b7606e39462 Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Wed, 11 Jul 2018 16:40:18 +0200 Subject: [PATCH 3/3] first cut for strict project matching mode to ensure live hovers are detected and shown only for relevant projects --- atom-extensions/atom-spring-boot/package.json | 5 + .../ls/BootLanguageServerPreferencesPage.java | 3 + .../tooling/boot/ls/Constants.java | 1 + .../DelegatingStreamConnectionProvider.java | 5 + .../tooling/boot/ls/PrefsInitializer.java | 1 + .../commons/boot/app/cli/SpringBootApp.java | 6 ++ .../vscode/boot/BootLanguageServerParams.java | 23 ++-- .../ide/vscode/boot/java/BootJavaConfig.java | 5 + .../BootJavaLanguageServerComponents.java | 5 + .../java/handlers/BootJavaHoverProvider.java | 2 +- .../handlers/DefaultRunningAppProvider.java | 100 ++++++++++++++++++ .../java/handlers/RunningAppProvider.java | 15 ++- .../LiveAppURLSymbolProvider.java | 4 +- .../SpringLiveChangeDetectionWatchdog.java | 21 ++-- .../java/utils/SpringLiveHoverWatchdog.java | 20 +++- .../harness/MockRunningAppProvider.java | 5 +- .../vscode-spring-boot/package.json | 5 + 17 files changed, 188 insertions(+), 38 deletions(-) create mode 100644 headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/DefaultRunningAppProvider.java diff --git a/atom-extensions/atom-spring-boot/package.json b/atom-extensions/atom-spring-boot/package.json index 8105e05f8..ae159e74b 100644 --- a/atom-extensions/atom-spring-boot/package.json +++ b/atom-extensions/atom-spring-boot/package.json @@ -29,6 +29,11 @@ "type": "boolean", "default": false, "description": "Enable/Disable detecting changes of running Spring Boot applications" + }, + "strict-project-matching.on": { + "type": "boolean", + "default": false, + "description": "Use restrictive mechanism to match live running boot apps automatically with projects in your workspace" } }, "dependencies": { diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPreferencesPage.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPreferencesPage.java index 9a9284fcf..0f9c934e6 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPreferencesPage.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPreferencesPage.java @@ -39,6 +39,9 @@ public class BootLanguageServerPreferencesPage extends FieldEditorPreferencePage BooleanFieldEditor liveChangeDetectionPrefEditor = new BooleanFieldEditor(Constants.PREF_CHANGE_DETECTION, "Live Boot Change Detection", getFieldEditorParent()); addField(liveChangeDetectionPrefEditor); + + BooleanFieldEditor strictProjectMatchingPrefEditor = new BooleanFieldEditor(Constants.PREF_STRICT_PROJECT_MATCH, "Use restrictive mechanism to match live running boot apps automatically with projects in your workspace", getFieldEditorParent()); + addField(strictProjectMatchingPrefEditor); } } diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/Constants.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/Constants.java index f187a70ac..1b55284de 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/Constants.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/Constants.java @@ -20,5 +20,6 @@ public class Constants { public static final String PREF_BOOT_HINTS = "boot-java.boot-hints.on"; public static final String PREF_CHANGE_DETECTION = "boot-java.change-detection.on"; + public static final String PREF_STRICT_PROJECT_MATCH = "boot-java.strict-project-matching.on"; } diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/DelegatingStreamConnectionProvider.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/DelegatingStreamConnectionProvider.java index b347e8c78..0cda14d40 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/DelegatingStreamConnectionProvider.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/DelegatingStreamConnectionProvider.java @@ -125,13 +125,18 @@ public class DelegatingStreamConnectionProvider implements StreamConnectionProvi Map bootJavaObj = new HashMap<>(); Map bootHint = new HashMap<>(); Map bootChangeDetection = new HashMap<>(); + Map bootStrictProjectMatching = new HashMap<>(); bootHint.put("on", BootLanguageServerPlugin.getDefault().getPreferenceStore().getBoolean(Constants.PREF_BOOT_HINTS)); bootChangeDetection.put("on", BootLanguageServerPlugin.getDefault().getPreferenceStore().getBoolean(Constants.PREF_CHANGE_DETECTION)); + bootStrictProjectMatching.put("on", BootLanguageServerPlugin.getDefault().getPreferenceStore().getBoolean(Constants.PREF_STRICT_PROJECT_MATCH)); bootJavaObj.put("boot-hints", bootHint); bootJavaObj.put("change-detection", bootChangeDetection); + bootJavaObj.put("strict-project-matching", bootStrictProjectMatching); + settings.put("boot-java", bootJavaObj); + this.languageServer.getWorkspaceService().didChangeConfiguration(new DidChangeConfigurationParams(settings)); } diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/PrefsInitializer.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/PrefsInitializer.java index cb8fdaa5e..2d054b1d0 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/PrefsInitializer.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/PrefsInitializer.java @@ -27,6 +27,7 @@ public class PrefsInitializer extends AbstractPreferenceInitializer { public void initializeDefaultPreferences() { BootLanguageServerPlugin.getDefault().getPreferenceStore().setDefault(Constants.PREF_BOOT_HINTS, true); BootLanguageServerPlugin.getDefault().getPreferenceStore().setDefault(Constants.PREF_CHANGE_DETECTION, false); + BootLanguageServerPlugin.getDefault().getPreferenceStore().setDefault(Constants.PREF_STRICT_PROJECT_MATCH, false); } } diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java index e6c494c13..cede514b9 100644 --- a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java +++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java @@ -53,6 +53,7 @@ import com.sun.tools.attach.VirtualMachineDescriptor; /** * @author Martin Lippert */ +@SuppressWarnings("restriction") public class SpringBootApp { private static final String SPRINGFRAMEWORK_BOOT_DOMAIN = "org.springframework.boot"; @@ -163,6 +164,11 @@ public class SpringBootApp { return (String) props.get("sun.java.command"); } + public String getSystemProperty(String propName) throws IOException { + Properties props = this.vm.getSystemProperties(); + return (String) props.get(propName); + } + public boolean containsSystemProperty(Object key) throws IOException { Properties props = this.vm.getSystemProperties(); return props.containsKey(key); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/BootLanguageServerParams.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/BootLanguageServerParams.java index 327876984..3393e900d 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/BootLanguageServerParams.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/BootLanguageServerParams.java @@ -16,6 +16,7 @@ import java.util.Arrays; import java.util.Optional; import org.eclipse.lsp4j.TextDocumentIdentifier; +import org.springframework.ide.vscode.boot.java.handlers.DefaultRunningAppProvider; import org.springframework.ide.vscode.boot.java.handlers.RunningAppProvider; import org.springframework.ide.vscode.boot.java.utils.SpringLiveHoverWatchdog; import org.springframework.ide.vscode.boot.jdt.ls.JavaProjectsService; @@ -48,7 +49,7 @@ import org.springframework.ide.vscode.commons.util.text.IDocument; /** * Parameters for creating Boot Properties language server - * + * * @author Alex Boyko * @author Kris De Volder */ @@ -58,10 +59,10 @@ public class BootLanguageServerParams { public final JavaProjectFinder projectFinder; public final ProjectObserver projectObserver; public final SpringPropertyIndexProvider indexProvider; - + //Boot Properies public final TypeUtilProvider typeUtilProvider; - + //Boot Java public final RunningAppProvider runningAppProvider; public final Duration watchDogInterval; @@ -100,7 +101,7 @@ public class BootLanguageServerParams { jdtProjectCache, indexProvider, (IDocument doc) -> new TypeUtil(jdtProjectCache.find(new TextDocumentIdentifier(doc.getUri()))), - RunningAppProvider.DEFAULT, + new DefaultRunningAppProvider(), SpringLiveHoverWatchdog.DEFAULT_INTERVAL ); }; @@ -108,9 +109,9 @@ public class BootLanguageServerParams { private static JavaProjectsService createFallbackProjectCache(SimpleLanguageServer server) { CompositeJavaProjectFinder javaProjectFinder = new CompositeJavaProjectFinder(); - - JavadocService javadocService = (uri, cpe) -> JavaDocProviders.createFor(cpe); - + + JavadocService javadocService = (uri, cpe) -> JavaDocProviders.createFor(cpe); + MavenProjectCache mavenProjectCache = new MavenProjectCache(server, MavenCore.getDefault(), true, Paths.get(IJavaProject.PROJECT_CACHE_FOLDER), javadocService); javaProjectFinder.addJavaProjectFinder(new MavenProjectFinder(mavenProjectCache)); @@ -118,19 +119,19 @@ public class BootLanguageServerParams { javaProjectFinder.addJavaProjectFinder(new GradleProjectFinder(gradleProjectCache)); CompositeProjectOvserver projectObserver = new CompositeProjectOvserver(Arrays.asList(mavenProjectCache, gradleProjectCache)); - + return new JavaProjectsService() { - + @Override public void removeListener(Listener listener) { projectObserver.removeListener(listener); } - + @Override public void addListener(Listener listener) { projectObserver.addListener(listener); } - + @Override public Optional find(TextDocumentIdentifier doc) { return javaProjectFinder.find(doc); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaConfig.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaConfig.java index 7d2dc7b73..81a0353e5 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaConfig.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaConfig.java @@ -33,6 +33,11 @@ public class BootJavaConfig { return enabled != null && enabled.booleanValue(); } + public boolean isStrictProjectMatchingEnabled() { + Boolean enabled = settings.getBoolean("boot-java", "strict-project-matching", "on"); + return enabled != null && enabled.booleanValue(); + } + public void handleConfigurationChange(Settings newConfig) { Log.info("Settings received: "+newConfig); this.settings = newConfig; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java index fb1ba06a9..ad2ce30f8 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java @@ -36,6 +36,7 @@ import org.springframework.ide.vscode.boot.java.handlers.BootJavaReferencesHandl import org.springframework.ide.vscode.boot.java.handlers.BootJavaWorkspaceSymbolHandler; import org.springframework.ide.vscode.boot.java.handlers.CodeLensProvider; import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider; +import org.springframework.ide.vscode.boot.java.handlers.DefaultRunningAppProvider; import org.springframework.ide.vscode.boot.java.handlers.HighlightProvider; import org.springframework.ide.vscode.boot.java.handlers.HoverProvider; import org.springframework.ide.vscode.boot.java.handlers.ReferenceProvider; @@ -196,6 +197,10 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent else { liveChangeDetectionWatchdog.disableHighlights(); } + + if (serverParams.runningAppProvider instanceof DefaultRunningAppProvider) { + ((DefaultRunningAppProvider) serverParams.runningAppProvider).setStrictProjectMatching(config.isStrictProjectMatchingEnabled()); + } }); server.onInitialize(this::initialize); 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 300c8a587..cd270b4e6 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 @@ -287,7 +287,7 @@ public class BootJavaHoverProvider implements HoverHandler { private SpringBootApp[] getRunningSpringApps(IJavaProject project) { try { - return runningAppProvider.getAllRunningSpringApps().toArray(new SpringBootApp[0]); + return runningAppProvider.getAllRunningSpringApps(project).toArray(new SpringBootApp[0]); } catch (Exception e) { Log.log(e); return new SpringBootApp[0]; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/DefaultRunningAppProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/DefaultRunningAppProvider.java new file mode 100644 index 000000000..0c0e2215e --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/DefaultRunningAppProvider.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2018 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.java.handlers; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp; +import org.springframework.ide.vscode.commons.java.IClasspath; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath; +import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE; +import org.springframework.ide.vscode.commons.util.CollectorUtil; + +/** + * @author Martin Lippert + */ +public class DefaultRunningAppProvider implements RunningAppProvider { + + private boolean strictProjectMatchingEnabled = false; + + public void setStrictProjectMatching(boolean strictProjectMatchingEnabled) { + System.out.println("USE STRICT MODE: " + strictProjectMatchingEnabled); + this.strictProjectMatchingEnabled = strictProjectMatchingEnabled; + } + + @Override + public Collection getAllRunningSpringApps(IJavaProject project) throws Exception { + Collection apps = SpringBootApp.getAllRunningSpringApps(); + + if (project != null && strictProjectMatchingEnabled) { + return apps.stream().filter((app) -> { + return doesProjectMatch(app, project); + }).collect(CollectorUtil.toImmutableList()); + } + else { + return apps; + } + } + + private boolean doesProjectMatch(SpringBootApp app, IJavaProject project) { + if (doesProjectNameMatch(app, project)) return true; + if (doesProjectThinJarWrapperMatch(app, project)) return true; + if (doesClasspathMatch(app, project)) return true; + + return false; + } + + public static boolean doesClasspathMatch(SpringBootApp app, IJavaProject project) { + try { + Set runningAppClasspath = new HashSet<>(); + Collections.addAll(runningAppClasspath, app.getClasspath()); + + return doesClasspathMatch(runningAppClasspath, project); + } + catch (Exception e) { + return false; + } + } + + public static boolean doesClasspathMatch(Set runningAppClasspath, IJavaProject project) throws Exception { + IClasspath classpath = project.getClasspath(); + Collection entries = classpath.getClasspathEntries(); + for (CPE cpe : entries) { + if (Classpath.ENTRY_KIND_SOURCE.equals(cpe.getKind())) { + String path = cpe.getOutputFolder(); + if (runningAppClasspath.contains(path)) { + return true; + } + } + } + + return false; + } + + public static boolean doesProjectThinJarWrapperMatch(SpringBootApp app, IJavaProject project) { + return false; + } + + public static boolean doesProjectNameMatch(SpringBootApp app, IJavaProject project) { + try { + String projectName = app.getSystemProperty("spring.boot.project.name"); + return projectName != null && projectName.equals(project.getElementName()); + } + catch (Exception e) { + return false; + } + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/RunningAppProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/RunningAppProvider.java index 7ccf04f77..9b8f974d5 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/RunningAppProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/RunningAppProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Pivotal, Inc. + * Copyright (c) 2017, 2018 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 @@ -13,13 +13,20 @@ package org.springframework.ide.vscode.boot.java.handlers; import java.util.Collection; import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp; +import org.springframework.ide.vscode.commons.java.IJavaProject; import com.google.common.collect.ImmutableList; public interface RunningAppProvider { - public static final RunningAppProvider DEFAULT = SpringBootApp::getAllRunningSpringApps; - public static final RunningAppProvider NULL = () -> ImmutableList.of(); + public static final RunningAppProvider NULL = (project) -> ImmutableList.of(); - Collection getAllRunningSpringApps() throws Exception; + /** + * returns all running spring boot applications on the local machine and if a project + * gets passed to the method invocation, strict project matching is taken into account if enabled + * + * @param project If set (and strict project macthing is enabled), only those running boot apps that can be matched to the project are returned) + * @throws Exception + */ + Collection getAllRunningSpringApps(IJavaProject project) throws Exception; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/LiveAppURLSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/LiveAppURLSymbolProvider.java index f0e1efba4..dd6da0561 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/LiveAppURLSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/LiveAppURLSymbolProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Pivotal, Inc. + * Copyright (c) 2017, 2018 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 @@ -41,7 +41,7 @@ public class LiveAppURLSymbolProvider { List result = new ArrayList<>(); try { - SpringBootApp[] runningApps = runningAppProvider.getAllRunningSpringApps().toArray(new SpringBootApp[0]); + SpringBootApp[] runningApps = runningAppProvider.getAllRunningSpringApps(null).toArray(new SpringBootApp[0]); for (SpringBootApp app : runningApps) { try { String host = app.getHost(); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java index 3340a4edf..7b8c77b0e 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java @@ -13,7 +13,6 @@ package org.springframework.ide.vscode.boot.java.utils; import java.nio.file.Paths; import java.time.Duration; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -33,18 +32,16 @@ import org.eclipse.lsp4j.Range; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents; +import org.springframework.ide.vscode.boot.java.handlers.DefaultRunningAppProvider; import org.springframework.ide.vscode.boot.java.handlers.RunningAppProvider; import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.java.links.VSCodeSourceLinks; import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp; import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean; -import org.springframework.ide.vscode.commons.java.IClasspath; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver; import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver.Listener; -import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath; -import org.springframework.ide.vscode.commons.languageserver.jdt.ls.Classpath.CPE; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; /** @@ -66,6 +63,7 @@ public class SpringLiveChangeDetectionWatchdog { private final Set observedProjects; private boolean changeDetectionEnabled = false; + private Timer timer; public SpringLiveChangeDetectionWatchdog( @@ -134,7 +132,7 @@ public class SpringLiveChangeDetectionWatchdog { public void update() { if (changeDetectionEnabled) { try { - SpringBootApp[] runningBootApps = runningAppProvider.getAllRunningSpringApps().toArray(new SpringBootApp[0]); + SpringBootApp[] runningBootApps = runningAppProvider.getAllRunningSpringApps(null).toArray(new SpringBootApp[0]); Change[] changes = changeHistory.checkForChanges(runningBootApps); if (changes != null && changes.length > 0) { for (Change change : changes) { @@ -215,16 +213,9 @@ public class SpringLiveChangeDetectionWatchdog { Collections.addAll(runningClasspath, app.getClasspath()); for (IJavaProject project : this.observedProjects) { - IClasspath classpath = project.getClasspath(); - Collection entries = classpath.getClasspathEntries(); - for (CPE cpe : entries) { - if (Classpath.ENTRY_KIND_SOURCE.equals(cpe.getKind())) { - String path = cpe.getOutputFolder(); - if (runningClasspath.contains(path)) { - result.add(project); - break; - } - } + if (DefaultRunningAppProvider.doesClasspathMatch(runningClasspath, project)) { + result.add(project); + break; } } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveHoverWatchdog.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveHoverWatchdog.java index b85c0d78c..ed51b1dc0 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveHoverWatchdog.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveHoverWatchdog.java @@ -38,7 +38,7 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument; public class SpringLiveHoverWatchdog { public static final Duration DEFAULT_INTERVAL = Duration.ofMillis(5000); - + Logger logger = LoggerFactory.getLogger(SpringLiveHoverWatchdog.class); private final long POLLING_INTERVAL_MILLISECONDS; @@ -53,6 +53,7 @@ public class SpringLiveHoverWatchdog { private JavaProjectFinder projectFinder; + private void refreshEnablement() { boolean shouldEnable = highlightsEnabled && hasInterestingProject(watchedDocs.stream()); if (shouldEnable) { @@ -144,7 +145,8 @@ public class SpringLiveHoverWatchdog { try { if (runningBootApps == null) { - runningBootApps = runningAppProvider.getAllRunningSpringApps().toArray(new SpringBootApp[0]); + IJavaProject project = identifyProject(docURI); + runningBootApps = runningAppProvider.getAllRunningSpringApps(project).toArray(new SpringBootApp[0]); } boolean hasCurrentRunningBootApps = runningBootApps != null && runningBootApps.length > 0; @@ -167,8 +169,10 @@ public class SpringLiveHoverWatchdog { protected void update() { if (this.watchedDocs.size() > 0) { try { - SpringBootApp[] runningBootApps = runningAppProvider.getAllRunningSpringApps().toArray(new SpringBootApp[0]); for (String docURI : watchedDocs) { + IJavaProject project = identifyProject(docURI); + SpringBootApp[] runningBootApps = runningAppProvider.getAllRunningSpringApps(project).toArray(new SpringBootApp[0]); + update(docURI, runningBootApps); } } catch (Exception e) { @@ -177,6 +181,16 @@ public class SpringLiveHoverWatchdog { } } + private IJavaProject identifyProject(String docURI) { + TextDocument doc = this.server.getTextDocumentService().get(docURI); + if (doc != null) { + return projectFinder.find(doc.getId()).orElse(null); + } + else { + return null; + } + } + private void publishLiveHints(String docURI, Range[] ranges) { server.getClient().highlight(new HighlightParams(new TextDocumentIdentifier(docURI), Arrays.asList(ranges))); } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/project/harness/MockRunningAppProvider.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/project/harness/MockRunningAppProvider.java index ca181f0f0..900bd13b6 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/project/harness/MockRunningAppProvider.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/project/harness/MockRunningAppProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Pivotal, Inc. + * Copyright (c) 2017, 2018 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 @@ -10,6 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.project.harness; +import static org.mockito.Matchers.anyObject; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -32,7 +33,7 @@ public class MockRunningAppProvider { public MockRunningAppProvider() { try { - when(provider.getAllRunningSpringApps()).thenReturn(mockedApps); + when(provider.getAllRunningSpringApps(anyObject())).thenReturn(mockedApps); } catch (Exception e) { throw ExceptionUtil.unchecked(e); } diff --git a/vscode-extensions/vscode-spring-boot/package.json b/vscode-extensions/vscode-spring-boot/package.json index 07ec73c70..197a1c525 100644 --- a/vscode-extensions/vscode-spring-boot/package.json +++ b/vscode-extensions/vscode-spring-boot/package.json @@ -73,6 +73,11 @@ "default": false, "description": "Enable/Disable detecting changes of running Spring Boot applications" }, + "boot-java.strict-project-matching.on": { + "type": "boolean", + "default": false, + "description": "Use restrictive mechanism to match live running boot apps automatically with projects in your workspace" + }, "spring-boot.ls.java.home": { "type": [ "string",