es.darkhogg.hazelnutt.Hazelnutt.java Source code

Java tutorial

Introduction

Here is the source code for es.darkhogg.hazelnutt.Hazelnutt.java

Source

/**
 * This file is part of Hazelnutt.
 * 
 * Hazelnutt 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.
 * 
 * Hazelnutt 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 Hazelnutt.  If not, see <http://www.gnu.org/licenses/>.
 */
package es.darkhogg.hazelnutt;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.LinkedList;
import java.util.Queue;

import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.DailyRollingFileAppender;
import org.apache.log4j.EnhancedPatternLayout;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.varia.NullAppender;

import es.darkhogg.util.Version;

public final class Hazelnutt {

    /**
     * Version of the program
     */
    private static final Version VERSION = new Version(1, 0, 8, 2);

    /**
     * Logger for the whole application
     */
    private static final Logger LOGGER;
    static {
        Logger.getRootLogger().addAppender(NullAppender.getNullAppender());

        try {
            LOGGER = Logger.getLogger(Hazelnutt.class);
            LOGGER.addAppender(new ConsoleAppender(new EnhancedPatternLayout("%d{HH:mm:ss.SSS} %5p : %m%n"),
                    ConsoleAppender.SYSTEM_OUT));
            LOGGER.addAppender(
                    new DailyRollingFileAppender(new EnhancedPatternLayout("%d{HH:mm:ss.SSS} %5p : %m%n"),
                            "log" + System.getProperty("file.separator") + "Hazelnutt.log", "'.'yyyy-MM-dd"));
            //LOGGER.addAppender( new SwingPanelAppender( FRAME.getLogPanel(), true ) );
            LOGGER.setLevel(Level.TRACE);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Configuration for the whole application
     */
    private static final Configuration CONFIG;
    static {
        File cfgFile = new File("./Hazelnutt.properties");
        PropertiesConfiguration cfg = null;
        try {
            cfg = new PropertiesConfiguration(cfgFile);
        } catch (ConfigurationException e) {
            throw new RuntimeException(e);
        }

        cfg.setAutoSave(true);

        CONFIG = cfg;
    }

    /**
     * Main frame of the program
     */
    private static final EditorFrame FRAME;
    static {
        FRAME = new EditorFrame();
    }

    /**
     * Returns the current version of the application as an integer, where each
     * byte is a version component.
     * 
     * @return This application version
     */
    public static Version getVersion() {
        return VERSION;
    }

    /**
     * Returns an already initialized and configured Logger for the whole
     * application.
     * 
     * @return This application logger
     */
    public static Logger getLogger() {
        return LOGGER;
    }

    /**
     * Returns an already created and initialized JFrame which is the main
     * frame for this application.
     * 
     * @return This application main frame
     */
    public static EditorFrame getFrame() {
        return FRAME;
    }

    /**
     * Returns an already created, loaded and ready to be used Configuration
     * for the whole application.
     * 
     * @return This application configuration object
     */
    public static Configuration getConfiguration() {
        return CONFIG;
    }

    /**
     * Tries to restart the application in at most <i>time</i> milliseconds for
     * every alive thread.
     * 
     * @param time Number of milliseconds to wait for each thread to terminate
     * @return If something have happened before terminating the application
     */
    public static boolean restart(long time) {
        Logger logger = getLogger();
        logger.info("Trying to restart application...");

        // Get the path to java executable
        File javaBinDir = new File(System.getProperty("java.home"), "bin");
        logger.debug("Java directory: '" + javaBinDir.getAbsolutePath() + "'");

        File[] possiblePaths = { new File(javaBinDir, "javaw.exe"), new File(javaBinDir, "java.exe"),
                new File(javaBinDir, "java") };
        File javaPath;
        int i = 0;
        do {
            javaPath = possiblePaths[i];
            i++;
        } while (i < possiblePaths.length && !javaPath.exists());
        logger.debug("Java executable: '" + javaPath.getAbsolutePath() + "'");

        // Get path to JAR
        File jarFile = null;
        try {
            jarFile = new File(Hazelnutt.class.getProtectionDomain().getCodeSource().getLocation().toURI());
        } catch (URISyntaxException e) {
            e.printStackTrace();
            return false;
        }

        String[] command = null;
        if (!jarFile.isDirectory()) {
            logger.debug("JAR file: '" + jarFile.getAbsolutePath() + "'");
            command = new String[] { javaPath.getPath(), "-jar", jarFile.getPath() };
        } else {
            File classDir = jarFile;
            logger.debug("Class path: '" + classDir.getAbsolutePath() + "'");
            command = new String[] { javaPath.getPath(), "-classpath",
                    jarFile.getPath() + ";.;" + System.getProperty("java.class.path"), Hazelnutt.class.getName() };
            System.out.println(
                    "\"" + command[0] + "\" \"" + command[1] + "\" \"" + command[2] + "\" \"" + command[3] + "\"");
        }

        // Execute
        try {
            Runtime.getRuntime().exec(command);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }

        // Terminate this application
        terminate(time);
        return true;
    }

    /**
     * Terminates the application in at most <i>time</i> milliseconds for
     * every alive thread. 
     * 
     * @param time Number of milliseconds to wait for each thread to terminate
     */
    public static void terminate(long time) {
        Logger logger = getLogger();
        logger.info("Terminating application...");

        try {
            getFrame().dispose();

            // Get the root thread group
            ThreadGroup rootThreadGroup = Thread.currentThread().getThreadGroup();
            while (rootThreadGroup.getParent() != null) {
                rootThreadGroup = rootThreadGroup.getParent();
            }

            // Declare some collections
            Queue<ThreadGroup> threadGroups = new LinkedList<ThreadGroup>();
            Queue<Thread> threads = new LinkedList<Thread>();

            // Get ALL groups
            threadGroups.add(rootThreadGroup);
            while (!threadGroups.isEmpty()) {
                ThreadGroup group = threadGroups.remove();

                Thread[] subThreads = new Thread[group.activeCount() * 2];
                //group.enumerate( subThreads );
                for (Thread subThread : subThreads) {
                    if (subThread != null) {
                        threads.add(subThread);
                    }
                }

                ThreadGroup[] subThreadGroups = new ThreadGroup[group.activeGroupCount() * 2];
                for (ThreadGroup subThreadGroup : subThreadGroups) {
                    if (subThreadGroup != null) {
                        threadGroups.add(subThreadGroup);
                    }
                }
            }

            // Join a maximum of time milliseconds for all non-daemon threads
            while (!threads.isEmpty()) {
                Thread thread = threads.remove();
                LOGGER.trace(thread);

                if (!thread.isDaemon() && thread != Thread.currentThread()) {
                    logger.trace("Waiting for thread '" + thread.getName() + "'");
                    thread.join(time);
                    if (thread.isAlive()) {
                        logger.trace("Interrupting thread '" + thread.getName() + "'");
                        thread.interrupt();
                    }
                }
            }

        } catch (Throwable e) {
            LOGGER.warn("Interrupted while terminating application", e);

        } finally {
            // Exit the program
            System.exit(0);
        }
    }

    /**
     * Runs the application
     * 
     * @param args
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        // Print some version information
        LOGGER.log(Level.OFF, "----------------");
        LOGGER.info("Hazelnutt " + VERSION);

        LOGGER.trace("Selecting Look&Feel...");

        // Select the L&F from configuration or the default if not present
        String slaf = CONFIG.getString("Hazelnutt.gui.lookAndFeel");
        if (slaf == null) {
            LOGGER.info("Configuration entry for L&F missing, creating default");
            slaf = UIManager.getSystemLookAndFeelClassName();
        }

        // Set it or print an error
        try {
            UIManager.setLookAndFeel(slaf);
        } catch (Exception e) {
            LOGGER.warn("Error while selecting the L&F \"" + slaf + "\", leaving default");
        }

        // Update the configuration with the currently selected L&F
        LookAndFeel laf = UIManager.getLookAndFeel();
        LOGGER.debug("L&F selected: " + laf.getName() + " (" + laf.getClass().getName() + ")");
        CONFIG.setProperty("Hazelnutt.gui.lookAndFeel", laf.getClass().getName());

        // Load the frame
        LOGGER.trace("Launching main frame...");
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                SwingUtilities.updateComponentTreeUI(FRAME);
                FRAME.setVisible(true);
            }
        });
    }
}