feat(editor): F4.5b the device sheet for routers and home routers
Measured first: SheetRun now types into FILIUS' router and home router
panels, records five forwarding tables (holeTabelle) and steps in the
panel's table. Java turns a card address that passes the pattern but not
IP.ipCheck (".0.0.1") into null and the router panel throws; an empty
gateway is marked red yet taken; a refused table cell is stored as null;
a home router's DHCP client leaves its DHCP server running. None of the
nulls is adopted. The core's routeTableRows matches all five tables.
- doc: card addresses (the first card mirrored in the device's settings),
router gateway, RIP, manual routes (a new row once all four cells pass,
a cell, removal); the sheet reads cards with what their cable joins and
the whole table
- editor: Java's tabs (general, each card titled by its address, the
forwarding table greyed out under RIP; general, LAN, WAN on a home
router); the open card's cable drawn active in Java's green
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1129,3 +1129,31 @@ Gemessen (03.10.2026):
|
||||
Name wird zur MAC-Adresse und bleibt es nach dem Abschalten (bei der
|
||||
IP-Adresse nicht).
|
||||
* „DHCP zur Konfiguration verwenden“ schaltet den eigenen DHCP-Server ab.
|
||||
|
||||
### Vermittlungsrechner und Heimrouter (F4.5b)
|
||||
|
||||
`SheetRun` tippt seitdem auch in `JVermittlungsrechnerKonfiguration` (erste
|
||||
Karte, Gateway) und `JGatewayConfiguration` (Gateway, WAN, LAN). Felder ohne
|
||||
eigene Prüfmethode markiert es mit dem Muster ihres Tastenhörers. Dazu
|
||||
schreibt es Javas Weiterleitungstabellen für fünf Aufbauten (`tables`:
|
||||
`holeTabelle` mit den Kennzeichen der manuellen Zeilen) und Schritte in der
|
||||
Tabelle des Panels (`edits`: `JWeiterleitungsTabelle`, nur manuelle Zeilen
|
||||
gezeigt). Ein Panel, das wirft, gehört zur Messung (`error`).
|
||||
|
||||
Gemessen (03.10.2026):
|
||||
|
||||
* Karte eines Routers: Markieren und Übernehmen stimmen überein (anders als
|
||||
beim Rechner wird „10..0.0.1“ verworfen), bis auf „.0.0.1“: nicht
|
||||
markiert, die Adresse wird `null`, und das Panel wirft danach eine
|
||||
`NullPointerException` (`holeTabelle`). Beim Heimrouter wird „.1.2.3“
|
||||
ebenso `null`, ohne Ausnahme.
|
||||
* Gateway von Router und Heimrouter: Der Tastenhörer prüft mit
|
||||
`musterIpAdresse`, ein leeres Feld ist also rot, wird aber übernommen.
|
||||
* DHCP am Heimrouter (WAN) lässt den eigenen DHCP-Server laufen.
|
||||
* Tabelle: eigene Adressen (neueste Karte zuerst), eigene Netze (ebenso),
|
||||
localhost, die manuellen Zeilen (durch `ipCheck`: „010.020.0.0“ wird
|
||||
10.20.0.0), das Standard-Gateway über die letzte Karte in seinem Netz,
|
||||
ohne solche über die erste.
|
||||
* Tabelle bearbeiten: Eine Zelle, die das Muster nicht besteht („abc“, „“,
|
||||
„10..0.0“), wird als `null` gespeichert; eine neue Zeile erst, wenn alle
|
||||
vier Zellen gültig sind; „Neuer Eintrag“ zweimal ergibt eine offene Zeile.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Types into FILIUS' own settings panels (JHostKonfiguration,
|
||||
// JSwitchKonfiguration, JModemKonfiguration) and lets them take the text as
|
||||
// JSwitchKonfiguration, JModemKonfiguration, JVermittlungsrechnerKonfiguration,
|
||||
// JGatewayConfiguration) and lets them take the text as
|
||||
// they do when a field loses the focus (aenderungenAnnehmen), then writes,
|
||||
// for each case, whether the panel marked the text red while typing, what the
|
||||
// device holds afterwards and what the field shows then (updateAttribute):
|
||||
@@ -8,25 +9,38 @@
|
||||
// Java-style unicode escapes (backslash, u, four hex digits) for anything
|
||||
// else, one case a line:
|
||||
//
|
||||
// <host|switch|modem> <field> <text> the text may be empty
|
||||
// <host|switch|modem|router|homeRouter> <field> <text> the text may be empty
|
||||
//
|
||||
// Fields: host name, ip, mask, gateway, dns; switch name, ssid, retention;
|
||||
// modem name, port. After the cases, a few flows of the check boxes
|
||||
// ("flows"): a host's name while it shows its address or MAC address, and
|
||||
// DHCP switched on while its own DHCP server runs.
|
||||
// modem name, port; router name, ip, mask (its first interface), gateway;
|
||||
// homeRouter name, gateway, wanIp, wanMask, lanIp, lanMask. A field without
|
||||
// a check method of its own is marked as its key listener marks it (the
|
||||
// pattern). After the cases, a few flows ("flows"): a host's name while it
|
||||
// shows its address or MAC address, DHCP switched on while the device's own
|
||||
// DHCP server runs; then a router's forwarding table as Java shows it
|
||||
// (Weiterleitungstabelle.holeTabelle, "tables") and its rows edited in the
|
||||
// panel's table (JWeiterleitungsTabelle, "edits").
|
||||
//
|
||||
// Usage: java -cp filius.jar:lib/*:classes SheetRun <cases txt> <output json>
|
||||
|
||||
import filius.gui.GUIContainer;
|
||||
import filius.gui.netzwerksicht.JKonfiguration;
|
||||
import filius.gui.netzwerksicht.JWeiterleitungsTabelle;
|
||||
import filius.hardware.NetzwerkInterface;
|
||||
import filius.hardware.knoten.Gateway;
|
||||
import filius.hardware.knoten.Host;
|
||||
import filius.hardware.knoten.Modem;
|
||||
import filius.hardware.knoten.Rechner;
|
||||
import filius.hardware.knoten.Switch;
|
||||
import filius.hardware.knoten.Vermittlungsrechner;
|
||||
import filius.rahmenprogramm.EingabenUeberpruefung;
|
||||
import filius.software.system.Betriebssystem;
|
||||
import filius.software.system.GatewayFirmware;
|
||||
import filius.software.system.InternetKnotenBetriebssystem;
|
||||
import filius.software.system.ModemFirmware;
|
||||
import filius.software.system.SwitchFirmware;
|
||||
import filius.software.system.VermittlungsrechnerBetriebssystem;
|
||||
import filius.software.vermittlungsschicht.Weiterleitungstabelle;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -35,17 +49,22 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
public class SheetRun {
|
||||
/** A private field of a panel; "name#i" is the i-th of an array. */
|
||||
static Object get(Object panel, String name) throws Exception {
|
||||
Field field = panel.getClass().getDeclaredField(name);
|
||||
String[] parts = name.split("#");
|
||||
Field field = panel.getClass().getDeclaredField(parts[0]);
|
||||
field.setAccessible(true);
|
||||
return field.get(panel);
|
||||
Object value = field.get(panel);
|
||||
return parts.length == 1 ? value : ((Object[]) value)[Integer.parseInt(parts[1])];
|
||||
}
|
||||
|
||||
static void call(Object panel, String name) throws Exception {
|
||||
@@ -54,19 +73,33 @@ public class SheetRun {
|
||||
method.invoke(panel);
|
||||
}
|
||||
|
||||
/** The panel's field and its check (the method its key listener calls), per device and field. */
|
||||
/** The panel's field, its check (the method its key listener calls) or else the pattern its key listener checks, per device and field. */
|
||||
static final Map<String, String[]> FIELDS = new LinkedHashMap<>();
|
||||
static {
|
||||
FIELDS.put("host name", new String[] { "name", null });
|
||||
FIELDS.put("host ip", new String[] { "ipAdresse", "checkIpAddress" });
|
||||
FIELDS.put("host mask", new String[] { "netzmaske", "checkNetmask" });
|
||||
FIELDS.put("host gateway", new String[] { "gateway", "checkGatewayAddress" });
|
||||
FIELDS.put("host dns", new String[] { "dns", "checkDnsAddress" });
|
||||
FIELDS.put("switch name", new String[] { "name", null });
|
||||
FIELDS.put("switch ssid", new String[] { "ssid", "checkSSID" });
|
||||
FIELDS.put("switch retention", new String[] { "retentionTime", "checkRetentionTime" });
|
||||
FIELDS.put("modem name", new String[] { "name", null });
|
||||
FIELDS.put("modem port", new String[] { "tfPort", null });
|
||||
FIELDS.put("host name", new String[] { "name", null, null });
|
||||
FIELDS.put("host ip", new String[] { "ipAdresse", "checkIpAddress", null });
|
||||
FIELDS.put("host mask", new String[] { "netzmaske", "checkNetmask", null });
|
||||
FIELDS.put("host gateway", new String[] { "gateway", "checkGatewayAddress", null });
|
||||
FIELDS.put("host dns", new String[] { "dns", "checkDnsAddress", null });
|
||||
FIELDS.put("switch name", new String[] { "name", null, null });
|
||||
FIELDS.put("switch ssid", new String[] { "ssid", "checkSSID", null });
|
||||
FIELDS.put("switch retention", new String[] { "retentionTime", "checkRetentionTime", null });
|
||||
FIELDS.put("modem name", new String[] { "name", null, null });
|
||||
FIELDS.put("modem port", new String[] { "tfPort", null, null });
|
||||
FIELDS.put("router name", new String[] { "name", null, null });
|
||||
FIELDS.put("router ip", new String[] { "ipAdressen#0", null, "ip" });
|
||||
FIELDS.put("router mask", new String[] { "netzmasken#0", null, "mask" });
|
||||
FIELDS.put("router gateway", new String[] { "gateway", null, "ip" });
|
||||
FIELDS.put("homeRouter name", new String[] { "name", null, null });
|
||||
FIELDS.put("homeRouter gateway", new String[] { "gatewayName", null, "ip" });
|
||||
FIELDS.put("homeRouter wanIp", new String[] { "ipAddressWANPort", null, "ip" });
|
||||
FIELDS.put("homeRouter wanMask", new String[] { "netmaskWANPort", null, "mask" });
|
||||
FIELDS.put("homeRouter lanIp", new String[] { "ipAddressLANPort", null, "ip" });
|
||||
FIELDS.put("homeRouter lanMask", new String[] { "netmaskLANPort", null, "mask" });
|
||||
}
|
||||
|
||||
static Pattern pattern(String name) {
|
||||
return name.equals("ip") ? EingabenUeberpruefung.musterIpAdresse : EingabenUeberpruefung.musterSubNetz;
|
||||
}
|
||||
|
||||
static String stored(Object device, String key) {
|
||||
@@ -88,6 +121,25 @@ public class SheetRun {
|
||||
case "switch ssid": return firmware.getSSID();
|
||||
case "switch retention": return Long.toString(firmware.getRetentionTime());
|
||||
}
|
||||
} else if (device instanceof Vermittlungsrechner) {
|
||||
Vermittlungsrechner router = (Vermittlungsrechner) device;
|
||||
NetzwerkInterface first = router.getNetzwerkInterfaces().get(0);
|
||||
switch (key) {
|
||||
case "router name": return router.getName();
|
||||
case "router ip": return first.getIp();
|
||||
case "router mask": return first.getSubnetzMaske();
|
||||
case "router gateway": return ((InternetKnotenBetriebssystem) router.getSystemSoftware()).getStandardGateway();
|
||||
}
|
||||
} else if (device instanceof Gateway) {
|
||||
Gateway home = (Gateway) device;
|
||||
switch (key) {
|
||||
case "homeRouter name": return home.getName();
|
||||
case "homeRouter gateway": return ((InternetKnotenBetriebssystem) home.getSystemSoftware()).getStandardGateway();
|
||||
case "homeRouter wanIp": return home.holeWANInterface().getIp();
|
||||
case "homeRouter wanMask": return home.holeWANInterface().getSubnetzMaske();
|
||||
case "homeRouter lanIp": return home.holeLANInterface().getIp();
|
||||
case "homeRouter lanMask": return home.holeLANInterface().getSubnetzMaske();
|
||||
}
|
||||
} else if (device instanceof Modem) {
|
||||
Modem modem = (Modem) device;
|
||||
switch (key) {
|
||||
@@ -114,10 +166,82 @@ public class SheetRun {
|
||||
return sw;
|
||||
}
|
||||
case "modem": return new Modem();
|
||||
case "router": {
|
||||
Vermittlungsrechner router = new Vermittlungsrechner();
|
||||
router.setzeAnzahlAnschluesse(2);
|
||||
((InternetKnotenBetriebssystem) router.getSystemSoftware()).setStandardGateway("192.168.0.254");
|
||||
return router;
|
||||
}
|
||||
case "homeRouter": {
|
||||
Gateway home = new Gateway();
|
||||
((InternetKnotenBetriebssystem) home.getSystemSoftware()).setStandardGateway("192.168.0.254");
|
||||
return home;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(kind);
|
||||
}
|
||||
|
||||
/** A router's forwarding table (Weiterleitungstabelle.holeTabelle) with its manual flags. */
|
||||
static List<Object> table(String[] interfaces, String gateway, String[][] manual) {
|
||||
Vermittlungsrechner router = new Vermittlungsrechner();
|
||||
router.setzeAnzahlAnschluesse(interfaces.length / 2);
|
||||
for (int i = 0; i < interfaces.length / 2; i++) {
|
||||
router.getNetzwerkInterfaces().get(i).setIp(interfaces[2 * i]);
|
||||
router.getNetzwerkInterfaces().get(i).setSubnetzMaske(interfaces[2 * i + 1]);
|
||||
}
|
||||
VermittlungsrechnerBetriebssystem os = (VermittlungsrechnerBetriebssystem) router.getSystemSoftware();
|
||||
os.setStandardGateway(gateway);
|
||||
Weiterleitungstabelle table = os.getWeiterleitungstabelle();
|
||||
for (String[] row : manual) table.addManuellenEintrag(row[0], row[1], row[2], row[3]);
|
||||
List<Object> rows = new ArrayList<>();
|
||||
List<String[]> entries = table.holeTabelle();
|
||||
List<Boolean> flags = table.holeManuelleEintraegeFlags();
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
Map<String, Object> row = new LinkedHashMap<>();
|
||||
row.put("cells", Arrays.asList(entries.get(i)));
|
||||
row.put("manual", flags.get(i));
|
||||
rows.add(row);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Steps in the panel's table of a router with one manual row, only the
|
||||
* manual rows shown: {"<column>", text} sets a cell of the first row,
|
||||
* {"N<column>", text} of the last row, {"new"} adds a row, {"remove"}
|
||||
* removes the first; each step taken as the table takes it. The manual
|
||||
* rows afterwards (and the rows shown, when asked).
|
||||
*/
|
||||
static Map<String, Object> edit(String[][] steps, boolean shown) throws Exception {
|
||||
Vermittlungsrechner router = new Vermittlungsrechner();
|
||||
router.setzeAnzahlAnschluesse(2);
|
||||
VermittlungsrechnerBetriebssystem os = (VermittlungsrechnerBetriebssystem) router.getSystemSoftware();
|
||||
os.getWeiterleitungstabelle().addManuellenEintrag("172.16.0.0", "255.255.0.0", "192.168.0.2", "192.168.0.10");
|
||||
JKonfiguration panel = JKonfiguration.getInstance(router);
|
||||
JWeiterleitungsTabelle table = (JWeiterleitungsTabelle) get(panel, "weiterleitungstabelle");
|
||||
table.setzeAlleEintraegeAnzeigen(false);
|
||||
table.updateAttribute();
|
||||
for (String[] step : steps) {
|
||||
if (step[0].equals("new")) {
|
||||
table.neuerEintrag();
|
||||
} else if (step[0].equals("remove")) {
|
||||
table.setRowSelectionInterval(0, 0);
|
||||
table.markiertenEintragLoeschen();
|
||||
} else {
|
||||
boolean last = step[0].startsWith("N");
|
||||
int column = Integer.parseInt(last ? step[0].substring(1) : step[0]);
|
||||
table.setValueAt(step[1], last ? table.getRowCount() - 1 : 0, column);
|
||||
table.aenderungenAnnehmen();
|
||||
}
|
||||
}
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
List<Object> rows = new ArrayList<>();
|
||||
for (String[] row : os.getWeiterleitungstabelle().getManuelleTabelle()) rows.add(Arrays.asList(row));
|
||||
result.put("manual", rows);
|
||||
if (shown) result.put("rowsShown", table.getRowCount());
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// FILIUS' window keeps the JVM alive: end it on any failure too.
|
||||
try {
|
||||
@@ -148,9 +272,19 @@ public class SheetRun {
|
||||
if (names[1] != null) {
|
||||
call(panel, names[1]);
|
||||
marked = field.getForeground().equals(EingabenUeberpruefung.farbeFalsch);
|
||||
} else if (names[2] != null) {
|
||||
marked = !panel.ueberpruefen(pattern(names[2]), field);
|
||||
}
|
||||
// A panel that throws is part of the measurement ("error").
|
||||
String error = null;
|
||||
try {
|
||||
call(panel, "aenderungenAnnehmen");
|
||||
panel.updateAttribute();
|
||||
} catch (java.lang.reflect.InvocationTargetException thrown) {
|
||||
error = thrown.getCause().getClass().getSimpleName();
|
||||
} catch (RuntimeException thrown) {
|
||||
error = thrown.getClass().getSimpleName();
|
||||
}
|
||||
call(panel, "aenderungenAnnehmen");
|
||||
panel.updateAttribute();
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("device", words[0]);
|
||||
result.put("field", words[1]);
|
||||
@@ -159,6 +293,7 @@ public class SheetRun {
|
||||
result.put("marked", marked);
|
||||
result.put("stored", stored(device, key));
|
||||
result.put("shown", field.getText());
|
||||
if (error != null) result.put("error", error);
|
||||
cases.add(result);
|
||||
}
|
||||
|
||||
@@ -187,10 +322,45 @@ public class SheetRun {
|
||||
flows.put("dhcpClientStopsServer", !os.getDHCPServer().isAktiv());
|
||||
flows.put("dhcpClient", os.isDHCPKonfiguration());
|
||||
}
|
||||
// The same on a home router (its WAN card).
|
||||
{
|
||||
Gateway home = new Gateway();
|
||||
GatewayFirmware firmware = (GatewayFirmware) home.getSystemSoftware();
|
||||
firmware.getDHCPServer().setAktiv(true);
|
||||
JKonfiguration panel = JKonfiguration.getInstance(home);
|
||||
((JCheckBox) get(panel, "dhcp")).setSelected(true);
|
||||
call(panel, "aenderungenAnnehmen");
|
||||
flows.put("homeRouterDhcpClientStopsServer", !firmware.getDHCPServer().isAktiv());
|
||||
flows.put("homeRouterDhcpClient", firmware.isDHCPKonfiguration());
|
||||
}
|
||||
|
||||
// Forwarding tables: two interfaces, a gateway, manual rows.
|
||||
Map<String, Object> tables = new LinkedHashMap<>();
|
||||
String[][] manual = { { "172.16.0.0", "255.255.0.0", "192.168.1.2", "192.168.1.1" }, { "010.020.0.0", "255.255.0.0", "10.0.0.2", "10.0.0.1" } };
|
||||
tables.put("gatewayInSecondNetwork", table(new String[] { "10.0.0.1", "255.0.0.0", "192.168.1.1", "255.255.255.0" }, "192.168.1.254", manual));
|
||||
tables.put("gatewayInNoNetwork", table(new String[] { "10.0.0.1", "255.0.0.0", "192.168.1.1", "255.255.255.0" }, "172.30.0.1", manual));
|
||||
tables.put("gatewayInBothNetworks", table(new String[] { "10.0.0.1", "255.0.0.0", "10.1.0.1", "255.255.0.0" }, "10.1.0.254", new String[0][]));
|
||||
tables.put("noGateway", table(new String[] { "10.0.0.1", "255.0.0.0", "192.168.1.1", "255.255.255.0" }, "", manual));
|
||||
tables.put("threeInterfaces", table(new String[] { "10.0.0.1", "255.0.0.0", "192.168.1.1", "255.255.255.0", "172.16.5.1", "255.255.0.0" }, "10.0.0.254", new String[0][]));
|
||||
|
||||
// The panel's table: a manual row edited, a new row, a row removed (only the manual rows shown).
|
||||
Map<String, Object> edits = new LinkedHashMap<>();
|
||||
edits.put("invalidCell", edit(new String[][] { { 0 + "", "abc" } }, false));
|
||||
edits.put("emptyCell", edit(new String[][] { { 0 + "", "" } }, false));
|
||||
edits.put("leadingZeros", edit(new String[][] { { 0 + "", "010.0.0.0" } }, false));
|
||||
edits.put("dottedTwice", edit(new String[][] { { 0 + "", "10..0.0" } }, false));
|
||||
edits.put("maskCell", edit(new String[][] { { 1 + "", "255.0.255.0" } }, false));
|
||||
edits.put("newRowThreeCells", edit(new String[][] { { "new" }, { "N0", "10.9.0.0" }, { "N1", "255.255.0.0" }, { "N2", "10.0.0.9" } }, false));
|
||||
edits.put("newRowFourCells", edit(new String[][] { { "new" }, { "N0", "10.9.0.0" }, { "N1", "255.255.0.0" }, { "N2", "10.0.0.9" }, { "N3", "10.0.0.1" } }, false));
|
||||
edits.put("newRowInvalidCell", edit(new String[][] { { "new" }, { "N0", "10.9.0.0" }, { "N1", "255.255.0.0" }, { "N2", "10.0.0.9" }, { "N3", "10..0.0.1" } }, false));
|
||||
edits.put("newRowTwice", edit(new String[][] { { "new" }, { "new" } }, true));
|
||||
edits.put("removeRow", edit(new String[][] { { "remove" } }, false));
|
||||
|
||||
Map<String, Object> output = new LinkedHashMap<>();
|
||||
output.put("cases", cases);
|
||||
output.put("flows", flows);
|
||||
output.put("tables", tables);
|
||||
output.put("edits", edits);
|
||||
try (FileOutputStream out = new FileOutputStream(args[1])) {
|
||||
out.write((FlsOracle.Json.write(output, "") + "\n").getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user