Package ca.eandb.jdcp.worker

Source Code of ca.eandb.jdcp.worker.MainWindow$Options

/*
* Copyright (c) 2008 Bradley W. Kimmel
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

package ca.eandb.jdcp.worker;

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.MenuShortcut;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.TrayIcon.MessageType;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Properties;
import java.util.concurrent.ThreadFactory;
import java.util.prefs.Preferences;

import javax.security.auth.login.LoginException;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import javax.swing.text.Document;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

import org.apache.derby.jdbc.EmbeddedDataSource;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;

import ca.eandb.jdcp.JdcpUtil;
import ca.eandb.jdcp.remote.AuthenticationService;
import ca.eandb.jdcp.remote.JobService;
import ca.eandb.jdcp.remote.ProtocolVersionException;
import ca.eandb.jdcp.worker.policy.CourtesyMonitor;
import ca.eandb.jdcp.worker.policy.CourtesyMonitorFactory;
import ca.eandb.jdcp.worker.policy.PowerCourtesyMonitor;
import ca.eandb.jdcp.worker.policy.UnconditionalCourtesyMonitor;
import ca.eandb.util.args.ArgumentProcessor;
import ca.eandb.util.args.BooleanFieldOption;
import ca.eandb.util.args.IntegerFieldOption;
import ca.eandb.util.concurrent.BackgroundThreadFactory;
import ca.eandb.util.io.DocumentOutputStream;
import ca.eandb.util.progress.ProgressPanel;

/**
* @author Brad Kimmel
*
*/
public final class MainWindow extends JFrame {

  private static final boolean SYSTEM_TRAY_SUPPORTED = Double.parseDouble(System.getProperty("java.specification.version")) >= 1.6;

  private static final long serialVersionUID = 1L;
  private static final Logger logger = Logger.getLogger(MainWindow.class)//  @jve:decl-index=0:
  private static final Preferences pref = Preferences.userNodeForPackage(MainWindow.class);
  private static final int RECONNECT_TIMEOUT = 60;
  private JPanel jContentPane = null;
  private JSplitPane jSplitPane = null;
  private ProgressPanel progressPanel = null;
  private JEditorPane consolePane = null;
  private JScrollPane consoleScrollPane = null;
  private ConnectionDialog connectionDialog = null;
  private JLabel statusLabel = null;
  private ThreadServiceWorker worker = null;
  private Thread workerThread = null;
  private final Options options;
  private final PowerCourtesyMonitor powerMonitor = CourtesyMonitorFactory.INSTANCE
      .createPowerCourtesyMonitor();

  /**
   * Container class for command line options.
   * @author Brad Kimmel
   */
  public static final class Options {

    /** Number of CPUs to use to process worker threads. */
    public int numberOfCpus = -1;

    /** A value indicating if the program is being run on startup. */
    public boolean startup = false;

  };

  /**
   * This method initializes jSplitPane
   *
   * @return javax.swing.JSplitPane
   */
  private JSplitPane getJSplitPane() {
    if (jSplitPane == null) {
      jSplitPane = new JSplitPane();
      jSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
      jSplitPane.setDividerLocation(100);
      jSplitPane.setOneTouchExpandable(true);
      jSplitPane.setTopComponent(getProgressPanel());
      jSplitPane.setBottomComponent(getConsoleScrollPane());
      jSplitPane.setResizeWeight(1.0D);
    }
    return jSplitPane;
  }

  /**
   * This method initializes progressPanel
   *
   * @return ca.eandb.util.progress.ProgressPanel
   */
  private ProgressPanel getProgressPanel() {
    if (progressPanel == null) {
      progressPanel = new ProgressPanel();
    }
    return progressPanel;
  }

  /**
   * This method initializes consolePane
   *
   * @return javax.swing.JEditorPane
   */
  private JEditorPane getConsolePane() {
    if (consolePane == null) {
      consolePane = new JEditorPane();
      consolePane.setEditable(false);
      consolePane.setContentType("text/rtf");
    }
    return consolePane;
  }

  /**
   * This method initializes consoleScrollPane
   *
   * @return javax.swing.JScrollPane
   */
  private JScrollPane getConsoleScrollPane() {
    if (consoleScrollPane == null) {
      consoleScrollPane = new JScrollPane();
      consoleScrollPane.setViewportView(getConsolePane());
    }
    return consoleScrollPane;
  }

