2014-07-04 52 views
1

使用我的控制器類,我必須執行多個IO命令(例如:具有某些參數值的SSH,RCP命令)順序方式。每個命令都會得到一些時間來執行。如何以順序方式執行javaFX任務,服務

當每個命令開始執行時,我必須更新UI控制器。 然後根據執行結果(無論成功還是失敗)我必須再次更新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);  
    } 
} 

爲了實現這一目標逐漸UI更新我必須使用一些JavaFX的相關任務或服務相關的特徵(否則將應用程序掛起,直到完成所有的命令被執行,也將全部更新UI立刻)。但由於自然或併發性,我無法以順序方式(並非全部一次,一個接一個地)在任務或服務的幫助下執行這些命令。我該如何解決這個問題。提前致謝。

+3

看看順序執行示例:[如何重置JavaFX2中任務之間的進度指示器?](http://stackoverflow.com/questions/16368793/how-to-reset-progress-指示器之間的任務功能於javafx2) – jewelsea

回答

1

我想在項目中的確切要求,它可以完成任務和服務。你只需要一個正確的實現。
注意事項:
1.始終使用service或Platform.runLater啓動後臺任務。
2.如果要更新UI,必須從任務或服務完成。
3.將任務的進度屬性綁定到進度條的進度條,以便平滑更新。
4.同樣將Label的文本屬性綁定到任務的消息屬性,以平滑更新狀態或其他內容。

要執行外部命令狀外殼等我寫了下面的類:

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項目及其廣義的&精簡版項目。
希望這有助於