From 3565983496df5779edfaa9e53bdb10a06ecba934 Mon Sep 17 00:00:00 2001 From: Patrick Gniza Date: Sat, 22 Aug 2026 15:46:50 +0200 Subject: [PATCH] Update Wiki for 1.4.0 --- Base-Image.de.md | 9 ++- Base-Image.md | 9 ++- Build-System.de.md | 6 +- Build-System.md | 6 +- Configuration.de.md | 13 +++- Configuration.md | 12 +++- Home.de.md | 2 +- Home.md | 2 +- Java-Property-Agent.de.md | 127 +++++++++++++++++++++++++++++++++++--- Java-Property-Agent.md | 124 ++++++++++++++++++++++++++++++++++--- Project-Structure.de.md | 1 + Project-Structure.md | 1 + Reference-README.de.md | 8 ++- Reference-README.md | 7 ++- Romexis-Admin.de.md | 20 ++++-- Romexis-Admin.md | 20 ++++-- Romexis-Client.de.md | 111 +++++++++++++++++++++++++++++++++ Romexis-Client.md | 109 ++++++++++++++++++++++++++++++++ 18 files changed, 539 insertions(+), 48 deletions(-) diff --git a/Base-Image.de.md b/Base-Image.de.md index 740e2de..5b8992e 100644 --- a/Base-Image.de.md +++ b/Base-Image.de.md @@ -24,7 +24,7 @@ romexis-common/ - Firebird-Clientbibliotheken und -Werkzeuge - gemeinsame Betriebssystempakete - native Chilkat-Bibliothek und JAR -- `RomexisPropertyAgent.jar` +- `RomexisPropertyAgent.jar` mit eingebetteten RxCr2- und OptionPane-Transformern - Sicherheitsaktualisierungen Die aufwendigen Native-/Java-Artefakte werden dadurch einmal pro Architektur statt einmal pro Romexis-Version gebaut. @@ -39,11 +39,16 @@ Die aufwendigen Native-/Java-Artefakte werden dadurch einmal pro Architektur sta - Xvfb, Openbox und xcompmgr - x11vnc und noVNC/websockify - GTK-/Mesa-/OpenGL-Abhängigkeiten -- Chilkat und `RomexisPropertyAgent.jar` +- Chilkat und `RomexisPropertyAgent.jar` einschließlich Java-17-Swing-Lifecycle-Null-Guard - die aus `romexis-common/dxservice_dummy.c` gebaute DxService-Kompatibilitätsbibliothek Admin und Client installieren bzw. kompilieren diese Abhängigkeiten daher nicht erneut für jede Romexis-Version. +Das Agent-JAR enthält ASM und `RomexisOptionPaneUIPatch.class`; in den finalen +Containern ist kein separates ASM-Artefakt erforderlich. Der Patch transformiert +nur die betroffene In-Memory-Listenerklasse und schreibt das proprietäre +Romexis-JAR auf dem Datenträger nicht um. + --- ## Architekturspezifische Tags diff --git a/Base-Image.md b/Base-Image.md index de2a6fa..08ab770 100644 --- a/Base-Image.md +++ b/Base-Image.md @@ -24,7 +24,7 @@ romexis-common/ - Firebird client libraries and tools - common OS packages - Chilkat native library and JAR -- `RomexisPropertyAgent.jar` +- `RomexisPropertyAgent.jar` with embedded RxCr2 and OptionPane transformers - security updates The expensive native/Java artifacts are therefore built once per architecture instead of once per Romexis version. @@ -39,11 +39,16 @@ The expensive native/Java artifacts are therefore built once per architecture in - Xvfb, Openbox and xcompmgr - x11vnc and noVNC/websockify - GTK/Mesa/OpenGL dependencies -- Chilkat and `RomexisPropertyAgent.jar` +- Chilkat and `RomexisPropertyAgent.jar`, including the Java 17 Swing lifecycle null guard - the DxService compatibility library built from `romexis-common/dxservice_dummy.c` Admin and Client therefore do not repeatedly install or compile these dependencies for every Romexis version. +The agent JAR embeds ASM and `RomexisOptionPaneUIPatch.class`; no separate ASM +artifact is required in the final containers. The patch transforms only the +affected in-memory listener class and does not rewrite the proprietary Romexis +JAR on disk. + --- ## Architecture-Specific Tags diff --git a/Build-System.de.md b/Build-System.de.md index fa6a2c8..a5ce152 100644 --- a/Build-System.de.md +++ b/Build-System.de.md @@ -66,15 +66,15 @@ Er erzeugt: - Firebird-Clientbibliotheken und -Werkzeuge - Betriebssystemabhängigkeiten - Chilkat -- Java Property Agent +- Java Property Agent mit eingebetteten RxCr2- und RomexisOptionPaneUI-Runtime-Patches ### GUI-Runtime-Build -`romexis-gui-runtime` enthält den von Admin und Client gemeinsam verwendeten architekturspezifischen Grafik-Stack: Java 17/OpenJFX, X11/noVNC, Mesa/GTK, Chilkat, PropertyAgent und die DxService-Kompatibilitätsbibliothek. +`romexis-gui-runtime` enthält den von Admin und Client gemeinsam verwendeten architekturspezifischen Grafik-Stack: Java 17/OpenJFX, X11/noVNC, Mesa/GTK, Chilkat, PropertyAgent mit Java-17-OptionPane-Null-Guard und die DxService-Kompatibilitätsbibliothek. ### Gemeinsame Runtime-Quellen -`romexis-common/` ist der zentrale Quellort für `RomexisPropertyAgent.java`, die Chilkat-Patch-Quelle und `dxservice_dummy.c`. Diese Quellen werden in die passenden Runtime-Images kompiliert, statt in Verzeichnissen finaler Images dupliziert zu werden. +`romexis-common/` ist der zentrale Quellort für `RomexisPropertyAgent.java`, `RomexisOptionPaneUIPatch.java`, den RxCr2-Ersatz und `dxservice_dummy.c`. Der Agent-Build bettet ASM und beide gezielten Runtime-Patches in `RomexisPropertyAgent.jar` ein. Diese Quellen werden in die passenden Runtime-Images kompiliert, statt in Verzeichnissen finaler Images dupliziert zu werden. ### Server-Image-Build diff --git a/Build-System.md b/Build-System.md index 9e2c642..8df6bca 100644 --- a/Build-System.md +++ b/Build-System.md @@ -66,15 +66,15 @@ It produces: - Firebird client libraries and tools - OS dependencies - Chilkat -- Java property agent +- Java property agent with embedded RxCr2 and RomexisOptionPaneUI runtime patches ### GUI runtime build -`romexis-gui-runtime` contains the architecture-specific graphical stack shared by Admin and Client: Java 17/OpenJFX, X11/noVNC, Mesa/GTK, Chilkat, PropertyAgent and the DxService compatibility library. +`romexis-gui-runtime` contains the architecture-specific graphical stack shared by Admin and Client: Java 17/OpenJFX, X11/noVNC, Mesa/GTK, Chilkat, PropertyAgent with the Java 17 OptionPane null guard, and the DxService compatibility library. ### Shared runtime sources -`romexis-common/` is the single source location for `RomexisPropertyAgent.java`, the Chilkat patch source and `dxservice_dummy.c`. These sources are compiled into the appropriate runtime images instead of being duplicated in final image directories. +`romexis-common/` is the single source location for `RomexisPropertyAgent.java`, `RomexisOptionPaneUIPatch.java`, the RxCr2 replacement and `dxservice_dummy.c`. The agent build embeds ASM and both targeted runtime patches into `RomexisPropertyAgent.jar`. These sources are compiled into the appropriate runtime images instead of being duplicated in final image directories. ### Server image build diff --git a/Configuration.de.md b/Configuration.de.md index 4854f0e..0583ed0 100644 --- a/Configuration.de.md +++ b/Configuration.de.md @@ -148,7 +148,7 @@ ADMIN_JAVA_OPTS=-Xms256m -Xmx1024m ADMIN_LANGUAGE=de DEBUG_XTERM=false ADMIN_VNC_LIFECYCLE=true -ENABLE_PROPERTY_AGENT=false +ENABLE_PROPERTY_AGENT=true ``` Wichtiges Verhalten: @@ -217,4 +217,13 @@ Syntax: PROPERTY_AGENT_SET_= ``` -Dies ist vor allem für die Romexis-Server-Runtime relevant. Im Admin-Container ist der PropertyAgent standardmäßig deaktiviert. +Der Server verwendet den Agenten für Runtime-Properties und den RxCr2-Ersatz. +Admin aktiviert ihn standardmäßig für die Service-INI-Integration und den +Java-17-`RomexisOptionPaneUI`-Null-Guard. Der Client lädt denselben Agenten aus +der GUI-Runtime, deaktiviert RxCr2 und aktiviert standardmäßig den +OptionPane-Patch. + +```env +ROMEXIS_AGENT_RXCR2_PATCH=true +ROMEXIS_AGENT_OPTIONPANE_PATCH=true +``` diff --git a/Configuration.md b/Configuration.md index 262eee9..03cdeef 100644 --- a/Configuration.md +++ b/Configuration.md @@ -148,7 +148,7 @@ ADMIN_JAVA_OPTS=-Xms256m -Xmx1024m ADMIN_LANGUAGE=de DEBUG_XTERM=false ADMIN_VNC_LIFECYCLE=true -ENABLE_PROPERTY_AGENT=false +ENABLE_PROPERTY_AGENT=true ``` Important behavior: @@ -217,4 +217,12 @@ Syntax: PROPERTY_AGENT_SET_= ``` -This is primarily relevant for the Romexis server runtime. In the Admin container the PropertyAgent is disabled by default. +The server uses the agent for runtime properties and the RxCr2 replacement. +Admin enables the agent by default for its service-INI integration and the Java +17 `RomexisOptionPaneUI` null guard. The Client loads the same GUI-runtime agent, +disables RxCr2 and enables the OptionPane patch by default. + +```env +ROMEXIS_AGENT_RXCR2_PATCH=true +ROMEXIS_AGENT_OPTIONPANE_PATCH=true +``` diff --git a/Home.de.md b/Home.de.md index a3f72f5..cc89250 100644 --- a/Home.de.md +++ b/Home.de.md @@ -44,7 +44,7 @@ romexis-firebird-payload/ Builds a Firebird SQL payload from the official macOS installer. romexis-common/ - Contains shared PropertyAgent, Chilkat patch and DxService compatibility sources. + Enthält die gemeinsamen PropertyAgent-, RomexisOptionPaneUI-, RxCr2-Patch- und DxService-Kompatibilitätsquellen. romexis-base/ Builds the reusable Java 11 server runtime image. diff --git a/Home.md b/Home.md index 016767f..c6fce76 100644 --- a/Home.md +++ b/Home.md @@ -44,7 +44,7 @@ romexis-firebird-payload/ Builds a Firebird SQL payload from the official macOS installer. romexis-common/ - Contains shared PropertyAgent, Chilkat patch and DxService compatibility sources. + Contains the shared PropertyAgent, RomexisOptionPaneUI and RxCr2 patch sources, and DxService compatibility source. romexis-base/ Builds the reusable Java 11 server runtime image. diff --git a/Java-Property-Agent.de.md b/Java-Property-Agent.de.md index d275c08..083f871 100644 --- a/Java-Property-Agent.de.md +++ b/Java-Property-Agent.de.md @@ -4,11 +4,11 @@ ## Zweck -Der `RomexisPropertyAgent` ist ein kleiner Java-Instrumentation-Agent, den das Romexis-Docker-Projekt verwendet, um Romexis-`RxProperties` während des JVM-Starts zu konfigurieren. +Der `RomexisPropertyAgent` ist ein Java-Instrumentation-Agent, den das Romexis-Docker-Projekt verwendet, um Romexis-`RxProperties` zu konfigurieren und eng begrenzte Runtime-Kompatibilitätspatches während des JVM-Starts anzuwenden. Er ermöglicht es, ausgewählte Romexis-Runtime-Eigenschaften durch Umgebungsvariablen zu setzen, bevor die Romexis-Server-Anwendung vollständig startet. -Dies ist erforderlich, da bestimmtes Romexis-Verhalten sehr früh während des JVM-Starts festgelegt wird und später nicht zuverlässig durch Bearbeiten von Dateien im Container geändert werden kann. +Dies ist erforderlich, da bestimmtes Romexis-Verhalten sehr früh während des JVM-Starts festgelegt wird und ausgewählte Kompatibilitätskorrekturen vor dem Definieren der betroffenen Klassen angewendet werden müssen. --- @@ -67,7 +67,7 @@ Der Java-Agent-Ansatz vermeidet: - die Pflege benutzerdefinierter Binär-Patches - das erneute Bauen von Romexis selbst -Stattdessen kann die Docker-Runtime diese Einstellungen mit gewöhnlichen Umgebungsvariablen steuern. +Stattdessen kann die Docker-Runtime diese Einstellungen und gezielte Transformationen beim Laden von Klassen mit gewöhnlichen Umgebungsvariablen steuern. Proprietäre Romexis-JAR-Dateien bleiben auf dem Datenträger unverändert. Dies ist sicherer, einfacher zu pflegen und besser für automatisierte Deployments geeignet. @@ -105,6 +105,81 @@ Danach sucht er das passende öffentliche Feld in `RxProperties`. Existiert das Feld, liest der Agent den tatsächlichen Romexis-Property-Schlüssel und ruft die passende Methode `RxProperties.setProperty(...)` auf. +Der gleiche `premain`-Einstiegspunkt registriert außerdem Java-Instrumentation- +Transformer, bevor Romexis die betroffenen Klassen lädt. Jeder Transformer +gleicht genau einen Klassennamen ab und liefert die ursprünglichen Bytes +unverändert zurück, wenn der Patch deaktiviert, nicht anwendbar oder nicht sicher +ausführbar ist. + +--- + +## Runtime-Kompatibilitätspatches + +### RxCr2-Ersatz + +Die Server-Runtime kann `romexis_lib_resource.RxCr2` durch die eingebettete +Java-Standard-PBKDF2-Implementierung ersetzen. Dadurch entfällt die +serverseitige Abhängigkeit vom ursprünglichen Chilkat-basierten Passwort-Hashing, +ohne `RomexisServer.jar` zu verändern. + +```env +ROMEXIS_AGENT_RXCR2_PATCH=true +ROMEXIS_AGENT_RXCR2_SALT_MODE=base64 +ROMEXIS_AGENT_RXCR2_DEBUG=false +``` + +Admin und Client deaktivieren diesen serverspezifischen Ersatz. + +### RomexisOptionPaneUI-Null-Guard + +Admin und Client laufen unter Java 17. Ein konkretes Swing-Lifecycle-Rennen +wurde in folgender Methode beobachtet: + +```text +romexis_laf.RomexisOptionPaneUI$MyPCListener.propertyChange(...) +``` + +Unter neueren Java-Versionen, insbesondere Java 17, kann sich das Timing der +`PropertyChange`-Events im AWT-Event-Thread leicht unterscheiden. In diesem Fall +feuert das Event einen Sekundenbruchteil zu früh, bevor die Planmeca-Klasse ihre +UI-Komponente `m_MessageArea` initialisiert hat. Wenn Romexis anschließend die +bevorzugte Dialoggröße berechnet, führt der ursprüngliche Listener Folgendes aus: + +```java +m_MessageArea.getPreferredSize() +``` + +auf einer `null`-Referenz. Die resultierende `NullPointerException` tritt im +AWT-Event-Thread auf und kann die gesamte Anwendung beenden, statt nur das +Pop-up zu zeichnen. + +`RomexisOptionPaneUIPatch` verwendet die eingebettete ASM-Bibliothek und +transformiert ausschließlich die Methode +`propertyChange(PropertyChangeEvent)` des Listeners. Unmittelbar vor jedem +passenden `Container.getPreferredSize()`-Aufruf fügt er das Bytecode-Äquivalent +zu Folgendem ein: + +```java +if (container == null) { + return; +} +``` + +Alle anderen ursprünglichen Klassenbytes und das proprietäre Romexis-JAR bleiben +unverändert. Enthält eine künftige Romexis-Version das erwartete Bytecode-Muster +nicht mehr, protokolliert der Transformer einen Fehler und liefert die +unveränderten Klassenbytes zurück, statt den Anwendungsstart zu verhindern. + +Der Patch ist standardmäßig aktiv und kann in beiden Formen gesteuert werden: + +```env +ROMEXIS_AGENT_OPTIONPANE_PATCH=true +``` + +```text +-Dromexis.agent.optionpane.patch=true +``` + --- ## Unterstützte Werttypen @@ -142,13 +217,15 @@ Der Java Property Agent ist vorgesehen für: - automatisiertes Konfigurationsmanagement - Runtime-Anpassungen - Korrekturen der Plattformkompatibilität -- kontrollierte Overrides des Romexis-Serververhaltens +- kontrollierte Overrides des Romexis-Runtime-Verhaltens --- ## Build-Integration -Der Quellcode des Agents wird beim Build des Romexis-Server-Images kompiliert. +Die kanonischen Quellen liegen unter `romexis-common/`. Der Agent wird sowohl in +die Java-11-Server-Runtime als auch in die von Admin und Client gemeinsam +verwendete Java-17-GUI-Runtime eingebaut. Das Dockerfile verwendet eine dedizierte Build-Stage: @@ -156,12 +233,18 @@ Das Dockerfile verwendet eine dedizierte Build-Stage: agent-build ``` -Das Ergebnis wird in das finale Image kopiert als: +Das erzeugte JAR liegt abhängig von der Runtime unter folgenden Pfaden: ```text /opt/romexis/server/RomexisPropertyAgent.jar +/opt/romexis/admin/RomexisPropertyAgent.jar +/opt/romexis-runtime/RomexisPropertyAgent.jar ``` +Das Agent-JAR enthält `RomexisOptionPaneUIPatch.class`, den eingebetteten +RxCr2-Ersatz und ASM selbst. Zur Laufzeit ist deshalb keine zusätzliche +Java-Abhängigkeit erforderlich. + Das JAR-Manifest enthält: ```text @@ -178,7 +261,9 @@ Dadurch kann die JVM es laden über: ## Runtime-Integration -Der Romexis-Entrypoint fügt den Java-Agent dem JVM-Startbefehl von Romexis Server hinzu. +Server-Entrypoint, Admin-Launcher und Client-Launcher fügen den Java-Agenten ihrem +jeweiligen JVM-Startbefehl hinzu. Compose aktiviert ihn für Admin, und der Client +aktiviert ihn, wenn das JAR aus der gemeinsamen Runtime vorhanden ist. Das Property-Override wird damit angewendet, bevor `RomexisServer.jar` seine normale Startsequenz fortsetzt. @@ -188,6 +273,9 @@ Typische Runtime-Konfiguration: PROPERTY_AGENT_SET_KEY_B_KEYVAULT_PWD_LOCATION_SERVER_PROPERTIES=true ``` +Beim Client deaktiviert der Launcher den RxCr2-Ersatz explizit und aktiviert den +OptionPane-Patch. Auch Admin verwendet den OptionPane-Patch standardmäßig. + --- ## Beispielhafte Log-Ausgabe @@ -205,13 +293,21 @@ Unbekannte Eigenschaft: JavaAgent WARN: RxProperties field not found: SOME_UNKNOWN_FIELD ``` +Erfolgreiche Installation und Anwendung des Swing-Patches: + +```text +JavaAgent: RomexisOptionPaneUI MyPCListener null-guard transformer installed +JavaAgent: RomexisOptionPaneUI MyPCListener patched successfully; inserted null guards= +``` + --- ## Wichtige Hinweise -- Der Agent verändert keine Romexis-Binärdateien. -- Der Agent patcht keine Klassendateien. -- Der Agent ruft ausschließlich öffentliche `RxProperties`-Felder und Setter-Methoden auf. +- Der Agent verändert keine proprietären Romexis-JAR-Dateien auf dem Datenträger. +- Aktivierte Transformer können die In-Memory-Bytes ausdrücklich ausgewählter Klassen beim Laden verändern. +- Property-Overrides rufen öffentliche `RxProperties`-Felder und Setter-Methoden auf. +- Der OptionPane-Transformer ist auf eine Listener-Methode und ein fehlerhaftes Dereferenzierungsmuster begrenzt. - Unbekannte Felder werden mit einer Warnung ignoriert. - Dieser Mechanismus sollte nur für Eigenschaften verwendet werden, die verstanden und bewusst überschrieben werden. @@ -222,3 +318,14 @@ JavaAgent WARN: RxProperties field not found: SOME_UNKNOWN_FIELD | Eigenschaft | Wert | Grund | |---|---|---| | `KEY_B_KEYVAULT_PWD_LOCATION_SERVER_PROPERTIES` | `true` | Zwingt Romexis Server zu dem auf Server-Properties basierenden Verhalten, das für den Linux-Docker-Start erforderlich ist | + +--- + +## Runtime-Patch-Steuerung + +| Einstellung | Standard | Geltungsbereich | +|---|---|---| +| `ROMEXIS_AGENT_RXCR2_PATCH` | `true` | Serverseitiger RxCr2-Ersatz; von Admin und Client explizit deaktiviert | +| `ROMEXIS_AGENT_RXCR2_SALT_MODE` | `base64` | Salt-Interpretation der RxCr2-PBKDF2-Implementierung | +| `ROMEXIS_AGENT_RXCR2_DEBUG` | `false` | Zusätzliche nicht geheime RxCr2-Diagnoseausgaben | +| `ROMEXIS_AGENT_OPTIONPANE_PATCH` | `true` | Java-17-Swing-Lifecycle-Null-Guard für Admin und Client | diff --git a/Java-Property-Agent.md b/Java-Property-Agent.md index 7f6e2fb..cd858c0 100644 --- a/Java-Property-Agent.md +++ b/Java-Property-Agent.md @@ -4,11 +4,11 @@ ## Purpose -The `RomexisPropertyAgent` is a small Java Instrumentation Agent used by the Romexis Docker project to configure Romexis `RxProperties` during JVM startup. +The `RomexisPropertyAgent` is a Java Instrumentation Agent used by the Romexis Docker project to configure Romexis `RxProperties` and apply narrowly scoped runtime compatibility patches during JVM startup. It allows selected Romexis runtime properties to be set through environment variables before the Romexis Server application fully starts. -This is required because some Romexis behavior is decided very early during JVM startup and cannot reliably be changed later by editing files inside the container. +This is required because some Romexis behavior is decided very early during JVM startup and because selected compatibility fixes must be applied before the affected classes are defined. --- @@ -67,7 +67,7 @@ The Java agent approach avoids: - maintaining custom binary patches - rebuilding Romexis itself -Instead, the Docker runtime can control these settings using ordinary environment variables. +Instead, the Docker runtime can control these settings and targeted class-load-time transformations using ordinary environment variables. Proprietary Romexis JAR files remain unchanged on disk. This is safer, easier to maintain and better suited for automated deployments. @@ -105,6 +105,78 @@ Then it looks up the matching public field in `RxProperties`. If the field exists, the agent reads the actual Romexis property key and calls the matching `RxProperties.setProperty(...)` method. +The same `premain` entry point also registers Java instrumentation transformers +before Romexis loads the affected classes. Each transformer matches one exact +class name and returns the original bytes unchanged when the patch is disabled, +not applicable or cannot be applied safely. + +--- + +## Runtime Compatibility Patches + +### RxCr2 Replacement + +The server runtime can replace `romexis_lib_resource.RxCr2` with the embedded +Java-standard PBKDF2 implementation. This removes the server-side dependency on +the original Chilkat-based password hashing path without modifying +`RomexisServer.jar`. + +```env +ROMEXIS_AGENT_RXCR2_PATCH=true +ROMEXIS_AGENT_RXCR2_SALT_MODE=base64 +ROMEXIS_AGENT_RXCR2_DEBUG=false +``` + +Admin and Client disable this server-specific replacement. + +### RomexisOptionPaneUI Null Guard + +Admin and Client run on Java 17. A concrete Swing lifecycle race was observed in: + +```text +romexis_laf.RomexisOptionPaneUI$MyPCListener.propertyChange(...) +``` + +On newer Java versions, especially Java 17, the timing of `PropertyChange` +events on the AWT event thread can differ slightly. In this case the event can +fire a fraction too early, before the Planmeca class has initialized its +`m_MessageArea` UI component. When Romexis then calculates the preferred dialog +size, the original listener executes: + +```java +m_MessageArea.getPreferredSize() +``` + +against a `null` reference. The resulting `NullPointerException` occurs on the +AWT event thread and can terminate the complete application instead of merely +drawing the popup. + +`RomexisOptionPaneUIPatch` uses the bundled ASM library to transform only the +listener's `propertyChange(PropertyChangeEvent)` method. Immediately before each +matching `Container.getPreferredSize()` invocation, it inserts the bytecode +equivalent of: + +```java +if (container == null) { + return; +} +``` + +All other original class bytes and the proprietary Romexis JAR are preserved. +If a future Romexis version no longer contains the expected bytecode pattern, +the transformer logs an error and returns the unmodified class bytes instead of +making application startup fail. + +The patch is enabled by default and can be controlled with either form: + +```env +ROMEXIS_AGENT_OPTIONPANE_PATCH=true +``` + +```text +-Dromexis.agent.optionpane.patch=true +``` + --- ## Supported Value Types @@ -142,13 +214,15 @@ The Java Property Agent is intended for: - automated configuration management - runtime customization - platform compatibility fixes -- controlled Romexis server behavior overrides +- controlled Romexis runtime behavior overrides --- ## Build Integration -The agent source is compiled during the Romexis Server image build. +The canonical sources live in `romexis-common/`. The agent is built into both +the Java 11 server runtime and the shared Java 17 GUI runtime used by Admin and +Client. The Dockerfile uses a dedicated build stage: @@ -156,12 +230,18 @@ The Dockerfile uses a dedicated build stage: agent-build ``` -The result is copied into the final image as: +The resulting JAR is available at these runtime-specific paths: ```text /opt/romexis/server/RomexisPropertyAgent.jar +/opt/romexis/admin/RomexisPropertyAgent.jar +/opt/romexis-runtime/RomexisPropertyAgent.jar ``` +The agent JAR contains `RomexisOptionPaneUIPatch.class`, the embedded RxCr2 +replacement and ASM itself, so no external Java dependency is required at +runtime. + The JAR manifest contains: ```text @@ -178,7 +258,9 @@ This allows the JVM to load it through: ## Runtime Integration -The Romexis entrypoint adds the Java agent to the Romexis Server JVM startup command. +The Server entrypoint, Admin launcher and Client launcher add the Java agent to +their respective JVM startup commands. Compose enables it for Admin, and the +Client enables it when the shared runtime JAR is present. The property override is then applied before `RomexisServer.jar` continues its normal startup sequence. @@ -188,6 +270,9 @@ Typical runtime configuration: PROPERTY_AGENT_SET_KEY_B_KEYVAULT_PWD_LOCATION_SERVER_PROPERTIES=true ``` +For the Client, the launcher explicitly disables the RxCr2 replacement and +enables the OptionPane patch. Admin also uses the OptionPane patch by default. + --- ## Example Log Output @@ -205,13 +290,21 @@ Unknown property: JavaAgent WARN: RxProperties field not found: SOME_UNKNOWN_FIELD ``` +Successful Swing patch installation and application: + +```text +JavaAgent: RomexisOptionPaneUI MyPCListener null-guard transformer installed +JavaAgent: RomexisOptionPaneUI MyPCListener patched successfully; inserted null guards= +``` + --- ## Important Notes -- The agent does not modify Romexis binaries. -- The agent does not patch class files. -- The agent only calls public `RxProperties` fields and setter methods. +- The agent does not modify proprietary Romexis JAR files on disk. +- Enabled transformers can modify the in-memory bytes of explicitly targeted classes while they are loaded. +- Property overrides call public `RxProperties` fields and setter methods. +- The OptionPane transformer is limited to one listener method and one failing dereference pattern. - Unknown fields are ignored with a warning. - This mechanism should only be used for properties that are understood and intentionally overridden. @@ -223,4 +316,15 @@ JavaAgent WARN: RxProperties field not found: SOME_UNKNOWN_FIELD |---|---|---| | `KEY_B_KEYVAULT_PWD_LOCATION_SERVER_PROPERTIES` | `true` | Forces Romexis Server to use the server-properties based behavior required for Linux Docker startup | +--- + +## Runtime Patch Controls + +| Setting | Default | Scope | +|---|---|---| +| `ROMEXIS_AGENT_RXCR2_PATCH` | `true` | Server-side RxCr2 replacement; explicitly disabled by Admin and Client | +| `ROMEXIS_AGENT_RXCR2_SALT_MODE` | `base64` | Salt interpretation for the RxCr2 PBKDF2 implementation | +| `ROMEXIS_AGENT_RXCR2_DEBUG` | `false` | Additional non-secret RxCr2 diagnostics | +| `ROMEXIS_AGENT_OPTIONPANE_PATCH` | `true` | Java 17 Swing lifecycle null guard for Admin and Client | + diff --git a/Project-Structure.de.md b/Project-Structure.de.md index 3a25f16..f3e4435 100644 --- a/Project-Structure.de.md +++ b/Project-Structure.de.md @@ -26,6 +26,7 @@ │ └── ci-publish-manifests.sh ├── romexis-common/ │ ├── RomexisPropertyAgent.java +│ ├── RomexisOptionPaneUIPatch.java │ ├── dxservice_dummy.c │ └── patches-src/ ├── romexis-base/ diff --git a/Project-Structure.md b/Project-Structure.md index 656c98e..c4bef6d 100644 --- a/Project-Structure.md +++ b/Project-Structure.md @@ -26,6 +26,7 @@ │ └── ci-publish-manifests.sh ├── romexis-common/ │ ├── RomexisPropertyAgent.java +│ ├── RomexisOptionPaneUIPatch.java │ ├── dxservice_dummy.c │ └── patches-src/ ├── romexis-base/ diff --git a/Reference-README.de.md b/Reference-README.de.md index d914965..50db8c2 100644 --- a/Reference-README.de.md +++ b/Reference-README.de.md @@ -265,7 +265,7 @@ ADMIN_JAVA_OPTS=-Xms256m -Xmx1024m ADMIN_LANGUAGE=de DEBUG_XTERM=false ADMIN_VNC_LIFECYCLE=true -ENABLE_PROPERTY_AGENT=false +ENABLE_PROPERTY_AGENT=true ``` `ADMIN_LANGUAGE` unterstützt: @@ -544,7 +544,11 @@ Beispiel: PROPERTY_AGENT_SET_KEY_B_KEYVAULT_PWD_LOCATION_SERVER_PROPERTIES=true ``` -Dies ist hauptsächlich für die Romexis-Server-Laufzeit relevant. Im Admin-Container ist der PropertyAgent standardmäßig deaktiviert. +Der Server verwendet den Agenten hauptsächlich für Runtime-Properties. Admin +aktiviert ihn standardmäßig, und Admin sowie Client verwenden seinen +Java-17-`RomexisOptionPaneUI`-Null-Guard gegen die Swing-Lifecycle- +`NullPointerException`, die durch ein frühes `PropertyChange`-Event vor der +Initialisierung von `m_MessageArea` entsteht. --- diff --git a/Reference-README.md b/Reference-README.md index 9cfd768..b19d921 100644 --- a/Reference-README.md +++ b/Reference-README.md @@ -267,7 +267,7 @@ ADMIN_JAVA_OPTS=-Xms256m -Xmx1024m ADMIN_LANGUAGE=en DEBUG_XTERM=false ADMIN_VNC_LIFECYCLE=true -ENABLE_PROPERTY_AGENT=false +ENABLE_PROPERTY_AGENT=true ``` `ADMIN_LANGUAGE` supports: @@ -546,7 +546,10 @@ Example: PROPERTY_AGENT_SET_KEY_B_KEYVAULT_PWD_LOCATION_SERVER_PROPERTIES=true ``` -This is primarily relevant for the Romexis server runtime. In the Admin container the PropertyAgent is disabled by default. +The server uses the agent primarily for runtime properties. Admin enables the +agent by default, and Admin and Client use its Java 17 `RomexisOptionPaneUI` +null guard to prevent the Swing lifecycle `NullPointerException` caused by an +early `PropertyChange` event before `m_MessageArea` is initialized. --- diff --git a/Romexis-Admin.de.md b/Romexis-Admin.de.md index befd2b6..c4b0b89 100644 --- a/Romexis-Admin.de.md +++ b/Romexis-Admin.de.md @@ -123,20 +123,32 @@ ADMIN_JAVA_OPTS=-Xms256m -Xmx1024m ADMIN_LANGUAGE=de DEBUG_XTERM=false ADMIN_VNC_LIFECYCLE=true -ENABLE_PROPERTY_AGENT=false +ENABLE_PROPERTY_AGENT=true ``` --- ## PropertyAgent im Admin -Der Romexis PropertyAgent ist für den Admin-Container standardmäßig deaktiviert: +Der Romexis PropertyAgent ist für den Admin-Container standardmäßig aktiviert: ```env -ENABLE_PROPERTY_AGENT=false +ENABLE_PROPERTY_AGENT=true ``` -Grund: `RxProperties` ist während der Java-Agent-Phase `premain` beim Start von RomexisConfig nicht immer sichtbar. Der Server-Container verwendet den PropertyAgent weiterhin für die serverseitige Injektion von Laufzeiteigenschaften. +Der Agent setzt den Linux-spezifischen Admin-Service-INI-Pfad und stellt den für +den zuverlässigen Betrieb unter Java 17 erforderlichen `RomexisOptionPaneUI`- +Null-Guard bereit. Der Guard verhindert eine Swing-Lifecycle- +`NullPointerException`, wenn ein `PropertyChange`-Event den Planmeca-Listener +erreicht, bevor `m_MessageArea` initialisiert wurde. Der serverspezifische +RxCr2-Ersatz bleibt in Admin über `ROMEXIS_AGENT_RXCR2_PATCH=false` deaktiviert. + +Der Patch ist im Agenten standardmäßig aktiv. Nur für einen kontrollierten +Vergleich kann er folgendermaßen deaktiviert werden: + +```env +ROMEXIS_AGENT_OPTIONPANE_PATCH=false +``` --- diff --git a/Romexis-Admin.md b/Romexis-Admin.md index 0862265..9771481 100644 --- a/Romexis-Admin.md +++ b/Romexis-Admin.md @@ -123,20 +123,32 @@ ADMIN_JAVA_OPTS=-Xms256m -Xmx1024m ADMIN_LANGUAGE=de DEBUG_XTERM=false ADMIN_VNC_LIFECYCLE=true -ENABLE_PROPERTY_AGENT=false +ENABLE_PROPERTY_AGENT=true ``` --- ## PropertyAgent in Admin -The Romexis PropertyAgent is disabled by default for the Admin container: +The Romexis PropertyAgent is enabled by default for the Admin container: ```env -ENABLE_PROPERTY_AGENT=false +ENABLE_PROPERTY_AGENT=true ``` -Reason: `RxProperties` is not always visible during the Java agent `premain` phase when RomexisConfig is started. The server container still uses the PropertyAgent for server-side runtime property injection. +The agent sets the Linux-specific Admin service INI path and supplies the +`RomexisOptionPaneUI` null guard required for reliable operation on Java 17. +The guard prevents a Swing lifecycle `NullPointerException` when a +`PropertyChange` event reaches the Planmeca listener before `m_MessageArea` has +been initialized. The server-specific RxCr2 replacement remains disabled in +Admin through `ROMEXIS_AGENT_RXCR2_PATCH=false`. + +The patch is enabled by default inside the agent. It can be disabled only for a +controlled comparison with: + +```env +ROMEXIS_AGENT_OPTIONPANE_PATCH=false +``` --- diff --git a/Romexis-Client.de.md b/Romexis-Client.de.md index 9db1e3f..17512a2 100644 --- a/Romexis-Client.de.md +++ b/Romexis-Client.de.md @@ -74,3 +74,114 @@ romexis-client:latest ``` Zuerst werden die Architektur-Tags erstellt. Die öffentlichen Multi-Architektur-Tags werden erst veröffentlicht, wenn beide Architekturen erfolgreich abgeschlossen wurden. + +--- + +## Laufzeitverhalten + +Der Container startet Xvfb, Openbox, idesk, x11vnc und noVNC. Romexis selbst +startet nicht automatisch. Öffne den noVNC-Desktop und doppelklicke auf das +Symbol **Romexis Client**. Dadurch belegt eine ungenutzte Client-Sitzung keinen +großen Java-Heap, und der Anwendungsstart bleibt für den Bediener sichtbar. + +Der Launcher verhindert über eine Sperrdatei doppelte Romexis-Prozesse und +schreibt das Client-Protokoll nach: + +```text +/tmp/romexis-client.log +``` + +Das optionale Debug-Terminal wird über `CLIENT_DEBUG_XTERM` gesteuert. + +--- + +## Browser- und Runtime-Konfiguration + +Die Standardadresse im Browser lautet: + +```text +http://localhost:6081/vnc.html?autoconnect=true +``` + +| Variable | Standard | Zweck | +|---|---|---| +| `CLIENT_NOVNC_PORT` | `6081` | Veröffentlichter noVNC-Hostport | +| `CLIENT_VNC_PASSWORD` | `promax` | Passwort des internen VNC-Servers | +| `CLIENT_RESOLUTION` | `1280x900x24` | Auflösung des virtuellen Desktops | +| `CLIENT_JAVA_OPTS` | `-Xss500k -Xmx16G` | JVM-Optionen des Clients | +| `CLIENT_LANGUAGE` | `de` | Romexis-Sprache | +| `CLIENT_COUNTRY` | `DE` | Land der Java-Locale | +| `CLIENT_DEBUG_XTERM` | `false` | Aktiviert ein zusätzliches Debug-Terminal | +| `ROMEXIS_AGENT_OPTIONPANE_PATCH` | `true` | Aktiviert die Java-17-Swing-Lifecycle-Korrektur | + +Compose veröffentlicht nur noVNC. x11vnc lauscht innerhalb des Containers auf +Port `5900`, wird standardmäßig aber nicht als Hostport veröffentlicht. + +--- + +## RMI-Auflösung und Identität + +Der Client verwendet den öffentlichen `SERVER_RMI_HOSTNAME` als Server- und +Zertifikatsidentität. Beim Containerstart wird dieser Hostname auf die interne +Adresse des Compose-Dienstes `romexis` abgebildet. Der Client-Launcher verbindet +sich auch bei übersetzten öffentlichen Hostports mit den festen Containerports +`1099` und `2099`. + +Bei einer Portübersetzung sollte ein DNS-Name statt einer IP-Adresse verwendet +werden. Eine IP-Adresse kann nicht über `/etc/hosts` auf den internen Dienst +umgebogen werden. + +--- + +## RomexisOptionPaneUI-Patch + +Beim Start des Clients wird der gemeinsame `RomexisPropertyAgent` geladen. Sein +serverspezifischer RxCr2-Ersatz ist deaktiviert, der OptionPane-Patch dagegen +standardmäßig aktiv. + +Unter Java 17 kann ein AWT-Property-Change-Event einen Sekundenbruchteil zu früh +ausgeführt werden, bevor die Planmeca-Klasse `m_MessageArea` initialisiert hat. +Wenn der ursprüngliche Listener danach die Dialoggröße berechnet, ruft er +`getPreferredSize()` auf dieser `null`-Referenz auf. Die resultierende +`NullPointerException` tritt im AWT-Event-Thread auf und kann die gesamte +Anwendung beenden, statt nur das Pop-up zu zeichnen. + +`RomexisOptionPaneUIPatch` transformiert ausschließlich +`romexis_laf.RomexisOptionPaneUI$MyPCListener.propertyChange()` und ergänzt +unmittelbar vor dem fehlerhaften Aufruf einen Null-Guard. Das ursprüngliche +Romexis-JAR bleibt auf dem Datenträger unverändert. Der Patch sollte nur für +einen kontrollierten Vergleich deaktiviert werden: + +```env +ROMEXIS_AGENT_OPTIONPANE_PATCH=false +``` + +--- + +## Persistente Daten und Healthcheck + +Die Client-ProgramData liegen getrennt vom Server- und Admin-Zustand: + +```text +${ROMEXIS_DATA_ROOT}/docker/client/programdata + -> /ProgramData/Planmeca/Romexis +``` + +Der Healthcheck prüft X-Display, laufenden `Romexis.jar`-Prozess und noVNC-Port. +Da Romexis bedarfsgesteuert startet, kann der Dienst bis zum Doppelklick auf das +Desktop-Symbol im Zustand `starting` bleiben oder `unhealthy` werden. + +--- + +## Betrieb und Fehleranalyse + +```bash +docker compose up -d romexis-client +docker compose logs -f romexis-client +docker compose exec romexis-client tail -f /tmp/romexis-client.log +``` + +Wenn kein Desktop erscheint, prüfe die Meldungen von Xvfb, Openbox, x11vnc und +websockify im Containerprotokoll. Beendet sich Romexis nach dem Aktivieren des +Symbols, prüfe `/tmp/romexis-client.log` und stelle sicher, dass +`SERVER_RMI_HOSTNAME` auf den internen Dienst `romexis` aufgelöst wird. diff --git a/Romexis-Client.md b/Romexis-Client.md index 89d2fec..28b2eac 100644 --- a/Romexis-Client.md +++ b/Romexis-Client.md @@ -74,3 +74,112 @@ romexis-client:latest ``` The architecture tags are created first. The public multi-architecture tags are published only after both architectures completed successfully. + +--- + +## Runtime Behavior + +The container starts Xvfb, Openbox, idesk, x11vnc and noVNC. Romexis itself is +not started automatically. Open the noVNC desktop and double-click the +**Romexis Client** icon. This keeps an unused Client session from consuming a +large Java heap and makes application startup visible to the operator. + +The launcher uses a lock file to prevent duplicate Romexis processes and writes +the Client log to: + +```text +/tmp/romexis-client.log +``` + +The optional debug terminal is controlled by `CLIENT_DEBUG_XTERM`. + +--- + +## Browser and Runtime Configuration + +The default browser URL is: + +```text +http://localhost:6081/vnc.html?autoconnect=true +``` + +| Variable | Default | Purpose | +|---|---|---| +| `CLIENT_NOVNC_PORT` | `6081` | Published noVNC host port | +| `CLIENT_VNC_PASSWORD` | `promax` | Password for the internal VNC server | +| `CLIENT_RESOLUTION` | `1280x900x24` | Virtual desktop resolution | +| `CLIENT_JAVA_OPTS` | `-Xss500k -Xmx16G` | Client JVM options | +| `CLIENT_LANGUAGE` | `de` | Romexis language | +| `CLIENT_COUNTRY` | `DE` | Java locale country | +| `CLIENT_DEBUG_XTERM` | `false` | Enables an additional debug terminal | +| `ROMEXIS_AGENT_OPTIONPANE_PATCH` | `true` | Enables the Java 17 Swing lifecycle fix | + +Compose publishes noVNC only. x11vnc listens on port `5900` inside the +container but is not exposed as a host port by default. + +--- + +## RMI Resolution and Identity + +The Client uses the public `SERVER_RMI_HOSTNAME` as the server and certificate +identity. During container startup, that hostname is mapped to the internal +address of the Compose service `romexis`. The Client launcher connects to the +fixed container ports `1099` and `2099`, even when the corresponding public host +ports are translated. + +Use a DNS hostname rather than an IP address when port translation is required. +An IP address cannot be remapped to the internal service through `/etc/hosts`. + +--- + +## RomexisOptionPaneUI Patch + +The shared `RomexisPropertyAgent` is loaded when the Client starts. Its +server-specific RxCr2 replacement is disabled, while the OptionPane patch is +enabled by default. + +Under Java 17, an AWT property-change event can run a fraction too early, +before the Planmeca class has initialized `m_MessageArea`. When the original +listener subsequently calculates the dialog size, it calls +`getPreferredSize()` on this `null` reference. The resulting +`NullPointerException` occurs on the AWT event thread and can terminate the +complete application instead of merely drawing the popup. + +`RomexisOptionPaneUIPatch` transforms only +`romexis_laf.RomexisOptionPaneUI$MyPCListener.propertyChange()` and inserts a +null guard immediately before the failing call. The original Romexis JAR stays +unchanged on disk. Disable the patch only for a controlled comparison: + +```env +ROMEXIS_AGENT_OPTIONPANE_PATCH=false +``` + +--- + +## Persistent Data and Healthcheck + +Client ProgramData is stored separately from Server and Admin state: + +```text +${ROMEXIS_DATA_ROOT}/docker/client/programdata + -> /ProgramData/Planmeca/Romexis +``` + +The healthcheck validates the X display, the running `Romexis.jar` process and +the noVNC port. Because Romexis starts on demand, the service can remain in +`starting` or become `unhealthy` until the desktop icon has been used. + +--- + +## Operations and Troubleshooting + +```bash +docker compose up -d romexis-client +docker compose logs -f romexis-client +docker compose exec romexis-client tail -f /tmp/romexis-client.log +``` + +If no desktop appears, check the Xvfb, Openbox, x11vnc and websockify messages in +the container log. If Romexis exits after the icon is activated, inspect +`/tmp/romexis-client.log` and confirm that `SERVER_RMI_HOSTNAME` resolves to the +internal `romexis` service.