Clone
3
Java Property Agent
Patrick Gniza edited this page 2026-08-22 15:46:50 +02:00

Deutsch | English

Java Property Agent

Purpose

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 because selected compatibility fixes must be applied before the affected classes are defined.


Why the Agent Exists

When starting RomexisServer.jar under Linux, Romexis internally selected behavior that matched the macOS runtime path.

That macOS-specific behavior was not compatible with the Linux Docker environment.

The critical property was:

KEY_B_KEYVAULT_PWD_LOCATION_SERVER_PROPERTIES

For the Romexis Server to start correctly inside the Linux container, this property had to be set to:

true

This makes Romexis behave like the Windows server runtime in this area and use the expected server properties based key vault password location.

Without this override, the Romexis Server startup under Linux could fail because the wrong platform-specific property handling was selected.


Required Docker Setting

The most important environment variable currently used by the Docker image is:

PROPERTY_AGENT_SET_KEY_B_KEYVAULT_PWD_LOCATION_SERVER_PROPERTIES=true

This is translated by the Java agent into:

RxProperties.setProperty(
    RxProperties.KEY_B_KEYVAULT_PWD_LOCATION_SERVER_PROPERTIES,
    true
);

This override is one of the reasons why Romexis Server can run reliably in the Linux-based container.


Why a Java Agent Instead of Patching Files?

The Java agent approach avoids:

  • patching Romexis application files
  • modifying proprietary Romexis JARs
  • editing configuration files after startup has already begun
  • maintaining custom binary patches
  • rebuilding Romexis itself

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.


How It Works

The agent is loaded by the JVM before the Romexis application starts.

It scans all environment variables with the prefix:

PROPERTY_AGENT_SET_

The part after the prefix is interpreted as a field name from:

romexis_lib_base.types.RxProperties

Example:

PROPERTY_AGENT_SET_KEY_B_KEYVAULT_PWD_LOCATION_SERVER_PROPERTIES=true

The agent removes the prefix:

KEY_B_KEYVAULT_PWD_LOCATION_SERVER_PROPERTIES

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.

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:

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:

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:

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:

ROMEXIS_AGENT_OPTIONPANE_PATCH=true
-Dromexis.agent.optionpane.patch=true

Supported Value Types

The agent automatically converts values to one of the following types:

Environment value Java type
true / false Boolean
integer values Integer
all other values String

Unknown Properties

If an environment variable references a field that does not exist in RxProperties, the agent does not fail the startup.

Instead, it logs a warning:

JavaAgent WARN: RxProperties field not found: <field>

This makes the mechanism safe for optional or version-dependent properties.


Intended Use Cases

The Java Property Agent is intended for:

  • Docker deployments
  • Kubernetes deployments
  • automated configuration management
  • runtime customization
  • platform compatibility fixes
  • controlled Romexis runtime behavior overrides

Build Integration

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:

agent-build

The resulting JAR is available at these runtime-specific paths:

/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:

Premain-Class: RomexisPropertyAgent

This allows the JVM to load it through:

-javaagent:/opt/romexis/server/RomexisPropertyAgent.jar

Runtime Integration

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.

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

Successful property application:

JavaAgent: set KEY_B_KEYVAULT_PWD_LOCATION_SERVER_PROPERTIES=true
JavaAgent: 1 properties applied

Unknown property:

JavaAgent WARN: RxProperties field not found: SOME_UNKNOWN_FIELD

Successful Swing patch installation and application:

JavaAgent: RomexisOptionPaneUI MyPCListener null-guard transformer installed
JavaAgent: RomexisOptionPaneUI MyPCListener patched successfully; inserted null guards=<count>

Important Notes

  • 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.

Current Critical Property

Property Value Reason
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