com.redblackit.web.server.HostNetUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.redblackit.web.server.HostNetUtils.java

Source

/*
 * Copyright 2002-2011 the original author or authors, or Red-Black IT Ltd, as appropriate.
 *
 * 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 com.redblackit.web.server;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Random;

import org.apache.log4j.Logger;
import org.springframework.util.Assert;

/**
 * Utility class that finds free BSD ports for use in testing scenario's.
 * 
 * Based on the Spring test class of the same name, but allowing supplied ports
 * to be checked 9and so used) first
 */
public abstract class HostNetUtils {

    public static final int MIN_SAFE_PORT = 1024;

    public static final int MAX_PORT = 65535;

    private static final Random random = new Random();

    private static final Logger logger = Logger.getLogger("web.server");

    /**
     * Returns the number of a free port in the default range.
     */
    public static int getFreePort() {
        return getFreePort(0, 0, 0);
    }

    /**
     * Returns the number of a free port in the default range, starting from
     * supplied value
     * 
     * @param startPort
     *            port value to try first
     */
    public static int getFreePort(int startPort) {
        return getFreePort(0, 0, startPort);
    }

    /**
     * Returns the number of a free port in the given range, starting from
     * supplied value. Note that the supplied value need not be between the min
     * and max values, but will be ignored if <= 0.
     * 
     * @param minPort
     *            minimum port value (default MIN_SAFE_PORT)
     * @param maxPort
     *            maximum port value (default MAX_PORT)
     * @param startPort
     *            port value to try first
     */
    public static int getFreePort(int minPort, int maxPort, int startPort) {

        if (minPort <= 0) {
            logger.info("defaulting minPort:" + minPort + "->" + MIN_SAFE_PORT);
            minPort = MIN_SAFE_PORT;
        }

        if (maxPort <= 0 || maxPort > MAX_PORT) {
            logger.info("defaulting maxPort:" + maxPort + "->" + MAX_PORT);
            maxPort = MAX_PORT;
        }

        Assert.state(minPort < maxPort, "after defaulting, minPort=" + minPort + " >= maxPort=" + maxPort);

        if (startPort > 0 && isPortAvailable(startPort)) {
            logger.info("Using startPort=" + startPort);
            return startPort;
        }

        int candidatePort;
        int portRange = maxPort - minPort;
        int searchCounter = 0;
        do {
            if (++searchCounter > portRange) {
                throw new IllegalStateException(
                        String.format("There were no ports available in the range %d to %d", minPort, maxPort));
            }
            candidatePort = getRandomPort(minPort, portRange);
            logger.info("Trying candidatePort=" + candidatePort);
        } while (!isPortAvailable(candidatePort));

        logger.info("Using candidatePort=" + candidatePort);
        return candidatePort;
    }

    /**
     * Get local hostname
     * 
     * @return hostname
     */
    public static String getLocalHostname() {
        String localhost;
        try {
            localhost = InetAddress.getLocalHost().getHostName();
            logger.debug("localhost=" + localhost);
        } catch (UnknownHostException ex) {
            localhost = "localhost";
            logger.warn("couldn't get localhost name, defaulting to localhost");
        }

        logger.debug("resulting localhost=" + localhost);
        return localhost;
    }

    /**
     * Main providing facility to run from command line
     * 
     * @param args
     */
    public void main(String[] args) {
        final String msgpfx = HostNetUtils.getLocalHostname() + "-" + HostNetUtils.class.getName();
        logger.info(msgpfx + " " + Arrays.toString(args));
        try {
            final int startPort = (args.length > 0 ? Integer.valueOf(args[0]) : -1);
            final int minPort = (args.length > 1 ? Integer.valueOf(args[1]) : MIN_SAFE_PORT);
            final int maxPort = (args.length > 2 ? Integer.valueOf(args[2]) : MAX_PORT);

            final int freePort = getFreePort(minPort, maxPort, startPort);
            logger.info(msgpfx + ":freePort=" + freePort);

        } catch (Throwable t) {
            logger.fatal(msgpfx + " usage:java " + msgpfx + " [startPort [minPort [maxPort]]]", t);
        }
    }

    /**
     * Get a rendom port value
     * 
     * @param minPort
     * @param portRange
     * @return
     */
    private static int getRandomPort(int minPort, int portRange) {
        return minPort + random.nextInt(portRange);
    }

    /**
     * Check if port is available
     * 
     * @param port
     * @return
     */
    private static boolean isPortAvailable(int port) {
        ServerSocket serverSocket;
        try {
            serverSocket = new ServerSocket();
        } catch (IOException ex) {
            throw new IllegalStateException("Unable to create ServerSocket.", ex);
        }

        try {
            InetSocketAddress sa = new InetSocketAddress(port);
            serverSocket.bind(sa);
            return true;
        } catch (IOException ex) {
            return false;
        } finally {
            try {
                serverSocket.close();
            } catch (IOException ex) {
                // ignore
            }
        }
    }

}