com.ciphertool.zodiacengine.CipherSolutionEngine.java Source code

Java tutorial

Introduction

Here is the source code for com.ciphertool.zodiacengine.CipherSolutionEngine.java

Source

/**
 * Copyright 2012 George Belden
 * 
 * This file is part of ZodiacEngine.
 * 
 * ZodiacEngine is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * ZodiacEngine is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * ZodiacEngine. If not, see <http://www.gnu.org/licenses/>.
 */

package com.ciphertool.zodiacengine;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ciphertool.zodiacengine.dao.CipherDao;
import com.ciphertool.zodiacengine.dto.CipherDto;
import com.ciphertool.zodiacengine.entities.Cipher;
import com.ciphertool.zodiacengine.genetic.adapters.SolutionChromosome;
import com.ciphertool.zodiacengine.util.SolutionEvaluator;
import com.ciphertool.zodiacengine.util.SolutionGenerator;

public class CipherSolutionEngine {
    private static Logger log = Logger.getLogger(CipherSolutionEngine.class);
    private static long numIterations;
    private static int maxThreads;
    private static int monitorSleepMillis;
    private static CipherDao cipherDao;
    private static String cipherName;
    private static SolutionGenerator solutionGenerator;
    private static SolutionEvaluator solutionEvaluator;

    /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        // Spin up the Spring application context
        setUp();

        CipherDto cipherDto = null;
        Runnable cipherTask = null;
        Thread cipherWorker = null;
        long threadIterations = 0;
        Cipher cipher = cipherDao.findByCipherName(cipherName);

        long start = System.currentTimeMillis();

        List<Thread> threads = new ArrayList<Thread>();
        List<CipherDto> cipherDtos = new ArrayList<CipherDto>();

        if (maxThreads > numIterations) {
            log.warn("The number of threads is greater than the number of tasks.  Reducing thread count to "
                    + numIterations + ".");

            maxThreads = (int) numIterations;
        }

        log.info("Beginning solution generation.  Generating " + numIterations + " solutions using " + maxThreads
                + " threads.");

        for (int i = 1; i <= maxThreads; i++) {
            threadIterations = (numIterations / maxThreads);
            if (i == 1) {
                /*
                 * If the number of iterations doesn't divide evenly among the
                 * threads, add the remainder to the first thread
                 */
                threadIterations += (numIterations % maxThreads);
            }

            cipherDto = new CipherDto(String.valueOf(i), cipher);
            cipherDtos.add(cipherDto);

            cipherTask = new CipherSolutionRunnable(threadIterations, solutionGenerator, solutionEvaluator,
                    cipherDto);

            cipherWorker = new Thread(cipherTask, String.valueOf(i));

            cipherWorker.start();
            threads.add(cipherWorker);
        }

        /*
         * Keep checking threads until no more are left running
         */
        int running = 0;
        do {
            running = 0;
            for (Thread thread : threads) {
                if (thread.isAlive()) {
                    running++;
                }
            }

            /*
             * There's no need to loop through this as fast as possible. Sleep
             * for a short period so that there isn't so much overhead from
             * monitoring the threads' state.
             */
            Thread.sleep(monitorSleepMillis);
        } while (running > 0);

        long totalSolutions = 0;
        long totalMatchSum = 0;
        long uniqueMatchSum = 0;
        long adjacentMatchSum = 0;

        BigInteger cipherId = cipher.getId();
        int rows = cipher.getRows();
        int columns = cipher.getColumns();
        SolutionChromosome solutionMostMatches = new SolutionChromosome(cipherId, 0, 0, 0, rows, columns);
        SolutionChromosome solutionMostUnique = new SolutionChromosome(cipherId, 0, 0, 0, rows, columns);
        SolutionChromosome solutionMostAdjacent = new SolutionChromosome(cipherId, 0, 0, 0, rows, columns);

