Статьи

Выполнение исполняемой командной строки из Java

В этом посте мы рассмотрим общую потребность разработчиков Java. Выполнять и управлять внешним процессом изнутри Java. Поскольку эта задача довольно распространена, мы решили найти библиотеку Java, которая поможет нам в этом. 

Требования от такой библиотеки: 

  1. Выполните процесс асинхронно. 
  2. Возможность прервать выполнение процесса.
  3. Возможность дождаться завершения процесса.
  4. На выходе процесса уведомления.
  5. Возможность убить процесс в случае зависания.
  6. Получить код завершения процесса.

Родной JDK мало чем помогает. К счастью, у нас есть 
Apache Commons Exe . На самом деле все гораздо проще, но все же не так просто, как мы надеялись. Мы написали небольшую обертку сверху. 

Вот подпись метода, которую мы выставляем:

public static Future <Long> runProcess (финальная командная строка CommandLine, финальный обработчик ProcessExecutorHandler, финальный long watchdogTimeout) выдает IOException;
  1. Возвращает будущее <Long>. Это охватывает раздел 1,2,3,6. 
  2. Экземпляр ProcessExecutorHandler передается в функцию. Этот экземпляр на самом деле является слушателем любого вывода процесса. Это покрывает раздел 4 в нашем требовании.
  3. И последнее, но не менее важное: вы предоставляете тайм-аут. Если выполнение процесса занимает больше времени, чем указано, вы предполагаете, что процесс завис, и завершите его. В этом случае код ошибки, возвращаемый процессом, будет -999. 

Это оно! Реализация может быть найдена в фрагменте кода ниже. Наслаждаться.

import org.apache.commons.exec. *;
import org.apache.commons.exec.Executor;
импорт java.io.IOException;
импорт java.util.concurrent. *;


открытый класс ProcessExecutor {
    public static final Long WATCHDOG_EXIST_VALUE = -999L;

    public static Future <Long> runProcess (финальная командная строка CommandLine, финальный обработчик ProcessExecutorHandler, финальный long watchdogTimeout) выдает IOException {

        ExecutorService executor = Executors.newSingleThreadExecutor ();
        Future <Long> result = executor.submit (new ProcessCallable (watchdogTimeout, handler, commandline));
        executor.shutdown ();
        вернуть результат; 
  }
   закрытый статический класс ProcessCallable реализует Callable <Long> {

        частный длинный сторожевой тайм-аут;
        закрытый обработчик ProcessExecutorHandler;
        частная командная строка CommandLine;

        private ProcessCallable (long watchdogTimeout, обработчик ProcessExecutorHandler, командная строка CommandLine) {
            this.watchdogTimeout = watchdogTimeout;
            this.handler = обработчик;
            this.commandline = командная строка;
        }

        @Override
        public Long call () выдает исключение {
            Executor executor = new DefaultExecutor ();
            executor.setProcessDestroyer (новый ShutdownHookProcessDestroyer ());
            ExecuteWatchdog watchDog = new ExecuteWatchdog (watchdogTimeout);
            executor.setWatchdog (Watchdog);
            executor.setStreamHandler (новый PumpStreamHandler (новый MyLogOutputStream (обработчик, true), новый MyLogOutputStream (обработчик, false)));
            Long exitValue;
            пытаться {
                exitValue = new Long (executor.execute (commandline));

            } catch (ExecuteException e) {
                exitValue = new Long (e.getExitValue ());
            }
            если (watchDog.killedProcess ()) {
                exitValue = WATCHDOG_EXIST_VALUE;
            }

            return exitValue;


        }

    }

    закрытый статический класс MyLogOutputStream extends LogOutputStream {

        закрытый обработчик ProcessExecutorHandler;
        приватное логическое предисловиеToStandardOutput;

        private MyLogOutputStream (обработчик ProcessExecutorHandler, логическое предисловиеToStandardOutput) {
            this.handler = обработчик;
            this.forewordToStandardOutput = forewordToStandardOutput;
        }

        @Override
        защищенная пустота processLine (строковая строка, уровень int) {
            if (forewordToStandardOutput) {
                handler.onStandardOutput (линия);
            }
            еще {
                handler.onStandardError (линия);
            }
        }
    }


}
// интерфейс.
открытый интерфейс ProcessExecutorHandler {
    public void onStandardOutput (String msg);
    public void onStandardError (String msg);

}

import org.apache.commons.exec. *;
import org.apache.commons.exec.Executor;
импорт java.io.IOException;
импорт java.util.concurrent. *;


открытый класс ProcessExecutor {
    public static final Long WATCHDOG_EXIST_VALUE = -999L;

    публичное статическое будущее
 
   runProcess (финальная командная строка CommandLine, финальный обработчик ProcessExecutorHandler, финальный длинный watchdogTimeout) выдает IOException {

        ExecutorService executor = Executors.newSingleThreadExecutor ();
        return executor.submit (новый ProcessCallable (watchdogTimeout, обработчик, командная строка));

    }

    закрытый статический класс ProcessCallable реализует Callable
  
   {


        частный длинный сторожевой тайм-аут;
        закрытый обработчик ProcessExecutorHandler;
        частная командная строка CommandLine;

        private ProcessCallable (long watchdogTimeout, обработчик ProcessExecutorHandler, командная строка CommandLine) {
            this.watchdogTimeout = watchdogTimeout;
            this.handler = обработчик;
            this.commandline = командная строка;
        }

        @Override
        public Long call () выдает исключение {
            Executor executor = new DefaultExecutor ();
            executor.setProcessDestroyer (новый ShutdownHookProcessDestroyer ());
            ExecuteWatchdog watchDog = new ExecuteWatchdog (watchdogTimeout);
            executor.setWatchdog (Watchdog);
            executor.setStreamHandler (новый PumpStreamHandler (новый MyLogOutputStream (обработчик, true), новый MyLogOutputStream (обработчик, false)));
            Long exitValue;
            пытаться {
                exitValue = new Long (executor.execute (commandline));

            } catch (ExecuteException e) {
                exitValue = new Long (e.getExitValue ());
            }
            если (watchDog.killedProcess ()) {
                exitValue = WATCHDOG_EXIST_VALUE;
            }

            return exitValue;


        }

    }

    закрытый статический класс MyLogOutputStream extends LogOutputStream {

        закрытый обработчик ProcessExecutorHandler;
        приватное логическое предисловиеToStandardOutput;

        private MyLogOutputStream (обработчик ProcessExecutorHandler, логическое предисловиеToStandardOutput) {
            this.handler = обработчик;
            this.forewordToStandardOutput = forewordToStandardOutput;
        }

        @Override
        защищенная пустота processLine (строковая строка, уровень int) {
            if (forewordToStandardOutput) {
                handler.onStandardOutput (линия);
            }
            еще {
                handler.onStandardError (линия);
            }
        }
    }


}
// интерфейс.
открытый интерфейс ProcessExecutorHandler {
    public void onStandardOutput (String msg);
    public void onStandardError (String msg);

}