  /**
   * @param args
   * @throws IOException
   */
  public static void main(String[] args) throws IOException {
    Properties props = new Properties(System.getProperties());
    props.load(MainWindow.class.getResourceAsStream("system.properties"));
    System.setProperties(props);

    ArgumentProcessor<Options> argProcessor = new ArgumentProcessor<Options>();
    argProcessor.addOption("ncpus", 'n', new IntegerFieldOption<Options>("numberOfCpus"));
    argProcessor.addOption("startup", 'S', new BooleanFieldOption<Options>("startup"));

    final Options options = new Options();
    argProcessor.process(args, options);

    if (options.startup && !pref.getBoolean("runOnStartup", true)) {
      return;
    }

    JdcpUtil.initialize();

    ConsoleAppender appender = new ConsoleAppender();
    appender.setLayout(new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN));
    appender.setTarget(ConsoleAppender.SYSTEM_ERR);
    appender.setFollow(true);
    appender.activateOptions();
    BasicConfigurator.configure(appender);

    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        MainWindow thisClass = new MainWindow(options);
        if (!options.startup) {
          thisClass.setVisible(true);
        }
      }
    });
  }

  /**
   * Creates a <code>MainWindow</code> using the specified
   * <code>Options</code>.
   * @param options The <code>Options</code> to use to configure the behavior
   *     of the program.
   */
  public MainWindow(Options options) {
    super();
    this.options = options;
    initialize();
  }

  /**
   * This is the default constructor
   */
  public MainWindow() {
    this(new Options());
  }

  /**
   * This method initializes this
   *
   * @return void
   */
  private void initialize() {
    this.setSize(300, 200);
    this.setContentPane(getJContentPane());
    this.setTitle("JDCP Worker");
    this.addWindowListener(new WindowAdapter() {
      public void windowOpened(WindowEvent e) {
        connectConsole();
      }
    });

    JMenuBar menuBar = new JMenuBar();
    JMenu menu;
    JMenuItem item;

    menu = new JMenu("File");
    menu.setMnemonic('F');
    menuBar.add(menu);

    item = new JMenuItem("Change connection", 'c');
    item.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        changeConnection();
      }
    });
    menu.add(item);

    item = new JMenuItem("Preferences", 'p');
    item.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        openPreferences();
      }
    });
    menu.add(item);

    menu.addSeparator();

    item = new JMenuItem("Exit", 'x');
    item.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        exit();
      }
    });
    menu.add(item);

    this.setJMenuBar(menuBar);

    if (SYSTEM_TRAY_SUPPORTED) {
      initializeSystemTray();
    }

    startWorker();
  }

  /**
   * Initializes the system tray icon.
   *
   * REQUIRES JAVA SE 6 OR HIGHER.
   */
  private void initializeSystemTray() {
    if (SystemTray.isSupported()) {

      URL imageUrl = MainWindow.class.getResource("jdcp-32.png");
      Image image = Toolkit.getDefaultToolkit().getImage(imageUrl);
      final TrayIcon icon = new TrayIcon(image, "JDCP Worker");
      icon.setImageAutoSize(true);

      PopupMenu popup = new PopupMenu();
      MenuItem popupItem = new MenuItem("Open JDCP Worker");
      popupItem.setShortcut(new MenuShortcut(KeyEvent.VK_O));
      popupItem.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          MainWindow.this.setVisible(true);
          MainWindow.this.setState(JFrame.NORMAL);
          MainWindow.this.toFront();
        }
      });
      popup.add(popupItem);

      popupItem = new MenuItem("Exit");
      popupItem.setShortcut(new MenuShortcut(KeyEvent.VK_X));
      popupItem.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          exit();
        }
      });
      popup.add(popupItem);

      icon.setPopupMenu(popup);
      icon.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          MainWindow.this.setVisible(true);
          MainWindow.this.setState(JFrame.NORMAL);
          MainWindow.this.toFront();
        }
      });

      setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
      addWindowListener(new WindowAdapter() {
        private boolean first = true;
        public void windowClosing(WindowEvent e) {
          MainWindow.this.setVisible(false);
          if (first) {
            icon.displayMessage(
                "JDCP Worker",
                "JDCP Worker is still running.  To exit, right click this icon and click 'exit'.",
                MessageType.INFO);
            first = false;
          }
        }
      });

      try {
        SystemTray.getSystemTray().add(icon);
      } catch (AWTException e) {
        logger.error("Could not add system tray icon.", e);
      }

    }
  }

  private void openPreferences() {
    final PreferencesDialog dialog = new PreferencesDialog(this);
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        dialog.setPowerSettingsEnabled(powerMonitor != null);
        dialog.setVisible(true);
        if (!dialog.isCancelled()) {
          onPreferencesChanged();
        }
      }
    });
  }

  private void onPreferencesChanged() {
    int maxCpus = pref.getInt("maxCpus", 0);
    int availableCpus = Runtime.getRuntime().availableProcessors();
    if (maxCpus <= 0 || maxCpus > availableCpus) {
      maxCpus = availableCpus;
    }
    worker.setMaxWorkers(maxCpus);

    if (powerMonitor != null) {
      boolean requireAC = pref.getBoolean("requireAC", false);
      int minBattLife = pref.getInt("minBattLife", 0);
      int minBattLifeWhileChg = pref.getInt("minBattLifeWhileChg", 0);
      minBattLife = Math.min(Math.max(minBattLife, 0), 100);
      minBattLifeWhileChg = Math.min(Math.max(minBattLifeWhileChg, 0), 100);
      powerMonitor.setRequireAC(requireAC);
      powerMonitor.setMinBatteryLifePercent(minBattLife);
      powerMonitor.setMinBatteryLifePercentWhileCharging(minBattLifeWhileChg);
      powerMonitor.update();
    }
  }

  private void changeConnection() {
    startWorker();
  }

  private void exit() {
    getConnectionDialog().dispose();
    System.exit(0);
  }

  private JobService reconnect() {
    return connect(RECONNECT_TIMEOUT);
  }

  private JobService connect() {
    return connect(0);
  }

  private JobService connect(int timeout) {
    final ConnectionDialog dialog = getConnectionDialog();
    JobService service = null;
    boolean showMessages = true;
    do {
      if (MainWindow.this.isVisible()) {
        dialog.setTimeout(timeout);
        try {
          SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
              dialog.setVisible(true);
            }
          });
          if (dialog.isCancelled()) {
            break;
          }
          showMessages = !dialog.isTimedOut();
        } catch (InterruptedException e) {
          break;
        } catch (InvocationTargetException e) {
          logger.error("Exception raised while displaying connection dialog.", e);
          break;
        }
      } else {
        final Thread thisThread = Thread.currentThread();
        WindowAdapter l = new WindowAdapter() {
          public void windowActivated(WindowEvent e) {
            thisThread.interrupt();
          }
        };
        MainWindow.this.addWindowListener(l);
        try {
          Calendar endTimeout = Calendar.getInstance();
          endTimeout.add(Calendar.SECOND, timeout);
          while (true) {
            Calendar now = Calendar.getInstance();
            if (!now.before(endTimeout)) {
              break;
            }
            long millis = endTimeout.getTimeInMillis()
                - now.getTimeInMillis();
            assert(millis > 0);
            try {
              Thread.sleep(millis);
            } catch (InterruptedException e) {
              if (MainWindow.this.isVisible()) {
                timeout = 0;
                break;
              }
            }
          }
          if (timeout == 0) {
            continue;
          }
        } finally {
          MainWindow.this.removeWindowListener(l);
        }
        showMessages = false;
      }
      service = connect(dialog.getHost(), dialog.getUser(), dialog.getPassword(), showMessages);
      if (!dialog.isTimedOut()) {
        timeout = 0;
      }
    } while (service == null);
    return service;
  }

  private JobService connect(String host, String user, String password, boolean showMessageDialog) {
    try {
      Registry registry = LocateRegistry.getRegistry(host, JdcpUtil.DEFAULT_PORT);
      AuthenticationService authService = (AuthenticationService) registry.lookup("AuthenticationService");
      return authService.authenticate(user, password, JdcpUtil.PROTOCOL_VERSION_ID);
    } catch (LoginException e) {
      logger.error("Authentication failed.", e);
      JOptionPane.showMessageDialog(this, "Authentication failed.  Please check your user name and password.", "Connection Failed", JOptionPane.WARNING_MESSAGE);
    } catch (RemoteException e) {
      logger.error("Could not connect to remote host.", e);
      if (showMessageDialog) {
        JOptionPane.showMessageDialog(this, "Could not connect to remote host.", "Connection Failed", JOptionPane.WARNING_MESSAGE);
      }
    } catch (NotBoundException e) {
      logger.error("Could not find AuthenticationService at remote host.", e);
      if (showMessageDialog) {
        JOptionPane.showMessageDialog(this, "Could find JDCP Server at remote host.", "Connection Failed", JOptionPane.WARNING_MESSAGE);
      }
    } catch (ProtocolVersionException e) {
      logger.error("Client is incompatible with the remote server.", e);
      if (showMessageDialog) {
        JOptionPane.showMessageDialog(this, "This client is incompatible with the remote server.  Please update the client and try again.", "Incompatible Client", JOptionPane.WARNING_MESSAGE);
      }
    }
    return null;
  }

  /**
   * Start the worker thread.
   */
  private void startWorker() {
    JobServiceFactory serviceFactory = new JobServiceFactory() {

      private boolean first = true;

      public JobService connect() {
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            setStatus("Connecting...");
          }
        });
        JobService service = first ? MainWindow.this.connect()
            : reconnect();
        if (service == null) {
          setVisible(false);
          throw new RuntimeException("Unable to connect");
        }
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            setStatus("Connected");
          }
        });
        first = false;
        return service;
      }
