From 6da13c1aa0621a966c76b2a29349bbed07f1b105 Mon Sep 17 00:00:00 2001
From: 4rthur-Root
Date: Wed, 10 Jun 2026 20:37:05 +0000
Subject: [PATCH 01/31] docs: add the drawio files
---
docs/Diagrammes/Arreter-VM.drawio | 15 +
docs/Diagrammes/Creer-Labo.drawio | 129 ++++++
docs/Diagrammes/Exporter-PDF.drawio | 15 +
docs/Diagrammes/Importer-VM.drawio | 15 +
docs/Diagrammes/Prendre-Snapshot.drawio | 120 ++++++
docs/Diagrammes/Restaurer-Snapshot.drawio | 15 +
docs/Diagrammes/SEQ1-Demarrer-VM.drawio | 15 +
docs/Diagrammes/UML.drawio | 463 ++++++++++++++++++++++
8 files changed, 787 insertions(+)
create mode 100644 docs/Diagrammes/Arreter-VM.drawio
create mode 100644 docs/Diagrammes/Creer-Labo.drawio
create mode 100644 docs/Diagrammes/Exporter-PDF.drawio
create mode 100644 docs/Diagrammes/Importer-VM.drawio
create mode 100644 docs/Diagrammes/Prendre-Snapshot.drawio
create mode 100644 docs/Diagrammes/Restaurer-Snapshot.drawio
create mode 100644 docs/Diagrammes/SEQ1-Demarrer-VM.drawio
create mode 100644 docs/Diagrammes/UML.drawio
diff --git a/docs/Diagrammes/Arreter-VM.drawio b/docs/Diagrammes/Arreter-VM.drawio
new file mode 100644
index 0000000..cc37d4e
--- /dev/null
+++ b/docs/Diagrammes/Arreter-VM.drawio
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/Diagrammes/Creer-Labo.drawio b/docs/Diagrammes/Creer-Labo.drawio
new file mode 100644
index 0000000..847d739
--- /dev/null
+++ b/docs/Diagrammes/Creer-Labo.drawio
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/Diagrammes/Exporter-PDF.drawio b/docs/Diagrammes/Exporter-PDF.drawio
new file mode 100644
index 0000000..85d2a17
--- /dev/null
+++ b/docs/Diagrammes/Exporter-PDF.drawio
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/Diagrammes/Importer-VM.drawio b/docs/Diagrammes/Importer-VM.drawio
new file mode 100644
index 0000000..6cd5329
--- /dev/null
+++ b/docs/Diagrammes/Importer-VM.drawio
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/Diagrammes/Prendre-Snapshot.drawio b/docs/Diagrammes/Prendre-Snapshot.drawio
new file mode 100644
index 0000000..2d5942f
--- /dev/null
+++ b/docs/Diagrammes/Prendre-Snapshot.drawio
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/Diagrammes/Restaurer-Snapshot.drawio b/docs/Diagrammes/Restaurer-Snapshot.drawio
new file mode 100644
index 0000000..9300d5c
--- /dev/null
+++ b/docs/Diagrammes/Restaurer-Snapshot.drawio
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/Diagrammes/SEQ1-Demarrer-VM.drawio b/docs/Diagrammes/SEQ1-Demarrer-VM.drawio
new file mode 100644
index 0000000..e9099ae
--- /dev/null
+++ b/docs/Diagrammes/SEQ1-Demarrer-VM.drawio
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/Diagrammes/UML.drawio b/docs/Diagrammes/UML.drawio
new file mode 100644
index 0000000..ed744ba
--- /dev/null
+++ b/docs/Diagrammes/UML.drawio
@@ -0,0 +1,463 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 9d295cb39ca5d9e2d2ecb9e2bad7e293037cebfc Mon Sep 17 00:00:00 2001
From: 4rthur-Root
Date: Wed, 10 Jun 2026 20:44:00 +0000
Subject: [PATCH 02/31] clean: remove decorative separator lines from pom.xml
and module-info.java
---
pom.xml | 14 +++++++-------
src/main/java/module-info.java | 10 +++++-----
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/pom.xml b/pom.xml
index 00d3d36..fd49685 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,7 +19,7 @@
-
+
org.openjfx
javafx-controls
@@ -31,21 +31,21 @@
${javafx.version}
-
+
org.xerial
sqlite-jdbc
3.49.1.0
-
+
org.apache.pdfbox
pdfbox
3.0.4
-
+
org.junit.jupiter
@@ -80,7 +80,7 @@
-
+
org.apache.maven.plugins
maven-compiler-plugin
@@ -88,7 +88,7 @@
+
org.openjfx
javafx-maven-plugin
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 930b3ae..873c65e 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -3,18 +3,18 @@
*/
module tg.cyberlabmanager {
- // ── JavaFX ──────────────────────────────────────────────────────────
+ // JavaFX
requires javafx.controls;
requires javafx.fxml;
- // ── JDBC + SQLite ────────────────────────────────────────────────────
+ // JDBC + SQLite
requires java.sql;
requires org.xerial.sqlitejdbc;
- // ── Export PDF ───────────────────────────────────────────────────────
+ // Export PDF
requires org.apache.pdfbox;
- // ── Logging (java.util.logging) ──────────────────────────────────────
+ // Logging
requires java.logging;
/*
@@ -26,7 +26,7 @@
opens tg.cyberlabmanager.controller to javafx.fxml;
opens tg.cyberlabmanager.ui to javafx.fxml;
- // ── Exports publics ──────────────────────────────────────────────────
+ // Exports publics
exports tg.cyberlabmanager.app;
exports tg.cyberlabmanager.controller;
exports tg.cyberlabmanager.model;
From 8cce02de2a425d6ac870fd13790d9b6807230cd5 Mon Sep 17 00:00:00 2001
From: 4rthur-Root
Date: Fri, 12 Jun 2026 16:55:01 +0000
Subject: [PATCH 03/31] Code: Implementation of VBoxException with IHypervisor
---
.../java/tg/cyberlabmanager/hypervisor/VBoxException.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/main/java/tg/cyberlabmanager/hypervisor/VBoxException.java b/src/main/java/tg/cyberlabmanager/hypervisor/VBoxException.java
index 9851744..3ae1587 100644
--- a/src/main/java/tg/cyberlabmanager/hypervisor/VBoxException.java
+++ b/src/main/java/tg/cyberlabmanager/hypervisor/VBoxException.java
@@ -1,16 +1,16 @@
package tg.cyberlabmanager.hypervisor;
/**
- * Exception specifique aux commandes VirtualBox executees via VBoxManage.
+ * Exception specifique aux commandes VirtualBox exécutées via VBoxManage.
*/
public class VBoxException extends HypervisorException {
- /** Code de sortie retourne par VBoxManage. */
+ /** Code de sortie retourné par VBoxManage. */
private final int exitCode;
- /** Sortie standard ou erreur retournee par VBoxManage. */
+ /** Sortie standard ou erreur retournée par VBoxManage. */
private final String output;
/**
- * Cree une exception VirtualBox avec le code de sortie et la sortie texte.
+ * Crée une exception VirtualBox avec le code de sortie et la sortie texte.
*
* @param message message decrivant l'erreur
* @param exitCode code de sortie de VBoxManage
From 2b2c8a02f3c9f20e636a75e20376ca0b4894f042 Mon Sep 17 00:00:00 2001
From: 4rthur-Root
Date: Fri, 12 Jun 2026 16:58:51 +0000
Subject: [PATCH 04/31] Code: Implementing Vboxorchestrator to run vboxmanage
commands
---
.../hypervisor/VBoxOrchestrator.java | 297 ++++++++++++++++--
1 file changed, 279 insertions(+), 18 deletions(-)
diff --git a/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java b/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java
index b8f432d..a0320d6 100644
--- a/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java
+++ b/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java
@@ -1,58 +1,319 @@
package tg.cyberlabmanager.hypervisor;
+import tg.cyberlabmanager.model.AppConfig;
import tg.cyberlabmanager.model.VMStatus;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
- * Implementation de {@link IHypervisor} pour VirtualBox via VBoxManage.
+ * Implémentation de {@link IHypervisor} pour VirtualBox via VBoxManage.
+ *
+ * À la construction, l'orchestrateur résout le chemin de VBoxManage en
+ * trois étapes :
+ *
+ * - Utilisation du chemin présent dans {@link AppConfig} s'il est valide.
+ * - Auto-détection dans les emplacements standards de l'OS.
+ * - Si introuvable, {@link #vboxManagePath} reste {@code null} ; toute
+ * opération lève une {@link HypervisorException} que l'UI intercepte
+ * pour inviter l'utilisateur à saisir le chemin manuellement.
+ *
*/
public class VBoxOrchestrator implements IHypervisor {
+
+ /** Regex pour analyser une ligne de {@code VBoxManage list vms} : {@code "Nom" {uuid}}. */
+ private static final Pattern LIST_VMS_PATTERN =
+ Pattern.compile("^\"(.+)\"\\s+\\{([0-9a-fA-F\\-]+)}$");
+
+ /** Chemin résolu vers VBoxManage, ou {@code null} si introuvable. */
+ private String vboxManagePath;
+
+ /**
+ * Crée un orchestrateur VirtualBox.
+ *
+ * Tente de résoudre VBoxManage depuis la configuration fournie,
+ * puis par auto-détection si nécessaire.
+ *
+ * @param config configuration de l'application (peut être {@code null})
+ */
+ public VBoxOrchestrator(AppConfig config) {
+ String configured = (config != null) ? config.getVboxManagePath() : null;
+
+ if (configured != null && !configured.isBlank() && isVBoxManageExecutable(configured)) {
+ this.vboxManagePath = configured;
+ } else {
+ this.vboxManagePath = detectVBoxManage();
+ }
+ }
+
/**
- * Cree un orchestrateur VirtualBox.
+ * Indique si VBoxManage a été résolu et est prêt à l'emploi.
+ *
+ * L'UI appelle cette méthode au démarrage pour décider si elle doit
+ * afficher une boîte de dialogue de configuration.
+ *
+ * @return {@code true} si VBoxManage est disponible
*/
- public VBoxOrchestrator() {
+ public boolean isReady() {
+ return vboxManagePath != null;
}
- /** {@inheritDoc} */
+ /**
+ * Met à jour le chemin de VBoxManage après saisie par l'utilisateur.
+ *
+ * @param path chemin vers l'exécutable VBoxManage
+ * @throws HypervisorException si le chemin est vide ou non exécutable
+ */
+ public void setVboxManagePath(String path) throws HypervisorException {
+ if (path == null || path.isBlank()) {
+ throw new HypervisorException("Le chemin de VBoxManage ne peut pas être vide.");
+ }
+ if (!isVBoxManageExecutable(path)) {
+ throw new HypervisorException(
+ "Impossible d'exécuter VBoxManage au chemin indiqué : " + path);
+ }
+ this.vboxManagePath = path;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Exécute {@code VBoxManage list vms} et retourne les paires
+ * {@code [nom, uuid]} pour chaque VM trouvée.
+ */
@Override
public List listVMs() throws HypervisorException {
- throw new UnsupportedOperationException("Not implemented yet");
+ String output = runCommand("list", "vms");
+ List vms = new ArrayList<>();
+
+ for (String line : output.split("\\r?\\n")) {
+ Matcher m = LIST_VMS_PATTERN.matcher(line.trim());
+ if (m.matches()) {
+ vms.add(new String[]{m.group(1), m.group(2)});
+ }
+ }
+
+ return vms;
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ *
+ * Exécute {@code VBoxManage showvminfo --machinereadable} et
+ * extrait le champ {@code VMState}.
+ */
@Override
public VMStatus getStatus(String uuid) throws HypervisorException {
- throw new UnsupportedOperationException("Not implemented yet");
+ String output = runCommand("showvminfo", uuid, "--machinereadable");
+
+ for (String line : output.split("\\r?\\n")) {
+ if (line.startsWith("VMState=")) {
+ String state = line.substring("VMState=".length())
+ .replace("\"", "").trim();
+ return parseVMStatus(state);
+ }
+ }
+
+ return VMStatus.UNKNOWN;
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ *
+ * Exécute {@code VBoxManage startvm --type headless}.
+ */
@Override
public void startVM(String uuid) throws HypervisorException {
- throw new UnsupportedOperationException("Not implemented yet");
+ runCommand("startvm", uuid, "--type", "headless");
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ *
+ * Exécute {@code VBoxManage controlvm poweroff}.
+ */
@Override
public void stopVM(String uuid) throws HypervisorException {
- throw new UnsupportedOperationException("Not implemented yet");
+ runCommand("controlvm", uuid, "poweroff");
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ *
+ * Exécute {@code VBoxManage controlvm savestate}.
+ */
@Override
public void saveState(String uuid) throws HypervisorException {
- throw new UnsupportedOperationException("Not implemented yet");
+ runCommand("controlvm", uuid, "savestate");
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ *
+ * Exécute {@code VBoxManage snapshot take }
+ * avec {@code --description} si une description est fournie.
+ */
@Override
- public void takeSnapshot(String uuid, String name, String description) throws HypervisorException {
- throw new UnsupportedOperationException("Not implemented yet");
+ public void takeSnapshot(String uuid, String name, String description)
+ throws HypervisorException {
+ if (description != null && !description.isBlank()) {
+ runCommand("snapshot", uuid, "take", name, "--description", description);
+ } else {
+ runCommand("snapshot", uuid, "take", name);
+ }
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ *
+ * Exécute {@code VBoxManage snapshot restore }.
+ */
@Override
public void restoreSnapshot(String uuid, String snapshotName) throws HypervisorException {
- throw new UnsupportedOperationException("Not implemented yet");
+ runCommand("snapshot", uuid, "restore", snapshotName);
+ }
+
+ /**
+ * Exécute une commande VBoxManage et retourne la sortie standard.
+ *
+ * @param args arguments passés à VBoxManage (sans le chemin du binaire)
+ * @return sortie texte produite par VBoxManage
+ * @throws HypervisorException si VBoxManage n'est pas configuré, si la
+ * commande échoue ou si une erreur I/O survient
+ */
+ private String runCommand(String... args) throws HypervisorException {
+ requireConfigured();
+
+ String[] command = new String[args.length + 1];
+ command[0] = vboxManagePath;
+ System.arraycopy(args, 0, command, 1, args.length);
+
+ try {
+ ProcessBuilder pb = new ProcessBuilder(command);
+ pb.redirectErrorStream(true);
+ Process process = pb.start();
+
+ String output = new String(
+ process.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
+ int exitCode = process.waitFor();
+
+ if (exitCode != 0) {
+ throw new VBoxException(
+ "Échec de la commande VBoxManage : " + String.join(" ", args),
+ exitCode, output);
+ }
+
+ return output;
+
+ } catch (VBoxException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new HypervisorException("Erreur I/O lors de l'exécution de VBoxManage.", e);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new HypervisorException("Exécution de VBoxManage interrompue.", e);
+ }
+ }
+
+ /**
+ * Vérifie que VBoxManage est configuré avant toute commande.
+ *
+ * @throws HypervisorException si le chemin n'a pas été résolu
+ */
+ private void requireConfigured() throws HypervisorException {
+ if (vboxManagePath == null) {
+ throw new HypervisorException(
+ "VBoxManage est introuvable. "
+ + "Veuillez configurer son chemin dans les paramètres de l'application.");
+ }
+ }
+
+ /**
+ * Parcourt les emplacements standards de l'OS pour trouver VBoxManage.
+ *
+ * @return premier chemin valide trouvé, ou {@code null}
+ */
+ private static String detectVBoxManage() {
+ String os = System.getProperty("os.name", "").toLowerCase();
+
+ for (String candidate : buildCandidatePaths(os)) {
+ if (isVBoxManageExecutable(candidate)) {
+ return candidate;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Construit la liste des chemins candidats selon l'OS.
+ *
+ * @param osName nom de l'OS en minuscules
+ * @return chemins à tester, du plus probable au moins probable
+ */
+ private static List buildCandidatePaths(String osName) {
+ List candidates = new ArrayList<>();
+
+ if (osName.contains("win")) {
+ // Commande nue d'abord (si VirtualBox est dans le PATH Windows)
+ candidates.add("VBoxManage.exe");
+ candidates.add("C:\\Program Files\\Oracle\\VirtualBox\\VBoxManage.exe");
+ candidates.add("C:\\Program Files (x86)\\Oracle\\VirtualBox\\VBoxManage.exe");
+ } else {
+ // Linux / macOS — PATH d'abord, puis chemins typiques
+ candidates.add("VBoxManage");
+ candidates.add("vboxmanage");
+ candidates.add("/usr/bin/VBoxManage");
+ candidates.add("/usr/local/bin/VBoxManage");
+ candidates.add("/opt/VirtualBox/VBoxManage");
+ }
+
+ return candidates;
+ }
+
+ /**
+ * Vérifie qu'un chemin pointe vers un VBoxManage fonctionnel en exécutant
+ * {@code --version}.
+ *
+ * La sortie est drainée pour éviter tout blocage du sous-processus.
+ *
+ * @param path chemin à tester
+ * @return {@code true} si VBoxManage répond avec un code de sortie 0
+ */
+ private static boolean isVBoxManageExecutable(String path) {
+ if (path == null || path.isBlank()) {
+ return false;
+ }
+ try {
+ ProcessBuilder pb = new ProcessBuilder(path, "--version");
+ pb.redirectErrorStream(true);
+ Process process = pb.start();
+ // Drainer la sortie pour ne pas bloquer le processus
+ process.getInputStream().transferTo(OutputStream.nullOutputStream());
+ return process.waitFor() == 0;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ /**
+ * Convertit un état VirtualBox brut en {@link VMStatus}.
+ *
+ * @param state valeur du champ {@code VMState} dans la sortie machinereadable
+ * @return statut correspondant, ou {@link VMStatus#UNKNOWN} si non reconnu
+ */
+ private static VMStatus parseVMStatus(String state) {
+ return switch (state) {
+ case "running" -> VMStatus.RUNNING;
+ case "poweroff" -> VMStatus.POWERED_OFF;
+ case "saved" -> VMStatus.SAVED;
+ case "paused" -> VMStatus.PAUSED;
+ default -> VMStatus.UNKNOWN;
+ };
}
}
From 3fb187ea2a24dd5ed1fe6c4c6d2e415952863523 Mon Sep 17 00:00:00 2001
From: 4rthur-Root
Date: Fri, 12 Jun 2026 19:01:57 +0000
Subject: [PATCH 05/31] Code: resolving risk of screen freezing of vboxmanage
path
---
.../cyberlabmanager/hypervisor/VBoxOrchestrator.java | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java b/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java
index a0320d6..a2173c7 100644
--- a/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java
+++ b/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java
@@ -8,6 +8,7 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -295,7 +296,14 @@ private static boolean isVBoxManageExecutable(String path) {
Process process = pb.start();
// Drainer la sortie pour ne pas bloquer le processus
process.getInputStream().transferTo(OutputStream.nullOutputStream());
- return process.waitFor() == 0;
+ // Pour éviter les freezes , on attend 5 secondes ou on tue le process
+ boolean complete = process.waitFor(5, TimeUnit.SECONDS);
+ if (!complete) {
+ process.destroyForcibly();
+ return false;
+ }
+ return process.exitValue() == 0;
+
} catch (Exception e) {
return false;
}
From 4bee7d3ff4ec72ffe02abf224abbd1d3b6447fdf Mon Sep 17 00:00:00 2001
From: 4rthur-Root
Date: Fri, 12 Jun 2026 19:58:17 +0000
Subject: [PATCH 06/31] Code: resolving the between status of VMs
---
.../hypervisor/VBoxOrchestrator.java | 39 +++++++++++++++----
1 file changed, 32 insertions(+), 7 deletions(-)
diff --git a/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java b/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java
index a2173c7..0d3b289 100644
--- a/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java
+++ b/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java
@@ -313,15 +313,40 @@ private static boolean isVBoxManageExecutable(String path) {
* Convertit un état VirtualBox brut en {@link VMStatus}.
*
* @param state valeur du champ {@code VMState} dans la sortie machinereadable
- * @return statut correspondant, ou {@link VMStatus#UNKNOWN} si non reconnu
+ * @return statut correspondant, ou {@link VMStatus#UNKNOWN} si non reconnu,
+ * Tous les petits états intermédiaires sont mappés intelligemment vers les états solides
*/
private static VMStatus parseVMStatus(String state) {
- return switch (state) {
- case "running" -> VMStatus.RUNNING;
- case "poweroff" -> VMStatus.POWERED_OFF;
- case "saved" -> VMStatus.SAVED;
- case "paused" -> VMStatus.PAUSED;
- default -> VMStatus.UNKNOWN;
+ if (state == null) {
+ return VMStatus.UNKNOWN;
+ }
+
+ // Normalisation pour éviter les problèmes de casse
+ String s = state.toLowerCase();
+
+ return switch (s) {
+ // ÉTATS ACTIFS
+ case "running",
+ "paused",
+ "resuming" -> VMStatus.RUNNING;
+
+ // ÉTATS ÉTEINTS (ou en transition vers éteint)
+ case "poweroff",
+ "poweredoff",
+ "aborted",
+ "stopping" -> VMStatus.POWERED_OFF;
+
+ // ÉTATS SAUVEGARDÉS (Hibernation)
+ case "saved",
+ "saving",
+ "suspended" -> VMStatus.SAVED;
+
+ // "starting" : La VM n'est pas encore utilisable.
+ case "starting" -> VMStatus.UNKNOWN;
+
+ // Tout le reste
+ // Inclut: restoring, snapshotting, teleporting, etc.
+ default -> VMStatus.UNKNOWN;
};
}
}
From 54735d7108670056559a3c1a9eaf2e1b9fd8ad1c Mon Sep 17 00:00:00 2001
From: 4rthur-Root
Date: Sat, 13 Jun 2026 07:34:49 +0000
Subject: [PATCH 07/31] Code: Creating a record class for listVms methode
---
src/main/java/tg/cyberlabmanager/model/VMDescriptor.java | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 src/main/java/tg/cyberlabmanager/model/VMDescriptor.java
diff --git a/src/main/java/tg/cyberlabmanager/model/VMDescriptor.java b/src/main/java/tg/cyberlabmanager/model/VMDescriptor.java
new file mode 100644
index 0000000..fb9a7c1
--- /dev/null
+++ b/src/main/java/tg/cyberlabmanager/model/VMDescriptor.java
@@ -0,0 +1,4 @@
+package tg.cyberlabmanager.model;
+
+public record VMDescriptor(String name, String uuid) {
+}
From 2592969c3f54b007b203a20f6f96a1eb9ed76392 Mon Sep 17 00:00:00 2001
From: 4rthur-Root
Date: Sat, 13 Jun 2026 10:25:30 +0000
Subject: [PATCH 08/31] Docs: Adding javadoc information to VMDescriptor
---
.../java/tg/cyberlabmanager/hypervisor/IHypervisor.java | 3 ++-
src/main/java/tg/cyberlabmanager/model/VMDescriptor.java | 9 +++++++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/main/java/tg/cyberlabmanager/hypervisor/IHypervisor.java b/src/main/java/tg/cyberlabmanager/hypervisor/IHypervisor.java
index 99ad3cf..0b17e83 100644
--- a/src/main/java/tg/cyberlabmanager/hypervisor/IHypervisor.java
+++ b/src/main/java/tg/cyberlabmanager/hypervisor/IHypervisor.java
@@ -1,5 +1,6 @@
package tg.cyberlabmanager.hypervisor;
+import tg.cyberlabmanager.model.VMDescriptor;
import tg.cyberlabmanager.model.VMStatus;
import java.util.List;
@@ -14,7 +15,7 @@ public interface IHypervisor {
* @return liste de couples ou tableaux de donnees representant les VM
* @throws HypervisorException si la recuperation echoue
*/
- List listVMs() throws HypervisorException;
+ List listVMs() throws HypervisorException;
/**
* Retourne le statut courant d'une machine virtuelle.
diff --git a/src/main/java/tg/cyberlabmanager/model/VMDescriptor.java b/src/main/java/tg/cyberlabmanager/model/VMDescriptor.java
index fb9a7c1..e6232c1 100644
--- a/src/main/java/tg/cyberlabmanager/model/VMDescriptor.java
+++ b/src/main/java/tg/cyberlabmanager/model/VMDescriptor.java
@@ -1,4 +1,13 @@
package tg.cyberlabmanager.model;
+/**
+ * Descripteur minimal d'une machine virtuelle découverte auprès de VirtualBox.
+ *
+ * Ce record sert à transporter l'identité affichable d'une VM sans charger
+ * le modèle métier complet.
+ *
+ * @param name nom de la machine virtuelle
+ * @param uuid UUID VirtualBox de la machine virtuelle
+ */
public record VMDescriptor(String name, String uuid) {
}
From a45e1688213d9b8ec3d95facef3ab5b15d157ad8 Mon Sep 17 00:00:00 2001
From: 4rthur-Root
Date: Sat, 13 Jun 2026 11:59:20 +0000
Subject: [PATCH 09/31] Code: Final correction of the regex
---
.../hypervisor/VBoxOrchestrator.java | 26 ++++++++++++-------
1 file changed, 17 insertions(+), 9 deletions(-)
diff --git a/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java b/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java
index 0d3b289..1aeb512 100644
--- a/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java
+++ b/src/main/java/tg/cyberlabmanager/hypervisor/VBoxOrchestrator.java
@@ -1,6 +1,7 @@
package tg.cyberlabmanager.hypervisor;
import tg.cyberlabmanager.model.AppConfig;
+import tg.cyberlabmanager.model.VMDescriptor;
import tg.cyberlabmanager.model.VMStatus;
import java.io.IOException;
@@ -29,7 +30,9 @@ public class VBoxOrchestrator implements IHypervisor {
/** Regex pour analyser une ligne de {@code VBoxManage list vms} : {@code "Nom" {uuid}}. */
private static final Pattern LIST_VMS_PATTERN =
- Pattern.compile("^\"(.+)\"\\s+\\{([0-9a-fA-F\\-]+)}$");
+ Pattern.compile(
+ "^\"([^\"]+)\"\\s+\\{([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-"
+ + "[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})\\}\\s*$");
/** Chemin résolu vers VBoxManage, ou {@code null} si introuvable. */
private String vboxManagePath;
@@ -88,14 +91,19 @@ public void setVboxManagePath(String path) throws HypervisorException {
* {@code [nom, uuid]} pour chaque VM trouvée.
*/
@Override
- public List listVMs() throws HypervisorException {
- String output = runCommand("list", "vms");
- List vms = new ArrayList<>();
+ public List listVMs() throws HypervisorException {
+ return parseListVMsOutput(runCommand("list", "vms"));
+ }
- for (String line : output.split("\\r?\\n")) {
- Matcher m = LIST_VMS_PATTERN.matcher(line.trim());
- if (m.matches()) {
- vms.add(new String[]{m.group(1), m.group(2)});
+ static List parseListVMsOutput(String output) {
+ List vms = new ArrayList<>();
+
+ if (output != null) {
+ for (String line : output.split("\\R")) {
+ Matcher matcher = LIST_VMS_PATTERN.matcher(line.trim());
+ if (matcher.matches()) {
+ vms.add(new VMDescriptor(matcher.group(1), matcher.group(2)));
+ }
}
}
@@ -266,7 +274,7 @@ private static List buildCandidatePaths(String osName) {
candidates.add("C:\\Program Files\\Oracle\\VirtualBox\\VBoxManage.exe");
candidates.add("C:\\Program Files (x86)\\Oracle\\VirtualBox\\VBoxManage.exe");
} else {
- // Linux / macOS — PATH d'abord, puis chemins typiques
+ // Linux / macOS (PATH d'abord, puis chemins typiques)
candidates.add("VBoxManage");
candidates.add("vboxmanage");
candidates.add("/usr/bin/VBoxManage");
From 1eb3802868a2d74ad5cfa1d5d5ef1508532b9e54 Mon Sep 17 00:00:00 2001
From: 4rthur-Root
Date: Sat, 13 Jun 2026 12:01:50 +0000
Subject: [PATCH 10/31] Other: Forgot but add UML png
---
docs/Diagrammes/UML.drawio.png | Bin 0 -> 1161897 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 docs/Diagrammes/UML.drawio.png
diff --git a/docs/Diagrammes/UML.drawio.png b/docs/Diagrammes/UML.drawio.png
new file mode 100644
index 0000000000000000000000000000000000000000..1ea70796d68f16610a18db9a1cee9fd3b498d075
GIT binary patch
literal 1161897
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