Support for user-defined logging.groups

This commit is contained in:
Kris De Volder
2018-11-14 09:42:01 -08:00
parent 336ad0c979
commit 0eb6614617
15 changed files with 135 additions and 67 deletions

View File

@@ -25,9 +25,9 @@ import org.springframework.ide.vscode.commons.java.IJavaProject;
* @author Kris De Volder
*/
public interface JavaProjectFinder {
Optional<IJavaProject> find(TextDocumentIdentifier doc);
default JavaProjectFinder filter(Predicate<IJavaProject> acceptWhen) {
return doc -> this.find(doc).flatMap(jp -> {
if (acceptWhen.test(jp)) {

View File

@@ -18,9 +18,6 @@ import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.logging.Logger;
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
import org.springframework.ide.vscode.commons.util.StringUtil;
/**
* A collection of data that can be searched with a simple 'fuzzy' string
* matching algorithm. Clients must override 'getKey' method to define how
@@ -167,4 +164,8 @@ public abstract class FuzzyMap<E> implements Iterable<E> {
return entries.size();
}
public TreeMap<String, E> getTreeMap() {
return entries;
}
}

View File

@@ -30,6 +30,7 @@ import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.boot.metadata.AdHocSpringPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.ClassReferenceProvider;
import org.springframework.ide.vscode.boot.metadata.LoggerNameProvider;
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.PropertyInfo;
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.ValueProviderRegistry;
@@ -75,7 +76,7 @@ public class BootLanguagServerBootApp {
return new ValueProviderRegistry();
}
@Bean InitializingBean initializeValueProviders(ValueProviderRegistry r, @Qualifier("adHocProperties") SpringPropertyIndexProvider adHocProperties) {
@Bean InitializingBean initializeValueProviders(ValueProviderRegistry r, @Qualifier("adHocProperties") ProjectBasedPropertyIndexProvider adHocProperties) {
return () -> {
r.def("logger-name", new LoggerNameProvider(adHocProperties).FACTORY);
r.def("class-reference", ClassReferenceProvider.FACTORY);

View File

@@ -20,6 +20,7 @@ import org.springframework.ide.vscode.boot.java.links.JavaElementLocationProvide
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.boot.metadata.AdHocSpringPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
import org.springframework.ide.vscode.boot.properties.BootPropertiesLanguageServerComponents;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
@@ -47,7 +48,7 @@ public class BootLanguageServerInitializer implements InitializingBean {
@Autowired YamlASTProvider parser;
@Autowired YamlStructureProvider yamlStructureProvider;
@Autowired YamlAssistContextProvider yamlAssistContextProvider;
@Qualifier("adHocProperties") @Autowired SpringPropertyIndexProvider adHocProperties;
@Qualifier("adHocProperties") @Autowired ProjectBasedPropertyIndexProvider adHocProperties;
private CompositeLanguageServerComponents components;
private VscodeCompletionEngineAdapter completionEngineAdapter;

View File

@@ -21,9 +21,7 @@ import org.springframework.ide.vscode.boot.java.utils.SpringLiveHoverWatchdog;
import org.springframework.ide.vscode.boot.jdt.ls.JavaProjectsService;
import org.springframework.ide.vscode.boot.jdt.ls.JavaProjectsServiceWithFallback;
import org.springframework.ide.vscode.boot.jdt.ls.JdtLsProjectCache;
import org.springframework.ide.vscode.boot.metadata.AdHocSpringPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.DefaultSpringPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndex;
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.ValueProviderRegistry;
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil;

View File

@@ -64,6 +64,7 @@ import org.springframework.ide.vscode.boot.java.value.ValueCompletionProcessor;
import org.springframework.ide.vscode.boot.java.value.ValueHoverProvider;
import org.springframework.ide.vscode.boot.java.value.ValuePropertyReferencesProvider;
import org.springframework.ide.vscode.boot.metadata.AdHocSpringPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
import org.springframework.ide.vscode.commons.languageserver.composable.LanguageServerComponents;
@@ -97,7 +98,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
private final BootLanguageServerParams serverParams;
private final SpringIndexer indexer;
private final SpringPropertyIndexProvider propertyIndexProvider;
private final SpringPropertyIndexProvider adHocPropertyIndexProvider;
private final ProjectBasedPropertyIndexProvider adHocPropertyIndexProvider;
private final SpringLiveHoverWatchdog liveHoverWatchdog;
private final SpringLiveChangeDetectionWatchdog liveChangeDetectionWatchdog;
private final ProjectObserver projectObserver;
@@ -114,7 +115,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
BootLanguageServerParams serverParams,
SourceLinks sourceLinks,
CompilationUnitCache cuCache,
SpringPropertyIndexProvider adHocIndexProvider
ProjectBasedPropertyIndexProvider adHocIndexProvider
) {
this.server = server;
this.serverParams = serverParams;
@@ -264,13 +265,13 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
protected ICompletionEngine createCompletionEngine(
JavaProjectFinder javaProjectFinder,
SpringPropertyIndexProvider indexProvider,
SpringPropertyIndexProvider adHocIndexProvider
ProjectBasedPropertyIndexProvider adHocIndexProvider
) {
Map<String, CompletionProvider> providers = new HashMap<>();
providers.put(org.springframework.ide.vscode.boot.java.scope.Constants.SPRING_SCOPE,
new ScopeCompletionProcessor());
providers.put(org.springframework.ide.vscode.boot.java.value.Constants.SPRING_VALUE,
new ValueCompletionProcessor(indexProvider, adHocIndexProvider));
new ValueCompletionProcessor(javaProjectFinder, indexProvider, adHocIndexProvider));
JavaSnippetManager snippetManager = new JavaSnippetManager(server::createSnippetBuilder);
snippetManager.add(

View File

@@ -16,6 +16,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.eclipse.jdt.core.dom.ASTNode;
@@ -25,11 +26,15 @@ import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.lsp4j.InsertTextFormat;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider;
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.PropertyInfo;
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.FuzzyMap;
import org.springframework.ide.vscode.commons.util.FuzzyMap.Match;
@@ -41,9 +46,11 @@ import org.springframework.ide.vscode.commons.util.text.IDocument;
public class ValueCompletionProcessor implements CompletionProvider {
private final SpringPropertyIndexProvider indexProvider;
private SpringPropertyIndexProvider adHocIndexProvider;
private final ProjectBasedPropertyIndexProvider adHocIndexProvider;
private final JavaProjectFinder projectFinder;
public ValueCompletionProcessor(SpringPropertyIndexProvider indexProvider, SpringPropertyIndexProvider adHocIndexProvider) {
public ValueCompletionProcessor(JavaProjectFinder projectFinder, SpringPropertyIndexProvider indexProvider, ProjectBasedPropertyIndexProvider adHocIndexProvider) {
this.projectFinder = projectFinder;
this.indexProvider = indexProvider;
this.adHocIndexProvider = adHocIndexProvider;
}
@@ -206,10 +213,13 @@ public class ValueCompletionProcessor implements CompletionProvider {
}
//Then also add 'ad-hoc' properties (see https://www.pivotaltracker.com/story/show/153107266).
index = adHocIndexProvider.getIndex(doc);
for (Match<PropertyInfo> m : index.find(prefix)) {
if (suggestedKeys.add(m.data.getId())) {
matches.add(m);
Optional<IJavaProject> p = projectFinder.find(new TextDocumentIdentifier(doc.getUri()));
if (p.isPresent()) {
index = adHocIndexProvider.getIndex(p.get());
for (Match<PropertyInfo> m : index.find(prefix)) {
if (suggestedKeys.add(m.data.getId())) {
matches.add(m);
}
}
}
return matches;

View File

@@ -12,12 +12,9 @@ package org.springframework.ide.vscode.boot.metadata;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
@@ -30,7 +27,6 @@ import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFin
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
import org.springframework.ide.vscode.commons.util.FileObserver;
import org.springframework.ide.vscode.commons.util.FuzzyMap;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.yaml.ast.NodeUtil;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.nodes.MappingNode;
@@ -42,7 +38,7 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
public class AdHocSpringPropertyIndexProvider implements SpringPropertyIndexProvider {
public class AdHocSpringPropertyIndexProvider implements ProjectBasedPropertyIndexProvider {
private static final Logger log = LoggerFactory.getLogger(AdHocSpringPropertyIndexProvider.class);
@@ -54,10 +50,8 @@ public class AdHocSpringPropertyIndexProvider implements SpringPropertyIndexProv
}
private Cache<IJavaProject, SimplePropertyIndex> indexes;
final private JavaProjectFinder projectFinder;
public AdHocSpringPropertyIndexProvider(JavaProjectFinder projectFinder, ProjectObserver projectObserver, FileObserver fileObserver) {
this.projectFinder = projectFinder;
this.indexes = CacheBuilder.newBuilder().build();
if (projectObserver != null) {
projectObserver.addListener(ProjectObserver.onAny(project -> indexes.invalidate(project)));
@@ -78,31 +72,24 @@ public class AdHocSpringPropertyIndexProvider implements SpringPropertyIndexProv
@Override
public FuzzyMap<PropertyInfo> getIndex(IDocument doc) {
Optional<IJavaProject> jp = projectFinder.find(new TextDocumentIdentifier(doc.getUri()));
if (jp.isPresent()) {
return getIndex(jp.get());
public FuzzyMap<PropertyInfo> getIndex(IJavaProject jp) {
if (jp!=null) {
try {
return indexes.get(jp, () -> {
SimplePropertyIndex index = new SimplePropertyIndex();
IClasspathUtil.getSourceFolders(jp.getClasspath()).forEach(sourceFolder -> {
processFile(this::parseProperties, new File(sourceFolder, "application.properties"), index);
processFile(this::parseYaml, new File(sourceFolder, "application.yml"), index);
});
return index;
});
} catch (ExecutionException e) {
log.error("", e);
}
}
return SpringPropertyIndex.EMPTY_INDEX;
}
private FuzzyMap<PropertyInfo> getIndex(IJavaProject jp) {
try {
return indexes.get(jp, () -> {
SimplePropertyIndex index = new SimplePropertyIndex();
IClasspathUtil.getSourceFolders(jp.getClasspath()).forEach(sourceFolder -> {
processFile(this::parseProperties, new File(sourceFolder, "application.properties"), index);
processFile(this::parseYaml, new File(sourceFolder, "application.yml"), index);
});
return index;
});
} catch (ExecutionException e) {
log.error("", e);
}
return null;
}
private void processFile(Function<File, Properties> parserFunction, File file, SimplePropertyIndex index) {
Properties props = parserFunction.apply(file);
if (props!=null) {

View File

@@ -11,12 +11,18 @@
package org.springframework.ide.vscode.boot.metadata;
import java.util.Collection;
import java.util.Map;
import java.util.SortedMap;
import java.util.function.Function;
import org.springframework.ide.vscode.boot.metadata.ValueProviderRegistry.ValueProviderStrategy;
import org.springframework.ide.vscode.boot.metadata.hints.StsValueHint;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import reactor.core.publisher.Flux;
import reactor.util.function.Tuples;
@@ -31,17 +37,35 @@ import reactor.util.function.Tuples;
*/
public class LoggerNameProvider extends CachingValueProvider {
private final SpringPropertyIndexProvider adhocProperties;
private static final String LOGGING_GROUPS_PREFIX = "logging.group.";
public LoggerNameProvider(SpringPropertyIndexProvider adhocProperties) {
private final ProjectBasedPropertyIndexProvider adhocProperties;
public LoggerNameProvider(ProjectBasedPropertyIndexProvider adhocProperties) {
this.adhocProperties = adhocProperties;
}
public final Function<Map<String, Object>, ValueProviderStrategy> FACTORY = (params) -> this;
Collection<String> loggerNames(IJavaProject jp) {
Builder<String> builder = ImmutableSet.builder();
SortedMap<String, PropertyInfo> index = adhocProperties.getIndex(jp).getTreeMap();
index = index.subMap(LOGGING_GROUPS_PREFIX, LOGGING_GROUPS_PREFIX+Character.MAX_VALUE);
for (String prop : index.keySet()) {
System.out.println(prop);
if (prop.startsWith(LOGGING_GROUPS_PREFIX)) {
builder.add(prop.substring(LOGGING_GROUPS_PREFIX.length()));
}
}
return builder.build();
}
@Override
protected Flux<StsValueHint> getValuesAsync(IJavaProject javaProject, String query) {
return Flux.concat(
Flux.fromIterable(loggerNames(javaProject))
.map(loggerName -> Tuples.of(StsValueHint.create(loggerName), FuzzyMatcher.matchScore(query, loggerName)))
.filter(t -> t.getT2()!=0.0),
javaProject.getIndex()
.fuzzySearchPackages(query)
.map(t -> Tuples.of(StsValueHint.create(t.getT1()), t.getT2())),
@@ -53,4 +77,5 @@ public class LoggerNameProvider extends CachingValueProvider {
.flatMapIterable(l -> l)
.map(t -> t.getT1());
}
}

View File

@@ -0,0 +1,19 @@
/*******************************************************************************
* 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.metadata;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.util.FuzzyMap;
@FunctionalInterface
public interface ProjectBasedPropertyIndexProvider {
FuzzyMap<PropertyInfo> getIndex(IJavaProject jp);
}

View File

@@ -13,6 +13,7 @@ package org.springframework.ide.vscode.boot.bootiful;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ide.vscode.boot.editor.harness.AdHocPropertyHarness;
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
@Configuration
@@ -21,7 +22,7 @@ public class AdHocPropertyHarnessTestConf {
return new AdHocPropertyHarness();
}
@Bean SpringPropertyIndexProvider adHocProperties(AdHocPropertyHarness adHocProperties) {
@Bean ProjectBasedPropertyIndexProvider adHocProperties(AdHocPropertyHarness adHocProperties) {
return adHocProperties.getIndexProvider();
}
}

View File

@@ -10,6 +10,7 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.editor.harness;
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
import org.springframework.ide.vscode.boot.metadata.PropertyInfo;
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
import org.springframework.ide.vscode.commons.util.FuzzyMap;
@@ -23,9 +24,9 @@ public class AdHocPropertyHarness {
}
};
protected final SpringPropertyIndexProvider adHocIndexProvider = doc -> adHocProperties;
protected final ProjectBasedPropertyIndexProvider adHocIndexProvider = project -> adHocProperties;
public SpringPropertyIndexProvider getIndexProvider() {
public ProjectBasedPropertyIndexProvider getIndexProvider() {
return adHocIndexProvider;
}

View File

@@ -33,8 +33,7 @@ public class AdHocSpringPropertyIndexProviderTest {
);
AdHocSpringPropertyIndexProvider indexer = new AdHocSpringPropertyIndexProvider(projects.finder, projects.observer, null);
TextDocument doc = new TextDocument(project.uri("src/main/java/SomeClass.java"), LanguageId.JAVA);
assertProperties(indexer.getIndex(doc),
assertProperties(indexer.getIndex(project),
//alphabetic order
"some-adhoc-bar",
"some-adhoc-foo"
@@ -52,8 +51,7 @@ public class AdHocSpringPropertyIndexProviderTest {
);
AdHocSpringPropertyIndexProvider indexer = new AdHocSpringPropertyIndexProvider(projects.finder, projects.observer, null);
TextDocument doc = new TextDocument(project.uri("src/main/java/SomeClass.java"), LanguageId.JAVA);
assertProperties(indexer.getIndex(doc),
assertProperties(indexer.getIndex(project),
//alphabetic order
"from-yaml.adhoc.bar",
"from-yaml.adhoc.foo"
@@ -68,19 +66,18 @@ public class AdHocSpringPropertyIndexProviderTest {
);
AdHocSpringPropertyIndexProvider indexer = new AdHocSpringPropertyIndexProvider(projects.finder, projects.observer, null);
TextDocument doc = new TextDocument(project.uri("src/main/java/SomeClass.java"), LanguageId.JAVA);
assertProperties(indexer.getIndex(doc),
assertProperties(indexer.getIndex(project),
"initial-property"
);
project.ensureFile("new-sourcefolder/application.properties", "new-property=whatever");
assertProperties(indexer.getIndex(doc),
assertProperties(indexer.getIndex(project),
"initial-property"
);
project.createSourceFolder("new-sourcefolder");
assertProperties(indexer.getIndex(doc),
assertProperties(indexer.getIndex(project),
"initial-property",
"new-property"
);
@@ -94,19 +91,18 @@ public class AdHocSpringPropertyIndexProviderTest {
);
AdHocSpringPropertyIndexProvider indexer = new AdHocSpringPropertyIndexProvider(projects.finder, projects.observer, projects.fileObserver);
TextDocument doc = new TextDocument(project.uri("src/main/java/SomeClass.java"), LanguageId.JAVA);
assertProperties(indexer.getIndex(doc),
assertProperties(indexer.getIndex(project),
"initial-property"
);
project.ensureFile("src/main/resources/application.properties", "from-properties=whatever");
assertProperties(indexer.getIndex(doc),
assertProperties(indexer.getIndex(project),
"from-properties"
);
project.ensureFile("src/main/resources/application.yml", "from-yaml: whatever");
assertProperties(indexer.getIndex(doc),
assertProperties(indexer.getIndex(project),
"from-properties",
"from-yaml"
);

View File

@@ -61,6 +61,7 @@ public class ValueCompletionTest {
@Autowired private BootLanguageServerHarness harness;
@Autowired private IJavaProject testProject;
@Autowired private JavaProjectFinder projectFinder;
private Editor editor;
@@ -121,7 +122,7 @@ public class ValueCompletionTest {
@Test
public void testPrefixIdentification() {
ValueCompletionProcessor processor = new ValueCompletionProcessor(null, null);
ValueCompletionProcessor processor = new ValueCompletionProcessor(projectFinder, null, null);
assertEquals("pre", processor.identifyPropertyPrefix("pre", 3));
assertEquals("pre", processor.identifyPropertyPrefix("prefix", 3));

View File

@@ -35,6 +35,7 @@ import org.springframework.context.annotation.Import;
import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest;
import org.springframework.ide.vscode.boot.bootiful.PropertyEditorTestConf;
import org.springframework.ide.vscode.boot.editor.harness.AbstractPropsEditorTest;
import org.springframework.ide.vscode.boot.editor.harness.AdHocPropertyHarness;
import org.springframework.ide.vscode.boot.editor.harness.StyledStringMatcher;
import org.springframework.ide.vscode.boot.metadata.CachingValueProvider;
import org.springframework.ide.vscode.boot.metadata.PropertiesLoader;
@@ -59,8 +60,9 @@ import com.google.common.io.Files;
@Import(PropertyEditorTestConf.class)
public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
@Autowired
private DefinitionLinkAsserts definitionLinkAsserts;
@Autowired DefinitionLinkAsserts definitionLinkAsserts;
@Autowired AdHocPropertyHarness adHocProperties;
@Configuration static class TestConf {
@Bean LanguageId defaultLanguageId() {
@@ -1148,6 +1150,30 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest {
);
}
@Test public void userDefinedLoggerGroups() throws Exception {
useProject(createPredefinedMavenProject("empty-boot-2.1.0-app"));
adHocProperties.add("logging.group.foobar");
adHocProperties.add("logging.group.user-defined");
assertCompletionWithLabel(
"logging.level.<*>"
, //==============
"user-defined",
//=>
"logging.level.user-defined=<*>"
);
assertCompletionWithLabel(
"logging.level.<*>"
, //==============
"foobar",
//=>
"logging.level.foobar=<*>"
);
}
@Test public void testPropertyMapKeyCompletions() throws Exception {
useProject(createPredefinedMavenProject("empty-boot-2.1.0-app"));
assertCompletionWithLabel(