Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

I had a need to support multiple hardware random number generators (RNG) in a project. I started with an RngProvider abstract class. This class defines the functionality that will be the same and defines a method that will contain the functionality that is unique per RNG.

Queue size
We set the desired queue length to be 80k integers per hardware RNG which will allow us to cache enough integers to make over 3k decks of cards. 80k integers per integration doesn’t take up any space worth worrying about. 80k * 4 / 1024 = 312.5kb. That is practically free. Cache away. A queue fill operation is going to be triggered when the queue is 1/4 full.

LinkedBlockingQueue
I chose a linked blocking queue because I needed synchronized access to prevent the random integer from being selected more than once. The blocking operations are within the BlockingQueue interface. I used put() and take() to queue and dequeue with blocking until the queue is available.

Available
I created this property as a way to add or remove the device without having to stop/start the server, if the device supports that kind of functionality. The thinking was that the constructor would set it to available, the nextInt() would check to see if it was empty and set it to unavailable, if necessary, and the implementation of the getRandomIntegerData() method would set it to available as it adds integers.

getRandomIntegerData()
This method defines the method that would be filled in by the specific implementation needed by the various hardware devices.

nextInt()
This method is used to retrieve an integer from the specific integer queue and also start the thread that will manage adding integers to the queue, if necessary.

FillQueue
This thread is created when a number is requested to be removed from the queue. If the size of the queue has dropped below a specified number, then the getRandomIntegerData() method is called to replenish the integer data. The block of code that determines if the integer data is to be replenished is synchronized to prevent multiple thread executions from trying to replenish the queue at the same time.

package com.cdi.rng;

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

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * Interface to define random number generator providers.
 * @author norris.shelton
 */
public abstract class RngProvider {
    /** SLF4J logger object. */
    protected Logger logger = LoggerFactory.getLogger(getClass());
    /** The desired size of the integer queue. */
    public static final int DESIRED_QUEUE_LENGTH = 80000;
    /** The minimum integer queue size. */
    public static final int MIN_QUEUE_LENGTH = DESIRED_QUEUE_LENGTH / 4;
    /** Is this RNG provider available. */
    boolean available = false;
    /** Queue of integers for consumption. */
    protected BlockingQueue<Integer> integerQueue = new LinkedBlockingQueue<>(DESIRED_QUEUE_LENGTH);

    /**
     * Is this random number generator provider available.
     * @return true if available for use, else false
     */
    public boolean isAvailable() {
        return available;
    }

    /**
     * Sets that this random number generator is available.
     * @param available true if available, else false
     */
    public void setAvailable(boolean available) {
        this.available = available;
    }

    /**
     * Fills the integer queue with integers.
     * @throws Exception
     */
    public abstract void getRandomIntegerData() throws Exception;

    /**
     * Return the next random integer.
     * @return random signed integer
     */
    public int nextInt() throws InterruptedException {
        logger.debug("Using {} provider", getClass());
        FillQueue fillQueue = new FillQueue();
        fillQueue.run();

        // if taking the last one
        if (integerQueue.size() <= 1) {
            setAvailable(false);
            logger.warn("Pulling the last integer from {} queue", getClass());
        }

        return integerQueue.take();
    }

    /**
     * Thread used to fill the queue asynchronously.
     */
    public class FillQueue extends Thread {
        /**
         * When an object implementing interface <code>Runnable</code> is used to create a thread, starting the thread
         * causes the object's <code>run</code> method to be called in that separately executing thread.
         * <p/>
         * The general contract of the method <code>run</code> is that it may take any action whatsoever.
         * @see Thread#run()
         */
        @Override
        public void run() {
            synchronized (this) {
                if (integerQueue.size() < MIN_QUEUE_LENGTH) {
                    try {
                        getRandomIntegerData();
                    } catch (Exception e) {
                        logger.error("Unable to add integers to queue by thread", e);
                    }
                }
            }
        }
    }
}

December 17th, 2014

Posted In: Java

Tags: , , , , , , , , , ,

Leave a Comment

I was loading a java resource via the classloader. I had the need to know where the file was on the file system.

    /**
     * Gets the absolute path of a file loaded via a classloader.
     * @param classpathFile file to be loaded from the classpath.
     * @return absolute file path of the file
     * @throws URISyntaxException
     */
    public static String getAbsoluteFilePath(String classpathFile) throws URISyntaxException {
        String absoluteFilePath = "";
        URL url = CommonUtil.class.getResource(classpathFile);
        if (url != null) {
            Path path = Paths.get(url.toURI());
            if (path != null) {
                absoluteFilePath = path.toString();
            }
        }
        return absoluteFilePath;
    }

February 14th, 2014

Posted In: Java, java ninja, Javaninja

Tags: , , , , , , , , ,

Leave a Comment

WP to LinkedIn Auto Publish Powered By : XYZScripts.com