Files
mxaccessgw/clients/java/JavaClientDesign.md
T
Joseph Doherty 397d3c5c4f rename: apply ZB.MOM.WW prefix to all client SDKs + fix pre-existing alarm-RPC breaks
Rename across every client surface using each language's idiomatic convention:

  * .NET   clients/dotnet/MxGateway.Client[.Cli|.Tests]/
             -> clients/dotnet/ZB.MOM.WW.MxGateway.Client[.Cli|.Tests]/
             namespaces -> ZB.MOM.WW.MxGateway.Client[.Cli|.Tests]
             contracts ProjectReference repointed to ZB.MOM.WW.MxGateway.Contracts
             sln migrated to slnx (dotnet sln migrate)
  * Python src/mxgateway -> src/zb_mom_ww_mxgateway
             src/mxgateway_cli -> src/zb_mom_ww_mxgateway_cli
             distribution: mxaccess-gateway-client -> zb-mom-ww-mxaccess-gateway-client
  * Rust   crate: mxgateway-client -> zb-mom-ww-mxgateway-client
             build.rs proto path repointed
  * Java   subprojects: mxgateway-{client,cli} -> zb-mom-ww-mxgateway-{client,cli}
             packages com.dohertylan.mxgateway -> com.zb.mom.ww.mxgateway
             group   com.dohertylan.mxgateway -> com.zb.mom.ww.mxgateway
             rootProject mxaccessgw-java -> zb-mom-ww-mxaccessgw-java
  * Go     generate-proto.ps1 proto path repointed; module path and
             package mxgateway kept (Go convention).
  * proto-inputs.json: generatedOutputs.python updated to new package path.
  * scripts/run-client-e2e-tests.ps1: Java CLI install path + gradle task
             updated to zb-mom-ww-mxgateway-cli.

CLI binary names (mxgw, mxgw-py, mxgw-go, mxgateway-cli) and wire-level
identifiers (MXGATEWAY_* env vars, the mxgw_<id>_<secret> API key
prefix, protobuf package names like mxaccess_gateway.v1, all MXAccess
references) intentionally NOT renamed.

