uk.co.unclealex.process.builder.BasicProcessRequest.java Source code

Java tutorial

Introduction

Here is the source code for uk.co.unclealex.process.builder.BasicProcessRequest.java

Source

/**
 * Copyright 2012 Alex Jones
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under 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.    
 *
 */

package uk.co.unclealex.process.builder;

import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import uk.co.unclealex.process.ProcessCallback;
import uk.co.unclealex.process.ProcessResult;
import uk.co.unclealex.process.gobblers.StderrStreamGobbler;
import uk.co.unclealex.process.gobblers.StdoutStreamGobbler;
import uk.co.unclealex.process.gobblers.StreamGobbler;
import uk.co.unclealex.process.stream.StandardInputSupplier;

import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.io.Closeables;

/**
 * A class that will run a process given the correct information.
 * 
 * @author alex
 * 
 */
public class BasicProcessRequest {

    /** The Constant log. */
    private static final Logger log = LoggerFactory.getLogger(BasicProcessRequest.class);

    /**
     * The executor used to execute the command.
     */
    private final ExecutorService executor;

    /**
     * Create a new process request.
     * 
     * @param executor
     *          the executor
     */
    public BasicProcessRequest(ExecutorService executor) {
        this.executor = executor;
    }

    /**
     * Prepare and execute a process.
     * 
     * @param command
     *          The command to process.
     * @param processCallbacks
     *          The {@link ProcessCallback}s to call.
     * @param arguments
     *          The arguments to supply to the command.
     * @param standardInputSupplier
     *          The {@link StandardInputSupplier} to provide data to standard
     *          input.
     * @return A {@link Callable} which, when executed, will return a
     *         {@link ProcessResult} containing the return value, output and
     *         error.
     * @throws IOException
     *           Thrown if there is an unexpected issue calling the command.
     */
    public final Callable<ProcessResult> execute(String command, Iterable<ProcessCallback> processCallbacks,
            Iterable<String> arguments, StandardInputSupplier standardInputSupplier) throws IOException {
        final ProcessCallback processCallback = new ChainingProcessCallback(processCallbacks);
        final List<String> commandline = Lists.newArrayList();
        commandline.add(command);
        Iterables.addAll(commandline, arguments);
        ProcessBuilder processBuilder = new ProcessBuilder(commandline);
        final Process process = processBuilder.start();
        String threadName = Joiner.on(' ').join(processBuilder.command());
        final StreamGobbler stdoutStreamGobbler = new StdoutStreamGobbler(process, threadName, processCallback);
        final StreamGobbler stderrStreamGobbler = new StderrStreamGobbler(process, threadName, processCallback);
        ExecutorService executor = getExecutor();
        final Future<String> stdoutFuture = executor.submit(stdoutStreamGobbler);
        final Future<String> stderrFuture = executor.submit(stderrStreamGobbler);
        try {
            final OutputStream stdin = process.getOutputStream();
            if (standardInputSupplier != null) {
                standardInputSupplier.setStandardInputStream(stdin);
            }
            Callable<ProcessResult> processExecution = new Callable<ProcessResult>() {
                @Override
                public ProcessResult call() throws IOException {
                    try {
                        process.waitFor();
                        int returnCode = process.exitValue();
                        processCallback.processFinished(returnCode);
                        String output = stdoutFuture.get();
                        String error = stderrFuture.get();
                        return new ProcessResult(returnCode, output, error);
                    } catch (InterruptedException e) {
                        log.warn("Process " + Joiner.on(' ').join(commandline) + " was interrupted.", e);
                        throw new IOException("Process " + Joiner.on(' ').join(commandline) + " was interrupted.",
                                e);
                    } catch (ExecutionException e) {
                        log.warn("Process " + Joiner.on(' ').join(commandline) + " errored unexpectedly.", e);
                        throw new IOException(
                                "Process " + Joiner.on(' ').join(commandline) + " errored unexpectedly.", e);
                    } finally {
                        Closeables.closeQuietly(stdin);
                        Closeables.closeQuietly(stderrStreamGobbler);
                        Closeables.closeQuietly(stdoutStreamGobbler);
                    }
                }
            };
            return processExecution;
        } catch (IOException e) {
            throw new IOException("The process " + Joiner.on(' ').join(commandline) + " failed.", e);
        }
    }

    /**
     * Gets the executor used to execute the command.
     * 
     * @return the executor
     */
    public ExecutorService getExecutor() {
        return executor;
    }

}