org.eclipse.acute.OmnisharpStreamConnectionProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.acute.OmnisharpStreamConnectionProvider.java

Source

/*******************************************************************************
 * Copyright (c) 2017 Red Hat Inc. and others.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *  Mickael Istria (Red Hat Inc.) - Initial implementation
 *******************************************************************************/
package org.eclipse.acute;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilterInputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.BoundedInputStream;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.lsp4e.server.StreamConnectionProvider;
import org.eclipse.osgi.util.NLS;

public class OmnisharpStreamConnectionProvider implements StreamConnectionProvider {

    private boolean DEBUG = Boolean.parseBoolean(System.getProperty("omnisharp.lsp.debug")); //$NON-NLS-1$

    private Process process;

    public OmnisharpStreamConnectionProvider() {
    }

    private boolean showDotnetCommandError = true;

    @Override
    public void start() throws IOException {
        // workaround for https://github.com/OmniSharp/omnisharp-node-client/issues/265
        try {
            Process restoreProcess = Runtime.getRuntime()
                    .exec(new String[] { AcutePlugin.getDotnetCommand(showDotnetCommandError), "restore" }); //$NON-NLS-1$
            showDotnetCommandError = true;
            try {
                restoreProcess.waitFor();
            } catch (InterruptedException e) {
                AcutePlugin.logError(e);
            }
        } catch (IllegalStateException e) {
            showDotnetCommandError = false;
            AcutePlugin.getDefault().getLog()
                    .log(new Status(IStatus.ERROR, AcutePlugin.getDefault().getBundle().getSymbolicName(),
                            Messages.omnisharpStreamConnection_dotnetRestoreError));
        }

        String commandLine = System.getenv("OMNISHARP_LANGUAGE_SERVER_COMMAND"); //$NON-NLS-1$
        if (commandLine == null) {
            File serverPath = getServer();
            commandLine = getDefaultCommandLine(serverPath);
        }
        if (commandLine != null) {
            this.process = Runtime.getRuntime().exec(commandLine);
        } else {
            AcutePlugin.getDefault().getLog()
                    .log(new Status(IStatus.ERROR, AcutePlugin.getDefault().getBundle().getSymbolicName(),
                            Messages.omnisharpStreamConnection_omnisharpNotFoundError));
        }
    }

    /**
     *
     * @return path to server, unzipping it if necessary. Can be null is fragment is missing.
     */
    private @Nullable File getServer() throws IOException {
        File serverPath = new File(AcutePlugin.getDefault().getStateLocation().toFile(), "omnisharp-roslyn"); //$NON-NLS-1$
        if (!serverPath.exists()) {
            serverPath.mkdirs();
            try (InputStream stream = FileLocator.openStream(AcutePlugin.getDefault().getBundle(),
                    new Path("omnisharp-roslyn.tar"), true); //$NON-NLS-1$
                    TarArchiveInputStream tarStream = new TarArchiveInputStream(stream);) {
                TarArchiveEntry entry = null;
                while ((entry = tarStream.getNextTarEntry()) != null) {
                    if (!entry.isDirectory()) {
                        File targetFile = new File(serverPath, entry.getName());
                        targetFile.getParentFile().mkdirs();
                        InputStream in = new BoundedInputStream(tarStream, entry.getSize()); // mustn't be closed
                        try (FileOutputStream out = new FileOutputStream(targetFile);) {
                            IOUtils.copy(in, out);
                            if (!Platform.OS_WIN32.equals(Platform.getOS())) {
                                int xDigit = entry.getMode() % 10;
                                targetFile.setExecutable(xDigit > 0, (xDigit & 1) == 1);
                                int wDigit = (entry.getMode() / 10) % 10;
                                targetFile.setWritable(wDigit > 0, (wDigit & 1) == 1);
                                int rDigit = (entry.getMode() / 100) % 10;
                                targetFile.setReadable(rDigit > 0, (rDigit & 1) == 1);
                            }
                        }
                    }
                }
            }
        }
        return serverPath;
    }

    /**
     *
     * @param commandLine
     * @return the command-line to run the server, or null is expected resources are not found
     * @throws IOException
     */
    protected @Nullable String getDefaultCommandLine(File serverPath) throws IOException {
        File serverFileUrl = null;
        if (Platform.OS_WIN32.equals(Platform.getOS())) {
            serverFileUrl = new File(serverPath, "server/Omnisharp.exe"); //$NON-NLS-1$
        } else {
            serverFileUrl = new File(serverPath, "run"); //$NON-NLS-1$
        }

        if (serverFileUrl == null || !serverFileUrl.exists()) {
            AcutePlugin.logError(NLS.bind(Messages.omnisharpStreamConnection_serverNotFoundError, serverPath));
            return null;
        } else if (!serverFileUrl.canExecute()) {
            AcutePlugin
                    .logError(NLS.bind(Messages.omnisharpStreamConnection_serverNotExecutableError, serverFileUrl));
            // return value anyway
        }
        return serverFileUrl.getAbsolutePath() + " -stdio -lsp"; //$NON-NLS-1$
    }

    @Override
    public InputStream getInputStream() {
        if (DEBUG) {
            return new FilterInputStream(process.getInputStream()) {
                @Override
                public int read() throws IOException {
                    int res = super.read();
                    System.err.print((char) res);
                    return res;
                }

                @Override
                public int read(byte[] b, int off, int len) throws IOException {
                    int bytes = super.read(b, off, len);
                    byte[] payload = new byte[bytes];
                    System.arraycopy(b, off, payload, 0, bytes);
                    System.err.print(new String(payload));
                    return bytes;
                }

                @Override
                public int read(byte[] b) throws IOException {
                    int bytes = super.read(b);
                    byte[] payload = new byte[bytes];
                    System.arraycopy(b, 0, payload, 0, bytes);
                    System.err.print(new String(payload));
                    return bytes;
                }
            };
        } else {
            return process.getInputStream();
        }
    }

    @Override
    public OutputStream getOutputStream() {
        if (DEBUG) {
            return new FilterOutputStream(process.getOutputStream()) {
                @Override
                public void write(int b) throws IOException {
                    System.err.print((char) b);
                    super.write(b);
                }

                @Override
                public void write(byte[] b) throws IOException {
                    System.err.print(new String(b));
                    super.write(b);
                }

                @Override
                public void write(byte[] b, int off, int len) throws IOException {
                    byte[] actual = new byte[len];
                    System.arraycopy(b, off, actual, 0, len);
                    System.err.print(new String(actual));
                    super.write(b, off, len);
                }
            };
        } else {
            return process.getOutputStream();
        }
    }

    @Override
    public void stop() {
        if (process != null) {
            process.destroy();
        }
    }

    @Override
    public @Nullable InputStream getErrorStream() {
        return process.getErrorStream();
    }

}