Skip to content

Commit

Permalink
Implements socket based connection
Browse files Browse the repository at this point in the history
Implementation of transport using plain sockets.
  • Loading branch information
gorkem committed Oct 5, 2016
1 parent 33a0cc8 commit 4909082
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 16 deletions.
41 changes: 33 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
[![Build Status](https://travis-ci.org/gorkem/java-language-server.svg?branch=master)](https://travis-ci.org/gorkem/java-language-server)

This repository contains only the server implementation.
This repository contains only the server implementation.
For Visual Studio Code extension that uses this server visit
[vscode-java](https://github.com/gorkem/vscode-java)
=========================

java-language-server
java-language-server
=====================

java-language-server is a server implementation that provides Java language smartness.
The server adheres to the [language server protocol](https://github.com/Microsoft/language-server-protocol)
and can be used with any editor that supports the protocol. The server utilizes [Eclipse
The server adheres to the [language server protocol](https://github.com/Microsoft/language-server-protocol)
and can be used with any editor that supports the protocol. The server utilizes [Eclipse
JDT](http://www.eclipse.org/jdt/), [M2Eeclipse](http://www.eclipse.org/m2e/).

Features
Features
--------------
* As you type reporting of parsing and compilation errors
* Code completion
* Javadoc hovers
* Javadoc hovers
* Code outline
* Code navigation
* Code lens (references)
Expand All @@ -30,7 +30,7 @@ First Time Setup
--------------
0. Fork and clone the repository
1. Install Eclipse [Neon Java EE](http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/neonr)
that will have most needed already installed. Alternately,
that will have most needed already installed. Alternately,
you can get the [Eclipse IDE for Java developers](http://www.eclipse.org/downloads/packages/eclipse-ide-java-developers/neonr)
and just instal Eclipse PDE from marketplace.

Expand All @@ -49,9 +49,34 @@ Building from command line

2. This command will build the server into `/org.jboss.tools.vscode.product/target/repository` folder:
```bash
$ mvn clean verify
$ mvn clean verify
````

Managing connection types
-------------------------
Java Language server supports socket and named pipes to communicate with the client.
Client can communicate its preferred connection methods by setting up environment
variables
* For using named pipes set the following environment variables before starting
the server.
```
STDIN_PIPE_NAME --> where client reads from
STDOUT_PIPE_NAME --> where client writes to
```
* For using plain sockets set the following environment variables before starting the
server.
```
STDIN_PORT --> client reads
STDOUT_PORT --> client writes to
```
optionally you can set host values for socket connections
```
STDIN_HOST
STDOUT_HOST
```
For both connection types the client is expected to create the connections
and wait for server the connect.
Feedback
---------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.jboss.tools.langs.base.ResponseError.ReservedCode;
import org.jboss.tools.langs.transport.Connection;
import org.jboss.tools.langs.transport.NamedPipeConnection;
import org.jboss.tools.langs.transport.SocketConnection;
import org.jboss.tools.langs.transport.TransportMessage;
import org.jboss.tools.vscode.internal.ipc.CancelMonitor;
import org.jboss.tools.vscode.internal.ipc.NotificationHandler;
Expand Down Expand Up @@ -145,20 +146,34 @@ protected LSPServer(){
public void connect() throws IOException{
this.notificationHandlers = buildNotificationHandlers();
this.requestHandlers = buildRequestHandlers();

final String stdInName = System.getenv("STDIN_PIPE_NAME");
final String stdOutName = System.getenv("STDOUT_PIPE_NAME");
if (stdInName == null || stdOutName == null) {
//XXX temporary hack to let unit tests run
System.err.println("Unable to connect to named pipes");
initExecutor();
connection = initConnection();
if(connection == null ){
//Temporary for tests to run
System.err.println("Failied to initialize connection");
return;
}
initExecutor();
connection = new NamedPipeConnection(stdOutName, stdInName);
connection.start();
startDispatching();
}


private Connection initConnection(){
final String stdInName = System.getenv("STDIN_PIPE_NAME");
final String stdOutName = System.getenv("STDOUT_PIPE_NAME");
if (stdInName != null && stdOutName != null) {
return new NamedPipeConnection(stdOutName, stdInName);
}
final String wHost = System.getenv().getOrDefault("STDIN_HOST","localhost");
final String rHost = System.getenv().getOrDefault("STDOUT_HOST","localhost");
final String wPort = System.getenv().get("STDIN_PORT");
final String rPort = System.getenv().get("STDOUT_PORT");
if(rPort != null && wPort != null ){
return new SocketConnection(rHost, Integer.parseInt(rPort), wHost, Integer.parseInt(wPort));
}
return null;
}

/**
*
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*******************************************************************************
* Copyright (c) 2016 Red Hat Inc. and others.
* 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:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package org.jboss.tools.langs.transport;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;

import org.jboss.tools.vscode.internal.ipc.IPCPlugin;

public class SocketConnection extends AbstractConnection {


private class ReaderThread extends Thread{

private InputStream stream;

public ReaderThread() {
super("LSP_ReaderThread");
}

@Override
public void run() {
try {
stream = connectReadChannel();
startWriterThread();
} catch (IOException e1) {
//TODO: write failed to connect.
}

while(true){
TransportMessage message;
try {
message = TransportMessage.fromStream(stream, DEFAULT_CHARSET);
if(message == null ){
//Stream disconnected exit reader thread
IPCPlugin.logError("Empty message read");
break;
}
inboundQueue.add(message);
} catch (IOException e) {
//continue
}
}
}
}

private class WriterThread extends Thread{

private OutputStream stream;

public WriterThread() {
super("LSP_WriterThread");
}

@Override
public void run() {
try {
stream = connectWriteChannel();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while (true) {
try {
TransportMessage message = outboundQueue.take();
message.send(stream, DEFAULT_CHARSET);
stream.flush();
} catch (InterruptedException e) {
break;//exit
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

private final String readHost;
private final String writeHost;
private final int readPort;
private final int writePort;

private Socket writeSocket;
private Socket readSocket;

private ServerSocket server;

public SocketConnection(String readHost, int readPort , String writeHost, int writePort) {
this.readHost = readHost;
this.readPort = readPort;
this.writeHost = writeHost;
this.writePort = writePort;
}

@Override
public void start() throws IOException {
ReaderThread readerThread = new ReaderThread();
readerThread.setDaemon(true);
readerThread.start();
}

public void startWriterThread() throws IOException{

WriterThread writerThread = new WriterThread();
writerThread.setDaemon(true);
writerThread.start();
}

@Override
public void close() {
try {
if(readSocket != null)
readSocket.close();
if(writeSocket != null )
writeSocket.close();
if(server != null)
server.close();
} catch (IOException e) {
// TODO: handle exception
}
}

private InputStream connectReadChannel() throws IOException{
readSocket = new Socket(readHost,readPort);
return readSocket.getInputStream();
}

private OutputStream connectWriteChannel() throws IOException{
writeSocket = new Socket(writeHost, writePort);
return writeSocket.getOutputStream();

}

}

0 comments on commit 4909082

Please sign in to comment.