Fix pre-existing alarms-over-gateway breaks unblocked by the rename:

  * mxaccess_gateway.proto: add missing public message QueryActiveAlarmsRequest
    {session_id, client_correlation_id, alarm_filter_prefix} and missing
    rpc QueryActiveAlarms(QueryActiveAlarmsRequest) returns
    (stream ActiveAlarmSnapshot). All four typed clients referenced
    these but they were absent from the proto.
  * MxAccessGatewayService.QueryActiveAlarms: implement the new RPC on
    the server, streaming from IGatewayAlarmService.CurrentAlarms with
    optional alarm_filter_prefix filter.
  * clients/dotnet/.../DiscoverHierarchyOptions.cs: add the hand-written
    .NET POCO that wraps DiscoverHierarchyRequest (referenced by
    GalaxyRepositoryClient.DiscoverHierarchyAsync but never authored).
  * Drop retired session_id field references from
    AcknowledgeAlarmRequest/AcknowledgeAlarmReply test fixtures across
    .NET, Rust, Go, and Python clients.
  * Rust integration test: add the missing stream_alarms impl on the
    fake MxAccessGateway server (the trait gained the method, fake
    didn't).
  * Rust CLI test: bump expected gatewayProtocolVersion 2 -> 3.

Regenerated artifacts updated in this commit:
  * src/ZB.MOM.WW.MxGateway.Contracts/Generated/{MxaccessGateway,MxaccessGatewayGrpc}.cs
  * clients/python/src/zb_mom_ww_mxgateway/generated/*_pb2{,_grpc}.py
  * clients/go/internal/generated/*.pb.go
(C# regenerated by Grpc.Tools on contracts build; Python and Go via
their generate-proto.ps1 scripts; Rust regenerates from .proto via
tonic-build at compile time so no checked-in artefact.)

Verification: 472 server tests, 275 worker tests (9 dev-rig skipped),
18 integration tests (live MxAccess + LDAP + Galaxy), 57 .NET client
tests, 32 Rust workspace tests, 39 Python tests, all Go packages, and
gradle build for Java all pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 19:09:34 -04:00

5.6 KiB

Java Client Detailed Design

Purpose

Provide a Java client library for MXAccess Gateway, plus a test CLI and unit tests. The Java client should work for JVM services and operator tooling.

Follow the Java Style Guide for handwritten code and the Protobuf Style Guide for generated contract inputs.

Build Layout

Recommended Gradle multi-project layout:

clients/java/
  settings.gradle
  build.gradle
  src/main/generated/
  zb-mom-ww-mxgateway-client/
    build.gradle
    src/main/java/com/dohertylan/mxgateway/client/
    src/test/java/com/dohertylan/mxgateway/client/
  zb-mom-ww-mxgateway-cli/
    build.gradle
    src/main/java/com/dohertylan/mxgateway/cli/

Alternative Maven layout is acceptable if the repo standardizes on Maven.

Target Java:

  • Java 21 recommended.
  • The Gradle scaffold uses the Java 21 toolchain for compilation and tests.

Expected dependencies:

  • grpc-netty-shaded
  • grpc-protobuf
  • grpc-stub
  • protobuf-java
  • picocli
  • junit-jupiter
  • mockito if needed

Library API

Suggested API:

public final class MxGatewayClient implements AutoCloseable {
    public static MxGatewayClient connect(MxGatewayClientOptions options);
    public MxGatewaySession openSession(OpenSessionOptions options);
    public MxCommandReply invoke(MxCommandRequest request);
    public CompletableFuture<MxCommandReply> invokeAsync(MxCommandRequest request);
    public void close();
}

public final class MxGatewaySession implements AutoCloseable {
    public String sessionId();
    public int register(String clientName);
    public void unregister(int serverHandle);
    public int addItem(int serverHandle, String item);
    public int addItem2(int serverHandle, String item, String context);
    public void advise(int serverHandle, int itemHandle);
    public List<SubscribeResult> addItemBulk(int serverHandle, List<String> tagAddresses);
    public List<SubscribeResult> adviseItemBulk(int serverHandle, List<Integer> itemHandles);
    public List<SubscribeResult> removeItemBulk(int serverHandle, List<Integer> itemHandles);
    public List<SubscribeResult> unAdviseItemBulk(int serverHandle, List<Integer> itemHandles);
    public List<SubscribeResult> subscribeBulk(int serverHandle, List<String> tagAddresses);
    public List<SubscribeResult> unsubscribeBulk(int serverHandle, List<Integer> itemHandles);
    public void write(int serverHandle, int itemHandle, MxValue value, int userId);
    public Iterator<MxEvent> streamEvents();
    public void streamEventsAsync(StreamObserver<MxEvent> observer);
    public void close();
}

Expose generated protobuf classes for callers that need raw access.

Options

public final class MxGatewayClientOptions {
    URI endpoint;
    String apiKey;
    boolean plaintext;
    Path caCertificatePath;
    String serverNameOverride;
    Duration connectTimeout;
    Duration callTimeout;
}

Authentication

Use a gRPC ClientInterceptor to attach:

authorization: Bearer <api key>

Redact API keys in toString, logs, and CLI output.

TLS

Support:

  • plaintext for local development,
  • TLS with default JVM trust store,
  • custom CA certificate file,
  • server name override for test environments.

Streaming

Support both:

  • blocking iterator for simple CLIs,
  • async StreamObserver for services.

Do not reorder events. Stream cancellation should call ClientCall.cancel.

Error Handling

Recommended exceptions:

MxGatewayException
MxGatewayAuthenticationException
MxGatewayAuthorizationException
MxGatewaySessionException
MxGatewayWorkerException
MxGatewayCommandException
MxAccessException

MxGatewayCommandException should carry the raw command reply when available.

Test CLI

Binary wrapper name:

mxgw-java

Use picocli.

Commands:

mxgw-java version
mxgw-java smoke --endpoint localhost:5000 --api-key-env MXGATEWAY_API_KEY --plaintext --item TestChildObject.TestInt
mxgw-java stream-events --session-id <id> --json
mxgw-java write --session-id <id> --server-handle 1 --item-handle 1 --type int32 --value 123

JSON output can use Jackson or protobuf JSON formatting. Keep it deterministic.

Unit Tests

Use JUnit 5.

Use InProcessServerBuilder and InProcessChannelBuilder for fake gRPC tests.

Required tests:

  • auth interceptor attaches metadata,
  • key redaction,
  • plaintext and TLS channel setup,
  • request construction helpers,
  • value conversion,
  • status/error mapping,
  • blocking event stream iteration,
  • async stream observer cancellation,
  • CLI parsing,
  • JSON output.

Integration Tests

Skip unless:

MXGATEWAY_INTEGRATION=1

Use JUnit assumptions. Integration flow should open, register, add, advise, stream for bounded time, and close.

Packaging

Publish library and CLI separately:

  • mxgateway-client jar,
  • mxgateway-cli runnable distribution.

Generated protobuf code should be produced during the build from shared proto files and should not be hand-edited.

Current Build

Run the Java scaffold checks from clients/java:

gradle test

The mxgateway-client project generates the gateway and worker protobuf/gRPC bindings into src/main/generated, compiles the generated contracts, and runs JUnit 5 tests. The mxgateway-cli project builds a Picocli-based mxgw-java entry point for later command implementation.