/*
* The MIT License (MIT)
*
* Copyright (c) 2015 Almex
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
package be.raildelays.javafx.controller.batch;
import be.raildelays.javafx.service.BatchScheduledService;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javafx.util.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.step.job.JobParametersExtractor;
import java.net.URL;
import java.time.ZoneId;
import java.util.Date;
import java.util.ResourceBundle;
/**
* @author Almex
* @since 1.2
*/
public abstract class AbstractBatchController implements Initializable, BatchController {
@FXML
protected Button startButton;
@FXML
protected Button stopButton;
@FXML
protected Button restartButton;
@FXML
protected Button abandonButton;
@FXML
protected ProgressBar progressBar;
@FXML
protected ProgressIndicator progressIndicator;
@FXML
protected Label progressLabel;
protected String jobName;
protected BatchScheduledService service;
protected JobParametersExtractor propertiesExtractor;
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractBatchController.class);
@Override
public void initialize(URL location, ResourceBundle resources) {
service.setOnSucceeded(event -> doRefreshProgress());
service.setOnFailed(event -> {
final Throwable error = service.getException();
progressLabel.setText("ERROR");
LOGGER.error("An error occurred!", error);
});
service.stateProperty().addListener((ObservableValue<? extends Worker.State> observable,
Worker.State oldValue,
Worker.State newValue) -> executeStateChange());
service.setDelay(Duration.seconds(1));
service.setPeriod(Duration.seconds(1));
progressLabel.setText("");
resetButtons();
}
protected void executeStateChange() {
JobExecution jobExecution = service.getJobExecution();
if (service.isStarted()) {
switch (jobExecution.getStatus()) {
case STARTING:
startButton.setDisable(true);
stopButton.setDisable(false);
abandonButton.setDisable(true);
restartButton.setDisable(true);
break;
case STARTED:
startButton.setDisable(true);
stopButton.setDisable(false);
abandonButton.setDisable(true);
restartButton.setDisable(true);
break;
case COMPLETED:
resetButtons();
break;
case FAILED:
startButton.setDisable(true);
stopButton.setDisable(true);
abandonButton.setDisable(false);
restartButton.setDisable(false);
break;
case STOPPING:
startButton.setDisable(true);
stopButton.setDisable(true);
abandonButton.setDisable(true);
restartButton.setDisable(true);
break;
case STOPPED:
startButton.setDisable(true);
stopButton.setDisable(true);
abandonButton.setDisable(false);
restartButton.setDisable(false);
break;
case ABANDONED:
resetButtons();
break;
default:
}
} else {
resetButtons();
}
}
protected void resetButtons() {
startButton.setDisable(false);
stopButton.setDisable(true);
abandonButton.setDisable(true);
restartButton.setDisable(true);
}
public void doRestart() {
service.restart();
startButton.setDisable(true);
stopButton.setDisable(false);
abandonButton.setDisable(true);
restartButton.setDisable(true);
doRefreshProgress();
}
public void doAbandon() {
if (service.abandon()) {
resetButtons();
doRefreshProgress();
}
}
public void doStop() {
if (service.stop()) {
stopButton.setDisable(true);
stopButton.setDisable(true);
abandonButton.setDisable(true);
restartButton.setDisable(true);
doRefreshProgress();
}
}
public void doStart() {
JobParameters jobParameters = propertiesExtractor.getJobParameters(null, null);
JobParametersBuilder builder = new JobParametersBuilder(jobParameters);
startButton.setDisable(true);
stopButton.setDisable(false);
abandonButton.setDisable(true);
restartButton.setDisable(true);
progressBar.setProgress(0.0);
progressIndicator.setProgress(0.0);
progressLabel.setText("");
if (service.isRunning()) {
service.cancel();
}
addExtraJobParameters(builder);
service.reset();
service.start(jobName, builder.toJobParameters());
doRefreshProgress();
}
protected abstract void addExtraJobParameters(JobParametersBuilder builder);
@Override
public void destroy() {
service.stop();
service.cancel();
service.reset();
}
protected void doRefreshProgress() {
if (service.isStarted()) {
final JobExecution jobExecution = service.getJobExecution();
final long stepDoneCount = jobExecution.getStepExecutions().stream()
.filter(stepExecution -> !stepExecution.getStatus().isRunning())
.count();
final long stepNumber = jobExecution.getStepExecutions().size();
double progress = (double) stepDoneCount / stepNumber;
String status = jobExecution.getStatus().name();
if (!jobExecution.isRunning()) {
service.cancel();
progress = 1;
}
progressBar.setProgress(progress);
progressIndicator.setProgress(progress);
progressLabel.setText(status);
}
}
@Override
public void setService(BatchScheduledService service) {
this.service = service;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
@Override
public void setPropertiesExtractor(JobParametersExtractor propertiesExtractor) {
this.propertiesExtractor = propertiesExtractor;
}
}