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

net.openhft.chronicle.wire.channel.impl.ChronicleChannelUtils Maven / Gradle / Ivy

There is a newer version: 2.27ea1
Show newest version
package net.openhft.chronicle.wire.channel.impl;

import net.openhft.chronicle.bytes.MethodReader;
import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.io.Closeable;
import net.openhft.chronicle.core.io.IORuntimeException;
import net.openhft.chronicle.core.io.InvalidMarshallableException;
import net.openhft.chronicle.threads.Pauser;
import net.openhft.chronicle.threads.PauserMode;
import net.openhft.chronicle.wire.channel.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.net.URL;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;

/**
 * This is the ChronicleChannelUtils class.
 * The class provides utility methods related to operations and handling of the {@link ChronicleChannel}.
 * Designed as a purely static utility class, it should not be instantiated.
 */
@SuppressWarnings("deprecation")
public final class ChronicleChannelUtils {

    // Private constructor to prevent instantiation
    private ChronicleChannelUtils() {
    }

    /**
     * Creates and returns a new instance of the {@link ChronicleChannel} using the provided configurations.
     * If the initial connection receives a redirect header, the method will attempt to connect to the redirected address.
     * Once connected, the method decides on the type of channel (buffered or simple) based on the configuration.
     *
     * @param socketRegistry The socket registry to use for the new channel.
     * @param channelCfg     The configurations for the new channel.
     * @param headerOut      The header for outgoing messages.
     * @return A new instance of {@link ChronicleChannel}, either buffered or a simple connection based on configurations.
     * @throws InvalidMarshallableException if there's an error while marshalling.
     */
    public static ChronicleChannel newChannel(SocketRegistry socketRegistry,
                                              ChronicleChannelCfg channelCfg,
                                              ChannelHeader headerOut,
                                              @Nullable Consumer closeCallback) throws InvalidMarshallableException {
        // Creation of the initial TCP connection
        TCPChronicleChannel simpleConnection = new TCPChronicleChannel(channelCfg, headerOut, socketRegistry);

        if (closeCallback != null)
            simpleConnection.closeCallback(closeCallback);

        final ChannelHeader marshallable = simpleConnection.headerIn();
        Jvm.debug().on(ChronicleChannel.class, "Client got " + marshallable);

        // Handling of a redirection scenario
        if (marshallable instanceof RedirectHeader) {
            Closeable.closeQuietly(simpleConnection);
            RedirectHeader rh = (RedirectHeader) marshallable;
            for (String location : rh.locations()) {
                try {
                    URL url = ChronicleContext.urlFor(location);
                    channelCfg.addHostnamePort(url.getHost(), url.getPort());
                    return newChannel(socketRegistry, channelCfg, headerOut,null);

                } catch (IORuntimeException e) {
                    Jvm.debug().on(ChronicleChannel.class, e);
                }
            }
            throw new IORuntimeException("No urls available " + rh);
        }

        // Decision on the type of Chronicle channel to return
        return channelCfg.buffered()
                ? new BufferedChronicleChannel(simpleConnection, channelCfg.pauserMode().get())
                : simpleConnection;
    }

    @Deprecated(/* To be removed in x.27 */)
    public static ChronicleChannel newChannel(SocketRegistry socketRegistry, ChronicleChannelCfg channelCfg, ChannelHeader headerOut) throws InvalidMarshallableException {
        return newChannel(socketRegistry, channelCfg, headerOut, null);
    }

    /**
     * Converts an event handler associated with a {@link ChronicleChannel} into a runnable task.
     * The returned task can then be executed in a separate thread. During its run, the task efficiently waits
     * for events, handling them as they occur and pausing when no events are available.
     *
     * @param chronicleChannel The channel on which events occur.
     * @param eventHandler     The event handler that processes the events.
     * @return A {@link Runnable} representation of the event handler, tailored to handle and wait for events efficiently.
     */
    @NotNull
    public static Runnable eventHandlerAsRunnable(ChronicleChannel chronicleChannel, Object eventHandler) {
        // Creation of the method reader for the provided event handler
        @SuppressWarnings("resource") final MethodReader reader = chronicleChannel.methodReader(eventHandler);

        // Determination of the closed status of the handler
        final BooleanSupplier handlerClosed;
        if (eventHandler instanceof Closeable) {
            Closeable sh = (Closeable) eventHandler;
            handlerClosed = sh::isClosed;
        } else {
            handlerClosed = () -> false;
        }

        // The main event handling logic
        return () -> {
            try {
                PauserMode pauserMode = chronicleChannel.channelCfg().pauserMode();
                if (pauserMode == null)
                    pauserMode = PauserMode.balanced;
                Pauser pauser = pauserMode.get();
                while (true) {
                    if (chronicleChannel.isClosed()) {
                        Jvm.debug().on(eventHandler.getClass(), "Reader on " + chronicleChannel + " is closed");
                        break;
                    }
                    if (handlerClosed.getAsBoolean()) {
                        Jvm.debug().on(eventHandler.getClass(), "Handler " + eventHandler + " is closed");
                        break;
                    }

                    if (reader.readOne())
                        pauser.reset();
                    else
                        pauser.pause();
                }
            } catch (Throwable t) {
                if (!chronicleChannel.isClosed() && !handlerClosed.getAsBoolean())
                    Jvm.warn().on(eventHandler.getClass(), "Error stopped reading thread", t);
            } finally {
                Closeable.closeQuietly(reader);
                Closeable.closeQuietly(eventHandler);
            }
        };
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy