/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.utils.executor; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; import java.util.Map.Entry; import java.util.Set; import org.apache.commons.exec.OS; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import de.rcenvironment.core.toolkitbridge.transitional.ConcurrencyUtils; import de.rcenvironment.toolkit.modules.concurrency.api.TaskDescription; /** * A {@link CommandLineExecutor} that executes the given commands locally. * * @author Robert Mischke * */ public class LocalCommandLineExecutor extends AbstractCommandLineExecutor implements CommandLineExecutor { /** Top-level command token template for Linux invocation. */ private static final String[] LINUX_SHELL_TOKENS = { "/bin/sh", "-c", "[command]" }; /** Top-level command token template for Windows invocation. */ private static final String[] WINDOWS_SHELL_TOKENS = { "cmd.exe", "/c", "[command]" }; private File workDir; private Process process; private Log log = LogFactory.getLog(getClass()); /** * Creates a local executor with the given path as its working directory. If the given path is * not a directory, it is created. * * @param workDirPath the directory on the local system to use for execution * * @throws IOException if the given {@link File} is not a directory and also could not be * created */ public LocalCommandLineExecutor(File workDirPath) throws IOException { this.workDir = workDirPath; } @Override public void start(String commandString) throws IOException { start(commandString, null); } @Override public void start(String commandString, final InputStream stdinStream) throws IOException { if (!workDir.isDirectory()) { // try to create the work directory workDir.mkdirs(); if (!workDir.isDirectory()) { throw new IOException("Failed to create provided work directory " + workDir.getAbsolutePath()); } } // build environment key/value array Set<Entry<String, String>> entries = env.entrySet(); String[] envArray = new String[entries.size()]; int pos = 0; for (Entry<String, String> entry : entries) { envArray[pos++] = entry.getKey() + "=" + entry.getValue(); } // build the top-level token array String[] commandTokens; if (OS.isFamilyWindows()) { commandTokens = Arrays.copyOf(WINDOWS_SHELL_TOKENS, WINDOWS_SHELL_TOKENS.length); commandTokens[WINDOWS_SHELL_TOKENS.length - 1] = commandString; } else { commandTokens = Arrays.copyOf(LINUX_SHELL_TOKENS, LINUX_SHELL_TOKENS.length); commandTokens[LINUX_SHELL_TOKENS.length - 1] = commandString; } // TODO rewrite to use Apache Commons-Exec? process = Runtime.getRuntime().exec(commandTokens, envArray, workDir); if (stdinStream != null) { final OutputStream stdin = process.getOutputStream(); ConcurrencyUtils.getAsyncTaskService().execute(new Runnable() { @Override @TaskDescription("LocalCommandLineExecutor input stream pipe") public void run() { try { IOUtils.copy(stdinStream, stdin); stdin.close(); } catch (IOException e) { // TODO propagate to outside? log.error("Error writing STDIN stream", e); } }; }); } } @Override public String getWorkDirPath() { return workDir.getAbsolutePath(); } @Override public InputStream getStdout() { // TODO make buffered? return process.getInputStream(); } @Override public InputStream getStderr() { // TODO make buffered? return process.getErrorStream(); } @Override public int waitForTermination() throws IOException, InterruptedException { return process.waitFor(); } @Override public void uploadFileToWorkdir(File localFile, String remoteLocation) throws IOException { File targetFile = new File(workDir, remoteLocation); log.debug("Local copy from " + localFile.getAbsolutePath() + " to " + targetFile.getAbsolutePath()); FileUtils.copyFile(localFile, targetFile); }; @Override public void downloadFileFromWorkdir(String remoteLocation, File localFile) throws IOException { FileUtils.copyFile(new File(workDir, remoteLocation), localFile); } @Override public void downloadWorkdir(File localDir) throws IOException { FileUtils.copyDirectory(workDir, localDir); } @Override public void remoteCopy(String remoteSource, String remoteTarget) throws IOException { FileUtils.copyFile(new File(remoteSource), new File(remoteTarget)); } @Override public void uploadDirectoryToWorkdir(File localDirectory, String remoteLocation) throws IOException { File targetDirectory = new File(workDir, remoteLocation); targetDirectory.mkdirs(); FileUtils.copyDirectory(localDirectory, targetDirectory); } @Override public void downloadDirectoryFromWorkdir(String remoteLocation, File localDirectory) throws IOException { FileUtils.copyDirectory(new File(workDir, remoteLocation), localDirectory); } @Override public void downloadFile(String remoteLocation, File localFile) throws IOException { FileUtils.copyFile(new File(remoteLocation), localFile); } @Override public void downloadDirectory(String remoteLocation, File localDirectory) throws IOException { FileUtils.copyDirectory(new File(remoteLocation), localDirectory); } @Override public void uploadFile(File localFile, String remoteLocation) throws IOException { FileUtils.copyFile(localFile, new File(remoteLocation)); } @Override public void uploadDirectory(File localDirectory, String remoteLocation) throws IOException { FileUtils.copyDirectory(localDirectory, new File(remoteLocation)); } }