# 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](./style-guides/JavaStyleGuide.md) for handwritten code and the [Protobuf Style Guide](./style-guides/ProtobufStyleGuide.md) for generated contract inputs. ## Build Layout Recommended Gradle multi-project layout: ```text clients/java/ settings.gradle build.gradle mxgateway-client/ build.gradle src/main/java/com/dohertylan/mxgateway/client/ src/test/java/com/dohertylan/mxgateway/client/ 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. 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 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 void write(int serverHandle, int itemHandle, MxValue value, int userId); public Iterator streamEvents(); public void streamEventsAsync(StreamObserver 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 ``` 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: ```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 --json mxgw-java write --session-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: - `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.