All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.kroxylicious.test.client.KafkaClientHandler Maven / Gradle / Ivy

/*
 * Copyright Kroxylicious Authors.
 *
 * Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
 */
package io.kroxylicious.test.client;

import java.util.Deque;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedDeque;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import io.kroxylicious.test.codec.DecodedRequestFrame;

/**
 * Simple kafka handle capable of sending one or more requests to a server side.
 */
public class KafkaClientHandler extends ChannelInboundHandlerAdapter {
    private static final Logger LOGGER = LoggerFactory.getLogger(KafkaClientHandler.class);

    private final Deque> queue = new ConcurrentLinkedDeque<>();
    private ChannelHandlerContext ctx;

    // Read/Mutated by the Netty thread only.
    private boolean channelActivationSeen;

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) {
        this.ctx = ctx;
        ctx.fireChannelRegistered();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        this.channelActivationSeen = true;
        processPendingWrites();
        ctx.fireChannelActive();
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        LOGGER.warn("Kafka test client received unexpected exception, closing connection.", cause);
        ctx.close();
    }

    /**
     * Sends a request frame.  If the channel is not yet active, the request is queued up until it
     * is.
     * 
* The response to the request is returned by the future. If the request has no response the * future will complete once the request is sent and yield a null value. * * @param decodedRequestFrame request frame to send * @return future that will yield the response along with a sequenceNumber indicating the order it was received by the client. */ public CompletableFuture sendRequest(DecodedRequestFrame decodedRequestFrame) { queue.addLast(decodedRequestFrame); processPendingWrites(); return decodedRequestFrame.getResponseFuture(); } private void processPendingWrites() { ctx.executor().execute(() -> { if (!channelActivationSeen) { return; } while (queue.peek() != null) { var msg = queue.removeFirst(); ctx.writeAndFlush(msg).addListener(c -> { var responseFuture = msg.getResponseFuture(); if (c.cause() != null) { // I/O failed etc responseFuture.completeExceptionally(c.cause()); } else if (!msg.hasResponse()) { responseFuture.complete(null); } }); } }); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy