Processbuilder зависает при выполнении пакетного скрипта

ProcessBuilder просто зависает и не завершается. Я видел многочисленные статьи, опубликованные на эту тему, но мне все еще не удалось решить эту проблему. Может ли кто-нибудь увидеть проблему с этим или иметь предложение?

Я пытаюсь выполнить пакетный файл, который разрешает пользователям почту в активном каталоге.

КОД:

    private void initialize() {
    frame = new JFrame();
    frame.setBounds(100, 100, 450, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JButton button = new JButton("TEST");
    button.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent arg0) {

            System.out.println("Starting process");

            ProcessBuilder pb = new ProcessBuilder(
                    "cmd.exe",
                    "/C",
                    "Y:\\mail-enable-users-groups.bat");
            Process process = null;
            try 
            {
                process = pb.start();

                ProcessOutputThread t = new ProcessOutputThread(process.getInputStream(), new StringBuffer());
                t.start();

                process.waitFor();
                t.interrupt();
            } 
            catch (IOException e1) 
            {
                e1.printStackTrace();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }

            System.out.println("Process ended");
        }
    });

    frame.add(button);
}

private static class ProcessOutputThread extends Thread
{
    private StringBuffer m_output;
    private InputStream m_inputStream;

    public ProcessOutputThread(InputStream inputstream, StringBuffer output) 
    {
        super( "ProcessOutputThread" );
        m_inputStream = inputstream;
        m_output = output;
    }

    @Override
    public void run() {
        byte[] buffer = new byte[ 8192 ];

        try {
            while( true )
            {
                int available = m_inputStream.available();

                if( available == 0 )
                {
                    try
                    {
                        Thread.sleep( 100 );
                    }
                    catch( InterruptedException e )
                    {
                        break;
                    }

                    continue;
                }

                int len = Math.min( buffer.length, available );
                len = m_inputStream.read( buffer, 0, len );
                String outString = new String( buffer, 0, len );
                m_output.append( outString );

                System.out.println(outString);
            }
        }
        catch( IOException e ) 
        {
            e.printStackTrace();
        }
    }
}

ПАКЕТНЫЙ ФАЙЛ:

PowerShell.exe -command ". 'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1'; Connect-ExchangeServer -auto; Get-User -RecipientTypeDetails User -Filter { UserPrincipalName -ne $Null } | Enable-Mailbox

ВЫХОД:

Y:\>PowerShell.exe -command ". 'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1'; Connect-ExchangeServer -auto; Get-User -RecipientTypeDetails User -Filter { UserPrincipalName -ne $Null } | Enable-Mailbox

person JBuenoJr    schedule 24.08.2013    source источник
comment
Да, пакетный скрипт выполняется вне Java-приложения.   -  person JBuenoJr    schedule 25.08.2013
comment
Попробуйте поставить waitFor после чтения выходного потока   -  person MadProgrammer    schedule 25.08.2013
comment
Кажется, это запускает пакетный файл, но теперь кажется, что выполнение выполняется только руками. Возможно, что-то делать с фактическим пакетным файлом?? Это должно занять около 8 секунд, но, похоже, просто зависает. См. обновленный код и текущий вывод.   -  person JBuenoJr    schedule 25.08.2013


Ответы (1)


Вы ожидаете своего процесса, но процесс генерирует некоторый вывод и довольно скоро блокируется, пока вы не прочитаете этот вывод. Это мертвая блокировка, которую вы должны решить, прочитав вывод перед вызовом p.waitFor().

Немного сложно обрабатывать вывод, потому что вам нужно его дождаться. В первой итерации вашего цикла, вероятно, нет вывода, потому что вашей внешней программе требуется некоторое время для его создания. Таким образом, readline() вернет null, и ваша программа завершится.

В прошлом я справлялся с такими ситуациями, создавая поток, который считывает вывод. В основной теме я сделал p.waitFor(), как это сделали вы.

Я бы рекомендовал использовать apache exec вместо того, чтобы заниматься этим самостоятельно.


Обновление: если вам нужно сделать это самостоятельно, вот способ:

Создайте отдельный поток и прочитайте вывод. Не прекращайте читать. В своем основном потоке вызовите p.waitFor(), а после этого вызовите join() в своем потоке. При обнаружении InterruptedException внутри вашего потока убедитесь, что вы прочитали весь доступный вывод до конца, а затем завершите свой поток.

Пример кода:

private static class C_ProcessOutputThread extends Thread {
    private StringBuffer m_output;
    private InputStream m_inputStream;

    public C_ProcessOutputThread(
            InputStream inputstream,
            StringBuffer output
    ) {
        super( "ProcessOutputThread" );
        m_inputStream = inputstream;
        m_output = output;
    }

    @Override
    public void run() {
        byte[] buffer = new byte[ 8192 ];

        try {
            while( true ) {
                int available = m_inputStream.available();

                if( available == 0 ) {
                    try {
                        Thread.sleep( 100 );
                    }
                    catch( InterruptedException e ) {
                        break;
                    }

                    continue;
                }

                int len = Math.min( buffer.length, available );
                len = m_inputStream.read( buffer, 0, len );
                String outString = new String( buffer, 0, len );
                m_output.append( outString );
            }
        }
        catch( IOException e ) {
            e.printStackTrace();
        }
    }
}
person tangens    schedule 24.08.2013
comment
К сожалению, я не могу использовать apache exec... Не могли бы вы подробнее рассказать о создании другого потока для чтения вывода?? Это решение звучит правильно, и я тоже пытаюсь проверить его сейчас. - person JBuenoJr; 25.08.2013
comment
Не повезло :( ... Я даже реализовал ваш пример кода. available = 0 почти сразу и дает тот же результат, что и в моем вопросе. Он выводит это и просто зависает. - person JBuenoJr; 25.08.2013
comment
Извините, кажется, вы приняли промежуточное состояние моего ответа... Пожалуйста, измените вызов interrupt() на join(). - person tangens; 25.08.2013