com.cisco.dvbu.ps.common.util.ScriptExecutor.java Source code

Java tutorial

Introduction

Here is the source code for com.cisco.dvbu.ps.common.util.ScriptExecutor.java

Source

/**
 * (c) 2014 Cisco and/or its affiliates. All rights reserved.
 * 
 * This software is released under the Eclipse Public License. The details can be found in the file LICENSE. 
 * Any dependent libraries supplied by third parties are provided under their own open source licenses as 
 * described in their own LICENSE files, generally named .LICENSE.txt. The libraries supplied by Cisco as 
 * part of the Composite Information Server/Cisco Data Virtualization Server, particularly csadmin-XXXX.jar, 
 * csarchive-XXXX.jar, csbase-XXXX.jar, csclient-XXXX.jar, cscommon-XXXX.jar, csext-XXXX.jar, csjdbc-XXXX.jar, 
 * csserverutil-XXXX.jar, csserver-XXXX.jar, cswebapi-XXXX.jar, and customproc-XXXX.jar (where -XXXX is an 
 * optional version number) are provided as a convenience, but are covered under the licensing for the 
 * Composite Information Server/Cisco Data Virtualization Server. They cannot be used in any way except 
 * through a valid license for that product.
 * 
 * This software is released AS-IS!. Support for this software is not covered by standard maintenance agreements with Cisco. 
 * Any support for this software by Cisco would be covered by paid consulting agreements, and would be billable work.
 * 
 */
package com.cisco.dvbu.ps.common.util;

/* 
 * mtinius: 2014-02-28 resolve issue with long file paths.
 * 
 * A new process builder is required because the full command must be created on initialization.
 * This resolves the "file too long" error that occurs in windows when executing a command line that exceeds 260 characters.
 * Previously, the 2 commands were executed below which has the affect of doing a cd <long path> and then executing the VCS command.  
 * That was the issue with windows.   Windows uses a different api when executing a cd to a path and it fails.
 *     processBuilder.directory(contextFolder);
 *     processBuilder.command(newCommand);  
 *     
 * By creating a process that includes the entire path as a single command, windows uses an API call that is not bound by the 260 character limit and
 *    thus this command succeeds with very long paths.
 * 
 * To illustrate the point...
 *    This will succeed:  return new ProcessBuilder("svn", "add", new File(DIRECTORY, FILE).getAbsolutePath()).start();
 *                        This is basically doing a svn add path\file in one step.
 *                        This will work with paths longer than 260 characters
 * 
 *    This will fail:     return new ProcessBuilder("svn", "add", FILE).directory(new File(DIRECTORY)).start();
 *                        Fails with CreateProcess error=267, The directory name is invalid
 *                        This is basically doing a cd <long path> and svn add file in two steps.
 *                        It will fail on cd <long path>
 */

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.cisco.dvbu.ps.common.exception.CompositeException;
import com.cisco.dvbu.ps.common.util.CommonUtils;
import com.cisco.dvbu.ps.common.util.CompositeLogger;

public class ScriptExecutor {

    private String execFromDir;
    private List<String> envList;
    private List<String> scriptArgsList;
    private ScriptStreamHandler inputStreamHandler;
    private ScriptStreamHandler errorStreamHandler;
    private static Log logger = LogFactory.getLog(ScriptExecutor.class);

    public ScriptExecutor(final String execFromDir, final List<String> scriptArgsList, final List<String> envList) {
        if (scriptArgsList == null)
            throw new NullPointerException("The scriptArgsList is required.");
        this.scriptArgsList = scriptArgsList;
        this.execFromDir = execFromDir;
        this.envList = envList;
    }

    public int executeCommand(String errorFile) {
        int exitValue = -99;

        String prefix = "ScriptExecutor::";
        String command = "";
        try {
            // Print out the command and execution directory
            for (int i = 0; i < scriptArgsList.size(); i++) {
                command = command + scriptArgsList.get(i) + " ";
            }
            if (logger.isDebugEnabled()) {
                logger.debug(prefix + "-------------------------------------------------");
                logger.debug(prefix + "Command:  " + CommonUtils.maskCommand(command));
                logger.debug(prefix + "Exec Dir: " + execFromDir.toString());
            }

            // Build a new process to execute
            ProcessBuilder pb = new ProcessBuilder(scriptArgsList);

            // Setup the environment variables
            Map<String, String> env = pb.environment();
            for (int i = 0; i < envList.size(); i++) {
                String envVar = envList.get(i).toString();
                StringTokenizer st = new StringTokenizer(envVar, "=");
                if (st.hasMoreTokens()) {
                    String property = st.nextToken();
                    String propertyVal = "";
                    try {
                        propertyVal = st.nextToken();
                    } catch (Exception e) {
                    }
                    env.put(property, propertyVal);

                    if (logger.isDebugEnabled()) {
                        logger.debug(prefix + "Env Var:  " + CommonUtils.maskCommand(envVar));
                    }
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug(prefix + "-------------------------------------------------");
            }

            // Setup up the execute from directory
            File execDir = new File(execFromDir);
            pb.directory(execDir);

            if (logger.isDebugEnabled()) {
                logger.debug("");
                logger.debug("ProcessBuilder::pb.command:                    "
                        + CommonUtils.maskCommand(pb.command().toString()));
                logger.debug("ProcessBuilder::pb.directory:                  " + pb.directory().toString());
                logger.debug("ProcessBuilder::pb.directory.getAbsolutePath:  " + pb.directory().getAbsolutePath());
                logger.debug("ProcessBuilder::pb.directory.getCanonicalPath: " + pb.directory().getCanonicalPath());
                logger.debug("");
                logger.debug("ProcessBuilder::pb.environment:                "
                        + CommonUtils.maskCommand(pb.environment().toString()));
                logger.debug(prefix + "-------------------------------------------------");
                logger.debug("");
            }

            // Execute the command
            Process process = pb.start();

            OutputStream stdOutput = process.getOutputStream();

            InputStream inputStream = process.getInputStream();
            InputStream errorStream = process.getErrorStream();

            inputStreamHandler = new ScriptStreamHandler(inputStream, stdOutput);
            errorStreamHandler = new ScriptStreamHandler(errorStream);

            inputStreamHandler.start();
            errorStreamHandler.start();

            exitValue = process.waitFor();

            if (logger.isDebugEnabled()) {
                logger.debug(prefix + "exitValue for process.waitFor is: " + exitValue);
            }

            if (exitValue > 0) {
                logger.error("Error executing command=" + CommonUtils.maskCommand(command));
                logger.error("Error=" + CommonUtils.maskCommand(getStandardErrorFromCommand().toString()));
            } else {
                if (logger.isInfoEnabled()) {
                    logger.info("Successfully executed command:\n" + CommonUtils.maskCommand(command));
                    logger.info("Output:\n" + getStandardOutputFromCommand().toString());
                }
            }

        } catch (IOException e) {
            CompositeLogger.logException(e, e.getMessage());
            throw new CompositeException(e);
        } catch (InterruptedException e) {
            CompositeLogger.logException(e, e.getMessage());
            throw new CompositeException(e);
        }
        return exitValue;

    }

    /**
     * Get the standard output (stdout) from the command you just exec'd.
     */
    public StringBuilder getStandardOutputFromCommand() {
        return inputStreamHandler.getOutputBuffer();
    }

    /**
     * Get the standard error (stderr) from the command you just exec'd.
     */
    public StringBuilder getStandardErrorFromCommand() {
        return errorStreamHandler.getOutputBuffer();
    }

}