If Apache Iggy is useful to you, give it a star on GitHubStar apache/iggy
Apache Iggy
SDKJava

The Java SDK, with blocking and CompletableFuture clients over TCP, and which servers they pair with.

The Iggy Java SDK is a client library for interacting with the Iggy server from Java applications. It provides a blocking client and an async client (based on CompletableFuture) over TCP, plus a blocking HTTP client. The artifact is published to Maven Central and the source code lives in foreign/java.

Server compatibility

This documentation targets server 0.9.0 and SDK 0.9.0. The TCP transport speaks the VSR (Viewstamped Replication) wire protocol. The Java artifact 0.8.0 uses the older protocol. When working from source, build the SDK and the server from the same repository checkout.

Installation

Use Java 17 or newer. The SDK is published to Maven Central.

Maven

Add the dependency under the project element in pom.xml:

<dependencies>
    <dependency>
        <groupId>org.apache.iggy</groupId>
        <artifactId>iggy</artifactId>
        <version>0.9.0</version>
    </dependency>
</dependencies>

Gradle

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.apache.iggy:iggy:0.9.0'
}

Check Maven Central for the latest published version. Snapshot builds are available from the ASF snapshot repository.

Quick start

The snippets below follow the getting-started example. Stream, topic, and partition IDs are 0-based: the first partition of a topic is partition 0.

Start a development server using the example setup, with iggy/iggy credentials, then run the producer before the consumer. Bootstrap credentials do not replace recovered credentials.

Producer

import org.apache.iggy.client.blocking.tcp.IggyTcpClient;
import org.apache.iggy.identifier.StreamId;
import org.apache.iggy.identifier.TopicId;
import org.apache.iggy.message.Message;
import org.apache.iggy.message.Partitioning;
import org.apache.iggy.topic.CompressionAlgorithm;
import java.math.BigInteger;
import java.util.List;

public class Producer {

    static final String STREAM_NAME = "sample-stream";
    static final StreamId STREAM_ID = StreamId.of(STREAM_NAME);
    static final String TOPIC_NAME = "sample-topic";
    static final TopicId TOPIC_ID = TopicId.of(TOPIC_NAME);

    public static void main(String[] args) {
        try (var client = IggyTcpClient.builder()
                .host("127.0.0.1")
                .port(8090)
                .credentials("iggy", "iggy")
                .buildAndLogin()) {

            // Re-running this example is fine: only create what is missing.
            if (client.streams().getStream(STREAM_ID).isEmpty()) {
                client.streams().createStream(STREAM_NAME);
            }
            if (client.topics().getTopic(STREAM_ID, TOPIC_ID).isEmpty()) {
                client.topics().createTopic(
                        STREAM_ID,
                        1L,
                        CompressionAlgorithm.None,
                        BigInteger.ZERO,
                        BigInteger.ZERO,
                        TOPIC_NAME);
            }

            Partitioning partitioning = Partitioning.partitionId(0L);
            for (int i = 0; i < 10; i++) {
                String payload = "message-" + i;
                client.messages().sendMessages(
                        STREAM_ID,
                        TOPIC_ID,
                        partitioning,
                        List.of(Message.of(payload)));
                System.out.println("Sent: " + payload);
            }
        }
    }
}

createTopic also has an overload with a trailing Map<String, HeaderValue> of named topic options, for option keys the server catalog gained after the SDK build shipped.

Consumer

import org.apache.iggy.client.blocking.tcp.IggyTcpClient;
import org.apache.iggy.consumergroup.Consumer;
import org.apache.iggy.identifier.StreamId;
import org.apache.iggy.identifier.TopicId;
import org.apache.iggy.message.Message;
import org.apache.iggy.message.PolledMessages;
import org.apache.iggy.message.PollingStrategy;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Optional;

public class SampleConsumer {

    static final StreamId STREAM_ID = StreamId.of("sample-stream");
    static final TopicId TOPIC_ID = TopicId.of("sample-topic");

    public static void main(String[] args) {
        try (var client = IggyTcpClient.builder()
                .host("127.0.0.1")
                .port(8090)
                .credentials("iggy", "iggy")
                .buildAndLogin()) {

            BigInteger offset = BigInteger.ZERO;
            Consumer consumer = Consumer.of(0L);

            while (true) {
                PolledMessages polledMessages = client.messages().pollMessages(
                        STREAM_ID,
                        TOPIC_ID,
                        Optional.of(0L),
                        consumer,
                        PollingStrategy.offset(offset),
                        10L,
                        false);

                if (polledMessages.messages().isEmpty()) {
                    break;
                }
                for (Message message : polledMessages.messages()) {
                    String payload = new String(message.payload(), StandardCharsets.UTF_8);
                    System.out.printf("Offset: %d, Payload: %s%n", message.header().offset(), payload);
                    offset = message.header().offset().add(BigInteger.ONE);
                }
            }
        }
    }
}

The consumer reads partition 0 independently and stops on an empty poll. Its cursor starts at offset 0 or the earliest retained message each time it runs; autoCommit is disabled, so this sample does not store its progress on the server.

Client types and configuration

org.apache.iggy.Iggy is the unified entrypoint for building clients. Iggy.tcpClientBuilder().blocking() returns the same builder as IggyTcpClient.builder() used above.

import org.apache.iggy.Iggy;

// Blocking TCP client
var client = Iggy.tcpClientBuilder()
    .blocking()
    .host("localhost")
    .port(8090)
    .credentials("iggy", "iggy")
    .buildAndLogin();

// Async TCP client (CompletableFuture-based)
var asyncClient = Iggy.tcpClientBuilder()
    .async()
    .host("localhost")
    .port(8090)
    .credentials("iggy", "iggy")
    .buildAndLogin()
    .join();

// Blocking HTTP client
var httpClient = Iggy.httpClientBuilder()
    .blocking()
    .url("http://localhost:3000")
    .credentials("iggy", "iggy")
    .buildAndLogin();

Close clients when finished: client.close(), asyncClient.close().join(), and httpClient.close(). The HTTP close method declares IOException.

The TCP builder also accepts TLS and resilience options. Start the TLS development server and run this fragment with examples/java as the working directory:

import java.time.Duration;
import org.apache.iggy.Iggy;
import org.apache.iggy.config.RetryPolicy;

var client = Iggy.tcpClientBuilder()
    .blocking()
    .host("localhost")
    .port(8090)
    .enableTls()
    .tlsCertificate("../../core/certs/iggy_ca_cert.pem")
    .connectionTimeout(Duration.ofSeconds(10))
    .requestTimeout(Duration.ofSeconds(30))
    .retryPolicy(RetryPolicy.exponentialBackoff())
    .credentials("iggy", "iggy")
    .buildAndLogin();

Beyond streams, topics, and messages, the client exposes consumer groups, partitions, users, and personal access tokens through client.consumerGroups(), client.partitions(), client.users(), and client.personalAccessTokens(). The SDK's custom exception types inherit from IggyException; failed futures can wrap them in CompletionException when joined.

Examples

Runnable examples covering the async client, message headers and envelopes, multi-tenant setups, and TLS live in examples/java. See the examples page for how to run them.

On this page