diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/config/LanguageServerInitializer.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/config/LanguageServerInitializer.java new file mode 100644 index 000000000..02e75f22d --- /dev/null +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/config/LanguageServerInitializer.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * 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.commons.languageserver.config; + +import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; + +/** + * Callback to apply configuration to a {@link SimpleLanguageServer}. THis callback is + * called meant to be called on a newly instantiated SimpleLanguageServer, right after it + * was created (and prior to actually starting the language server). + * + * @author Kris De Volder + */ +public interface LanguageServerInitializer { + void initialize(SimpleLanguageServer server) throws Exception; +} diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java index ce8c7d1ab..2e79bca71 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java @@ -167,7 +167,7 @@ public class SimpleLanguageServer implements Sts4LanguageServer, LanguageClientA return null; } - protected synchronized QuickfixRegistry getQuickfixRegistry() { + public synchronized QuickfixRegistry getQuickfixRegistry() { if (quickfixRegistry==null) { quickfixRegistry = new QuickfixRegistry(); } diff --git a/headless-services/commons/language-server-starter/src/main/java/org/springframework/ide/vscode/languageserver/starter/LanguageServerAutoconf.java b/headless-services/commons/language-server-starter/src/main/java/org/springframework/ide/vscode/languageserver/starter/LanguageServerAutoconf.java index 64db73ab5..e56acd0b7 100644 --- a/headless-services/commons/language-server-starter/src/main/java/org/springframework/ide/vscode/languageserver/starter/LanguageServerAutoconf.java +++ b/headless-services/commons/language-server-starter/src/main/java/org/springframework/ide/vscode/languageserver/starter/LanguageServerAutoconf.java @@ -16,6 +16,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.ide.vscode.commons.languageserver.LanguageServerRunner; +import org.springframework.ide.vscode.commons.languageserver.config.LanguageServerInitializer; import org.springframework.ide.vscode.commons.languageserver.config.LanguageServerProperties; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; @@ -32,8 +33,10 @@ public class LanguageServerAutoconf { } @ConditionalOnMissingBean - @Bean public SimpleLanguageServer languageServer(LanguageServerProperties props) { - return new SimpleLanguageServer(props.getExtensionId()); + @Bean public SimpleLanguageServer languageServer(LanguageServerProperties props, LanguageServerInitializer initializer) throws Exception { + SimpleLanguageServer server = new SimpleLanguageServer(props.getExtensionId()); + initializer.initialize(server); + return server; } } diff --git a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java index d1fe537c5..c47d91509 100644 --- a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java +++ b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java @@ -99,6 +99,7 @@ import org.springframework.ide.vscode.commons.languageserver.JavadocResponse; import org.springframework.ide.vscode.commons.languageserver.ProgressParams; import org.springframework.ide.vscode.commons.languageserver.STS4LanguageClient; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; +import org.springframework.ide.vscode.commons.languageserver.config.LanguageServerInitializer; import org.springframework.ide.vscode.commons.languageserver.jdt.ls.ClasspathListenerParams; import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixEdit.CursorMovement; import org.springframework.ide.vscode.commons.languageserver.util.LanguageServerTestListener; @@ -147,6 +148,15 @@ public class LanguageServerHarness { public static final Duration HIGHLIGHTS_TIMEOUT = Duration.ofMillis(15000000000L); //Why so long? + public static LanguageServerHarness create(String extensionId, LanguageServerInitializer initializer) throws Exception { + Callable factory = () -> { + SimpleLanguageServer s = new SimpleLanguageServer(extensionId); + initializer.initialize(s); + return s; + }; + return new LanguageServerHarness<>(factory); + } + public LanguageServerHarness(Callable factory) throws Exception { this(factory, LanguageId.PLAINTEXT); } diff --git a/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerBootApp.java b/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerBootApp.java index 8e91eb914..4e233b01b 100644 --- a/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerBootApp.java +++ b/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerBootApp.java @@ -14,7 +14,6 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.ide.vscode.commons.util.LogRedirect; -import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngineOptions; @SpringBootApplication public class ManifestYamlLanguageServerBootApp { @@ -29,9 +28,4 @@ public class ManifestYamlLanguageServerBootApp { @Bean public String serverName() { return SERVER_NAME; } - - @Bean ManifestYamlLanguageServer languageServer() { - return new ManifestYamlLanguageServer(); - } - } diff --git a/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java b/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerInitializer.java similarity index 85% rename from headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java rename to headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerInitializer.java index b84b6291f..8d9538d33 100644 --- a/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java +++ b/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerInitializer.java @@ -16,6 +16,7 @@ import java.util.List; import java.util.concurrent.Callable; import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ide.vscode.commons.cloudfoundry.client.ClientTimeouts; import org.springframework.ide.vscode.commons.cloudfoundry.client.CloudFoundryClientFactory; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetCache; @@ -26,6 +27,7 @@ import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.Clien import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.NoTargetsException; import org.springframework.ide.vscode.commons.cloudfoundry.client.v2.DefaultCloudFoundryClientFactoryV2; import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter; +import org.springframework.ide.vscode.commons.languageserver.config.LanguageServerInitializer; import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfoProvider; import org.springframework.ide.vscode.commons.languageserver.hover.VscodeHoverEngineAdapter; import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine; @@ -48,33 +50,33 @@ import org.springframework.ide.vscode.commons.yaml.reconcile.TypeBasedYamlSymbol import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaBasedReconcileEngine; import org.springframework.ide.vscode.commons.yaml.schema.YValueHint; import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; import org.yaml.snakeyaml.Yaml; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -public class ManifestYamlLanguageServer extends SimpleLanguageServer { +@Component +public class ManifestYamlLanguageServerInitializer implements LanguageServerInitializer { private Yaml yaml = new Yaml(); private CfJson cfJson = new CfJson(); private ManifestYmlSchema schema; private CFTargetCache cfTargetCache; - private final ImmutableSet FALLBACK_YML_IDS = ImmutableSet.of(LanguageId.of("yml"), LanguageId.of("yaml")); - final private ClientParamsProvider defaultClientParamsProvider; - - public ManifestYamlLanguageServer() { - this(DefaultCloudFoundryClientFactoryV2.INSTANCE, CfCliParamsProvider.getInstance()); - } - - public ManifestYamlLanguageServer(CloudFoundryClientFactory cfClientFactory, ClientParamsProvider defaultClientParamsProvider) { - super("vscode-manifest-yaml"); - this.defaultClientParamsProvider = defaultClientParamsProvider; + private CloudFoundryClientFactory cfClientFactory; + ClientParamsProvider defaultClientParamsProvider; + private SimpleLanguageServer server; + @Override + public void initialize(SimpleLanguageServer server) throws Exception { + Assert.isNull(this.server, "This initializer should only be called once"); + this.server = server; this.cfTargetCache = new CFTargetCache(ImmutableList.of(this.defaultClientParamsProvider), cfClientFactory, new ClientTimeouts()); - SimpleTextDocumentService documents = getTextDocumentService(); - SimpleWorkspaceService workspace = getWorkspaceService(); + SimpleTextDocumentService documents = server.getTextDocumentService(); + SimpleWorkspaceService workspace = server.getWorkspaceService(); YamlASTProvider parser = new YamlParser(yaml); @@ -83,10 +85,10 @@ public class ManifestYamlLanguageServer extends SimpleLanguageServer { YamlStructureProvider structureProvider = YamlStructureProvider.DEFAULT; YamlAssistContextProvider contextProvider = new SchemaBasedYamlAssistContextProvider(schema); YamlCompletionEngine yamlCompletionEngine = new YamlCompletionEngine(structureProvider, contextProvider, YamlCompletionEngineOptions.DEFAULT); - VscodeCompletionEngineAdapter completionEngine = createCompletionEngineAdapter(this, yamlCompletionEngine); + VscodeCompletionEngineAdapter completionEngine = server.createCompletionEngineAdapter(server, yamlCompletionEngine); HoverInfoProvider infoProvider = new YamlHoverInfoProvider(parser, structureProvider, contextProvider); - HoverHandler hoverEngine = new VscodeHoverEngineAdapter(this, infoProvider); - YamlQuickfixes quickfixes = new YamlQuickfixes(getQuickfixRegistry(), getTextDocumentService(), structureProvider); + HoverHandler hoverEngine = new VscodeHoverEngineAdapter(server, infoProvider); + YamlQuickfixes quickfixes = new YamlQuickfixes(server.getQuickfixRegistry(), server.getTextDocumentService(), structureProvider); YamlSchemaBasedReconcileEngine engine = new YamlSchemaBasedReconcileEngine(parser, schema, quickfixes); ASTTypeCache astTypeCache = new ASTTypeCache(); @@ -128,6 +130,19 @@ public class ManifestYamlLanguageServer extends SimpleLanguageServer { applyCfLoginParameterSettings(info); } }); + + } + + private final ImmutableSet FALLBACK_YML_IDS = ImmutableSet.of(LanguageId.of("yml"), LanguageId.of("yaml")); + + @Autowired + public ManifestYamlLanguageServerInitializer() { + this(DefaultCloudFoundryClientFactoryV2.INSTANCE, CfCliParamsProvider.getInstance()); + } + + public ManifestYamlLanguageServerInitializer(CloudFoundryClientFactory cfClientFactory, ClientParamsProvider defaultClientParamsProvider) { + this.cfClientFactory = cfClientFactory; + this.defaultClientParamsProvider = defaultClientParamsProvider; } private void applyCfLoginParameterSettings(CfTargetsInfo info) { @@ -143,13 +158,13 @@ public class ManifestYamlLanguageServer extends SimpleLanguageServer { // // this FALLBACK_YML_ID got introduced to workaround a limitation in LSP4E, which sets the file extension as language ID to the document // - validateWith(doc.getId(), engine); + server.validateWith(doc.getId(), engine); } else { - validateWith(doc.getId(), IReconcileEngine.NULL); + server.validateWith(doc.getId(), IReconcileEngine.NULL); } } - protected ManifestYmlHintProviders getHintProviders() { + private ManifestYmlHintProviders getHintProviders() { Callable> buildPacksProvider = new ManifestYamlCFBuildpacksProvider(getCfTargetCache()); Callable> servicesProvider = new ManifestYamlCFServicesProvider(getCfTargetCache()); Callable> domainsProvider = new ManifestYamlCFDomainsProvider(getCfTargetCache()); diff --git a/headless-services/manifest-yaml-language-server/src/main/resources/application.yml b/headless-services/manifest-yaml-language-server/src/main/resources/application.yml index e69de29bb..0feee175b 100644 --- a/headless-services/manifest-yaml-language-server/src/main/resources/application.yml +++ b/headless-services/manifest-yaml-language-server/src/main/resources/application.yml @@ -0,0 +1,2 @@ +languageserver: + extension-id: vscode-manifest-yaml \ No newline at end of file diff --git a/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlEditorTest.java b/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlEditorTest.java index 017297e07..5607ef14e 100644 --- a/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlEditorTest.java +++ b/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlEditorTest.java @@ -33,6 +33,7 @@ import org.springframework.ide.vscode.commons.cloudfoundry.client.CFServiceInsta import org.springframework.ide.vscode.commons.cloudfoundry.client.CFStack; import org.springframework.ide.vscode.commons.cloudfoundry.client.ClientRequests; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.NoTargetsException; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; import org.springframework.ide.vscode.commons.util.Unicodes; import org.springframework.ide.vscode.commons.util.text.LanguageId; import org.springframework.ide.vscode.languageserver.testharness.CodeAction; @@ -43,12 +44,14 @@ import com.google.common.collect.ImmutableList; public class ManifestYamlEditorTest { - LanguageServerHarness harness; + LanguageServerHarness harness; MockCloudfoundry cloudfoundry = new MockCloudfoundry(); @Before public void setup() throws Exception { - harness = new LanguageServerHarness( - ()-> new ManifestYamlLanguageServer(cloudfoundry.factory, cloudfoundry.defaultParamsProvider), + SimpleLanguageServer server = new SimpleLanguageServer("vscode-manifest-yaml"); + new ManifestYamlLanguageServerInitializer(cloudfoundry.factory, cloudfoundry.defaultParamsProvider).initialize(server); + harness = new LanguageServerHarness<>( + ()-> server, LanguageId.CF_MANIFEST ); harness.intialize(null); @@ -67,8 +70,8 @@ public class ManifestYamlEditorTest { } @Test public void reconcileRunsOnDocumentOpenAndChange() throws Exception { - LanguageServerHarness harness = new LanguageServerHarness(ManifestYamlLanguageServer::new, LanguageId.CF_MANIFEST); - harness.intialize(null); +// LanguageServerHarness harness = new LanguageServerHarness(ManifestYamlLanguageServerInitializer::new, LanguageId.CF_MANIFEST); +// harness.intialize(null); Editor editor = harness.newEditor( "somemap: val\n"+ diff --git a/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerTest.java b/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerInitializerTest.java similarity index 76% rename from headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerTest.java rename to headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerInitializerTest.java index bb534b85b..3315dc8f8 100644 --- a/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerTest.java +++ b/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServerInitializerTest.java @@ -29,20 +29,22 @@ import org.eclipse.lsp4j.TextDocumentSyncKind; import org.junit.Test; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFClientParams; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.ClientParamsProvider; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServerWrapper; import org.springframework.ide.vscode.commons.util.text.LanguageId; import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness; import com.google.gson.JsonParser; -public class ManifestYamlLanguageServerTest { +public class ManifestYamlLanguageServerInitializerTest { public static File getTestResource(String name) throws URISyntaxException { - return Paths.get(ManifestYamlLanguageServerTest.class.getResource(name).toURI()).toFile(); + return Paths.get(ManifestYamlLanguageServerInitializerTest.class.getResource(name).toURI()).toFile(); } @Test public void createAndInitializeServerWithWorkspace() throws Exception { - LanguageServerHarness harness = new LanguageServerHarness(ManifestYamlLanguageServer::new); + LanguageServerHarness harness = LanguageServerHarness.create("vscode-manifest-yaml", new ManifestYamlLanguageServerInitializer()); File workspaceRoot = getTestResource("/workspace/"); assertExpectedInitResult(harness.intialize(workspaceRoot)); } @@ -50,7 +52,7 @@ public class ManifestYamlLanguageServerTest { @Test public void createAndInitializeServerWithoutWorkspace() throws Exception { File workspaceRoot = null; - LanguageServerHarness harness = new LanguageServerHarness(ManifestYamlLanguageServer::new); + LanguageServerHarness harness = LanguageServerHarness.create("vscode-manifest-yaml", new ManifestYamlLanguageServerInitializer()); assertExpectedInitResult(harness.intialize(workspaceRoot)); } @@ -93,17 +95,19 @@ public class ManifestYamlLanguageServerTest { @Test public void changeCfClientParams() throws Exception { MockCloudfoundry cloudfoundry = new MockCloudfoundry(); - ManifestYamlLanguageServer manifestYamlLanguageServer = new ManifestYamlLanguageServer(cloudfoundry.factory, cloudfoundry.defaultParamsProvider); + ManifestYamlLanguageServerInitializer serverInitializer = new ManifestYamlLanguageServerInitializer(cloudfoundry.factory, cloudfoundry.defaultParamsProvider); + SimpleLanguageServer server = new SimpleLanguageServer("vscode-manifest-yaml"); + serverInitializer.initialize(server); - LanguageServerHarness harness = new LanguageServerHarness( - () -> manifestYamlLanguageServer, + LanguageServerHarness harness = new LanguageServerHarness<>( + () -> server, LanguageId.CF_MANIFEST ); harness.intialize(null); // This is an initial target, for example from cf CLI - assertEquals(1, getAllParams(manifestYamlLanguageServer.getParamsProvider()).size()); - assertEquals(Arrays.asList("test.io"), manifestYamlLanguageServer.getCfTargets()); + assertEquals(1, getAllParams(serverInitializer.getParamsProvider()).size()); + assertEquals(Arrays.asList("test.io"), serverInitializer.getCfTargets()); // This tests a change in workspace (e.g. boot dash) that results in two more targets created. DidChangeConfigurationParams params = new DidChangeConfigurationParams(); @@ -111,11 +115,11 @@ public class ManifestYamlLanguageServerTest { JsonParser parser = new JsonParser(); params.setSettings(parser.parse(new InputStreamReader(getClass().getResourceAsStream("/cf-targets1.json")))); - manifestYamlLanguageServer.getWorkspaceService().didChangeConfiguration(params); - assertEquals(3, getAllParams(manifestYamlLanguageServer.getParamsProvider()).size()); + server.getWorkspaceService().didChangeConfiguration(params); + assertEquals(3, getAllParams(serverInitializer.getParamsProvider()).size()); // End result should have the initial target as well as the two additional targets obtained on workspace change - assertEquals(Arrays.asList("test.io", "api.system.demo-gcp.springapps.io", "api.run.pivotal.io"), manifestYamlLanguageServer.getCfTargets()); + assertEquals(Arrays.asList("test.io", "api.system.demo-gcp.springapps.io", "api.run.pivotal.io"), serverInitializer.getCfTargets()); } private List getAllParams(List providers) throws Exception { diff --git a/headless-services/manifest-yaml-language-server/src/test/resources/logback-test.xml b/headless-services/manifest-yaml-language-server/src/test/resources/logback-test.xml new file mode 100644 index 000000000..303f30396 --- /dev/null +++ b/headless-services/manifest-yaml-language-server/src/test/resources/logback-test.xml @@ -0,0 +1,15 @@ + + + + + System.err + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + \ No newline at end of file