startup report added

This commit is contained in:
Niklas Aumueller 2026-03-06 19:02:46 +01:00
parent 1c1709f018
commit d5fdc9bcee
3 changed files with 105 additions and 24 deletions

View File

@ -5,6 +5,7 @@ import vassistent.model.AppState;
import vassistent.service.*;
import vassistent.util.AppConfigValidator;
import vassistent.util.ConfigLoader;
import vassistent.util.Logger;
import javax.swing.*;
import java.util.Properties;
@ -99,9 +100,13 @@ public class ApplicationInitializer {
context.setProcessManagerService(new ProcessManagerService(config));
Logger.info("PROCESS", "Starting configured external processes");
ProcessManagerService.StartupReport startupReport =
context.getProcessManagerService().startProcesses();
logProcessStartupReport(startupReport);
if (startupReport.hasFailures()) {
context.getProcessManagerService().shutdown();
throw new IllegalStateException(startupReport.buildFailureMessage());
@ -144,4 +149,51 @@ public class ApplicationInitializer {
return trimmed;
}
/**
* Logs startup status for all process components and the global startup result.
*
* @param startupReport startup status report from {@link ProcessManagerService}
*/
private static void logProcessStartupReport(
ProcessManagerService.StartupReport startupReport
) {
logProcessStartStatus(startupReport.getMqttSimulator());
logProcessStartStatus(startupReport.getUnreal());
if (startupReport.hasFailures()) {
Logger.error("PROCESS", startupReport.buildFailureMessage());
return;
}
Logger.info("PROCESS", "External process startup completed successfully");
}
/**
* Logs one startup component status from the process startup report.
*
* @param status startup status for one managed process component
*/
private static void logProcessStartStatus(
ProcessManagerService.ProcessStartStatus status
) {
String component = status.getComponentName();
if (!status.isEnabled()) {
Logger.info("PROCESS", component + " startup skipped (disabled)");
return;
}
if (status.isStarted()) {
Logger.info("PROCESS", component + " startup succeeded");
return;
}
String error = status.getErrorMessage();
if (error == null || error.isBlank()) {
Logger.error("PROCESS", component + " startup failed");
} else {
Logger.error("PROCESS", component + " startup failed: " + error);
}
}
}

View File

@ -8,6 +8,8 @@ import vassistent.util.Logger;
import javax.swing.*;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Updates the dashboard chart and level bar whenever application state changes.
@ -16,6 +18,7 @@ public class DashboardController {
private final StatisticsService statisticsService;
private final DashboardView dashboardView;
private final ExecutorService dashboardUpdateExecutor;
/**
* Creates a dashboard controller and subscribes to app state changes.
@ -31,6 +34,12 @@ public class DashboardController {
) {
this.statisticsService = statisticsService;
this.dashboardView = dashboardView;
this.dashboardUpdateExecutor =
Executors.newSingleThreadExecutor(runnable -> {
Thread thread = new Thread(runnable, "dashboard-update");
thread.setDaemon(true);
return thread;
});
appState.addListener(this::onStateChanged);
}
@ -41,21 +50,22 @@ public class DashboardController {
* @param state latest application state
*/
private void onStateChanged(AppState state) {
dashboardUpdateExecutor.execute(() -> {
List<RatioPoint> points =
statisticsService.getLastNAverages(120);
List<RatioPoint> points =
statisticsService.getLastNAverages(120);
SwingUtilities.invokeLater(() -> {
SwingUtilities.invokeLater(() -> {
Logger.info("STATISTICS",
"Entries loaded: " + points.size());
Logger.info("STATISTICS",
"Entries loaded: " + points.size());
dashboardView.updateChart(points);
dashboardView.updateChart(points);
if (!points.isEmpty()) {
double ratio = points.get(points.size() - 1).getRatio();
dashboardView.updateProblemLevel(ratio);
}
if (!points.isEmpty()) {
double ratio = points.get(points.size() - 1).getRatio();
dashboardView.updateProblemLevel(ratio);
}
});
});
}
}

View File

@ -1,7 +1,11 @@
package vassistent.model;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
/**
@ -9,12 +13,13 @@ import java.util.function.Consumer;
*/
public class AppState {
private long dataVersion = 0;
private boolean mqttConnected;
private ProblemLevel problemLevel = ProblemLevel.NONE;
private final AtomicLong dataVersion = new AtomicLong(0);
private final AtomicBoolean mqttConnected = new AtomicBoolean(false);
private final AtomicReference<ProblemLevel> problemLevel =
new AtomicReference<>(ProblemLevel.NONE);
private final List<Consumer<AppState>> listeners =
new ArrayList<>();
new CopyOnWriteArrayList<>();
/**
* Registers a state listener that is notified on relevant updates.
@ -22,14 +27,19 @@ public class AppState {
* @param listener callback receiving the current state instance
*/
public void addListener(Consumer<AppState> listener) {
listeners.add(listener);
listeners.add(
Objects.requireNonNull(
listener,
"listener must not be null"
)
);
}
/**
* Notifies all currently registered listeners.
*/
private void notifyListeners() {
new ArrayList<>(listeners).forEach(l -> l.accept(this));
listeners.forEach(listener -> listener.accept(this));
}
/**
@ -38,7 +48,7 @@ public class AppState {
* @return current problem level
*/
public ProblemLevel getProblemLevel() {
return problemLevel;
return problemLevel.get();
}
/**
@ -47,8 +57,14 @@ public class AppState {
* @param problemLevel new problem level
*/
public void setProblemLevel(ProblemLevel problemLevel) {
this.problemLevel = problemLevel;
dataVersion++;
this.problemLevel.set(
Objects.requireNonNull(
problemLevel,
"problemLevel must not be null"
)
);
dataVersion.incrementAndGet();
notifyListeners();
}
@ -58,7 +74,7 @@ public class AppState {
* @return {@code true} if connected, otherwise {@code false}
*/
public boolean isMqttConnected() {
return mqttConnected;
return mqttConnected.get();
}
/**
@ -67,8 +83,11 @@ public class AppState {
* @param mqttConnected new MQTT connection flag
*/
public void setMqttConnected(boolean mqttConnected) {
if (this.mqttConnected != mqttConnected) {
this.mqttConnected = mqttConnected;
boolean previous =
this.mqttConnected.getAndSet(mqttConnected);
if (previous != mqttConnected) {
dataVersion.incrementAndGet();
notifyListeners();
}
}