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

io.kroxylicious.proxy.internal.net.DefaultNetworkBindingOperationProcessor 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.proxy.internal.net;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

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

import io.netty.bootstrap.ServerBootstrap;

public class DefaultNetworkBindingOperationProcessor implements NetworkBindingOperationProcessor {

    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultNetworkBindingOperationProcessor.class);

    /** Queue of network binding operations */
    private final BlockingQueue> queue = new LinkedBlockingQueue<>();

    private final AtomicBoolean running = new AtomicBoolean();

    /** Executor that performs the binding operations */
    private final ExecutorService networkBindingExecutor = Executors.newFixedThreadPool(2, r -> {
        var t = new Thread(r);
        t.setDaemon(true);
        return t;
    });

    private static final NetworkBindingOperation POISON_PILL = new NetworkBindingOperation<>(false) {
        CompletableFuture swallowed = new CompletableFuture<>();

        @Override
        public int port() {
            throw new UnsupportedOperationException();
        }

        @Override
        public CompletableFuture getFuture() {
            return swallowed;
        }

        @Override
        public void performBindingOperation(ServerBootstrap serverBootstrap, ExecutorService executorService) {
            throw new UnsupportedOperationException();
        }
    };

    @Override
    public void enqueueNetworkBindingEvent(NetworkBindingOperation o) {
        queue.add(o);
    }

    @Override
    public void start(ServerBootstrap plainServerBootstrap, ServerBootstrap tlsServerBootstrap) {
        if (!running.compareAndSet(false, true)) {
            return;
        }

        var unused = networkBindingExecutor.submit(() -> {
            try {
                do {
                    var networkBindingOperation = queue.take();
                    if (networkBindingOperation == POISON_PILL) {
                        return;
                    }

                    var bootstrap = networkBindingOperation.tls() ? tlsServerBootstrap : plainServerBootstrap;
                    try {
                        networkBindingOperation.performBindingOperation(bootstrap, networkBindingExecutor);
                    }
                    catch (Exception e) {
                        // We don't expect performBindingOperation to throw an exception but if it does,
                        // we don't want to break the executor loop.
                        LOGGER.error("Unexpected error performing the binding operation", e);
                    }
                } while (!Thread.interrupted());
            }
            catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException(e);
            }
            finally {
                POISON_PILL.getFuture().complete(null);
                networkBindingExecutor.shutdown();
                LOGGER.debug("Network event processor shutdown");
            }
        });
    }

    @Override
    public void close() {
        if (!running.compareAndSet(true, false)) {
            networkBindingExecutor.shutdown();
            return;
        }

        enqueueNetworkBindingEvent(POISON_PILL);
        boolean shutdown = false;
        try {
            POISON_PILL.getFuture().get(1, TimeUnit.MINUTES);
        }
        catch (Exception e) {
            if (e instanceof InterruptedException) {
                Thread.currentThread().interrupt();
            }
            throw new RuntimeException(e);
        }
        finally {
            if (!shutdown) {
                networkBindingExecutor.shutdownNow();
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy