2013-07-03 1 views
0

У меня есть два вызова, которые я выполняю с помощью CommonsExec - один из них - стандартный синхронный вызов, в котором я вызываю пакетный файл для компиляции проекта maven, а следующий - асинхронный вызов также для пакета файл, который запускает скомпилированный проект командной строки.Apache CommonsExec асинхронный вызов, предотвращающий вызов синхронизации

Пакетные файлы Maven выглядеть

call mvn package 

Это делается в два раза, чтобы скомпилировать и запустить две программы.

Это работает отлично в первый раз, но второй вызов сборки синхронизации по какой-то причине не возвращается, хотя выведенный в журнал вывод показывает, что сборка завершена успешно. Программа, очевидно, не запускается.

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

Может кто поможет здесь?

Код для вышеперечисленного

private static final String LAUNCH_CLIENT_FORMAT = "\"%s\\start.bat\" http://localhost:%d" + ENDPOINT; 
private static final String COMPILE_FORMAT = "\"%s\\compile.bat\""; 

private static boolean compileAndLaunch(String aiDirectory, int port) { 
    System.out.println("Compiling " + aiDirectory + " for port " + port); 
    if (!run(String.format(COMPILE_FORMAT, aiDirectory), aiDirectory)) 
    return false; 

    System.out.println("Done compiling " + aiDirectory + " for port " + port + ", launching..."); 
    if (!runAsync(String.format(LAUNCH_CLIENT_FORMAT, aiDirectory, port), aiDirectory)) 
    return false; 

    return true; 
} 

private static boolean run(String command, String directory) { 
    DefaultExecutor executor = getExecutor(directory); 
    System.out.println("Running " + command); 
    CommandLine commandLine = CommandLine.parse(command); 
    try { 
    executor.execute(commandLine); 
    } 
    catch (ExecuteException e) { 
    System.out.println("Failed to execute " + command); 
    return false; 
    } 
    catch (IOException e) { 
    System.out.println("IO Exception running " + command); 
    return false; 
    } 
    return true; 
} 

private static DefaultExecutor getExecutor(String directory) { 
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 
    PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream); 
    DefaultExecutor executor = new DefaultExecutor(); 
    executor.setWorkingDirectory(new File(directory)); 
    executor.setStreamHandler(streamHandler); 
    return executor; 
} 

private static boolean runAsync(String command, String directory) { 

    CommandLine commandLine = CommandLine.parse(command); 
    System.out.println("Running async " + command); 
    DefaultExecutor executor = getExecutor(directory); 
    DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler(); 
    try { 
    executor.execute(commandLine, resultHandler); 
    } 
    catch (ExecuteException e) { 
    System.out.println("Failed to execute " + command); 
    return false; 
    } 
    catch (IOException e) { 
    System.out.println("IO Exception running " + command); 
    return false; 
    } 
    return true; 
} 
+0

'но второй вызов построения синхронизации не возвращается' - вы имеете в виду асинхронный здесь? Не стесняйтесь включать свой код, иначе ответы просто догадываются о том, что вы делаете. –

+0

Эй - Я строю синхронно, а затем запускаю программу асинхронно. Вторая сборка не заканчивается, хотя на выходе отображается BUILD SUCCESSFUL. Я добавлю код. –

+0

Выполняют ли два набора командных файлов в одном каталоге? Может ли это быть тупиком в самом maven? Что произойдет, если вы запустите четыре команды из командной строки в той же последовательности. Я не мог воспроизвести проблему, когда я заменил сборку просто вызовом «sleep x». Тогда вторая синхронная команда будет работать без проблем, пока предыдущая асинхронная команда все еще работает. Заставляет меня думать, что тупик находится в пакетных сценариях или в maven. – Keith

ответ

3

Это ваш обратный вызов:

DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler(); 

Это ваш асинхронный исполнитель:

executor.execute(commandLine, resultHandler); 

Но, в асинхронном режиме, сразу после вызов executor.execute() метод будет продолжаться, но пока что-то не произойдет в другом потоке и resultHandler.onProcessComplete() или resultHandler.onProcessFailed(), вы все еще не знаете, закончилось ли выполнение, и не следует выходить из метода runAsync().

Я считаю, что изменить способ к чему-то, как это будет работать:

private static boolean runAsync(String command, String directory) { 

    CommandLine commandLine = CommandLine.parse(command); 
    System.out.println("Running async " + command); 
    DefaultExecutor executor = getExecutor(directory); 
    DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler(); 
    try { 
    executor.execute(commandLine, resultHandler); 
    resultHandler.waitFor(); 
    if(resultHandler.getException() != null){ 
     throw resultHandler.getException(); 
    } 
    } 
    catch (ExecuteException e) { 
    System.out.println("Failed to execute " + command); 
    return false; 
    } 
    catch (IOException e) { 
    System.out.println("IO Exception running " + command); 
    return false; 
    } 
    return true; 
} 

Поскольку resultHandler.waitFor() заставит ждать нить, пока не закончится выполнение.

Но это то же самое, что и в синхронном режиме. Только если оба вызова асинхронны, вы выиграете в производительности, потому что они будут работать параллельно, и вы будете ждать, пока оба не закончатся.

+0

В чем смысл DefaultExecuteResultHandler(), если он все равно должен блокироваться? Вы должны всегда расширять его? – JohnyTex

+1

Нет причин, но если есть много команд для выполнения, было бы полезно. Нужно будет изменить параметр 'command', чтобы ввести' List 'или' String [] '. По другому вопросу вы также можете реализовать «ExecuteResultHandler». –