Package pdfdb.app

Source Code of pdfdb.app.Application$StartupProtector

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package pdfdb.app;

import java.io.*;
import java.net.ServerSocket;
import java.sql.*;
import java.util.*;
import java.util.concurrent.*;
import javax.swing.*;
import pdfdb.data.db.*;
import pdfdb.gui.frames.*;
import pdfdb.indexing.fileservice.PollingFileChangeMonitor;
import pdfdb.settings.*;

/** The main application class, ensures single instance and hooks the
*  frame up to the data events.
* @author ug22cmg */
public class Application
{

    private static Application instance = null;
    private PollingFileChangeMonitor poller = null;
    private MainFrame frame = null;
    private ExecutorService pool = null;
    private StartupProtector startup = null;
    private static final Object LOCK = new Object();
    private static final String FIRST_START_MESSAGE =
            "Before you can run the application for the very\n" +
            "first time you must save some important settings\n" +
            "such as the directory/drive to be searched. The \n" +
            "preferences window will now open so you can do this.";

    /** Intializes the application and displays the main frame.
     * @param rootDirectory The directory to listen to. */
    public Application(String directory) throws Exception
    {
        try
        {
            //System.setErr(null);
            //System.setOut(null);
            InitializerService starter = new InitializerService(directory);
            initializeApplication();
            showInterface();
            ensureSingularInstance();
            pool.execute(starter);
        }
        catch (ApplicationAlreadyRunningException le)
        {
            showLockError();
        }
        catch (Throwable e)
        {
            error(true);
        }
    }

    /** Initializes the application instance and registers a shutdown hook */
    private void initializeApplication()
    {
        Thread shutdownThread = new Thread(new ShutdownHook());
        Runtime.getRuntime().addShutdownHook(shutdownThread);
        instance = this;
        pool = Executors.newCachedThreadPool();
    }

    /** Initializes the indexing service.
     * @param directory The directory to start indexing at.
     * @throws java.sql.SQLException If an error occurs. */
    private void initializeServices(String directory) throws SQLException
    {
        poller = new PollingFileChangeMonitor(directory);
        poller.start();
    }

    /** Shows an instance of the
     * @throws java.sql.SQLException */
    private void showInterface() throws SQLException
    {
        MainFrame f = MainFrame.getMainFrame();
        if (f == null)
        {
            frame = new MainFrame(false);
        }
        else
        {
            frame = f;
        }
    }

    /** Creates the lock file used to ensure single instance.
     * @throws java.io.IOException If the file cannot be created. */
    private void ensureSingularInstance() throws
            ApplicationAlreadyRunningException
    {
        pool.execute(startup = new StartupProtector());
    }

    /** Shows the lock error. */
    private void showLockError()
    {
        String err = "Only one instance of the program can be run at a time.";
        JOptionPane.showMessageDialog(null, err);
    }

    /** Gets the poller in a thread safe way.
     * @return The poller instance. */
    private synchronized PollingFileChangeMonitor getPoller()
    {
        return poller;
    }

    /** Gets the current application instance, in a thread safe way.
     * @return The instance of the current application or null. */
    private static Application getInstance()
    {
        synchronized (LOCK)
        {
            return instance;
        }
    }

    /** Adds an observer to the file change pipeline.
     * @param o The observer. */
    public static void addFileChangeObserver(Observer o)
    {
        Application app = getInstance();
        if (o == null)
        {
            throw new IllegalArgumentException();
        }
        if (app != null && app.getPoller() != null)
        {
            app.getPoller().addObserver(o);
        }
    }

    /** Removes the file observer.
     * @param o The observer to remove. */
    public static void removeFileChangeObserver(Observer o)
    {
        Application app = getInstance();
        if (o == null)
        {
            throw new IllegalArgumentException();
        }
        if (app != null && app.getPoller() != null)
        {
            app.getPoller().removeObserver(o);
        }
    }

    /** Displays the preferences dialog when no preferences file exists.
     * @throws java.io.IOException If an error occurs while saving
     * or loading. */
    private static void requestSettings() throws IOException
    {
        PreferencesFrame dialog = null;
        new File(".services").createNewFile();
        dialog =
                new PreferencesFrame(JFrame.getFrames()[0]);
        dialog.setVisible(true);
        if (dialog.getResult() != PreferencesFrame.APPROVED)
        {
            System.err.println("User failed to enter valid preferences.");
            System.exit(0);
        }
    }