        /*
         * Sum up all data from all CipherDtos passed to the threads
         */
        for (CipherDto nextCipherDto : cipherDtos) {
            log.debug("Best solution from thread " + nextCipherDto.getThreadName() + ": "
                    + nextCipherDto.getSolutionMostMatches());
            log.debug("Most unique solution from thread " + nextCipherDto.getThreadName() + ": "
                    + nextCipherDto.getSolutionMostUnique());
            log.debug("Solution with most adjacent matches from thread " + nextCipherDto.getThreadName() + ": "
                    + nextCipherDto.getSolutionMostAdjacent());

            totalSolutions += nextCipherDto.getNumSolutions();
            totalMatchSum += nextCipherDto.getTotalMatchSum();
            uniqueMatchSum += nextCipherDto.getUniqueMatchSum();
            adjacentMatchSum += nextCipherDto.getAdjacentMatchSum();

            /*
             * Find the Solution with the highest number of total matches
             */
            if (nextCipherDto.getSolutionMostMatches().getTotalMatches() > solutionMostMatches.getTotalMatches()) {
                solutionMostMatches = nextCipherDto.getSolutionMostMatches();
            }

            /*
             * Find the Solution with the highest number of unique matches in
             * plaintext
             */
            if (nextCipherDto.getSolutionMostUnique().getUniqueMatches() > solutionMostUnique.getUniqueMatches()) {
                solutionMostUnique = nextCipherDto.getSolutionMostUnique();
            }

            /*
             * Find the Solution with the highest number of adjacent matches in
             * plaintext
             */
            if (nextCipherDto.getSolutionMostAdjacent().getAdjacentMatchCount() > solutionMostAdjacent
                    .getAdjacentMatchCount()) {
                solutionMostAdjacent = nextCipherDto.getSolutionMostAdjacent();
            }
        }

        /*
         * Print out summary information
         */
        log.info("Took " + (System.currentTimeMillis() - start) + "ms to generate and validate " + totalSolutions
                + " solutions.");
        log.info("Most total matches achieved: " + solutionMostMatches.getTotalMatches());
        log.info("Average total matches: " + (totalMatchSum / totalSolutions));
        log.info("Best solution found: " + solutionMostMatches);
        log.info("Most unique matches achieved: " + solutionMostUnique.getUniqueMatches());
        log.info("Average unique matches: " + (uniqueMatchSum / totalSolutions));
        log.info("Solution with most unique matches found: " + solutionMostUnique);
        log.info("Most adjacent matches achieved: " + solutionMostAdjacent.getAdjacentMatchCount());
        log.info("Average adjacent matches: " + (adjacentMatchSum / totalSolutions));
        log.info("Solution with most adjacent matches found: " + solutionMostAdjacent);
    }

    /**
     * Spins up the Spring application context
     */
    private static void setUp() {
        @SuppressWarnings("unused")
        ApplicationContext context = new ClassPathXmlApplicationContext("beans-zodiac.xml");

        log.info("Spring context created successfully!");
    }

    /**
     * @param numIterations
     */
    @Required
    public void setNumIterations(long numIterations) {
        CipherSolutionEngine.numIterations = numIterations;
    }

    /**
     * @param setMaxThreads
     */
    @Required
    public void setMaxThreads(int maxThreads) {
        CipherSolutionEngine.maxThreads = maxThreads;
    }

    /**
     * @param monitorSleepMillis
     *            the monitorSleepMillis to set
     */
    @Required
    public void setMonitorSleepMillis(int monitorSleepMillis) {
        CipherSolutionEngine.monitorSleepMillis = monitorSleepMillis;
    }

    /**
     * @param cipherDao
     *            the cipherDao to set
     */
    @Required
    public void setCipherDao(CipherDao cipherDao) {
        CipherSolutionEngine.cipherDao = cipherDao;
    }

    /**
     * @param cipherName
     *            the cipherName to set
     */
    @Required
    public void setCipherName(String cipherName) {
        CipherSolutionEngine.cipherName = cipherName;
    }

    /**
     * @param solutionGenerator
     *            the solutionGenerator to set
     */
    @Required
    public void setSolutionGenerator(SolutionGenerator solutionGenerator) {
        CipherSolutionEngine.solutionGenerator = solutionGenerator;
    }

    /**
     * @param solutionEvaluator
     *            the solutionEvaluator to set
     */
    @Required
    public void setSolutionEvaluator(SolutionEvaluator solutionEvaluator) {
        CipherSolutionEngine.solutionEvaluator = solutionEvaluator;
    }
}