3030import com .google .common .base .Charsets ;
3131import com .google .common .net .HttpHeaders ;
3232import com .google .common .net .MediaType ;
33+ import javafx .concurrent .Task ;
3334import javafx .event .ActionEvent ;
3435import javafx .fxml .FXML ;
3536import javafx .fxml .Initializable ;
5657import java .text .MessageFormat ;
5758import java .util .*;
5859import java .util .List ;
60+ import java .util .concurrent .Callable ;
5961
6062/**
6163 * TRex Daemon FXM controller
@@ -87,6 +89,11 @@ public String pass(@NotNull String request) throws IOException {
8789 }
8890 }
8991
92+ @ FunctionalInterface
93+ interface ExceptionHandler {
94+ void handle (Throwable ex );
95+ }
96+
9097 @ FXML
9198 private ComboBox <String > hostnamesComboBox ;
9299
@@ -117,6 +124,8 @@ public String pass(@NotNull String request) throws IOException {
117124 @ FXML
118125 private Button startTRexButton ;
119126
127+ @ FXML TextField startTRexTimeoutTextField ;
128+
120129 @ FXML
121130 private Button loadDefaultConfigButton ;
122131
@@ -130,21 +139,31 @@ public String pass(@NotNull String request) throws IOException {
130139
131140 private UserConfigModel userConfigModel ;
132141 private String configFilename ;
142+ private Task <Void > currentPendingTask ;
133143
134144 private List <Control > controlsDisabledOnDisconnected ;
135145 private List <Control > controlsDisabledOnConnected ;
136146 private List <Control > controlsDisabledOnMetadataNotExists ;
137147 private List <Control > controlsDisabledOnConfigInvalid ;
138-
148+ private List < Control > controlsDisabledOnPendingTask ;
139149 @ Override
140150 public void initialize (URL location , ResourceBundle resources ) {
141151 initHostnamesComboBox ();
142152 controlsDisabledOnConnected = Arrays .asList (hostnamesComboBox , rpcPortTextField , connectButton );
143- controlsDisabledOnDisconnected = Arrays .asList (disconnectButton , startTRexButton , stopTRexButton );
153+ controlsDisabledOnDisconnected = Arrays .asList (disconnectButton , startTRexButton , startTRexTimeoutTextField , stopTRexButton );
144154 controlsDisabledOnMetadataNotExists = Arrays .asList (configEditTitledPane , loadDefaultConfigButton );
145- controlsDisabledOnConfigInvalid = Arrays .asList (startTRexButton );
155+ controlsDisabledOnConfigInvalid = Collections .singletonList (startTRexButton );
156+ controlsDisabledOnPendingTask = Arrays .asList (hostnamesComboBox , rpcPortTextField , connectButton , startTRexButton , startTRexTimeoutTextField , stopTRexButton , loadDefaultConfigButton );
157+
146158 configEditTitledPane .expandedProperty ().bind (configEditTitledPane .disableProperty ().not ());
147- this .configFilename = System .getProperty ("user.name" );
159+ configFilename = System .getProperty ("user.name" );
160+
161+ startTRexTimeoutTextField .textProperty ().addListener ((observable , oldValue , newValue ) -> {
162+ if (!newValue .matches ("\\ d*" )) {
163+ startTRexTimeoutTextField .setText (newValue .replaceAll ("[^\\ d]" , "" ));
164+ }
165+ });
166+
148167 refreshControlsAvailability ();
149168 }
150169
@@ -208,6 +227,12 @@ private void refreshControlsAvailability() {
208227 control .setDisable (true );
209228 }
210229 }
230+
231+ if (currentPendingTask != null ) {
232+ for (Control control : controlsDisabledOnPendingTask ) {
233+ control .setDisable (true );
234+ }
235+ }
211236 }
212237
213238 private boolean isConnected () {
@@ -216,6 +241,12 @@ private boolean isConnected() {
216241
217242 private void disconnect () {
218243 if (isConnected ()) {
244+
245+ if (currentPendingTask != null ){
246+ currentPendingTask .cancel ();
247+ currentPendingTask = null ;
248+ }
249+
219250 client = null ;
220251 metadata = null ;
221252
@@ -256,6 +287,10 @@ private String getPort() {
256287 return rpcPortTextField .getText ();
257288 }
258289
290+ private Integer getStartTimeout () {
291+ return Integer .valueOf (startTRexTimeoutTextField .getText ());
292+ }
293+
259294 private String getHostname () {
260295 return hostnamesComboBox .getSelectionModel ().getSelectedItem ();
261296 }
@@ -291,58 +326,93 @@ private void getMetadata() {
291326 }
292327
293328 private void startTRex () {
294- Boolean configUploaded = false ;
295- try {
296- configUploaded = client .createRequest ()
297- .id (getId ())
298- .method ("push_file" )
299- .param ("filename" , configFilename )
300- .param ("bin_data" , Base64 .getEncoder ().encodeToString (
301- userConfigModel .getYAMLString ().getBytes (Charsets .US_ASCII )))
302- .returnAs (Boolean .class )
303- .execute ();
304-
305- if (!configUploaded ) {
306- log (LogType .ERROR , "Config upload to TRex host failed (TRex Daemon IO error)" );
307- }
329+ scheduleTask (() -> {
330+ try {
331+ Boolean configUploaded = client .createRequest ()
332+ .id (getId ())
333+ .method ("push_file" )
334+ .param ("filename" , configFilename )
335+ .param ("bin_data" , Base64 .getEncoder ().encodeToString (
336+ userConfigModel .getYAMLString ().getBytes (Charsets .US_ASCII )))
337+ .returnAs (Boolean .class )
338+ .execute ();
339+
340+ if (!configUploaded ) {
341+ throw new RuntimeException ("Config upload to TRex host failed (TRex Daemon IO error)" );
342+ }
343+
344+ log (LogType .INFO , "Config was uploaded successfully" );
345+ } catch (RuntimeException ex ) {
346+ throw new RuntimeException (MessageFormat .format ("Config upload to TRex host failed: {0}" , ex ));
347+ } catch (JsonProcessingException ex ) {
348+ throw new RuntimeException (MessageFormat .format ("Config serialization failed: {0}" , ex ));
349+ }
350+
351+ Map <String , Object > cmdParams = new HashMap <>();
352+ try {
353+ String files_path = client .createRequest ()
354+ .id (getId ())
355+ .method ("get_files_path" )
356+ .returnAs (String .class )
357+ .execute ();
358+
359+ cmdParams .put ("cfg" , FilenameUtils .separatorsToUnix (Paths .get (files_path , configFilename ).toString ()));
360+ } catch (RuntimeException ex ) {
361+ throw new RuntimeException (MessageFormat .format ("Unable to get user configs path: {0}" , ex ));
362+ }
363+
364+ try {
365+ log (LogType .INFO , MessageFormat .format ("Starting TRex... (timeout is {0} sec)" , getStartTimeout ()));
366+ client .createRequest ()
367+ .id (getId ())
368+ .method ("start_trex" )
369+ .param ("trex_cmd_options" , cmdParams )
370+ .param ("user" , System .getProperty ("user.name" ))
371+ .param ("stateless" , true )
372+ .returnAs (Integer .class )
373+ .param ("timeout" , getStartTimeout ())
374+ .execute ();
375+
376+ } catch (RuntimeException ex ) {
377+ throw new RuntimeException (MessageFormat .format ("Unable to start TRex: {0} " , ex ));
378+ }
379+ return null ;
380+ },
381+ ex -> log (LogType .ERROR , ex .getMessage ()),
382+ () -> log (LogType .INFO , "TRex was started successfully" ),
383+ () -> log (LogType .WARNING , "TRex start was cancelled" )
384+ );
385+ }
308386
309- log (LogType .INFO , "Config uploaded successfully" );
310- } catch (RuntimeException ex ) {
311- log (LogType .ERROR , MessageFormat .format ("Config upload to TRex host failed: {0}" , ex ));
312- } catch (JsonProcessingException ex ) {
313- log (LogType .ERROR , MessageFormat .format ("Config serialization failed: {0}" , ex ));
387+ private void scheduleTask (Callable <Void > mainAction , ExceptionHandler onException , Runnable onSucceed , Runnable onCanceled ) {
388+ if (currentPendingTask != null ) {
389+ currentPendingTask .cancel ();
314390 }
315391
316- Map <String , Object > cmdParams = new HashMap <>();
317-
318- if (configUploaded ) {
319- try {
320- String files_path = client .createRequest ()
321- .id (getId ())
322- .method ("get_files_path" )
323- .returnAs (String .class )
324- .execute ();
325-
326- cmdParams .put ("cfg" , FilenameUtils .separatorsToUnix (Paths .get (files_path , configFilename ).toString ()));
327- } catch (RuntimeException ex ) {
328- log (LogType .ERROR , MessageFormat .format ("Unable to get user configs path: {0}" , ex ));
392+ currentPendingTask = new Task <Void >() {
393+ @ Override
394+ protected Void call () throws Exception {
395+ return mainAction .call ();
329396 }
330- }
397+ };
398+ currentPendingTask .setOnFailed (event -> {
399+ onException .handle (currentPendingTask .getException ());
400+ currentPendingTask = null ;
401+ refreshControlsAvailability ();
402+ });
403+ currentPendingTask .setOnSucceeded (event -> {
404+ onSucceed .run ();
405+ currentPendingTask = null ;
406+ refreshControlsAvailability ();
407+ });
408+ currentPendingTask .setOnCancelled (event -> {
409+ onCanceled .run ();
410+ currentPendingTask = null ;
411+ refreshControlsAvailability ();
412+ });
331413
332- try {
333- Integer trexSessionHandler = client .createRequest ()
334- .id (getId ())
335- .method ("start_trex" )
336- .param ("trex_cmd_options" , cmdParams )
337- .param ("user" , System .getProperty ("user.name" ))
338- .param ("stateless" , true )
339- .returnAs (Integer .class )
340- .param ("timeout" , 15 )
341- .execute ();
342- log (LogType .INFO , "TRex started successfully" );
343- } catch (RuntimeException ex ) {
344- log (LogType .ERROR , MessageFormat .format ("Unable to start TRex: {0} " , ex ));
345- }
414+ new Thread (currentPendingTask ).start ();
415+ refreshControlsAvailability ();
346416 }
347417
348418 private void stopTRex () {
0 commit comments