Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 38 additions & 12 deletions server/src/main/java/com/microsoft/java/bs/core/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import com.microsoft.java.bs.core.internal.gradle.GradleApiConnector;
import com.microsoft.java.bs.core.internal.log.LogHandler;
Expand All @@ -15,7 +18,7 @@
import com.microsoft.java.bs.core.internal.server.GradleBuildServer;
import com.microsoft.java.bs.core.internal.services.BuildTargetService;
import com.microsoft.java.bs.core.internal.services.LifecycleService;

import com.microsoft.java.bs.core.internal.utils.ServerNamedPipeStream;
import ch.epfl.scala.bsp4j.BuildClient;

/**
Expand All @@ -26,7 +29,8 @@ public class Launcher {
public static final Logger LOGGER = Logger.getLogger("GradleBuildServerLogger");

/**
* The property name for the directory location storing the plugin and init script.
* The property name for the directory location storing the plugin and init
* script.
Comment thread
Jiaaming marked this conversation as resolved.
Outdated
*/
public static final String PROP_PLUGIN_DIR = "plugin.dir";

Expand All @@ -36,12 +40,34 @@ public class Launcher {
public static void main(String[] args) {
checkRequiredProperties();

org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient> launcher = createLauncher();
org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient> launcher;
if (args.length > 0 && args[0] != null && !args[0].isEmpty()) {
Comment thread
Jiaaming marked this conversation as resolved.
Outdated
launcher = createLauncherUsingPipe(args[0]);
} else {
launcher = createLauncherUsingStdIo();
}

setupLoggers(launcher.getRemoteProxy());
launcher.startListening();
}

private static org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient> createLauncher() {
private static org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient>
createLauncherUsingPipe(String pipePath) {
ServerNamedPipeStream pipeStream = new ServerNamedPipeStream(pipePath);
try {
return createLauncher(pipeStream.getOutputStream(), pipeStream.getInputStream());
} catch (IOException e) {
throw new IllegalStateException("Error initializing the named pipe", e);
}
}

private static org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient> createLauncherUsingStdIo() {
return createLauncher(System.out, System.in);
}

private static org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient>
createLauncher(OutputStream outputStream,
InputStream inputStream) {
BuildTargetManager buildTargetManager = new BuildTargetManager();
PreferenceManager preferenceManager = new PreferenceManager();
GradleApiConnector connector = new GradleApiConnector(preferenceManager);
Expand All @@ -50,14 +76,14 @@ private static org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient> createLauncher()
connector, preferenceManager);
GradleBuildServer gradleBuildServer = new GradleBuildServer(lifecycleService,
buildTargetService);
org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient> launcher =
new org.eclipse.lsp4j.jsonrpc.Launcher.Builder<BuildClient>()
.setOutput(System.out)
.setInput(System.in)
.setLocalService(gradleBuildServer)
.setRemoteInterface(BuildClient.class)
.setExecutorService(Executors.newCachedThreadPool())
.create();
org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient> launcher = new
org.eclipse.lsp4j.jsonrpc.Launcher.Builder<BuildClient>()
.setOutput(outputStream)
.setInput(inputStream)
.setLocalService(gradleBuildServer)
.setRemoteInterface(BuildClient.class)
.setExecutorService(Executors.newCachedThreadPool())
.create();
buildTargetService.setClient(launcher.getRemoteProxy());
return launcher;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

package com.microsoft.java.bs.core.internal.utils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.StandardProtocolFamily;
import java.net.UnixDomainSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
* A factory for creating the streams for supported transmission methods.
*
* @author Gorkem Ercan
*
*/

public class ServerNamedPipeStream {
Comment thread
Jiaaming marked this conversation as resolved.
Outdated
private String pipeName;
private StreamProvider provider;

public ServerNamedPipeStream(String pipeName) {
this.pipeName = pipeName;
}

interface StreamProvider {
InputStream getInputStream() throws IOException;

OutputStream getOutputStream() throws IOException;
}

/**
* PipeStreamProvider.
*/
protected final class PipeStreamProvider implements StreamProvider {

private InputStream input;
private OutputStream output;
private String pipeName = ServerNamedPipeStream.this.pipeName;

public PipeStreamProvider() {
initializeNamedPipe();
}

@Override
public InputStream getInputStream() throws IOException {
return input;
}

@Override
public OutputStream getOutputStream() throws IOException {
return output;
}

private void initializeNamedPipe() {
File pipeFile = new File(this.pipeName);
if (isWindows()) {
try {
AsynchronousFileChannel clientChannel = AsynchronousFileChannel.open(
pipeFile.toPath(),
StandardOpenOption.READ,
StandardOpenOption.WRITE);
input = new NamedPipeInputStream(clientChannel);
output = new NamedPipeOutputStream(clientChannel);
} catch (IOException e) {
e.printStackTrace();
}
return;
}

try {
UnixDomainSocketAddress socketAddress = UnixDomainSocketAddress.of(pipeFile.toPath());
SocketChannel channel = SocketChannel.open(StandardProtocolFamily.UNIX);
channel.connect(socketAddress);
input = new NamedPipeInputStream(channel);
output = new NamedPipeOutputStream(channel);
} catch (IOException e) {
e.printStackTrace();
}
}
}

/**
* NamedPipeInputStream.
*/
public class NamedPipeInputStream extends InputStream {

private ReadableByteChannel unixChannel;
private AsynchronousFileChannel winChannel;
private ByteBuffer buffer = ByteBuffer.allocate(1024);
private int readyBytes = 0;

public NamedPipeInputStream(ReadableByteChannel channel) {
this.unixChannel = channel;
}

public NamedPipeInputStream(AsynchronousFileChannel channel) {
this.winChannel = channel;
}

@Override
public int read() throws IOException {
if (buffer.position() < readyBytes) {
return buffer.get() & 0xFF;
}
try {
buffer.clear();
if (winChannel != null) {
readyBytes = winChannel.read(buffer, 0).get();
} else {
readyBytes = unixChannel.read(buffer);
}
if (readyBytes == -1) {
return -1; // EOF
}
buffer.flip();
return buffer.get() & 0xFF;
} catch (InterruptedException | ExecutionException e) {
throw new IOException(e);
}
}
}

/**
* NamedPipeOutputStream.
*/
public class NamedPipeOutputStream extends OutputStream {
private WritableByteChannel unixChannel;
private AsynchronousFileChannel winChannel;
private ByteBuffer buffer = ByteBuffer.allocate(1);

public NamedPipeOutputStream(WritableByteChannel channel) {
this.unixChannel = channel;
}

public NamedPipeOutputStream(AsynchronousFileChannel channel) {
this.winChannel = channel;
}

@Override
public void write(int b) throws IOException {
buffer.clear();
buffer.put((byte) b);
buffer.position(0);
if (winChannel != null) {
Future<Integer> result = winChannel.write(buffer, 0);
try {
result.get();
} catch (Exception e) {
throw new IOException(e);
}
} else {
unixChannel.write(buffer);
}
}

@Override
public void write(byte[] b) throws IOException {
final int buffer_size = 1024;
int blocks = b.length / buffer_size;
int writeBytes = 0;
for (int i = 0; i <= blocks; i++) {
int offset = i * buffer_size;
int length = Math.min(b.length - writeBytes, buffer_size);
if (length <= 0) {
break;
}
writeBytes += length;
ByteBuffer buffer = ByteBuffer.wrap(b, offset, length);
if (winChannel != null) {
Future<Integer> result = winChannel.write(buffer, 0);
try {
result.get();
} catch (Exception e) {
throw new IOException(e);
}
} else {
unixChannel.write(buffer);
}
}
}
}

/**
* getSelectedStream.
*/
public StreamProvider getSelectedStream() {
if (provider == null) {
provider = createProvider();
}
return provider;
}

private StreamProvider createProvider() {

return new PipeStreamProvider();
}

public InputStream getInputStream() throws IOException {
return getSelectedStream().getInputStream();
}

public OutputStream getOutputStream() throws IOException {
return getSelectedStream().getOutputStream();
}

private static boolean isWindows() {
return System.getProperty("os.name").toLowerCase().contains("win");
}
}