From 2a3dac69c66b76f6da5e37617c8e5b8743bd76a8 Mon Sep 17 00:00:00 2001 From: BoykoAlex Date: Thu, 19 Oct 2017 15:26:30 -0400 Subject: [PATCH] Spring properties index aware of project changes --- .../boot/java/BootJavaLanguageServer.java | 10 ++- .../java/BootJavaLanguageServerParams.java | 2 +- .../DefaultSpringPropertyIndexProvider.java | 10 ++- .../SpringPropertiesIndexManager.java | 34 +++++++- .../java/utils/test/SpringIndexerTest.java | 5 -- .../utils/test/SpringPropertyIndexTest.java | 83 +++++++++++++++++++ .../harness/BootLanguageServerHarness.java | 7 +- 7 files changed, 134 insertions(+), 17 deletions(-) create mode 100644 headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringPropertyIndexTest.java diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java index 46441b849..786365024 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java @@ -48,7 +48,6 @@ import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; import org.springframework.ide.vscode.commons.languageserver.HighlightParams; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine; import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter; -import org.springframework.ide.vscode.commons.languageserver.java.CompositeJavaProjectFinder; 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.reconcile.IReconcileEngine; @@ -72,6 +71,7 @@ public class BootJavaLanguageServer extends SimpleLanguageServer { private final VscodeCompletionEngineAdapter completionEngine; private final SpringIndexer indexer; + private final SpringPropertyIndexProvider propertyIndexProvider; private final SpringLiveHoverWatchdog liveHoverWatchdog; private final ProjectObserver projectObserver; @@ -83,6 +83,8 @@ public class BootJavaLanguageServer extends SimpleLanguageServer { super("vscode-boot-java"); BootJavaLanguageServerParams serverParams = _params.create(this); + propertyIndexProvider = serverParams.indexProvider; + System.setProperty(LANGUAGE_SERVER_PROCESS_PROPERTY, LANGUAGE_SERVER_PROCESS_PROPERTY); JavaProjectFinder javaProjectFinder = serverParams.projectFinder; @@ -95,7 +97,7 @@ public class BootJavaLanguageServer extends SimpleLanguageServer { validateWith(doc.getId(), reconcileEngine); }); - ICompletionEngine bootCompletionEngine = createCompletionEngine(javaProjectFinder, serverParams.indexProvider); + ICompletionEngine bootCompletionEngine = createCompletionEngine(javaProjectFinder, propertyIndexProvider); completionEngine = createCompletionEngineAdapter(this, bootCompletionEngine); completionEngine.setMaxCompletions(100); documents.onCompletion(completionEngine::getCompletions); @@ -286,9 +288,11 @@ public class BootJavaLanguageServer extends SimpleLanguageServer { return projectFinder; } - public SpringIndexer getSpringIndexer() { return indexer; } + public SpringPropertyIndexProvider getSpringPropertyIndexProvider() { + return propertyIndexProvider; + } } diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerParams.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerParams.java index 2f9641e89..cc51d8f10 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerParams.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerParams.java @@ -54,7 +54,7 @@ public class BootJavaLanguageServerParams { return new BootJavaLanguageServerParams( javaProjectFinder, projectObserver, - new DefaultSpringPropertyIndexProvider(javaProjectFinder), + new DefaultSpringPropertyIndexProvider(javaProjectFinder, projectObserver), RunningAppProvider.DEFAULT ); }; diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java index 567adebac..f75dc6304 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java @@ -16,6 +16,7 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.ProgressService; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver; import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.text.IDocument; @@ -24,13 +25,18 @@ public class DefaultSpringPropertyIndexProvider implements SpringPropertyIndexPr private static final FuzzyMap EMPTY_INDEX = new SpringPropertyIndex(null); private JavaProjectFinder javaProjectFinder; - private SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager(); + private SpringPropertiesIndexManager indexManager; private ProgressService progressService = (id, msg) -> { /* ignore */ }; - public DefaultSpringPropertyIndexProvider(JavaProjectFinder javaProjectFinder) { + public DefaultSpringPropertyIndexProvider(JavaProjectFinder javaProjectFinder, ProjectObserver projectObserver) { this.javaProjectFinder = javaProjectFinder; + this.indexManager = new SpringPropertiesIndexManager(projectObserver); + } + + public DefaultSpringPropertyIndexProvider(JavaProjectFinder javaProjectFinder) { + this(javaProjectFinder, null); } @Override diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java index a7d3e6550..335037f18 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertiesIndexManager.java @@ -16,6 +16,8 @@ import java.util.Map; import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.ProgressService; +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.util.FuzzyMap; /** @@ -31,7 +33,31 @@ public class SpringPropertiesIndexManager { private Map indexes = null; private static int progressIdCt = 0; - public SpringPropertiesIndexManager() { + public SpringPropertiesIndexManager(ProjectObserver projectObserver) { + if (projectObserver != null) { + projectObserver.addListener(new Listener() { + + @Override + public void created(IJavaProject project) { + // ignore + } + + @Override + public void changed(IJavaProject project) { + invalidateIndex(project); + } + + @Override + public void deleted(IJavaProject project) { + invalidateIndex(project); + } + + }); + } + } + + public synchronized SpringPropertyIndex invalidateIndex(IJavaProject project) { + return indexes.remove(project); } public synchronized FuzzyMap get(IJavaProject project, ProgressService progressService) { @@ -45,17 +71,17 @@ public class SpringPropertiesIndexManager { if (progressService != null) { progressService.progressEvent(progressId, "Indexing Spring Boot Properties..."); } - + index = new SpringPropertyIndex(project.getClasspath()); indexes.put(project, index); - + if (progressService != null) { progressService.progressEvent(progressId, null); } } return index; } - + private static synchronized String getProgressId() { return DefaultSpringPropertyIndexProvider.class.getName()+ (progressIdCt++); } diff --git a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerTest.java b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerTest.java index b26cfeb56..d5136414e 100644 --- a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerTest.java +++ b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerTest.java @@ -20,7 +20,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -33,14 +32,10 @@ import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider; import org.springframework.ide.vscode.boot.java.requestmapping.Constants; import org.springframework.ide.vscode.boot.java.requestmapping.RequestMappingSymbolProvider; import org.springframework.ide.vscode.boot.java.utils.SpringIndexer; -import org.springframework.ide.vscode.commons.languageserver.java.CompositeJavaProjectFinder; -import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; -import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; import org.springframework.ide.vscode.commons.maven.MavenCore; import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness; import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness; import org.springframework.ide.vscode.project.harness.ProjectsHarness; -import org.springframework.ide.vscode.project.harness.PropertyIndexHarness; /** * @author Martin Lippert diff --git a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringPropertyIndexTest.java b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringPropertyIndexTest.java new file mode 100644 index 000000000..e2c9102cd --- /dev/null +++ b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringPropertyIndexTest.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2017 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.utils.test; + +import static org.mockito.Matchers.anyObject; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import java.io.File; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer; +import org.springframework.ide.vscode.boot.metadata.DefaultSpringPropertyIndexProvider; +import org.springframework.ide.vscode.commons.languageserver.ProgressService; +import org.springframework.ide.vscode.commons.maven.MavenCore; +import org.springframework.ide.vscode.commons.util.text.LanguageId; +import org.springframework.ide.vscode.commons.util.text.TextDocument; +import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness; +import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness; +import org.springframework.ide.vscode.project.harness.ProjectsHarness; + +/** + * Tests for Spring properties index in Boot Java server + * + * @author Alex Boyko + * + */ +public class SpringPropertyIndexTest { + + private LanguageServerHarness harness; + + private DefaultSpringPropertyIndexProvider propertyIndexProvider; + + @Before + public void setup() throws Exception { + harness = BootLanguageServerHarness.builder().build(); + } + + @Test + public void testScanningAllAnnotationsSimpleProjectUpfront() throws Exception { + harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-parent/test-annotation-indexing/").toURI())); + propertyIndexProvider = (DefaultSpringPropertyIndexProvider) harness.getServer().getSpringPropertyIndexProvider(); + + File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-parent/test-annotation-indexing/").toURI()); + + File javaFile = new File(directory, "/src/main/java/org/test/SimpleMappingClass.java"); + + TextDocument doc = new TextDocument(javaFile.toURI().toString(), LanguageId.JAVA); + + // Not cached yet, hence progress service invoked + ProgressService progressService = mock(ProgressService.class); + propertyIndexProvider.setProgressService(progressService); + propertyIndexProvider.getIndex(doc); + verify(progressService, atLeastOnce()).progressEvent(anyObject(), anyObject()); + + // Should be cached now, so progress service should not be touched + progressService = mock(ProgressService.class); + propertyIndexProvider.setProgressService(progressService); + propertyIndexProvider.getIndex(doc); + verify(progressService, never()).progressEvent(anyObject(), anyObject()); + + // Change POM file for the project + harness.changeFile(new File(directory, MavenCore.POM_XML).toURI().toString()); + + // POM has changed, hence project needs to be reloaded, cached value is cleared + progressService = mock(ProgressService.class); + propertyIndexProvider.setProgressService(progressService); + propertyIndexProvider.getIndex(doc); + verify(progressService, atLeastOnce()).progressEvent(anyObject(), anyObject()); + } + +} diff --git a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/project/harness/BootLanguageServerHarness.java b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/project/harness/BootLanguageServerHarness.java index 31618134f..4314d04e9 100644 --- a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/project/harness/BootLanguageServerHarness.java +++ b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/project/harness/BootLanguageServerHarness.java @@ -10,8 +10,6 @@ *******************************************************************************/ package org.springframework.ide.vscode.project.harness; -import java.util.concurrent.Callable; - import org.junit.Assert; import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer; import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerParams; @@ -72,6 +70,11 @@ public class BootLanguageServerHarness extends LanguageServerHarness