@Override public LanguageServer get(LanguageClient client, InputStream in, OutputStream out) { Launcher<LanguageServer> launcher = createLauncher(client, LanguageServer.class, in, out); LOG.debug("Created launcher for language server"); launcher.startListening(); LOG.debug("Started listening"); LanguageServer remoteProxy = launcher.getRemoteProxy(); LOG.debug("Got remote proxy"); return remoteProxy; }
private void startConnection() throws IOException { Launcher<JavaLanguageClient> launcher; ExecutorService executorService = Executors.newCachedThreadPool(); protocol = new JDTLanguageServer(projectsManager, preferenceManager); if (JDTEnvironmentUtils.inSocketStreamDebugMode()) { String host = JDTEnvironmentUtils.getClientHost(); Integer port = JDTEnvironmentUtils.getClientPort(); InetSocketAddress inetSocketAddress = new InetSocketAddress(host, port); AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open().bind(inetSocketAddress); try { AsynchronousSocketChannel socketChannel = serverSocket.accept().get(); InputStream in = Channels.newInputStream(socketChannel); OutputStream out = Channels.newOutputStream(socketChannel); Function<MessageConsumer, MessageConsumer> messageConsumer = it -> it; launcher = Launcher.createIoLauncher(protocol, JavaLanguageClient.class, in, out, executorService, messageConsumer); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException("Error when opening a socket channel at " + host + ":" + port + ".", e); } } else { ConnectionStreamFactory connectionFactory = new ConnectionStreamFactory(); InputStream in = connectionFactory.getInputStream(); OutputStream out = connectionFactory.getOutputStream(); Function<MessageConsumer, MessageConsumer> wrapper = new ParentProcessWatcher(this.languageServer); launcher = Launcher.createLauncher(protocol, JavaLanguageClient.class, in, out, executorService, wrapper); } protocol.connectClient(launcher.getRemoteProxy()); launcher.startListening(); }
private void handleConnection(final Socket client) { logger.debug("Client {} connected", client.getRemoteSocketAddress()); try { LanguageServerImpl languageServer = injector.getInstance(LanguageServerImpl.class); Launcher<LanguageClient> launcher = LSPLauncher.createServerLauncher(languageServer, client.getInputStream(), client.getOutputStream()); languageServer.connect(launcher.getRemoteProxy()); Future<?> future = launcher.startListening(); future.get(); } catch (IOException e) { logger.warn("Error communicating with LSP client {}", client.getRemoteSocketAddress()); } catch (InterruptedException e) { // go on, let the thread finish } catch (ExecutionException e) { logger.error("Error running the Language Server", e); } logger.debug("Client {} disconnected", client.getRemoteSocketAddress()); }
public void run() throws IOException, InterruptedException, ExecutionException { Injector injector = Guice.createInjector(module); GsonConfigurator gsonConf = injector.getInstance(GsonConfigurator.class); AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open() .bind(new InetSocketAddress(host, port)); ExecutorService threadPool = Executors.newCachedThreadPool(); log.info("The graphical server launcher is ready to accept new client requests"); while (true) { AsynchronousSocketChannel socketChannel = serverSocket.accept().get(); InputStream in = Channels.newInputStream(socketChannel); OutputStream out = Channels.newOutputStream(socketChannel); Consumer<GsonBuilder> configureGson = (GsonBuilder builder) -> gsonConf.configureGsonBuilder(builder); Function<MessageConsumer, MessageConsumer> wrapper = (MessageConsumer it) -> { return it; }; GLSPServer languageServer = injector.getInstance(GLSPServer.class); Launcher<GLSPClient> launcher = Launcher.createIoLauncher(languageServer, GLSPClient.class, in, out, threadPool, wrapper, configureGson); languageServer.connect(launcher.getRemoteProxy()); launcher.startListening(); log.info("Started language server for client " + socketChannel.getRemoteAddress()); } } }
@Test public void testDone() throws Exception { A a = new A() { @Override public void say(Param p) { } }; Launcher<A> launcher = Launcher.createLauncher(a, A.class, new ByteArrayInputStream("".getBytes()), new ByteArrayOutputStream()); Future<?> startListening = launcher.startListening(); startListening.get(TIMEOUT, TimeUnit.MILLISECONDS); Assert.assertTrue(startListening.isDone()); Assert.assertFalse(startListening.isCancelled()); }
@Test public void testDone() throws Exception { A a = new A() { @Override public void say(Param p) { } }; Launcher<A> launcher = DebugLauncher.createLauncher(a, A.class, new ByteArrayInputStream("".getBytes()), new ByteArrayOutputStream()); Future<?> startListening = launcher.startListening(); startListening.get(TIMEOUT, TimeUnit.MILLISECONDS); Assert.assertTrue(startListening.isDone()); Assert.assertFalse(startListening.isCancelled()); }
@Test public void testCustomGson() throws Exception { A a = new A() { @Override public void say(Param p) { } }; ByteArrayOutputStream out = new ByteArrayOutputStream(); TypeAdapter<Param> typeAdapter = new TypeAdapter<Param>() { @Override public void write(JsonWriter out, Param value) throws IOException { out.beginObject(); out.name("message"); out.value("bar"); out.endObject(); } @Override public Param read(JsonReader in) throws IOException { return null; } }; Launcher<A> launcher = DebugLauncher.createIoLauncher(a, A.class, new ByteArrayInputStream("".getBytes()), out, Executors.newCachedThreadPool(), c -> c, gsonBuilder -> {gsonBuilder.registerTypeAdapter(Param.class, typeAdapter);}); A remoteProxy = launcher.getRemoteProxy(); remoteProxy.say(new Param("foo")); Assert.assertEquals("Content-Length: 63\r\n\r\n" + "{\"type\":\"event\",\"seq\":1,\"event\":\"say\",\"body\":{\"message\":\"bar\"}}", out.toString()); }
Launcher<A> launcher = Launcher.createIoLauncher(a, A.class, new ByteArrayInputStream("".getBytes()), out, Executors.newCachedThreadPool(), c -> c, gsonBuilder -> {gsonBuilder.registerTypeAdapter(Param.class, typeAdapter);}); A remoteProxy = launcher.getRemoteProxy();
/** * Create a new Launcher for a given local service object, a given remote interface and an input and output stream. * Threads are started with the given executor service. The wrapper function is applied to the incoming and * outgoing message streams so additional message handling such as validation and tracing can be included. * * @param localService - the object that receives method calls from the remote service * @param remoteInterface - an interface on which RPC methods are looked up * @param in - input stream to listen for incoming messages * @param out - output stream to send outgoing messages * @param executorService - the executor service used to start threads * @param wrapper - a function for plugging in additional message consumers */ static <T> Launcher<T> createLauncher(Object localService, Class<T> remoteInterface, InputStream in, OutputStream out, ExecutorService executorService, Function<MessageConsumer, MessageConsumer> wrapper) { return createIoLauncher(localService, remoteInterface, in, out, executorService, wrapper); }
@SuppressFBWarnings("DM_DEFAULT_ENCODING") public void launch() { Function<MessageConsumer, MessageConsumer> loggingMessageConsumerAdapter = consumer -> { return message -> { log.debug("Message received to client: {}", message); consumer.consume(message); }; }; Launcher<LanguageClient> serverLauncher = LSPLauncher.createServerLauncher( languageServer, inputStream, outputStream, Executors.newCachedThreadPool(), loggingMessageConsumerAdapter); if (languageServer instanceof LanguageClientAware) { LanguageClient client = serverLauncher.getRemoteProxy(); ((LanguageClientAware) languageServer).connect(client); } serverLauncher.startListening(); } }
@Test public void testResponse2() throws Exception { // create client message String requestMessage = "{\"jsonrpc\": \"2.0\",\n" + "\"id\": 42,\n" + "\"method\": \"askServer\",\n" + "\"params\": { \"value\": \"bar\" }\n" + "}"; String clientMessage = getHeader(requestMessage.getBytes().length) + requestMessage; // create server side ByteArrayInputStream in = new ByteArrayInputStream(clientMessage.getBytes()); ByteArrayOutputStream out = new ByteArrayOutputStream(); MyServer server = new MyServerImpl(); Launcher<MyClient> serverSideLauncher = Launcher.createLauncher(server, MyClient.class, in, out); serverSideLauncher.startListening().get(TIMEOUT, TimeUnit.MILLISECONDS); Assert.assertEquals("Content-Length: 50" + CRLF + CRLF + "{\"jsonrpc\":\"2.0\",\"id\":42,\"result\":{\"value\":\"bar\"}}", out.toString()); }
Launcher<Object> launcher = Launcher.createIoLauncher(Arrays.asList(a, b), Arrays.asList(A.class, B.class), classLoader, in, out, Executors.newCachedThreadPool(), c -> c, null); launcher.startListening().get(TIMEOUT, TimeUnit.MILLISECONDS); assertEquals("foo1", paramA[0]); assertEquals("bar1", paramB[0]); Object remoteProxy = launcher.getRemoteProxy(); ((A) remoteProxy).say(new Param("foo2")); ((B) remoteProxy).ask(new Param("bar2"));
@Test public void testDebugServerCanBeLaunched() throws IOException { TestDebugServer testDebugServer = new TestDebugServer(); Launcher<IDebugProtocolClient> launcher = DSPLauncher.createServerLauncher(testDebugServer, new PipedInputStream(), new PipedOutputStream()); Future<Void> listening = launcher.startListening(); listening.cancel(true); } }
@Test public void testNotification() throws IOException { OutputEventArguments p = new OutputEventArguments(); p.setOutput("Hello World"); client.expectedNotifications.put("output", p); serverLauncher.getRemoteProxy().output(p); client.joinOnEmpty(); }
/** * Create a new Launcher for a given local service object, a given remote interface and an input and output stream. * Threads are started with the given executor service. The wrapper function is applied to the incoming and * outgoing message streams so additional message handling such as validation and tracing can be included. * * @param localService - the object that receives method calls from the remote service * @param remoteInterface - an interface on which RPC methods are looked up * @param in - input stream to listen for incoming messages * @param out - output stream to send outgoing messages * @param executorService - the executor service used to start threads * @param wrapper - a function for plugging in additional message consumers */ static <T> Launcher<T> createLauncher(Object localService, Class<T> remoteInterface, InputStream in, OutputStream out, ExecutorService executorService, Function<MessageConsumer, MessageConsumer> wrapper) { return createIoLauncher(localService, remoteInterface, in, out, executorService, wrapper); }
private Future<Void> runAsync(Connection connection) throws Exception { LanguageServer server = this.languageServer; ExecutorService executor = createServerThreads(); Function<MessageConsumer, MessageConsumer> wrapper = (MessageConsumer consumer) -> { return (msg) -> { try { consumer.consume(msg); } catch (UnsupportedOperationException e) { //log a warning and ignore. We are getting some messages from vsCode the server doesn't know about log.warn("Unsupported message was ignored!", e); } }; }; Launcher<STS4LanguageClient> launcher = Launcher.createLauncher(server, STS4LanguageClient.class, connection.in, connection.out, executor, wrapper ); if (server instanceof LanguageClientAware) { LanguageClient client = launcher.getRemoteProxy(); ((LanguageClientAware) server).connect(client); } return launcher.startListening(); }
/** * 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 Exception { int serverPort = properties.getStandalonePort(); log.info("Starting LS as standlone server port = {}", serverPort); Function<MessageConsumer, MessageConsumer> wrapper = consumer -> { MessageConsumer result = consumer; return result; }; Launcher<STS4LanguageClient> launcher = createSocketLauncher(languageServer, STS4LanguageClient.class, new InetSocketAddress("localhost", serverPort), createServerThreads(), wrapper); languageServer.connect(launcher.getRemoteProxy()); launcher.startListening().get(); }
@Test public void testEither() throws Exception { // create client message String requestMessage = "{\"jsonrpc\": \"2.0\",\n" + "\"id\": 42,\n" + "\"method\": \"askServer\",\n" + "\"params\": { \"either\": \"bar\", \"value\": \"foo\" }\n" + "}"; String clientMessage = getHeader(requestMessage.getBytes().length) + requestMessage; // create server side ByteArrayInputStream in = new ByteArrayInputStream(clientMessage.getBytes()); ByteArrayOutputStream out = new ByteArrayOutputStream(); MyServer server = new MyServerImpl(); Launcher<MyClient> serverSideLauncher = Launcher.createLauncher(server, MyClient.class, in, out); serverSideLauncher.startListening().get(TIMEOUT, TimeUnit.MILLISECONDS); Assert.assertEquals("Content-Length: 65" + CRLF + CRLF + "{\"jsonrpc\":\"2.0\",\"id\":42,\"result\":{\"value\":\"foo\",\"either\":\"bar\"}}", out.toString()); }
@Test public void testResponse() throws Exception { String clientMessage = "{\"type\":\"request\"," + "\"seq\":1,\n" + "\"command\":\"askServer\",\n" + " \"arguments\": { value: \"bar\" }\n" + "}"; String clientMessages = getHeader(clientMessage.getBytes().length) + clientMessage; // create server side ByteArrayInputStream in = new ByteArrayInputStream(clientMessages.getBytes()); ByteArrayOutputStream out = new ByteArrayOutputStream(); MyServer server = new MyServer() { @Override public CompletableFuture<MyParam> askServer(MyParam param) { return CompletableFuture.completedFuture(param); } }; Launcher<MyClient> serverSideLauncher = DebugLauncher.createLauncher(server, MyClient.class, in, out); serverSideLauncher.startListening().get(TIMEOUT, TimeUnit.MILLISECONDS); Assert.assertEquals("Content-Length: 103\r\n\r\n" + "{\"type\":\"response\",\"seq\":1,\"request_seq\":1,\"command\":\"askServer\",\"success\":true,\"body\":{\"value\":\"bar\"}}", out.toString()); }
@Test public void testNotification() throws IOException { MessageParams p = new MessageParams(); p.setMessage("Hello World"); p.setType(MessageType.Info); client.expectedNotifications.put("window/logMessage", p); serverLauncher.getRemoteProxy().logMessage(p); client.joinOnEmpty(); }