diff --git a/headless-services/commons/commons-language-server/pom.xml b/headless-services/commons/commons-language-server/pom.xml index 464751bc6..ce21ab97f 100644 --- a/headless-services/commons/commons-language-server/pom.xml +++ b/headless-services/commons/commons-language-server/pom.xml @@ -13,6 +13,10 @@ + + org.springframework.boot + spring-boot + org.springframework.ide.vscode commons-util diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/LaunguageServerApp.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/LanguageServerRunner.java similarity index 86% rename from headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/LaunguageServerApp.java rename to headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/LanguageServerRunner.java index 6959b1cd4..ff91453a9 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/LaunguageServerApp.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/LanguageServerRunner.java @@ -21,7 +21,6 @@ import java.net.SocketAddress; import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.Channels; -import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -36,55 +35,25 @@ import org.eclipse.lsp4j.services.LanguageClientAware; import org.eclipse.lsp4j.services.LanguageServer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.boot.CommandLineRunner; import org.springframework.ide.vscode.commons.languageserver.util.LoggingFormat; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; -import org.springframework.ide.vscode.commons.util.AsyncRunner; import org.springframework.ide.vscode.commons.util.Log; - /** - * Abstract class meant to minimize the amount of code needed to - * write to create suitable 'main' method to launch a language server. - *

- * The easiest way to use this is to create your own static main method. - * Then call this class's start method with a Provider as - * a argument. - *

- * Alternatively, you can also subclass it and implement the abstract - * `createServer` method. + * A CommandLineRunner that launches a language server. This meant to be used as a Spring bean + * in a SpringBoot app. * * @author Kris De Volder * @author Martin Lippert */ -public class LaunguageServerApp { +public class LanguageServerRunner implements CommandLineRunner { - public static final String STS4_LANGUAGESERVER_NAME = "sts4.languageserver.name"; - public static final String STANDALONE_STARTUP = "standalone-startup"; - private static final int SERVER_STANDALONE_PORT = 5007; + final static Logger log = LoggerFactory.getLogger(LanguageServerRunner.class); - final static Logger log = LoggerFactory.getLogger(LaunguageServerApp.class); - - private final String name; - private final Provider languageServerFactory; - - public LaunguageServerApp(String name, Provider languageServerFactory) { - super(); - this.name = name; - this.languageServerFactory = languageServerFactory; - } - - public void start() throws Exception { - System.setProperty(STS4_LANGUAGESERVER_NAME, name); //makes it easy to recognize language server processes. - LaunguageServerApp app = this; - if (System.getProperty(STANDALONE_STARTUP, "false").equals("true")) { - app.startAsServer(); - } else { - app.startAsClient(); - } - } - - public void startAsync() { - //TODO: feel a bit wasteful to have thread dedicated to just waiting for the server to stop. + @Override + public void run(String... args) throws Exception { + //TODO: feels a bit wasteful to have thread dedicated to just waiting for the server to stop. // Not sure how we can really avoid this though. Lsp4j is providing // lots of api that returns Futures which the only way to deal with them is blocking threads calling // their get method. @@ -100,6 +69,35 @@ public class LaunguageServerApp { ).start(); } + /** + * System property that is set when the app launches. This makes it easy for the JVM process to recognized + * as a languageserver by using (for example) JMX to read the system properties. + */ + public static final String STS4_LANGUAGESERVER_NAME = "sts4.languageserver.name"; + + public static final String STANDALONE_STARTUP = "standalone-startup"; //TODO: turn into spring boot property + private static final int SERVER_STANDALONE_PORT = 5007; //TODO: turn into spring boot property + + + private final String name; + private final Provider languageServerFactory; + + public LanguageServerRunner(String name, Provider languageServerFactory) { + super(); + this.name = name; + this.languageServerFactory = languageServerFactory; + } + + public void start() throws Exception { + System.setProperty(STS4_LANGUAGESERVER_NAME, name); //makes it easy to recognize language server processes. + LanguageServerRunner app = this; + if (System.getProperty(STANDALONE_STARTUP, "false").equals("true")) { + app.startAsServer(); + } else { + app.startAsClient(); + } + } + protected static class Connection { final InputStream in; final OutputStream out; @@ -224,11 +222,6 @@ public class LaunguageServerApp { } } - /** - * Listen for requests from the parent node process. - * Send replies asynchronously. - * When the request stream is closed, wait for 5s for all outstanding responses to compute, then return. - */ protected Future runAsync(Connection connection) throws Exception { LanguageServer server = createServer(); ExecutorService executor = createServerThreads(); @@ -261,4 +254,5 @@ public class LaunguageServerApp { final SimpleLanguageServer createServer() { return languageServerFactory.get(); } + } 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 41e5d874d..649c9d9dc 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 @@ -3,26 +3,19 @@ package org.springframework.ide.vscode.languageserver.starter; import javax.inject.Provider; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp; +import org.springframework.ide.vscode.commons.languageserver.LanguageServerRunner; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; @Configuration public class LanguageServerAutoconf { - @Bean public LaunguageServerApp serverApp( + @Bean public LanguageServerRunner serverApp( @Qualifier("serverName") String serverName, Provider languageServerFactory ) { - return new LaunguageServerApp(serverName, languageServerFactory); - } - - @Bean public CommandLineRunner serverStarter(LaunguageServerApp serverApp) { - return args -> { - serverApp.startAsync(); - }; + return new LanguageServerRunner(serverName, languageServerFactory); } }