# 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](../../docs/style-guides/JavaStyleGuide.md) for handwritten
code and the [Protobuf Style Guide](../../docs/style-guides/ProtobufStyleGuide.md) for
generated contract inputs.

## Build Layout

Recommended Gradle multi-project layout:

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

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

Target Java:

- Java 17 required (retargeted from 21 for Ignition 8.3 compatibility).
- The Gradle scaffold uses the Java 17 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:

```java
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

```java
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:

```text
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.

### Trust posture

The gateway can serve a self-signed certificate it generates itself (it has no
PKI). To make that usable, TLS is **lenient by default**: when the channel is not
plaintext and no `caCertificatePath` is set, the client builds
`GrpcSslContexts.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)`
(grpc-netty-shaded), so the gateway's self-signed certificate is accepted without
verification.

To verify the gateway instead:

- set `caCertificatePath` to pin a CA (full verification against that root), or
- set `requireCertificateValidation` to `true` to verify against the JVM trust
  store without pinning.

Pinning a CA always wins over the lenient default.

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

```java
MxGatewayException
MxGatewayAuthenticationException
MxGatewayAuthorizationException
MxGatewaySessionException
MxGatewayWorkerException
MxGatewayCommandException
MxAccessException
```

`MxGatewayCommandException` should carry the raw command reply when available.

## Test CLI

Binary wrapper name:

```text
mxgw-java
```

Use `picocli`.

Commands:

```text
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:

```text
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:

- `zb-mom-ww-mxgateway-client` jar,
- `zb-mom-ww-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`:

```powershell
gradle test
```

The `zb-mom-ww-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 `zb-mom-ww-mxgateway-cli` project
builds a Picocli-based `mxgw-java` entry point for later command implementation.

## Related Documentation

- [Client Libraries Detailed Design](../../docs/ClientLibrariesDesign.md)
- [Client Proto Generation](../../docs/ClientProtoGeneration.md)
- [Client Packaging](../../docs/ClientPackaging.md)
- [Java Style Guide](../../docs/style-guides/JavaStyleGuide.md)
