Как последовательно выполнять Задачи, Сервисы javaFX

1

С моим классом Controller я должен выполнить несколько команд ввода-вывода (например: SSH, команды RCP с некоторыми значениями параметров) последовательным образом. Каждая из этих команд получит некоторое количество времени для выполнения.

Я должен обновить UI-контроллер, когда каждая команда запускается. Затем, в зависимости от результата выполнения (с успехом или неудачей), я должен снова обновить интерфейс. Затем необходимо выполнить следующую команду с теми же шагами.

Выполнение каждой команды зависит от результата предыдущей команды. В качестве примера,

for (IOCommand command : commandsList) {

    // Update the UI before start the command execution  
    messageTextArea.append("Command " + command.getType() + " Stated");

    boolean result = commandExecutor(command);  

    if(result) {

      // Update the UI after successful execution  
      messageTextArea.append("Command " + command.getType() + " Successfully Executed");

      // Then go to next command execution 

    } else {

      // Update the UI after failure execution  
      messageTextArea.append("Command " + command.getType() + " Failed");

      // Fix the issue and do re execution
      commandReExecutor(command);       
    }
} 

Для выполнения этого постепенного обновления пользовательского интерфейса я должен использовать некоторые связанные с JavaFX задачи или связанные с ним функции (в противном случае он повесит приложение до тех пор, пока не завершится выполнение всех команд, а также обновит интерфейс пользователя сразу). Но из-за природы или параллелизма я не могу выполнять эти команды с помощью задачи или службы последовательно (не сразу, один за другим). Как я могу решить эту проблему. Заранее спасибо.

Теги:
javafx

1 ответ

1

Я хотел бы указать точное требование в проекте, и это можно сделать с помощью "Задачи и службы". Вам просто нужна правильная реализация.
Несколько заметок:
1. Всегда запускайте фоновое задание с помощью службы или Platform.runLater.
2. Если вы хотите обновить пользовательский интерфейс, это должно быть сделано либо из задачи, либо из службы.
3. Привяжите свойство выполнения задачи к значению индикатора выполнения для плавного обновления.
4. Аналогичным образом свяжите свойство text свойства Label с сообщением задачи для плавного обновления статуса или чего-то еще.

Для выполнения внешних команд, таких как shell и т.д. Я написал следующий класс:

package utils;

import controller.ProgressController;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.concurrent.Task;
import main.Installer;

public class ProcessExecutor extends Task<Integer>
{
    Logger logger =Logger.getLogger("ProcessExecutor");
    File dir;
   String []cmd;
    String cmds;
    int exitCode=-1;
    boolean NextStepExists=false;
    Task nextStep;
    public ProcessExecutor(String...cmd )
{
    this.cmd=cmd;
    this.dir=new File(System.getProperty("user.dir"));
    this.nextStep=null;
    NextStepExists=false;
}
public ProcessExecutor(Task nextStep,String...cmd )
{
    this.cmd=cmd;
    this.dir=new File(System.getProperty("user.dir"));
    this.nextStep=nextStep;
    NextStepExists=true;
}
public ProcessExecutor(Task nextStep,File dir,String...cmd)
{
    this.cmd=cmd;
    this.dir=dir;
    this.nextStep=nextStep;
    NextStepExists=true;
}


@Override
protected final Integer call()
{
    cmds=new String();
        for(String i:cmd)
            cmds+=i+" "; // just to log cmd array

    try
    {

        logger.info("Starting new process with cmd > "+cmds);

        ProcessBuilder processBuilder=new ProcessBuilder(cmd);
        processBuilder.directory(dir);
        processBuilder.redirectErrorStream(true);
        Map<String, String> env = processBuilder.environment();
        // create custom environment 
        env.put("JAVA_HOME", "/opt/jdk1.7.0_45/"); 

        Process pr=processBuilder.start();
        BufferedReader in = new BufferedReader(new InputStreamReader(pr.getInputStream()));
           String line = in.readLine();
            while (line != null) {
                logger.log(Level.FINE,line);
                ProgressController.instance.printToConsole(line);
                line = in.readLine();
            }
            BufferedReader er = new BufferedReader(new InputStreamReader(pr.getErrorStream()));
           String erLine = in.readLine();
            while (erLine != null) {
                logger.log(Level.FINE,erLine);
                ProgressController.instance.printToConsole(erLine);
                erLine = in.readLine();
            }


        exitCode=pr.waitFor();
        exitCode=pr.exitValue();
        logger.info("Exit Value="+exitCode);
        updateMessage("Completed Process");
        if(exitCode!=0 && exitCode!=1)
        {
            logger.info("Failed to execute process commands >"+cmds+" with exit code="+exitCode);
            failed();
        }

        else
        {
            logger.info("PE succeeded()");
            if(NextStepExists)
                Installer.pool.submit(nextStep);
            succeeded();
        }

    }
    catch(Exception e)
    {
        logger.log(Level.SEVERE,"Exception: Failed to execute process commands >"+cmds,e);
        updateMessage(e.getMessage());
    }

    return new Integer(exitCode);



}
@Override
public void failed()
{
    super.failed();
    logger.log(Level.SEVERE,"Failed to execute process commands >"+cmds+"; ExitCode="+exitCode);

}
}



Этот класс использует ProcessBuilder для создания требуемой среды для нового процесса,
Он ждет завершения выполнения процесса с помощью process.waitFor(),
каталог процесса может быть установлен с помощью processBuilder.directory(dir).

Чтобы выполнить одну задачу <> в любое время, используйте java.util.concurrent.ExecutorService

public ExecutorService pool=Executors.newSingleThreadExecutor();
pool.submit(new ProcessExecutor("installTomcat.bat","tomcat7"));
pool.submit(new ProcessExecutor("installPostgres.bat","postgresql","5432"));


Таким образом, вы можете выполнять пакетные файлы один за другим.
Executors.newSingleThreadExecutor() заботится о выполнении одной задачи в любое время и опротестовывает вновь отправленные задачи.

Я написал обобщенный рабочий пример последовательного выполнения здесь:
GitHub
Это проект NetBeans JavaFX и его обобщенная и урезанная версия проекта.
Надеюсь это поможет

Ещё вопросы

Сообщество Overcoder
Наверх
Меню