Java tutorial
/** * 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; } }