Spring properties index aware of project changes

This commit is contained in:
BoykoAlex
2017-10-19 15:26:30 -04:00
parent c02f96a812
commit 2a3dac69c6
7 changed files with 134 additions and 17 deletions

View File

@@ -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;
}
}

View File

@@ -54,7 +54,7 @@ public class BootJavaLanguageServerParams {
return new BootJavaLanguageServerParams(
javaProjectFinder,
projectObserver,
new DefaultSpringPropertyIndexProvider(javaProjectFinder),
new DefaultSpringPropertyIndexProvider(javaProjectFinder, projectObserver),
RunningAppProvider.DEFAULT
);
};

View File

@@ -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<ConfigurationMetadataProperty> 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

View File

@@ -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<IJavaProject, SpringPropertyIndex> 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<ConfigurationMetadataProperty> 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++);
}

View File

@@ -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

View File

@@ -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<BootJavaLanguageServer> 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());
}
}

View File

@@ -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<BootJavaLan
this.projectFinder = projectFinder;
return this;
}
public Builder propertyIndexProvider(SpringPropertyIndexProvider propertyIndexProvider) {
this.indexProvider = propertyIndexProvider;
return this;
}
}
/**