397d3c5c4f
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>
229 lines
9.6 KiB
Markdown
229 lines
9.6 KiB
Markdown
# Java Client
|
|
|
|
The Java client workspace contains the MXAccess Gateway client library,
|
|
generated protobuf/gRPC bindings, a Picocli test CLI project, and JUnit tests.
|
|
|
|
## Layout
|
|
|
|
```text
|
|
clients/java/
|
|
settings.gradle
|
|
build.gradle
|
|
src/main/generated/
|
|
zb-mom-ww-mxgateway-client/
|
|
zb-mom-ww-mxgateway-cli/
|
|
```
|
|
|
|
`mxgateway-client` generates Java protobuf and gRPC sources from
|
|
`../../src/ZB.MOM.WW.MxGateway.Contracts/Protos`. The Gradle protobuf plugin writes those
|
|
generated sources under `src/main/generated`, which matches the client proto
|
|
manifest in `../proto/proto-inputs.json`. Do not edit generated files by hand.
|
|
|
|
`mxgateway-client` exposes `MxGatewayClientOptions`, `MxGatewayClient`,
|
|
`MxGatewaySession`, value/status helpers, typed gateway exceptions, raw
|
|
generated stubs, and generated protobuf messages for parity tests.
|
|
|
|
`mxgateway-cli` depends on `mxgateway-client` and provides the `mxgw-java`
|
|
application entry point. The CLI supports version, session, command, event
|
|
streaming, write, and smoke-test commands with deterministic JSON output.
|
|
|
|
## Regenerating Protobuf Bindings
|
|
|
|
Run generation from `clients/java` after the shared `.proto` files or Java
|
|
output path changes:
|
|
|
|
```powershell
|
|
gradle :mxgateway-client:generateProto
|
|
```
|
|
|
|
## Client Usage
|
|
|
|
Create a client with explicit transport and auth options:
|
|
|
|
```java
|
|
MxGatewayClientOptions options = MxGatewayClientOptions.builder()
|
|
.endpoint("localhost:5000")
|
|
.apiKey(System.getenv("MXGATEWAY_API_KEY"))
|
|
.plaintext(true)
|
|
.build();
|
|
|
|
try (MxGatewayClient client = MxGatewayClient.connect(options);
|
|
MxGatewaySession session = client.openSession("java-client")) {
|
|
int serverHandle = session.register("java-client");
|
|
int itemHandle = session.addItem(serverHandle, "TestObject.TestInt");
|
|
session.advise(serverHandle, itemHandle);
|
|
session.write(serverHandle, itemHandle, MxValues.int32Value(123), 0);
|
|
}
|
|
```
|
|
|
|
Use `rawBlockingStub`, `rawFutureStub`, `rawAsyncStub`, `openSessionRaw`,
|
|
`closeSessionRaw`, `invoke`, and raw session helper methods when tests need the
|
|
underlying protobuf messages. `MxGatewayCommandException` and
|
|
`MxAccessException` preserve the raw `MxCommandReply` when the gateway returns a
|
|
data-bearing MXAccess failure.
|
|
|
|
`MxEventStream` implements `Iterator<MxEvent>` and `AutoCloseable`. Closing it
|
|
cancels the underlying gRPC stream. Canceling or timing out a Java client call
|
|
only stops the client from waiting; it does not abort an in-flight MXAccess COM
|
|
call on the worker STA.
|
|
|
|
## Galaxy Repository Browse
|
|
|
|
The Galaxy Repository service is a separate metadata-only gRPC service exposed
|
|
by the gateway. It lets clients enumerate the deployed Galaxy object hierarchy
|
|
and the dynamic attributes on each object so they know which tag references to
|
|
subscribe to via the MXAccess Gateway service. It uses the same API-key auth as
|
|
the gateway and requires the `metadata:read` scope.
|
|
|
|
`GalaxyRepositoryClient` mirrors the `MxGatewayClient` pattern (caller-managed
|
|
or owned channel, `MxGatewayClientOptions`, blocking + async variants). Three
|
|
RPCs are exposed:
|
|
|
|
```java
|
|
MxGatewayClientOptions options = MxGatewayClientOptions.builder()
|
|
.endpoint("localhost:5000")
|
|
.apiKey(System.getenv("MXGATEWAY_API_KEY"))
|
|
.plaintext(true)
|
|
.build();
|
|
|
|
try (GalaxyRepositoryClient galaxy = GalaxyRepositoryClient.connect(options)) {
|
|
boolean ok = galaxy.testConnection();
|
|
Optional<Instant> lastDeploy = galaxy.getLastDeployTime();
|
|
List<GalaxyObject> hierarchy = galaxy.discoverHierarchy();
|
|
}
|
|
```
|
|
|
|
`getLastDeployTime` returns `Optional.empty()` when the server reports
|
|
`present=false`. `discoverHierarchy` returns the generated `GalaxyObject` proto
|
|
messages directly so callers can read all fields (including the nested
|
|
`GalaxyAttribute` list) without an extra DTO layer.
|
|
|
|
The CLI exposes matching subcommands: `galaxy-test`, `galaxy-deploy-time`,
|
|
`galaxy-discover`, and `galaxy-watch`. They take the same `--endpoint`,
|
|
`--api-key-env`, `--plaintext`, `--ca-file`, `--server-name-override`,
|
|
`--timeout`, and `--json` options as the gateway commands.
|
|
|
|
```powershell
|
|
gradle :mxgateway-cli:run --args="galaxy-test --endpoint localhost:5000 --api-key-env MXGATEWAY_API_KEY --plaintext --json"
|
|
gradle :mxgateway-cli:run --args="galaxy-deploy-time --endpoint localhost:5000 --api-key-env MXGATEWAY_API_KEY --plaintext --json"
|
|
gradle :mxgateway-cli:run --args="galaxy-discover --endpoint localhost:5000 --api-key-env MXGATEWAY_API_KEY --plaintext --json"
|
|
```
|
|
|
|
### Watching deploy events
|
|
|
|
`GalaxyRepository.WatchDeployEvents` is a server-streaming RPC: the gateway
|
|
sends a bootstrap `DeployEvent` immediately on subscribe and then one event
|
|
each time it observes a new `galaxy.time_of_last_deploy`. The `sequence` field
|
|
is monotonic per server start; gaps mean the per-subscriber buffer dropped
|
|
older events because the consumer was too slow.
|
|
|
|
The client exposes both an iterator-style adaptor over the async stub and an
|
|
observer-callback variant. Both honour the channel-level `streamTimeout`.
|
|
|
|
```java
|
|
try (GalaxyRepositoryClient galaxy = GalaxyRepositoryClient.connect(options);
|
|
DeployEventStream events = galaxy.watchDeployEvents(/* lastSeenDeployTime */ null)) {
|
|
while (events.hasNext()) {
|
|
DeployEvent event = events.next();
|
|
// event.getSequence(), event.getObservedAt(),
|
|
// event.getTimeOfLastDeploy() / getTimeOfLastDeployPresent(),
|
|
// event.getObjectCount(), event.getAttributeCount()
|
|
}
|
|
}
|
|
```
|
|
|
|
Pass an `Instant` for `lastSeenDeployTime` to suppress the bootstrap event when
|
|
the cached deploy time matches what the caller already has. `DeployEventStream`
|
|
implements `Iterator<DeployEvent>` and `AutoCloseable`; closing it cancels the
|
|
underlying gRPC call.
|
|
|
|
For callback delivery (e.g. when the consumer wants to drive a queue or
|
|
reactive pipeline), use the async variant:
|
|
|
|
```java
|
|
DeployEventSubscription subscription = galaxy.watchDeployEventsAsync(
|
|
lastSeen,
|
|
new StreamObserver<>() {
|
|
@Override public void onNext(DeployEvent value) { /* ... */ }
|
|
@Override public void onError(Throwable t) { /* ... */ }
|
|
@Override public void onCompleted() { /* ... */ }
|
|
});
|
|
// later:
|
|
subscription.cancel(); // or subscription.close()
|
|
```
|
|
|
|
The matching CLI subcommand streams events until cancelled (Ctrl+C) and prints
|
|
one line per event in text mode or one JSON object per event with `--json`:
|
|
|
|
```powershell
|
|
gradle :mxgateway-cli:run --args="galaxy-watch --endpoint localhost:5000 --api-key-env MXGATEWAY_API_KEY --plaintext --json"
|
|
gradle :mxgateway-cli:run --args="galaxy-watch --endpoint localhost:5000 --api-key-env MXGATEWAY_API_KEY --plaintext --last-seen-deploy-time 2026-04-28T18:30:00Z --limit 5"
|
|
```
|
|
|
|
## CLI Usage
|
|
|
|
Run the CLI through Gradle:
|
|
|
|
```powershell
|
|
gradle :mxgateway-cli:run --args="version --json"
|
|
gradle :mxgateway-cli:run --args="open-session --endpoint localhost:5000 --api-key-env MXGATEWAY_API_KEY --plaintext --client-session-name java-cli --json"
|
|
gradle :mxgateway-cli:run --args="register --endpoint localhost:5000 --api-key-env MXGATEWAY_API_KEY --plaintext --session-id <id> --client-name java-cli --json"
|
|
gradle :mxgateway-cli:run --args="add-item --endpoint localhost:5000 --api-key-env MXGATEWAY_API_KEY --plaintext --session-id <id> --server-handle 1 --item TestObject.TestInt --json"
|
|
gradle :mxgateway-cli:run --args="advise --endpoint localhost:5000 --api-key-env MXGATEWAY_API_KEY --plaintext --session-id <id> --server-handle 1 --item-handle 1 --json"
|
|
gradle :mxgateway-cli:run --args="write --endpoint localhost:5000 --api-key-env MXGATEWAY_API_KEY --plaintext --session-id <id> --server-handle 1 --item-handle 1 --type int32 --value 123 --json"
|
|
gradle :mxgateway-cli:run --args="stream-events --endpoint localhost:5000 --api-key-env MXGATEWAY_API_KEY --plaintext --session-id <id> --limit 1 --json"
|
|
gradle :mxgateway-cli:run --args="smoke --endpoint localhost:5000 --api-key-env MXGATEWAY_API_KEY --plaintext --item TestObject.TestInt --json"
|
|
```
|
|
|
|
The CLI accepts `--api-key`, `--api-key-env`, `--plaintext`, `--ca-file`,
|
|
`--server-name-override`, `--timeout`, and `--json` on gateway commands. JSON
|
|
output redacts API keys.
|
|
|
|
Use TLS options for a secured gateway:
|
|
|
|
```powershell
|
|
gradle :mxgateway-cli:run --args="smoke --endpoint mxgateway.example.local:5001 --ca-file C:\certs\mxgateway-ca.pem --server-name-override mxgateway.example.local --api-key-env MXGATEWAY_API_KEY --item TestObject.TestInt --json"
|
|
```
|
|
|
|
## Build And Test
|
|
|
|
Run the Java checks from `clients/java`:
|
|
|
|
```powershell
|
|
gradle test
|
|
```
|
|
|
|
The build uses the Java 21 Gradle toolchain, compiles generated protobuf/gRPC
|
|
code, and runs JUnit 5 tests for the client wrapper, shared behavior fixtures,
|
|
in-process gRPC behavior, stream cancellation, and CLI parser/output behavior.
|
|
|
|
## Packaging
|
|
|
|
Create local library and CLI artifacts from `clients/java`:
|
|
|
|
```powershell
|
|
gradle :mxgateway-client:jar :mxgateway-cli:installDist
|
|
```
|
|
|
|
The library jar is under `zb-mom-ww-mxgateway-client/build/libs`. The installed CLI
|
|
distribution is under `zb-mom-ww-mxgateway-cli/build/install/mxgateway-cli`.
|
|
|
|
## Integration Checks
|
|
|
|
Run live checks only when a gateway and MXAccess-backed worker are available:
|
|
|
|
```powershell
|
|
$env:MXGATEWAY_INTEGRATION = '1'
|
|
$env:MXGATEWAY_ENDPOINT = 'localhost:5000'
|
|
$env:MXGATEWAY_API_KEY = '<gateway-api-key>'
|
|
$env:MXGATEWAY_TEST_ITEM = 'TestObject.TestInt'
|
|
gradle :mxgateway-cli:run --args="smoke --endpoint $env:MXGATEWAY_ENDPOINT --plaintext --api-key-env MXGATEWAY_API_KEY --item $env:MXGATEWAY_TEST_ITEM --json"
|
|
```
|
|
|
|
## Related Documentation
|
|
|
|
- [Client Packaging](../../docs/ClientPackaging.md)
|
|
- [Client Proto Generation](../../docs/ClientProtoGeneration.md)
|
|
- [Java Client Detailed Design](./JavaClientDesign.md)
|
|
- [Java Style Guide](../../docs/style-guides/JavaStyleGuide.md)
|