org.generationcp.ibpworkbench.launcher.Launcher.java Source code

Java tutorial

Introduction

Here is the source code for org.generationcp.ibpworkbench.launcher.Launcher.java

Source

/***************************************************************
 * Copyright (c) 2012, All Rights Reserved.
 * 
 * Generation Challenge Programme (GCP)
 * 
 * 
 * This software is licensed for use under the terms of the 
 * GNU General Public License (http://bit.ly/8Ztv8M) and the 
 * provisions of Part F of the Generation Challenge Programme 
 * Amended Consortium Agreement (http://bit.ly/KQX1nL)
 * 
 **************************************************************/
package org.generationcp.ibpworkbench.launcher;

import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Monitor;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tray;
import org.eclipse.swt.widgets.TrayItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Launcher {

    private static final Logger LOG = LoggerFactory.getLogger(Launcher.class);

    private final static int MAX_CONNECT_TRIES = 5;

    private String mysqlBinDir = "infrastructure/mysql/bin";
    private String tomcatDir = "infrastructure/tomcat";
    private String firstRunFilename = "first_run";

    private final static String TOMCAT_HOST = "localhost";
    private final static int TOMCAT_PORT = 18080;

    private final static String workbenchUrl = "http://" + TOMCAT_HOST + ":" + TOMCAT_PORT + "/ibpworkbench/main";

    private Display display;
    private Shell shell;

    private TrayItem trayItem;
    private Process mysqlProcess;
    private TomcatServer tomcatServer;

    private Label splashLabel;
    private Image splashImage;
    private Label progressLabel;
    private ProgressBar progressBar;

    private File icisIni;
    private File icisIniBakFile;

    private long mysqlHeadstartMillis = 1000;
    private long tomcatHeadstartMillis = 2000;

    private StartupThread startupThread;

    private Shell warningShell;
    private Label warningLabel;
    private Composite warningImageArea;
    private Button buttonOk;

    protected void initializeComponents() {
        display = new Display();
        shell = new Shell(display, SWT.NO_TRIM | SWT.INHERIT_DEFAULT);
        shell.setText("IBP Workbench");
        shell.setSize(640, 480);
        centerShellToPrimaryMonitor(shell);

        // add the splash image
        splashImage = new Image(display, "images/splash.png");
        splashLabel = new Label(shell, SWT.NONE);
        splashLabel.setImage(splashImage);

        // add progress label
        progressLabel = new Label(shell, SWT.NONE);
        progressLabel.moveAbove(splashLabel);
        progressLabel.setText("Loading...");
        progressLabel.setFont(new Font(display, "Helvetica", 12, SWT.ITALIC));
        progressLabel.setForeground(new Color(null, 0, 0, 178));

        // add the progress bar
        progressBar = new ProgressBar(shell, SWT.HORIZONTAL | SWT.INDETERMINATE);
        progressBar.moveAbove(splashLabel);

        // create the warning shell
        warningShell = new Shell(display, SWT.DIALOG_TRIM);
        warningShell.setSize(640, 480);
        warningShell.setText("IBP Workbench");
        centerShellToPrimaryMonitor(warningShell);

        warningLabel = new Label(warningShell, SWT.LEFT);
        warningLabel.setText(
                "IBPWorkbench will start MySQL and Tomcat for the first time.\nPlease \"Allow Access\" or \"Unblock\" it on your firewall.");

        warningImageArea = new Composite(warningShell, SWT.CENTER);

        buttonOk = new Button(warningShell, SWT.PUSH);
        buttonOk.setText("OK");
    }

    protected void initializeLayout() {
        // layout the splash screen
        layoutSplashShell();

        // layout the warning shell
        layoutWarningShell();
    }

    protected void centerShellToPrimaryMonitor(Shell shell) {
        // center shell to primary monitor
        Monitor monitor = display.getPrimaryMonitor();
        Rectangle monitorBounds = monitor.getBounds();

        Rectangle bounds = shell.getBounds();
        int x = (monitorBounds.x + (monitorBounds.width / 2)) - (bounds.width / 2);
        int y = (monitorBounds.y + (monitorBounds.height / 2)) - (bounds.height / 2);
        shell.setLocation(x, y);
    }

    protected void layoutSplashShell() {
        Rectangle shellBounds = shell.getBounds();
        splashLabel.setBounds(0, 0, shellBounds.width, shellBounds.height);

        final int vMargin = 5;
        final int hMargin = 40;
        Point progressLabelPreferredSize = progressLabel.computeSize(SWT.DEFAULT, SWT.DEFAULT);
        Point progressBarPreferredSize = progressBar.computeSize(SWT.DEFAULT, SWT.DEFAULT);

        int progressLabelY = shellBounds.height - vMargin - progressBarPreferredSize.y - vMargin
                - progressLabelPreferredSize.y;
        int progressBarY = shellBounds.height - vMargin - progressBarPreferredSize.y;

        progressLabel.setBounds(hMargin, progressLabelY, shellBounds.width - (2 * hMargin),
                progressLabelPreferredSize.y);
        progressBar.setBounds(hMargin, progressBarY, shellBounds.width - (2 * hMargin), progressBarPreferredSize.y);
    }

    protected void layoutWarningShell() {
        GridLayout layout = new GridLayout(1, true);

        GridData warningLabelLayoutData = new GridData();
        warningLabelLayoutData.grabExcessHorizontalSpace = false;
        warningLabelLayoutData.grabExcessVerticalSpace = false;
        warningLabel.setLayoutData(warningLabelLayoutData);

        GridData warningImageAreaLayoutData = new GridData(GridData.FILL_BOTH);
        warningImageAreaLayoutData.grabExcessHorizontalSpace = true;
        warningImageAreaLayoutData.grabExcessVerticalSpace = true;
        warningImageArea.setLayoutData(warningImageAreaLayoutData);

        GridData buttonOkLayoutData = new GridData();
        buttonOkLayoutData.grabExcessHorizontalSpace = false;
        buttonOkLayoutData.grabExcessVerticalSpace = false;
        buttonOkLayoutData.horizontalAlignment = SWT.RIGHT;
        buttonOkLayoutData.widthHint = 80;
        buttonOk.setLayoutData(buttonOkLayoutData);

        warningShell.setLayout(layout);
    }

    protected void initializeActions() {
        warningImageArea.addPaintListener(new PaintListener() {

            public void paintControl(PaintEvent e) {
                GC gc = e.gc;

                Point labelSize = warningImageArea.getSize();

                Image image = new Image(display, "images/unblock.png");
                int x = (labelSize.x - image.getImageData().width) / 2;
                int y = (labelSize.y - image.getImageData().height) / 2;

                gc.drawImage(image, x, y);
            }
        });

        buttonOk.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                warningShell.dispose();

                launchMySQLAndTomcat();
            }
        });

        warningShell.addShellListener(new ShellAdapter() {
            @Override
            public void shellClosed(ShellEvent e) {
                launchMySQLAndTomcat();
            }
        });

        progressLabel.addPaintListener(new PaintListener() {

            public void paintControl(PaintEvent e) {
                GC gc = e.gc;

                Rectangle bounds = progressLabel.getBounds();
                gc.drawImage(splashImage, bounds.x, bounds.y, bounds.width, bounds.height, 0, 0, bounds.width,
                        bounds.height);

                gc.drawText(progressLabel.getText(), 0, 0, true);
            }
        });
    }

    protected void launchMySQLProcess() {
        File workingDirPath = new File(mysqlBinDir).getAbsoluteFile();
        String mysqldPath = "mysqld.exe";
        String myIniPath = "../my.ini";

        ProcessBuilder pb = new ProcessBuilder(workingDirPath.getAbsolutePath() + File.separator + mysqldPath,
                "--defaults-file=" + myIniPath);
        pb.directory(workingDirPath);
        try {
            mysqlProcess = pb.start();
        } catch (IOException e) {
            LOG.error("IOException", e);
        }
    }

    protected void launchMySQLService() {
        ProcessBuilder pb = new ProcessBuilder("NET", "start", "MySQLIBWS");
        try {
            Process process = pb.start();
            if (process != null) {
                process.waitFor();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    protected void initializeMysql() {
        LOG.trace("Starting MySQL...");

        launchMySQLService();

        // give Tomcat a headstart
        try {
            Thread.sleep(mysqlHeadstartMillis);
        } catch (InterruptedException e) {
            LOG.error("Interrupted while waiting for MySQL to start", e);
        }

        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            LOG.error("Error encountered while trying to load JDBC Driver", e);
        }

        Connection conn = null;
        boolean success = false;
        int tryNum = 0;
        while (++tryNum < MAX_CONNECT_TRIES) {
            try {
                conn = DriverManager.getConnection("jdbc:mysql://localhost:13306/?user=root");
                success = true;
                break;
            } catch (SQLException e) {
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                LOG.error("Interrupted while trying to connect to MySQL", e);
                break;
            }
        }

        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                LOG.error("Error encountered while trying to close JDBC connection", e);
            }
        }

        if (!success) {
            LOG.trace("Unable to connect to MySQL after {} tries", tryNum);
        } else {
            LOG.trace("Connected to MySQL after {} tries", tryNum);
        }
    }

    protected void initializeTomcat() {
        LOG.trace("Starting Tomcat...");

        File tomcatBinPath = new File(tomcatDir).getAbsoluteFile();
        tomcatServer = new TomcatServer();
        tomcatServer.setCatalinaHome(tomcatBinPath.getAbsolutePath());

        tomcatServer.start();

        // give Tomcat a headstart
        try {
            Thread.sleep(tomcatHeadstartMillis);
        } catch (InterruptedException e) {
            LOG.error("Interrupted while waiting for Tomcat to start", e);
        }

        // try connecting to the workbench url
        HttpParams httpParams = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(httpParams, 5000);

        HttpClient httpClient;
        HttpGet httpGet;
        HttpResponse response;

        int tryNum = 0;
        boolean success = false;

        while (++tryNum < MAX_CONNECT_TRIES) {

            httpClient = new DefaultHttpClient(httpParams);
            httpGet = new HttpGet(workbenchUrl);
            response = null;

            try {
                response = httpClient.execute(httpGet);
            } catch (ClientProtocolException e) {
                LOG.error("ClientProtocolException", e);
            } catch (IOException e) {
                LOG.error("IOException", e);
            }

            if (response != null && response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                success = true;
                httpGet.releaseConnection();
                break;
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                LOG.error("Interrupted while trying to connect to Tomcat", e);
                break;
            }
        }

        if (!success) {
            LOG.trace("Unable to connect to Tomcat after {} tries", tryNum);
        } else {
            LOG.trace("Connected to Tomcat after {} tries", tryNum);
        }
    }

    protected void stopMySQLProcess() {
        if (mysqlProcess == null) {
            return;
        }

        mysqlProcess.destroy();

        try {
            mysqlProcess.waitFor();
        } catch (InterruptedException e) {
            LOG.error("Interrupted while waiting for MySQL to stop", e);
        }
    }

    protected void stopMySQLService() {
        ProcessBuilder pb = new ProcessBuilder("NET", "stop", "MySQLIBWS");
        try {
            Process process = pb.start();
            process.waitFor();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    protected void shutdownMysql() {
        LOG.trace("Stopping MySQL...");

        // 20121221 NOTE: We don't stop MySQL service since it maybe needed
        // by other tools.
        //stopMySQLService();
    }

    protected void shutdownWebApps() {
        LOG.trace("Stopping Tomcat...");

        tomcatServer.stopServer();
    }

    protected void renameIcisIni() {
        String tempDir = System.getProperty("java.io.tmpdir");
        icisIni = new File(tempDir + File.separator + "ICIS.ini");
        icisIniBakFile = new File(tempDir + File.separator + "ICIS.ini.bak");

        if (icisIni.exists()) {
            boolean result = icisIni.renameTo(icisIniBakFile);
            LOG.debug("Renamed ICIS.ini to ICIS.ini.bak: {}", result);
        }
    }

    protected void revertIcisIni() {
        if (icisIniBakFile.exists()) {
            boolean result = icisIniBakFile.renameTo(icisIni);
            LOG.debug("Renamed ICIS.ini.bak to ICIS.ini: {}", result);
        }
    }

    protected void launchMySQLAndTomcat() {
        // show the splash screen
        shell.open();
        shell.setActive();

        // start Tomcat and MySQL
        startupThread = new StartupThread();
        startupThread.start();
    }

    public void open() {
        File firstRunFile = new File(firstRunFilename);
        if (firstRunFile.exists()) {
            warningShell.open();
            firstRunFile.delete();
        } else {
            launchMySQLAndTomcat();
        }

        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
    }

    public void assemble() {
        initializeComponents();
        initializeLayout();
        initializeActions();
    }

    protected void createSystemTrayItem() {
        // get the System Tray
        Tray tray = display.getSystemTray();
        if (tray == null) {
            throw new RuntimeException("System tray not available");
        }

        // create a System Tray item
        trayItem = new TrayItem(tray, SWT.NONE);
        trayItem.setToolTipText("IBWorkbench");

        Image image = new Image(display, "images/systray.ico");
        trayItem.setImage(image);

        // create the menu
        final Menu menu = new Menu(shell, SWT.POP_UP);

        MenuItem launchWorkbenchItem = new MenuItem(menu, SWT.PUSH);
        launchWorkbenchItem.setText("Launch IBWorkbench");

        MenuItem exitItem = new MenuItem(menu, SWT.PUSH);
        exitItem.setText("Exit");

        // add listeners System Tray Item
        Listener showMenuListener = new Listener() {
            public void handleEvent(Event event) {
                menu.setVisible(true);
            }
        };
        trayItem.addListener(SWT.Selection, showMenuListener);
        trayItem.addListener(SWT.MenuDetect, showMenuListener);

        // add listener to the Launch IBPWorkbench listener
        launchWorkbenchItem.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                try {
                    Program.launch(workbenchUrl);
                } catch (Exception ex) {
                    LOG.error("Cannot launch workbench due to error", ex);
                }
            }
        });

        // add listener to the Exit menu item
        exitItem.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                LOG.debug("Exiting workbench launcher");

                try {
                    startupThread.join();
                } catch (InterruptedException e1) {
                    LOG.error("Interrupted while waiting for startup thread to stop", e);
                }

                trayItem.dispose();

                shell.dispose();

                shutdownMysql();
                shutdownWebApps();
                revertIcisIni();
            }
        });
    }

    protected static boolean isTomcatRunning() {
        Socket socket = null;
        try {
            socket = new Socket(TOMCAT_HOST, TOMCAT_PORT);
            return true;
        } catch (Exception e) {
            return false;
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                }
            }
        }
    }

    protected void setProgressText(final String progressText) {
        display.syncExec(new Runnable() {

            public void run() {
                progressLabel.setText(progressText);
                progressLabel.redraw();
            }
        });
    }

    private class StartupThread extends Thread {
        @Override
        public void run() {
            setProgressText("Renaming icis.ini...");

            // rename %TEMP%/icis.ini
            renameIcisIni();

            // initialize MySQL
            setProgressText("Starting MySQL...");
            initializeMysql();

            // initialize Tomcat
            setProgressText("Starting Tomcat...");
            initializeTomcat();

            // launch the workbench url
            display.asyncExec(new Runnable() {

                public void run() {
                    try {
                        Program.launch(workbenchUrl);
                    } catch (Exception ex) {
                        LOG.error("Cannot launch workbench due to error", ex);
                    }

                    // hide the splash screen
                    shell.setVisible(false);

                    // create the system tray item
                    createSystemTrayItem();
                }
            });
        }
    }

    public static void main(String[] args) {
        if (isTomcatRunning()) {
            LOG.info("Tomcat is already running. Launching workbench instead...");

            try {
                Program.launch(workbenchUrl);
            } catch (Exception ex) {
                LOG.error("Cannot launch workbench due to error", ex);
            }
            return;
        }

        Launcher launcher = new Launcher();
        launcher.assemble();

        launcher.open();
    }
}