//
//      public JobService connect() {
//        try {
//          SwingUtilities.invokeAndWait(task);
//        } catch (Exception e) {
//          logger.warn("Exception thrown trying to reconnect", e);
//          throw new RuntimeException(e);
//        }
//        if (task.service == null) {
//          throw new RuntimeException("No service.");
//        }
//        return task.service;
//      }

    };

    int availableCpus = Runtime.getRuntime().availableProcessors();
    if (options.numberOfCpus < 0) {
      options.numberOfCpus = pref.getInt("maxCpus", 0);
    }
    if (options.numberOfCpus <= 0 || options.numberOfCpus > availableCpus) {
      options.numberOfCpus = availableCpus;
    }

    if (worker != null) {
      setStatus("Shutting down worker...");
      worker.shutdown();
      try {
        workerThread.join();
      } catch (InterruptedException e) {
      }
      progressPanel.clear();
    }

    setStatus("Starting worker...");

    CourtesyMonitor courtesyMonitor = (powerMonitor != null) ? powerMonitor
        : new UnconditionalCourtesyMonitor();
    ThreadFactory threadFactory = new BackgroundThreadFactory();
    worker = new ThreadServiceWorker(serviceFactory, threadFactory,
        getProgressPanel(), courtesyMonitor);
    worker.setMaxWorkers(options.numberOfCpus);

    boolean cacheClassDefinitions = pref.getBoolean("cacheClassDefinitions", true);
    if (cacheClassDefinitions) {
      setStatus("Preparing data source...");
      EmbeddedDataSource ds = null;
      try {
        Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
        ds = new EmbeddedDataSource();
        ds.setConnectionAttributes("create=true");
        ds.setDatabaseName("classes");
        worker.setDataSource(ds);
      } catch (ClassNotFoundException e) {
        logger.error("Could not locate database driver.", e);
      } catch (SQLException e) {
        logger.error("Error occurred while initializing data source.", e);
      }
    }

    onPreferencesChanged();

    workerThread = new Thread(worker);
    workerThread.start();

  }

  private void setStatus(final String status) {
    statusLabel.setText(" " + status);
  }

  /**
   * This method initializes jContentPane
   *
   * @return javax.swing.JPanel
   */
  private JPanel getJContentPane() {
    if (jContentPane == null) {
      statusLabel = new JLabel();
      statusLabel.setText(" ");
      jContentPane = new JPanel();
      jContentPane.setLayout(new BorderLayout());
      jContentPane.add(getJSplitPane(), BorderLayout.CENTER);
      jContentPane.add(statusLabel, BorderLayout.SOUTH);
    }
    return jContentPane;
  }

  private ConnectionDialog getConnectionDialog() {
    if (connectionDialog == null) {
      connectionDialog = new ConnectionDialog(this);
    }
    return connectionDialog;
  }

  public void connectConsole() {
    Document document = getConsolePane().getDocument();

    System.setOut(new PrintStream(new DocumentOutputStream(document, SimpleAttributeSet.EMPTY)));

    MutableAttributeSet attributes = new SimpleAttributeSet();
    StyleConstants.setForeground(attributes, Color.RED);
    System.setErr(new PrintStream(new DocumentOutputStream(document, attributes)));
  }

}
TOP

Related Classes of ca.eandb.jdcp.worker.MainWindow$Options

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.