cn.dockerfoundry.ide.eclipse.server.core.internal.ProcessLauncher.java Source code

Java tutorial

Introduction

Here is the source code for cn.dockerfoundry.ide.eclipse.server.core.internal.ProcessLauncher.java

Source

/*******************************************************************************
 * Copyright (c) 2013, 2014 Pivotal Software, Inc. 
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License, 
 * Version 2.0 (the "License); you may not use this file except in compliance 
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *  
 *  Contributors:
 *     Pivotal Software, Inc. - initial API and implementation
 ********************************************************************************/
package cn.dockerfoundry.ide.eclipse.server.core.internal;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.io.IOUtils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;

/**
 * Launches a native process that blocks the current thread it is launched from
 * until the process exists. Throws CoreException if errors are generated during
 * the launch process, or there are no arguments to the process.
 */
public abstract class ProcessLauncher {

    /**
     * Returns when the process has exited without errors. This will wait for
     * the process to exist, therefore will block the current thread in which it
     * is running. If any errors occur, throws CoreException CoreException
     * @throws CoreException if any errors occur while the process is being
     * launched
     */
    public void run() throws CoreException {
        Exception error = null;
        Process p = null;
        try {

            List<String> processArguments = getProcessArguments();

            if (processArguments == null || processArguments.isEmpty()) {
                throw new CoreException(getErrorStatus("No process arguments were found")); //$NON-NLS-1$
            } else {

                ProcessBuilder processBuilder = new ProcessBuilder(processArguments);

                // Set any environment variables
                Map<String, String> envVars = getEnvironmentVariables();
                if (envVars != null) {
                    Map<String, String> actualVars = processBuilder.environment();
                    if (actualVars != null) {
                        for (Entry<String, String> entry : envVars.entrySet()) {
                            actualVars.put(entry.getKey(), entry.getValue());
                        }
                    }
                }

                p = processBuilder.start();

                if (p == null) {
                    throw new CoreException(getErrorStatus("No process was created.")); //$NON-NLS-1$
                } else {

                    StringBuffer errorBuffer = new StringBuffer();
                    // Clear the input and error streams to prevent the
                    // process
                    // from blocking
                    handleProcessIOAsynch(p, null, errorBuffer);

                    p.waitFor();

                    if (errorBuffer.length() > 0) {
                        throw new CoreException(getErrorStatus(errorBuffer.toString()));
                    } else if (p.exitValue() != 0) {
                        throw new CoreException(getErrorStatus("process exit value: " + p.exitValue())); //$NON-NLS-1$
                    }
                }
            }
        } catch (InterruptedException ex) {
            error = ex;
        } catch (IOException ioe) {
            error = ioe;
        } catch (SecurityException se) {
            error = se;
        } finally {
            if (p != null) {
                p.destroy();
            }
        }

        if (error != null) {
            throw error instanceof CoreException ? (CoreException) error : CloudErrorUtil.toCoreException(error);
        }

    }

    /**
     * The process IO needs to be handled in order to not block the process.
     * @param p
     * @return
     * @throws IOException
     */
    protected void handleProcessIOAsynch(Process p, StringBuffer inputBuffer, StringBuffer errorBuffer) {

        InputStream in = p.getInputStream();
        InputStream error = p.getErrorStream();

        if (in != null) {
            new ProcessStreamHandler(in, inputBuffer, getLaunchName()).start();
        }

        if (error != null) {
            new ProcessStreamHandler(error, errorBuffer, getLaunchName()).start();
        }

    }

    protected IStatus getErrorStatus(String body) {
        return getErrorStatus(body, null);
    }

    protected IStatus getErrorStatus(String body, Exception e) {
        String errorMessage = "Failure when launching " + getLaunchName() + " due to: " + body; //$NON-NLS-1$ //$NON-NLS-2$
        return e != null ? DockerFoundryPlugin.getErrorStatus(errorMessage, e)
                : DockerFoundryPlugin.getErrorStatus(errorMessage);
    }

    abstract protected String getLaunchName();

    abstract protected List<String> getProcessArguments() throws CoreException;

    abstract protected Map<String, String> getEnvironmentVariables() throws CoreException;

    protected static class ProcessStreamHandler {

        private final InputStream processInput;

        private final StringBuffer outputBuffer;

        private final String processName;

        public ProcessStreamHandler(InputStream processInput, StringBuffer outputBuffer, String processName) {
            this.processInput = processInput;
            this.outputBuffer = outputBuffer;
            this.processName = processName;
        }

        public void start() {
            BufferedReader reader = new BufferedReader(new InputStreamReader(processInput));
            try {
                String line = reader.readLine();
                while (line != null) {
                    if (outputBuffer != null) {
                        outputBuffer.append(line);
                        outputBuffer.append(' ');
                    }
                    line = reader.readLine();
                }
            } catch (IOException e) {
                DockerFoundryPlugin.logError("Error while reading input from process for: " + processName, e); //$NON-NLS-1$
            } finally {
                if (processInput != null) {
                    IOUtils.closeQuietly(processInput);
                }
            }
        }
    }

}