@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 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()); }
@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(); } }
/** * 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 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 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 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 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 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()); }
@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()); }
@Before public void setup() throws IOException { PipedInputStream inClient = new PipedInputStream(); PipedOutputStream outClient = new PipedOutputStream(); PipedInputStream inServer = new PipedInputStream(); PipedOutputStream outServer = new PipedOutputStream(); inClient.connect(outServer); outClient.connect(inServer); server = new AssertingEndpoint(); serverLauncher = LSPLauncher.createServerLauncher(ServiceEndpoints.toServiceObject(server, LanguageServer.class), inServer, outServer); serverListening = serverLauncher.startListening(); client = new AssertingEndpoint(); clientLauncher = LSPLauncher.createClientLauncher(ServiceEndpoints.toServiceObject(client, LanguageClient.class), inClient, outClient); clientListening = clientLauncher.startListening(); Logger logger = Logger.getLogger(StreamMessageProducer.class.getName()); logLevel = logger.getLevel(); logger.setLevel(Level.SEVERE); }
@Test public void testResponse1() 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: 52" + CRLF + CRLF + "{\"jsonrpc\":\"2.0\",\"id\":\"42\",\"result\":{\"value\":\"bar\"}}", out.toString()); }
@Test public void testEitherNull() throws Exception { // create client message String requestMessage = "{\"jsonrpc\": \"2.0\",\n" + "\"id\": 42,\n" + "\"method\": \"askServer\",\n" + "\"params\": { \"either\": null, \"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: 50" + CRLF + CRLF + "{\"jsonrpc\":\"2.0\",\"id\":42,\"result\":{\"value\":\"foo\"}}", out.toString()); }
@Test public void testValidationIssue2() throws Exception { String requestMessage1 = "{\"jsonrpc\": \"2.0\",\n" + "\"id\": \"1\",\n" + "\"method\": \"askServer\",\n" + "\"params\": { \"value\": null, \"nested\": { \"value\": null } }\n" + "}"; String clientMessages = getHeader(requestMessage1.getBytes().length) + requestMessage1; ByteArrayInputStream in = new ByteArrayInputStream(clientMessages.getBytes()); ByteArrayOutputStream out = new ByteArrayOutputStream(); MyServer server = new MyServerImpl(); Launcher<MyClient> serverSideLauncher = Launcher.createLauncher(server, MyClient.class, in, out, true, null); serverSideLauncher.startListening().get(TIMEOUT, TimeUnit.MILLISECONDS); Assert.assertEquals("Content-Length: 379" + CRLF + CRLF + "{\"jsonrpc\":\"2.0\",\"id\":\"1\",\"error\":{\"code\":-32600,\"message\":\"Multiple issues were found in \\u0027askServer\\u0027 request.\"," + "\"data\":[" + "{\"text\":\"The accessor \\u0027MyParam.getValue()\\u0027 must return a non-null value. Path: $.params.nested.value\",\"code\":-32602}," + "{\"text\":\"The accessor \\u0027MyParam.getValue()\\u0027 must return a non-null value. Path: $.params.value\",\"code\":-32602}" + "]}}", out.toString()); }
@Before public void setup() throws IOException { PipedInputStream inClient = new PipedInputStream(); PipedOutputStream outClient = new PipedOutputStream(); PipedInputStream inServer = new PipedInputStream(); PipedOutputStream outServer = new PipedOutputStream(); inClient.connect(outServer); outClient.connect(inServer); server = new AssertingEndpoint(); serverLauncher = DSPLauncher.createServerLauncher( ServiceEndpoints.toServiceObject(server, IDebugProtocolServer.class), inServer, outServer); serverListening = serverLauncher.startListening(); client = new AssertingEndpoint(); clientLauncher = DSPLauncher.createClientLauncher( ServiceEndpoints.toServiceObject(client, IDebugProtocolClient.class), inClient, outClient); clientListening = clientLauncher.startListening(); Logger logger = Logger.getLogger(StreamMessageProducer.class.getName()); logLevel = logger.getLevel(); logger.setLevel(Level.SEVERE); }
@Test public void testCanceled() throws Exception { A a = new A() { @Override public void say(Param p) { } }; Launcher<A> launcher = Launcher.createLauncher(a, A.class, new InputStream() { @Override public int read() throws IOException { try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } return '\n'; } }, new ByteArrayOutputStream()); Future<?> startListening = launcher.startListening(); startListening.cancel(true); Assert.assertTrue(startListening.isDone()); Assert.assertTrue(startListening.isCancelled()); }
@Test public void testMalformedJson1() throws Exception { String requestMessage1 = "{\"jsonrpc\": \"2.0\",\n" + "\"id\": \"1\",\n" + "\"method\": \"askServer\",\n" + "\"params\": { \"value\": }\n" + "}"; String requestMessage2 = "{\"jsonrpc\": \"2.0\",\n" + "\"id\": \"2\",\n" + "\"method\": \"askServer\",\n" + "\"params\": { \"value\": \"bar\" }\n" + "}"; String clientMessages = getHeader(requestMessage1.getBytes().length) + requestMessage1 + getHeader(requestMessage2.getBytes().length) + requestMessage2; ByteArrayInputStream in = new ByteArrayInputStream(clientMessages.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: 214" + CRLF + CRLF + "{\"jsonrpc\":\"2.0\",\"id\":\"1\",\"error\":{\"code\":-32700,\"message\":\"Message could not be parsed.\"," + "\"data\":{\"message\":\"com.google.gson.stream.MalformedJsonException: Expected value at line 4 column 22 path $.params.value\"}}}" + "Content-Length: 51" + CRLF + CRLF + "{\"jsonrpc\":\"2.0\",\"id\":\"2\",\"result\":{\"value\":\"bar\"}}", out.toString()); }
@Test public void testCanceled() throws Exception { A a = new A() { @Override public void say(Param p) { } }; Launcher<A> launcher = DebugLauncher.createLauncher(a, A.class, new InputStream() { @Override public int read() throws IOException { try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } return '\n'; } }, new ByteArrayOutputStream()); Future<?> startListening = launcher.startListening(); startListening.cancel(true); Assert.assertTrue(startListening.isDone()); Assert.assertTrue(startListening.isCancelled()); }
private void createAndLaunchLanguageServer(final InputStream in, final OutputStream out) { new Thread(() -> { LanguageServerState state = new DefaultLanguageServerState(); actualServer = new GroovyLanguageServer( state, new DefaultTextDocumentService(state), new DefaultWorkspaceService(state)); Launcher<LanguageClient> launcher = LSPLauncher.createServerLauncher( actualServer, in, out, false, new PrintWriter(System.out)); launcher.startListening(); }).start(); }
@Test public void testBothDirectionRequests() throws Exception { // create client side PipedInputStream in = new PipedInputStream(); PipedOutputStream out = new PipedOutputStream(); PipedInputStream in2 = new PipedInputStream(); PipedOutputStream out2 = new PipedOutputStream(); in.connect(out2); out.connect(in2); MyClient client = new MyClientImpl(); Launcher<MyServer> clientSideLauncher = Launcher.createLauncher(client, MyServer.class, in, out); // create server side MyServer server = new MyServerImpl(); Launcher<MyClient> serverSideLauncher = Launcher.createLauncher(server, MyClient.class, in2, out2); clientSideLauncher.startListening(); serverSideLauncher.startListening(); CompletableFuture<MyParam> fooFuture = clientSideLauncher.getRemoteProxy().askServer(new MyParam("FOO")); CompletableFuture<MyParam> barFuture = serverSideLauncher.getRemoteProxy().askClient(new MyParam("BAR")); Assert.assertEquals("FOO", fooFuture.get(TIMEOUT, TimeUnit.MILLISECONDS).value); Assert.assertEquals("BAR", barFuture.get(TIMEOUT, TimeUnit.MILLISECONDS).value); }