    /** Main entry-point for the application. Program arguments are not
     *  used.
     * @param args Unused program arguments. */
    public static void main(String[] args) throws Exception
    {
        if (args.length != 0 && args.length != 1)
        {
            System.out.println("Program arguments invalid.");
        }
        else
        {
            UserSettingsManager manager = UserSettingsManager.getInstance();
            String location = manager.get("SEARCH_LOCATION");
            if (location == null || location.equals("") ||
                    !new File(location).exists())
            {
                // Make a dummy main frame, this is used as the dialog must
                // have an owner, but we dont connect it to data yet.
                MainFrame f = new MainFrame(false);
                JOptionPane.showMessageDialog(null, FIRST_START_MESSAGE);
                f.setVisible(true);
                requestSettings();
                if (manager.get("SERVICES_LOCATION").equals(".services"))
                {
                    new File(".services").delete();
                    PluginSettingsManager pm = PluginSettingsManager.getInstance();
                    pm.save();
                }
                location = manager.get("SEARCH_LOCATION");
            }

            new Application(args.length == 0 ? location : args[0]);
        }
    }

    /** Shows the error message. and exits.
     * @param showMessage Whether to show the error message or not. */
    private void error(boolean showMessage)
    {
        if (showMessage)
        {
            String err = "There has been a problem and this application " +
                    "will now exit.";
            JOptionPane.showMessageDialog(MainFrame.getMainFrame(), err);
        }
        System.exit(1);
    }

    /** Protects the database from multiple instances. Creates a server socket
     *  and if unavailable, we know the application is already running. The
     * idea for this code is from:
     * http://www.rbgrn.net/blog/2008/05/java-single-application-instance.html
     * However the code is substantially different from that of the tutorial. */
    private class StartupProtector implements Runnable
    {

        private ServerSocket lock = null;
        private boolean shutdown = false;

        /** Initializes and throws an ApplicationAlreadyRunningException
         *  if the application is running.
         * @throws pdfdb.app.ApplicationAlreadyRunningException if running. */
        public StartupProtector() throws ApplicationAlreadyRunningException
        {
            try
            {
                lock = new ServerSocket(8275);
            }
            catch (IOException ioe)
            {
                throw new ApplicationAlreadyRunningException();
            }
        }

        /** Halts the lock */
        public void stop()
        {
            shutdown = true;
        }

        /** Runs the lock */
        @Override
        public void run()
        {
            while (!shutdown)
            {
                try
                {
                    lock.accept();
                }
                catch (IOException ex)
                {
                }
            }
        }
    }

    /** Initializes the application */
    private class InitializerService implements Runnable
    {

        private String directory;

        /** Initializes the service.
         * @param directory The directory to start searching at. */
        public InitializerService(String directory)
        {
            this.directory = directory;
        }

        /** Runs the InitializerService. */
        @Override
        public void run()
        {
            try
            {
                MainFrame.getMainFrame().setVisible(true);
                MainFrame.getMainFrame().setLoadingIsVisible(true);
                FileProvider.initialize();
                initializeServices(directory);
                MainFrame.getMainFrame().connect();
                MainFrame.getMainFrame().setLoadingIsVisible(false);
            }
            catch (SQLException ex)
            {
                error(false);
            }
        }
    }

    /** Shuts down the application's resources. */
    private class ShutdownHook implements Runnable
    {

        /** Called when System.exit is called, shuts down database and other
         *  secondary resources, and ensures prompt closure of the indexing
         * service. */
        @Override
        public void run()
        {
            int i = 0;
            if (poller != null)
            {
                poller.shutdown();
                while (poller.isActive() && i < 500)
                {
                    i++;
                }
            }
            if (pool != null)
            {
                pool.shutdown();
            }
            if (frame != null)
            {
                frame.shutdown();
            }
            DatabaseConnection.shutdown();
            instance = null;
            if (startup != null)
            {
                startup.stop();
            }
        }
    }
}
TOP

Related Classes of pdfdb.app.Application$StartupProtector

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.