refactored startup code to launch language server as standalone app, listening for clients to connect, into commons code
This commit is contained in:
@@ -15,10 +15,16 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
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;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -31,6 +37,7 @@ import org.eclipse.lsp4j.services.LanguageClient;
|
||||
import org.eclipse.lsp4j.services.LanguageClientAware;
|
||||
import org.eclipse.lsp4j.services.LanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LoggingFormat;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
|
||||
|
||||
/**
|
||||
@@ -38,24 +45,44 @@ import org.springframework.ide.vscode.commons.languageserver.util.LoggingFormat;
|
||||
* write to create suitable 'main' method to launch a language server.
|
||||
* <p>
|
||||
* The easiest way to use this is to create your own static main method.
|
||||
* Then call this class's start method with a Provider<LanguageServer> as
|
||||
* Then call this class's start method with a Provider<SimpleLanguageServer> as
|
||||
* a argument.
|
||||
* <p>
|
||||
* Alternatively, you can also subclass it and implement the abstract
|
||||
* `createServer` method.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public abstract class LaunguageServerApp {
|
||||
|
||||
public static void start(Provider<LanguageServer> languageServerFactory) throws IOException {
|
||||
private static final String STANDALONE_STARTUP = "standalone-startup";
|
||||
private static final int SERVER_STANDALONE_PORT = 5007;
|
||||
|
||||
public static void start(Provider<SimpleLanguageServer> languageServerFactory) throws IOException, InterruptedException {
|
||||
LaunguageServerApp app = new LaunguageServerApp() {
|
||||
@Override
|
||||
protected LanguageServer createServer() {
|
||||
protected SimpleLanguageServer createServer() {
|
||||
return languageServerFactory.get();
|
||||
}
|
||||
};
|
||||
app.start();
|
||||
|
||||
if (System.getProperty(STANDALONE_STARTUP, "false").equals("true")) {
|
||||
app.startAsServer();
|
||||
}
|
||||
else {
|
||||
app.start();
|
||||
}
|
||||
}
|
||||
|
||||
public static void startAsServer(Provider<SimpleLanguageServer> languageServerFactory) throws IOException, InterruptedException {
|
||||
LaunguageServerApp app = new LaunguageServerApp() {
|
||||
@Override
|
||||
protected SimpleLanguageServer createServer() {
|
||||
return languageServerFactory.get();
|
||||
}
|
||||
};
|
||||
app.startAsServer();
|
||||
}
|
||||
|
||||
protected static class Connection {
|
||||
@@ -112,7 +139,50 @@ public abstract class LaunguageServerApp {
|
||||
}
|
||||
}
|
||||
|
||||
private static Connection connectToNode() throws IOException {
|
||||
/**
|
||||
* starts up the language server and let it listen for connections from the outside
|
||||
* instead of connecting itself to an existing port or channel.
|
||||
*
|
||||
* This is meant for development only, to reduce turnaround times while working
|
||||
* on the language server from within an IDE, so that you can start the language
|
||||
* server right away in debug mode and let the vscode extension connect to that
|
||||
* instance instead of vice versa.
|
||||
*
|
||||
* Source of inspiration:
|
||||
* https://github.com/itemis/xtext-languageserver-example/blob/master/org.xtext.example.mydsl.ide/src/org/xtext/example/mydsl/ide/RunServer.java
|
||||
*/
|
||||
public void startAsServer() throws IOException, InterruptedException {
|
||||
LOG.info("Starting LS as standlone server");
|
||||
|
||||
Function<MessageConsumer, MessageConsumer> wrapper = consumer -> {
|
||||
MessageConsumer result = consumer;
|
||||
return result;
|
||||
};
|
||||
|
||||
SimpleLanguageServer languageServer = createServer();
|
||||
Launcher<STS4LanguageClient> launcher = createSocketLauncher(languageServer, STS4LanguageClient.class,
|
||||
new InetSocketAddress("localhost", SERVER_STANDALONE_PORT), Executors.newCachedThreadPool(), wrapper);
|
||||
|
||||
languageServer.connect(launcher.getRemoteProxy());
|
||||
Future<?> future = launcher.startListening();
|
||||
while (!future.isDone()) {
|
||||
Thread.sleep(10_000l);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> Launcher<T> createSocketLauncher(Object localService, Class<T> remoteInterface, SocketAddress socketAddress, ExecutorService executorService, Function<MessageConsumer, MessageConsumer> wrapper) throws IOException {
|
||||
AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open().bind(socketAddress);
|
||||
AsynchronousSocketChannel socketChannel;
|
||||
try {
|
||||
socketChannel = serverSocket.accept().get();
|
||||
return Launcher.createIoLauncher(localService, remoteInterface, Channels.newInputStream(socketChannel), Channels.newOutputStream(socketChannel), executorService, wrapper);
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Connection connectToNode() throws IOException {
|
||||
String port = System.getProperty("server.port");
|
||||
|
||||
if (port != null) {
|
||||
@@ -172,7 +242,7 @@ public abstract class LaunguageServerApp {
|
||||
launcher.startListening().get();
|
||||
}
|
||||
|
||||
protected abstract LanguageServer createServer();
|
||||
protected abstract SimpleLanguageServer createServer();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Pivotal, Inc.
|
||||
* Copyright (c) 2016, 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
|
||||
@@ -23,7 +23,7 @@ import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguage
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
LaunguageServerApp.start(() -> {
|
||||
JavaProjectFinder javaProjectFinder = BootJavaLanguageServer.DEFAULT_PROJECT_FINDER;
|
||||
SimpleLanguageServer server = new BootJavaLanguageServer(javaProjectFinder);
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
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;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.lsp4j.jsonrpc.Launcher;
|
||||
import org.eclipse.lsp4j.jsonrpc.MessageConsumer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.STS4LanguageClient;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
|
||||
/**
|
||||
* starts up the language server and let it listen for connections from the outside
|
||||
* instead of connecting itself to an existing port or channel.
|
||||
*
|
||||
* This is meant for development only, to reduce turnaround times while working
|
||||
* on the language server from within an IDE, so that you can start the language
|
||||
* server right away in debug mode and let the vscode extension connect to that
|
||||
* instance instead of vice versa.
|
||||
*
|
||||
* Source of inspiration:
|
||||
* https://github.com/itemis/xtext-languageserver-example/blob/master/org.xtext.example.mydsl.ide/src/org/xtext/example/mydsl/ide/RunServer.java
|
||||
*
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class StartupServer {
|
||||
|
||||
public static void main(String[] args) throws InterruptedException, IOException {
|
||||
|
||||
JavaProjectFinder javaProjectFinder = BootJavaLanguageServer.DEFAULT_PROJECT_FINDER;
|
||||
SimpleLanguageServer languageServer = new BootJavaLanguageServer(javaProjectFinder);
|
||||
|
||||
Function<MessageConsumer, MessageConsumer> wrapper = consumer -> {
|
||||
MessageConsumer result = consumer;
|
||||
return result;
|
||||
};
|
||||
|
||||
Launcher<STS4LanguageClient> launcher = createSocketLauncher(languageServer, STS4LanguageClient.class, new InetSocketAddress("localhost", 5007), Executors.newCachedThreadPool(), wrapper);
|
||||
|
||||
languageServer.connect(launcher.getRemoteProxy());
|
||||
Future<?> future = launcher.startListening();
|
||||
while (!future.isDone()) {
|
||||
Thread.sleep(10_000l);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> Launcher<T> createSocketLauncher(Object localService, Class<T> remoteInterface, SocketAddress socketAddress, ExecutorService executorService, Function<MessageConsumer, MessageConsumer> wrapper) throws IOException {
|
||||
AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open().bind(socketAddress);
|
||||
AsynchronousSocketChannel socketChannel;
|
||||
try {
|
||||
socketChannel = serverSocket.accept().get();
|
||||
return Launcher.createIoLauncher(localService, remoteInterface, Channels.newInputStream(socketChannel), Channels.newOutputStream(socketChannel), executorService, wrapper);
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,7 +29,7 @@ import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
LaunguageServerApp.start(() -> {
|
||||
JavaProjectFinder javaProjectFinder = BootPropertiesLanguageServer.DEFAULT_PROJECT_FINDER;
|
||||
DefaultSpringPropertyIndexProvider indexProvider = new DefaultSpringPropertyIndexProvider(javaProjectFinder);
|
||||
|
||||
@@ -19,7 +19,7 @@ import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguage
|
||||
public class Main {
|
||||
SimpleLanguageServer server = new ConcourseLanguageServer();
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
LaunguageServerApp.start(ConcourseLanguageServer::new);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguage
|
||||
public class Main {
|
||||
SimpleLanguageServer server = new ManifestYamlLanguageServer();
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
LaunguageServerApp.start(ManifestYamlLanguageServer::new);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user