| <div align="center"> |
| <picture> |
| <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/apache/iggy/refs/heads/master/assets/logo/SVG/iggy-apache-color-darkbg.svg"> |
| <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/apache/iggy/refs/heads/master/assets/logo/SVG/iggy-apache-color-lightbg.svg"> |
| <img alt="Apache Iggy" src="https://raw.githubusercontent.com/apache/iggy/refs/heads/master/assets/logo/SVG/iggy-apache-color-lightbg.svg" width="320"> |
| </picture> |
| </div> |
| |
| # Java SDK for Apache Iggy |
| |
| Official Java client SDK for [Apache Iggy](https://iggy.apache.org) message streaming. |
| |
| _This is part of the Apache Iggy monorepo. For the main project, see the [root repository](https://github.com/apache/iggy)._ |
| |
| ## Installation |
| |
| These examples target server **0.9.0**. SDK `0.9.0` is on Maven Central and works with server `0.9.0`. The older `0.8.0` artifact speaks the previous TCP protocol and does not work with server `0.9.0`. Java 17 or newer is required. |
| |
| Add the dependency to your project: |
| |
| **Gradle:** |
| |
| ```gradle |
| implementation 'org.apache.iggy:iggy:0.9.0' |
| ``` |
| |
| **Maven:** |
| |
| ```xml |
| <dependency> |
| <groupId>org.apache.iggy</groupId> |
| <artifactId>iggy</artifactId> |
| <version>0.9.0</version> |
| </dependency> |
| ``` |
| |
| See [Maven Central](https://central.sonatype.com/artifact/org.apache.iggy/iggy) for all published versions. |
| |
| ### Snapshot Versions |
| |
| Development builds of the next release carry the version `0.9.1-SNAPSHOT`. Get them from the ASF snapshot repository: |
| |
| **Gradle:** |
| |
| ```gradle |
| repositories { |
| mavenCentral() |
| maven { |
| url = uri("https://repository.apache.org/content/repositories/snapshots/") |
| } |
| } |
| |
| dependencies { |
| implementation 'org.apache.iggy:iggy:0.9.1-SNAPSHOT' |
| } |
| ``` |
| |
| **Maven:** |
| |
| ```xml |
| <repositories> |
| <repository> |
| <id>apache-snapshots</id> |
| <url>https://repository.apache.org/content/repositories/snapshots/</url> |
| <snapshots> |
| <enabled>true</enabled> |
| </snapshots> |
| </repository> |
| </repositories> |
| |
| <dependencies> |
| <dependency> |
| <groupId>org.apache.iggy</groupId> |
| <artifactId>iggy</artifactId> |
| <version>0.9.1-SNAPSHOT</version> |
| </dependency> |
| </dependencies> |
| ``` |
| |
| ## Quick Start |
| |
| `Iggy.tcpClientBuilder()` handles the routing and the session for you. Over TCP and TCP/TLS, the client keeps the consumer group membership on the coordinator. It polls each partition through a separate connection to the primary of that partition. |
| |
| Start the server with the [example prerequisites](../../examples/java/#running-examples) and matching credentials. The following snippets show alternative clients. Close a blocking client with `close()` or an async client with `close().join()` when finished. |
| |
| ### TCP Client (Blocking) |
| |
| ```java |
| import org.apache.iggy.Iggy; |
| |
| // Create and connect with auto-login |
| var client = Iggy.tcpClientBuilder() |
| .blocking() |
| .host("localhost") |
| .port(8090) |
| .credentials("iggy", "iggy") |
| .buildAndLogin(); |
| |
| // Or build, connect, and login separately |
| var client = Iggy.tcpClientBuilder() |
| .blocking() |
| .host("localhost") |
| .port(8090) |
| .build(); |
| client.connect(); |
| client.users().login("iggy", "iggy"); |
| ``` |
| |
| ### TCP Client (Async) |
| |
| ```java |
| import org.apache.iggy.Iggy; |
| |
| // Create async client |
| var asyncClient = Iggy.tcpClientBuilder() |
| .async() |
| .host("localhost") |
| .port(8090) |
| .credentials("iggy", "iggy") |
| .buildAndLogin() |
| .join(); |
| |
| // Or with manual connect and login |
| var asyncClient = Iggy.tcpClientBuilder() |
| .async() |
| .host("localhost") |
| .build(); |
| asyncClient.connect().join(); |
| asyncClient.users().login("iggy", "iggy").join(); |
| ``` |
| |
| ### HTTP Client |
| |
| ```java |
| import org.apache.iggy.Iggy; |
| |
| // Using URL |
| var httpClient = Iggy.httpClientBuilder() |
| .blocking() |
| .url("http://localhost:3000") |
| .credentials("iggy", "iggy") |
| .buildAndLogin(); |
| |
| // Using host/port |
| var httpClient = Iggy.httpClientBuilder() |
| .blocking() |
| .host("localhost") |
| .port(3000) |
| .credentials("iggy", "iggy") |
| .buildAndLogin(); |
| ``` |
| |
| ### TLS Support |
| |
| Both TCP and HTTP clients support TLS: |
| |
| ```java |
| // TCP with TLS |
| var secureClient = Iggy.tcpClientBuilder() |
| .blocking() |
| .host("iggy-server.example.com") |
| .port(8090) |
| .enableTls() |
| .tlsCertificate("/path/to/ca.pem") // Optional custom CA |
| .credentials("admin", "secret") |
| .buildAndLogin(); |
| |
| // HTTPS |
| var secureHttpClient = Iggy.httpClientBuilder() |
| .blocking() |
| .host("iggy-server.example.com") |
| .port(443) |
| .enableTls() |
| .credentials("admin", "secret") |
| .buildAndLogin(); |
| ``` |
| |
| ### Builder Options |
| |
| The client builders support additional configuration: |
| |
| ```java |
| var client = Iggy.tcpClientBuilder() |
| .blocking() |
| .host("localhost") |
| .port(8090) |
| .connectionTimeout(Duration.ofSeconds(10)) |
| .requestTimeout(Duration.ofSeconds(30)) |
| .retryPolicy(RetryPolicy.exponentialBackoff()) |
| .credentials("iggy", "iggy") |
| .buildAndLogin(); |
| ``` |
| |
| ### Event Loop Threads |
| |
| Each TCP client drives a single connection, so by default it creates an event loop group |
| with one thread. An application that opens many clients can instead register them all on |
| one caller-owned group. The clients never shut that group down. Close the clients first, |
| then shut the group down: |
| |
| ```java |
| var group = new MultiThreadIoEventLoopGroup(2, NioIoHandler.newFactory()); |
| |
| var producer = Iggy.tcpClientBuilder() |
| .blocking() |
| .eventLoopGroup(group) |
| .credentials("iggy", "iggy") |
| .buildAndLogin(); |
| var consumer = Iggy.tcpClientBuilder() |
| .blocking() |
| .eventLoopGroup(group) |
| .credentials("iggy", "iggy") |
| .buildAndLogin(); |
| |
| // ... later |
| producer.close(); |
| consumer.close(); |
| group.shutdownGracefully(); |
| ``` |
| |
| Do not block in a completion callback. Callbacks run on the group's loops, so a blocked |
| callback stalls every client that shares the group. |
| |
| ### Version Information |
| |
| ```java |
| // Get SDK version |
| String version = Iggy.version(); // e.g., "0.9.0" |
| |
| // Get detailed version info |
| IggyVersion info = Iggy.versionInfo(); |
| info.getVersion(); // Version string |
| info.getBuildTime(); // Build timestamp |
| info.getGitCommit(); // Git commit hash |
| info.getUserAgent(); // User-Agent string for HTTP |
| ``` |
| |
| ## Exception Handling |
| |
| The SDK's custom exception types inherit from `IggyException`. When you join a failed future, the cause can come back inside a `CompletionException`. The HTTP client's `close()` method declares `IOException`. Handle these two boundaries as well as the specific SDK errors. |
| |
| ## Examples |
| |
| See the **[Java Examples](../../examples/java/)** directory for runnable applications demonstrating the SDK: |
| |
| - **GettingStartedProducer**: synchronous message production with batch sending |
| - **GettingStartedConsumer**: synchronous consumption with polling loops |
| - **AsyncProducer**: non-blocking batch production with concurrent request submission |
| - **AsyncConsumer**: async consumption with backpressure and error recovery |
| |
| The examples README describes blocking and async clients, CompletableFuture patterns, and thread pool management. |
| |
| For Apache Flink integration, see the [Flink Connector Library](external-processors/iggy-connector-flink/iggy-connector-library/README.md). |
| |
| ## Building from Source |
| |
| This project uses the Gradle Wrapper. Due to Apache Software Foundation policy, the `gradle-wrapper.jar` binary is not checked into the repository. Instead, the `gradlew` script automatically downloads it on first run. |
| |
| ```bash |
| # Build the project |
| ./gradlew build |
| |
| # Run tests |
| ./gradlew test |
| ``` |
| |
| The wrapper script will: |
| |
| 1. Download `gradle-wrapper.jar` from the official Gradle repository if missing |
| 2. Verify the SHA256 checksum for security |
| 3. Execute the requested Gradle command |
| |
| No manual Gradle installation is required. |
| |
| **Note:** Only the Unix shell wrapper (`gradlew`) is provided. On Windows, use WSL or Git Bash, or install Gradle manually. |
| |
| ## Contributing |
| |
| Before opening a pull request: |
| |
| 1. **Format code:** `./gradlew spotlessApply` |
| 2. **Validate build:** `./gradlew check` |
| 3. **Use AssertJ for assertions:** Write test assertions with [AssertJ](https://assertj.github.io/doc/) (`assertThat(...)`) instead of JUnit assertions. |
| |
| These steps keep the code style compliant and make sure that all tests and checkstyle validations pass. |