ConnectionCompletionHandler.java
/*
* SPDX-FileCopyrightText: 2023-2025 Lucimber UG
* SPDX-License-Identifier: Apache-2.0
*/
package com.lucimber.dbus.netty;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.concurrent.Promise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Helper handler to complete the connection promise after full setup. */
class ConnectionCompletionHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionCompletionHandler.class);
private Promise<Void> connectPromise;
public ConnectionCompletionHandler(Promise<Void> connectPromise) {
this.connectPromise = connectPromise;
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt == DBusChannelEvent.MANDATORY_NAME_ACQUIRED) {
if (connectPromise.trySuccess(null)) {
LOGGER.debug(
"Connection process complete (mandatory name acquired). "
+ "Fulfilled connect promise.");
}
// Remove this handler from the pipeline as connection is complete
ctx.pipeline().remove(this);
LOGGER.debug(
"Removed ConnectionCompletionHandler from pipeline as connection is complete.");
} else if (evt == DBusChannelEvent.SASL_AUTH_FAILED
|| evt == DBusChannelEvent.MANDATORY_NAME_ACQUISITION_FAILED) {
String failureReason = "DBus connection setup failed: " + evt;
if (connectPromise.tryFailure(new RuntimeException(failureReason))) {
LOGGER.warn(
"Connection process failed at SASL or Mandatory Name stage. "
+ "Failed connect promise.");
}
// Remove this handler from the pipeline after failure
ctx.pipeline().remove(this);
LOGGER.debug("Removed ConnectionCompletionHandler from pipeline after failure.");
} else {
super.userEventTriggered(ctx, evt);
}
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
if (connectPromise.tryFailure(new java.nio.channels.ClosedChannelException())) {
LOGGER.warn(
"Channel became inactive before connection process completed. "
+ "Failing connect promise.");
}
super.channelInactive(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (connectPromise.tryFailure(cause)) {
LOGGER.error("Exception during connection setup. Failing connect promise.", cause);
}
// Don't remove self here, let the pipeline manage error propagation
// The channel will likely be closed by a tail handler or by Sasl/MandatoryName handlers.
super.exceptionCaught(ctx, cause);
}
/**
* Resets the connection completion handler to its initial state for reconnection. This method
* is called when the connection needs to be re-established.
*
* @param newConnectPromise the new promise to use for the reconnection attempt
*/
public void reset(Promise<Void> newConnectPromise) {
LOGGER.debug("Resetting ConnectionCompletionHandler for reconnection");
this.connectPromise = newConnectPromise;
}
}