Package org.factor45.malabarista.balancing

Source Code of org.factor45.malabarista.balancing.DefaultLoadBalancer

package org.factor45.malabarista.balancing;

import org.factor45.malabarista.logging.Logger;
import org.factor45.malabarista.network.TcpTunnelInboundHandler;
import org.factor45.malabarista.util.HostAndPort;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.ClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
* @author <a href="http://bruno.factor45.org/">Bruno de Carvalho</a>
*/
public class DefaultLoadBalancer implements LoadBalancer {

    // constants ------------------------------------------------------------------------------------------------------

    private static final Logger LOG = Logger.getLogger(DefaultLoadBalancer.class);
    private static final int TIMEOUT_IN_MILLIS = 3000;

    // configuration --------------------------------------------------------------------------------------------------

    private final String id;
    private final HostAndPort balancerAddress;
    private final BalancingStrategy balancingStrategy;
    private final Executor bossPool;
    private final Executor workerPool;
    private int timeoutInMillis;

    // internal vars --------------------------------------------------------------------------------------------------

    private final boolean internalPools;
    private volatile boolean running;
    private Channel acceptor;
    private ChannelGroup allChannels;
    private ServerBootstrap bootstrap;

    // constructors ---------------------------------------------------------------------------------------------------

    public DefaultLoadBalancer(String id, HostAndPort balancerAddress, BalancingStrategy balancingStrategy) {
        if (id == null) {
            throw new IllegalArgumentException("ID cannot be null");
        }
        if (balancerAddress == null) {
            throw new IllegalArgumentException("Balancer local address cannot be null");
        }

        if (balancingStrategy == null) {
            throw new IllegalArgumentException("Balancing strategy cannot be null");
        }

        this.id = id;
        this.balancerAddress = balancerAddress;
        this.balancingStrategy = balancingStrategy;

        this.internalPools = true;
        this.bossPool = Executors.newCachedThreadPool();
        this.workerPool = Executors.newCachedThreadPool();

        this.timeoutInMillis = TIMEOUT_IN_MILLIS;
    }

    public DefaultLoadBalancer(String id, HostAndPort balancerAddress, BalancingStrategy balancingStrategy,
                               Executor bossPool, Executor workerPool) {
        if (id == null) {
            throw new IllegalArgumentException("ID cannot be null");
        }

        if (balancerAddress == null) {
            throw new IllegalArgumentException("Balancer local address cannot be null");
        }

        if (balancingStrategy == null) {
            throw new IllegalArgumentException("Balancing strategy cannot be null");
        }

        if (bossPool == null) {
            throw new IllegalArgumentException("BossPool cannot be null");
        }

        if (workerPool == null) {
            throw new IllegalArgumentException("WorkerPool cannot be null");
        }

        this.id = id;
        this.balancerAddress = balancerAddress;
        this.balancingStrategy = balancingStrategy;

        this.internalPools = true;
        this.bossPool = Executors.newCachedThreadPool();
        this.workerPool = Executors.newCachedThreadPool();

        this.timeoutInMillis = TIMEOUT_IN_MILLIS;
    }

    // LoadBalancer ---------------------------------------------------------------------------------------------------

    @Override
    public synchronized boolean init() {
        if (this.running) {
            return true;
        }

        LOG.info("Launching {} on {}...", this, this.balancerAddress);

        this.bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(this.bossPool, this.workerPool));
        final ClientSocketChannelFactory clientSocketChannelFactory =
                new NioClientSocketChannelFactory(this.bossPool, this.workerPool);
        this.bootstrap.setOption("child.tcpNoDelay", true);
        this.allChannels = new DefaultChannelGroup(this.id + "-all-channels-" + Integer.toHexString(this.hashCode()));

        this.bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            @Override
            public ChannelPipeline getPipeline() throws Exception {
                return Channels.pipeline(new TcpTunnelInboundHandler(id, allChannels, clientSocketChannelFactory,
                                                                     balancingStrategy, timeoutInMillis));
            }
        });

        // Start up the server.
        if (this.balancerAddress.isAnyHost()) {
            this.acceptor = this.bootstrap.bind(new InetSocketAddress(this.balancerAddress.getPort()));
        } else {
            this.acceptor = this.bootstrap.bind(new InetSocketAddress(this.balancerAddress.getHost(),
                                                                      this.balancerAddress.getPort()));
        }
        boolean bound = this.acceptor.isBound();

        if (!bound) {
            LOG.error("Failed to bound {} to {}.", this, this.balancerAddress);
        } else {
            LOG.info("Successfully bound {} to {}.", this, this.balancerAddress);
        }

        return (this.running = true);
    }

    @Override
    public synchronized void terminate() {
        if (!this.running) {
            return;
        }

        LOG.info("Shutting down {}...", this.id);
        this.running = false;

        this.allChannels.close().awaitUninterruptibly();
        this.acceptor.close().awaitUninterruptibly();
        // never close the thread pool, that's a responsability for whoever provided it
        if (this.internalPools) {
            this.bootstrap.releaseExternalResources();
        }
        LOG.info("{} stopped.", this.id);
    }

    @Override
    public HostAndPort getBalancerAddress() {
        return this.balancerAddress;
    }

    @Override
    public List<HostAndPort> getTargetAddresses() {
        return this.balancingStrategy.geTargetAddresses();
    }

    @Override
    public BalancingStrategy getBalancingStrategy() {
        return this.balancingStrategy;
    }

    // low level overrides --------------------------------------------------------------------------------------------

    @Override
    public String toString() {
        return this.getClass().getSimpleName() + '@' + Integer.toHexString(this.hashCode());
    }
}
TOP

Related Classes of org.factor45.malabarista.balancing.DefaultLoadBalancer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.