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

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

There is a newer version: 2.27ea1
Show newest version
/*
 * Copyright 2016-2022 chronicle.software
 *
 *       https://chronicle.software
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.openhft.chronicle.wire.channel.impl;

import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.io.AbstractCloseable;
import net.openhft.chronicle.core.util.WeakIdentityHashMap;

import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URL;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListMap;

// TODO This is a simplified net.openhft.chronicle.network.TCPRegistry to cover the use cases tested
/**
 * This is the SocketRegistry class.
 * It provides a simplified representation of the net.openhft.chronicle.network.TCPRegistry, designed specifically for the tested use cases.
 * The primary functions of this class are to manage and provide server and client socket channels based on the given inputs.
 * It also maintains a collection of all opened closeable resources, ensuring they are closed properly upon shutting down the registry.
 */
public class SocketRegistry extends AbstractCloseable {

    // Mapping from a description to the corresponding server socket channel
    private final Map descToServerSocketChannelMap = new ConcurrentSkipListMap<>();

    // A set of closeable resources, maintained to ensure proper cleanup
    private final Set closeableSet =
            Collections.synchronizedSet(
                    Collections.newSetFromMap(
                            new WeakIdentityHashMap<>()));

    // Not thread-safe but deemed acceptable for the current use case
    int lastHost = 0;

    /**
     * Acquires a server socket channel using the provided URL.
     *
     * @param url The URL containing the hostname and port details.
     * @return An opened {@link ServerSocketChannel}.
     * @throws IOException If there's an error while opening the server socket channel.
     */
    public ServerSocketChannel acquireServerSocketChannel(URL url) throws IOException {
        return acquireServerSocketChannel(url.getHost(), url.getPort());
    }

    /**
     * Acquires or reuses an existing server socket channel based on the provided hostname and port.
     *
     * @param hostname The hostname for the server socket channel.
     * @param port The port for the server socket channel.
     * @return An opened {@link ServerSocketChannel}.
     * @throws IOException If there's an error while opening the server socket channel.
     */
    private synchronized ServerSocketChannel acquireServerSocketChannel(String hostname, int port) throws IOException {
        // Generate the description
        String description = hostname == null || hostname.isEmpty()
                ? "port" + port
                : port > 0
                ? hostname + ':' + port
                : hostname;
        ServerSocketChannel ssc = descToServerSocketChannelMap.get(description);
        if (ssc != null && ssc.isOpen())
            return ssc;
        ssc = ServerSocketChannel.open();
        addCloseable(ssc);
        ssc.bind(new InetSocketAddress(port));
        descToServerSocketChannelMap.put(description, ssc);
        return ssc;
    }

    /**
     * Creates and opens a client socket channel based on the provided hostname and port.
     * If the hostname contains multiple comma-separated entries, it rotates between them.
     *
     * @param hostname The hostname for the client socket channel.
     * @param port The port for the client socket channel.
     * @return An opened {@link SocketChannel}.
     * @throws IOException If there's an error while opening the socket channel.
     */
    public synchronized SocketChannel createSocketChannel(String hostname, int port) throws IOException {
        // Handle multiple hostnames scenario
        if (hostname.contains(",")) {
            String[] hostnames = hostname.split(",");
            int lastHost = this.lastHost;
            if (lastHost >= hostnames.length)
                lastHost = 0;
            hostname = hostnames[lastHost];
            this.lastHost = lastHost + 1;
        }
        final SocketChannel open = SocketChannel.open(new InetSocketAddress(hostname, port));
        Jvm.startup().on(getClass(), "Connected to " + hostname + ":" + port);
        return open;
    }

    /**
     * Adds a closeable resource to the registry's collection for tracking and proper cleanup.
     *
     * @param closeable The closeable resource to be tracked.
     */
    private void addCloseable(Closeable closeable) {
        closeableSet.add(closeable);
    }

    @Override
    protected synchronized void performClose() throws IllegalStateException {
        net.openhft.chronicle.core.io.Closeable.closeQuietly(closeableSet);
        closeableSet.clear();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy