Startup & Run Mode OptionsHomepage  « Case Study « Startup & Run Mode Options

In our final lesson of the section we look at the code for the Manufacturer application startup and also the saved run mode / run mode options.

Compiling The ManufacturerApplicationStartup Classgo to top of page Top

The ManufacturerApplicationStartup class initiates a log for the whole application, verifies the "look and feel" of the Manufacturer application and validates the run mode entered by the user.

Cut and paste the following code into your text editor and save it in the   c:\_Case_Study\src\client directory.


package client;

import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.*;

import java.io.IOException;
import java.util.logging.*;

/**
 * The Manufacturer Application startup that initiates a log for the whole application,
 * verifies the "look and feel" of the application and validates the run mode entered
 * by the user.
 * 
 * @author Kevin 
 * @version 1.0
 *
 */
public class ManufacturerApplicationStartup {
    /**
     * The Logger instance through which all log messages from this class are
     * routed. Logger namespace is s2cCaseStudy.
     */
    private static Logger log = Logger.getLogger("s2cCaseStudy"); // Log output

    /**
     * The main method to startup the Manufacturer Application.
     *
     */
    public static void main(String[] args) {
    	new ManufacturerApplicationStartup(args);
    }

    /**
     * Sets up a logger for the whole application, the default Swing look 
     * and feel and then passes control to either the ServerStartupWindow
     * class or the ManufacturerWindow class dependent on command line arguments
     * entered by the user.
     *
     * @param args The mode the user wishes to start the application in.
     * 
     *  ""        Start application in networked client mode. 
     *  "client"  Start application in non-networked client mode.
     *  "server"  Start application in server mode.
     */
    public ManufacturerApplicationStartup(String[] args) {
        /*
         * Setup a rotating file in default user directory for machine that will 
    	 * handle logs for the whole application
         */
        try {
            FileHandler manufacturerFileHandler = 
                    new FileHandler("C:\\_Case_Study\\s2cCaseStudy%g.log", 0, 10);
            manufacturerFileHandler.setFormatter(new SimpleFormatter());
            Logger log = Logger.getLogger("s2cCaseStudy");
            log.addHandler(manufacturerFileHandler);
            log.setLevel(Level.FINEST);
        } catch (IOException e) {
            log.log(Level.SEVERE, e.getMessage(), e);
        }
        log.entering("ManufacturerApplicationStartup", "ManufacturerApplicationStartup", args);
        // Try to set default Swing "look and feel" for this machine
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (UnsupportedLookAndFeelException uex) {
            log.log(Level.SEVERE, uex.getMessage(), uex);
        } catch (ClassNotFoundException cex) {
            log.log(Level.SEVERE, cex.getMessage(), cex);
        } catch (InstantiationException iex) {
            log.log(Level.SEVERE, iex.getMessage(), iex);
        } catch (IllegalAccessException iaex) {
            log.log(Level.SEVERE, iaex.getMessage(), iaex);
        }
        if (args.length == 0 || "client".equalsIgnoreCase(args[0])) {
            // Create an instance of the Manufacturer application window
            // Uncomment instantiation and remove println in View Part 2
            // new ManufacturerWindow(args);
            System.out.println("Client mode:");
        } else if ("server".equalsIgnoreCase(args[0])) {
            // Create an instance of the Manufacturer server startup application window
            // Uncomment instantiation and remove println in View Part 2
            // new ManufacturerServerStartupWindow();
            System.out.println("Server mode:");
        } else {
            /*
             * Invalid run mode entered on command line, so send error message 
             * information to the error output (usually the screen).
             */
            System.err.println("Command line run mode options are:");
            System.err.println("\"\" - (no command line option): starts networked client");
            System.err.println("\"client\"  - starts non-networked client");
            System.err.println("\"server\" - starts Manufacturer server application");
        }
        log.exiting("ManufacturerApplicationStartup", "ManufacturerApplicationStartup");
    }

    /**
     * Prompts the user with an error message in a centred alert window.
     *
     * @param msg The message to display in the error window.
     */
    public static void handleException(String msg) {
        JOptionPane alert = new JOptionPane(msg, JOptionPane.ERROR_MESSAGE,
                                JOptionPane.DEFAULT_OPTION);
        JDialog dialog = alert.createDialog(null, "Alert");
        // Display alert error screen in centre of window
        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        int x = (int) ((d.getWidth() - dialog.getWidth()) / 2);
        int y = (int) ((d.getHeight() - dialog.getHeight()) / 2);
        dialog.setLocation(x, y);
        dialog.setVisible(true);
    }
}

Compiling Our Source File With the -cp and -d Options

Open your command line editor:

Change to directory  cd c:\_Case_Study\src\client

Compile ManufacturerApplicationStartup.java using the java compiler with the -cp and -d options
  javac -cp ..\..\classes -d ..\..\classes ManufacturerApplicationStartup.java

Compiling The SavedRunModeOptions Classgo to top of page Top

The SavedRunModeOptions class provides read/write access to the user's saved run mode parameters on disk, so that next time they connect, we can offer the same run mode parameters as a default.


package client;

import java.io.*;
import java.util.*;
import java.util.logging.Logger;

/**
 * Provides read/write access to the user's saved run mode parameters on  disk, so 
 * that next time they connect, we can offer the same run mode parameters as a default.
 *
 */
public class SavedRunModeOptions {
    /**
     * The Logger instance. All log messages from this class are routed through
     * this member. The Logger namespace is s2cCaseStudy.
     */
    private static Logger log = Logger.getLogger("s2cCaseStudy"); // Log output

    /**
     * Key in Properties indicating that the value will be the manufacturer
     * file location.
     */
    public static final String FILE_LOCATION = "FileLocation";

    /**
     * Key in Properties indicating that the value will be the RMI Registry
     * server address.
     */
    public static final String SERVER_ADDRESS = "ServerAddress";

    /**
     * Key in Properties indicating that the value will be the port the RMI
     * registry listens on.
     */
    public static final String SERVER_PORT = "ServerPort";

    /**
     * The location where our SavedRunModeOptions file will be saved.
     */
    private static final String BASE_DIRECTORY = System.getProperty("user.dir");

    /**
     * the name of our properties file.
     */
    private static final String OPTIONS_FILENAME = "manufacturer.properties";

    /**
     * The file containing our saved run mode options.
     */
    private static File savedRunModeOptionsFile = new File(BASE_DIRECTORY, OPTIONS_FILENAME);

    /**
     * Only create SavedRunModeOptions Singleton first time through using double-checked 
     * locking to ensure private constructor is only synchronised once.
     */
    private volatile static SavedRunModeOptions uniqueSavedRunModeInstance;

    /**
     * The Properties for this application.
     */
    private Properties parameters = null;

    /**
     * Creates a new instance of SavedRunModeOptions. There should only ever be
     * one instance of this class (a Singleton), so we have made it private.
     */
    private SavedRunModeOptions() {
        log.entering("SavedRunModeOptions", "SavedRunModeOptions");
        parameters = loadParametersFromFile();

        if (parameters == null) {
            parameters = new Properties();
            parameters.setProperty(SERVER_ADDRESS, "localhost");
            parameters.setProperty(SERVER_PORT, "" + java.rmi.registry.Registry.REGISTRY_PORT);
        }
        log.exiting("SavedRunModeOptions", "SavedRunModeOptions");
    }

    /**
     * Clients of the SavedRunModeOptions class have to call this method to get the unique
     * instance (singleton) for this class as the constructor is private.
     * 
     * @return The singleton for SavedRunModeOptions class.
     */
    public static SavedRunModeOptions getSavedRunModeInstance() {
        if (uniqueSavedRunModeInstance == null) {
            synchronized (SavedRunModeOptions.class) {
                if (uniqueSavedRunModeInstance == null) {
                    uniqueSavedRunModeInstance = new SavedRunModeOptions();
                }
            }
        }
        return uniqueSavedRunModeInstance;
    }

    /**
     * Returns the value of the named parameter.
     * 
     * @param parameterName The name of the run mode parameter.
     * @return The value of the named run mode parameter.
     */
    public String getParameter(String parameterName) {
        log.entering("SavedRunModeOptions", "getParameter", parameterName);
        log.exiting("SavedRunModeOptions", "getParameter", parameters.getProperty(parameterName));
        return parameters.getProperty(parameterName);
    }

    /**
     * Updates the saved run mode parameters with the new values. 
     * 
     * @param parameterName The name of the run mode parameter.
     * @param parameterValue The value run mode parameter to be stored.
     */
    public void setParameter(String parameterName, String parameterValue) {
        log.entering("SavedRunModeOptions", "setParameter", 
                new Object[] {parameterName, parameterValue});
        parameters.setProperty(parameterName, parameterValue);
        saveParametersToFile();
        log.exiting("SavedRunModeOptions", "setParameter");
    }

    /**
     * Saves the parameters to a file so that they can be used again next time
     * the application starts.
     */
    private void saveParametersToFile() {
         log.entering("SavedRunModeOptions", "saveParametersToFile");

        try {
            synchronized (savedRunModeOptionsFile) {
                if (savedRunModeOptionsFile.exists()) {
                    savedRunModeOptionsFile.delete();
                }
                savedRunModeOptionsFile.createNewFile();
                FileOutputStream fos = new FileOutputStream(savedRunModeOptionsFile);
                parameters.store(fos, "Manufacturer Application run mode options");
                fos.close();
            }
        } catch (IOException e) {
            ManufacturerApplicationStartup.handleException("Unable to save run mode parameters"
                    + " to file. They wont be remembered next time you start.");
        }
    log.exiting("SavedRunModeOptions", "saveParametersToFile");
    }

    /**
     * Attempts to load the saved run mode parameter from the file so that the user does
     * not have to reenter all the information.
     * 
     * @return Properties loaded from file or null.
     */
    private Properties loadParametersFromFile() {
        log.entering("SavedRunModeOptions", "loadParametersFromFile");

        Properties loadedProperties = null;

        if (savedRunModeOptionsFile.exists() && savedRunModeOptionsFile.canRead()) {
            synchronized (savedRunModeOptionsFile) {
                try {
                    FileInputStream fis = new FileInputStream(savedRunModeOptionsFile);
                    loadedProperties = new Properties();
                    loadedProperties.load(fis);
                    fis.close();
               } catch (FileNotFoundException e) {
                    ManufacturerApplicationStartup.handleException("Unable to load run mode "
                            + "parameters. Default values will be used.\n" + e);
               } catch (IOException e) {
                    ManufacturerApplicationStartup.handleException("Unable to load run mode "
	                        + "parameters. Default values will be used.\n" + e);
               }
            }
        }
        log.exiting("SavedRunModeOptions", "loadParametersFromFile", loadedProperties);
        return loadedProperties;
    }
}

Compiling Our Source File With the -cp and -d Options

Open your command line editor:

Change to directory  cd c:\_Case_Study\src\client

Compile SavedRunModeOptions .java using the java compiler with the -cp and -d options
  javac -cp ..\..\classes -d ..\..\classes SavedRunModeOptions .java

Compiling The RunModeOptions Classgo to top of page Top

The RunModeOptions class creates a common panel used by both the client and server applications to specify the run mode options. The panel changes slightly dependent on run mode entered on application startup but has a "common feel" for all three run modes. A point of interest here is that we create an inner class that extends the java.util.Observable class; This class represents an observable object, or "data" in the model-view paradigm. An observable object can have one or more observers, which are objects that implements the Observer interface. What this means for the case study is that the RunModeDialog class which we will code in the View Part 2 - Validate Run Mode Options lesson will be notified whenever changes are made within the run mode options panel, so they can be validated within that dialog.

Cut and paste the following code into your text editor and save it in the   c:\_Case_Study\src\client directory.


package client;

import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.logging.Logger;
import java.util.Observable;
import javax.swing.*;

/**
 * A common panel used by both the client and server applications to specify the
 * run mode options. The panel changes slightly dependent on run mode entered
 * on application startup but has a "common feel" for all three run modes.
 * 
 * @see RunMode
 * 
 */
public class RunModeOptions extends JPanel {
    /**
     * The Logger instance. All log messages from this class are routed through
     * this member. The Logger namespace is s2cCaseStudy.
     */
    private static Logger log = Logger.getLogger("s2cCaseStudy"); // Log output

    /**
     * A version number for the RunModeOptions class so that serialisation can
     * occur without worrying about the underlying class changing between
     * serialisation and deserialisation.
     */
    private static final long serialVersionUID = 871964L;

    // Constants.
    private static final String FILE_LOCATION_LABEL = "Manufacturer file location: ";
    private static final String SERVER_PORT_LABEL = "Server port: ";
    private static final String FILE_LOCATION_TOOL_TIP
            = "The location of the Manufacturer file on the hard drive";
    private static final String FILE_IP_LOCATION_TOOL_TIP
            = "The server where the Manufacturer file is located (IP address)";
    private static final String SERVER_PORT_TOOL_TIP
            = "The port number the Server uses to listens for requests";
    private static final String FILE_EXTENSION = "txt";
    private static final String FILE_CHOOSER_DESCRIPTION
            = "Database files (*." + FILE_EXTENSION + ")";

    /**
     * An Observable class so interested users of this class can receive
     * automatic updates whenever run mode options change.
     */
    private RunModeObservable observerRunModeOptions = new RunModeObservable();

    // User modifiable fields and all buttons are defined here.
    private JTextField locationField = new JTextField(40);
    private JButton browseButton = new JButton("...");
    private JTextField portNumber = new PositiveIntVerify(5);

    private String location = null;
    private String port = null;
    private RunMode runMode = RunMode.NON_NETWORK_CLIENT;

    /**
     * Creates a new instance of RunModeOptions - the panel for configuring
     * database connectivity.
     *
     * @param runMode One of NON_NETWORK_CLIENT,
     * NETWORK_CLIENT, or SERVER.
     * 
     * @see RunMode
     */
    public RunModeOptions(RunMode runMode) {
        super();
        log.entering("RunModeOptions", "RunModeOptions");
        this.runMode = runMode;

        GridBagLayout gridbag = new GridBagLayout();
        GridBagConstraints constraints = new GridBagConstraints();
        this.setLayout(gridbag);
        /*
         * Standard options
         * Ensure there is always a gap between components
         */
        constraints.insets = new Insets(3, 3, 3, 3);
        // Build the Manufacturer file location row
        JLabel dbLocationLabel = new JLabel(FILE_LOCATION_LABEL);
        gridbag.setConstraints(dbLocationLabel, constraints);
        this.add(dbLocationLabel);

        if (runMode == RunMode.NETWORK_CLIENT) {
            locationField.setToolTipText(FILE_IP_LOCATION_TOOL_TIP);
            constraints.gridwidth = GridBagConstraints.REMAINDER;  //end row
        } else {
            locationField.setToolTipText(FILE_LOCATION_TOOL_TIP); //next-to-last in row
            constraints.gridwidth = GridBagConstraints.RELATIVE;
        }
        locationField.addFocusListener(new ActionHandler());
        locationField.setName(FILE_LOCATION_LABEL);
        gridbag.setConstraints(locationField, constraints);
        this.add(locationField);
        /*
         *  Add a browse button to allow navigation to the Manufacturer file
         *  in Server and non-network client modes. 
         */
        if ((runMode == RunMode.SERVER)
                || (runMode == RunMode.NON_NETWORK_CLIENT)) {
            browseButton.addActionListener(new BrowseForFile());
            constraints.gridwidth = GridBagConstraints.REMAINDER; //end row
            gridbag.setConstraints(browseButton, constraints);
            this.add(browseButton);
        }
        if ((runMode == RunMode.SERVER)
                || (runMode == RunMode.NETWORK_CLIENT)) {
            // Build the Server port row if applicable
            constraints.weightx = 0.0;
            JLabel serverPortLabel = new JLabel(SERVER_PORT_LABEL);
            constraints.gridwidth = 1;
            constraints.anchor = GridBagConstraints.EAST;
            gridbag.setConstraints(serverPortLabel, constraints);
            this.add(serverPortLabel);
            portNumber.addFocusListener(new ActionHandler());
            portNumber.setToolTipText(SERVER_PORT_TOOL_TIP);
            portNumber.setName(SERVER_PORT_LABEL);
            constraints.gridwidth = GridBagConstraints.REMAINDER; //end row
            constraints.anchor = GridBagConstraints.WEST;
            gridbag.setConstraints(portNumber, constraints);
            this.add(portNumber);
        }
        log.exiting("RunModeOptions", "RunModeOptions");
    }

    /**
     * Utility method to inform our observers of any changes the user makes to
     * the parameters on screen.
     *
     * @param updateType Enum specify which field has changed
     * @param payLoad the new data the user just entered.
     */
    private void updateObservers(RunModeOptionsUpdate.Update updateType, Object payLoad) {
		log.entering("RunModeOptions", "updateObservers");
		RunModeOptionsUpdate update = new RunModeOptionsUpdate(updateType, payLoad);
        observerRunModeOptions.setChanged();
        observerRunModeOptions.notifyObservers(update);
        log.exiting("RunModeOptions", "updateObservers");
    }

    /**
     * A utility class to handle user interactions with the panel. These are
     * not processed by the user of this panel, rather they are processed
     * internally, and an update is then sent to any observers.
     */
    private class ActionHandler implements FocusListener {
        /** {@inheritDoc} */
        public void focusGained(FocusEvent e) {
            // ignored - we don't do anything special when users enter a field
        }

        /** {@inheritDoc} */
        public void focusLost(FocusEvent e) {
            if (FILE_LOCATION_LABEL.equals(e.getComponent().getName())
                    && (!locationField.getText().equals(location))) {
                location = locationField.getText();
                updateObservers(RunModeOptionsUpdate.Update.FILE_LOCATION_MODIFIED,
                                location.trim());
            }
            if (SERVER_PORT_LABEL.equals(e.getComponent().getName())
                    && (!portNumber.getText().equals(port))) {
                port = portNumber.getText();
                updateObservers(RunModeOptionsUpdate.Update.PORT_MODIFIED, port.trim());
            }
        }
    }

    /**
     * A utility class that provides the user with the ability to browse for
     * the Manufacturer file rather than forcing them to remember (and type in) 
     * a fully qualified Manufacturer file location.
     */
    private class BrowseForFile implements ActionListener {
        /** {@inheritDoc} */
        public void actionPerformed(ActionEvent ae) {
        JFileChooser chooser = new JFileChooser(System.getProperty("user.dir"));
            chooser.addChoosableFileFilter(
                new javax.swing.filechooser.FileFilter() {
                    /**
                     * display files ending in ".txt" or any other object
                     * (directory or other selectable device).
                     */
                    public boolean accept(File f) {
                        if (f.isFile()) {
                            return f.getName().endsWith(FILE_EXTENSION);
                        } else {
                            return true;
                        }
                    }
                    /**
                     * provide a description for the types of files we are
                     * allowing to be selected.
                     */
                    public String getDescription() {
                        return FILE_CHOOSER_DESCRIPTION;
                    }
                }
            );

            // if the user selected a file, update the file name on screen
            if (JFileChooser.APPROVE_OPTION == chooser.showOpenDialog(null)) {
                locationField.setText(chooser.getSelectedFile().toString());
                location = locationField.getText();
                updateObservers(RunModeOptionsUpdate.Update.FILE_LOCATION_MODIFIED,
                                location.trim());
            }
        }
    }

    /**
     * Returns the run mode the Manufacturer application will be running in.
     * 
     * @return The run mode the Manufacturer application will be running in.
     * @see RunMode
     */
    public RunMode getApplicationMode() {
        log.entering("RunModeOptions", "getApplicationMode");
        log.exiting("RunModeOptions", "getApplicationMode", this.runMode);
        return this.runMode;
    }

    /**
     * Returns the contents of the Manufacturer location field.
     * 
     * @return the contents of the Manufacturer location field.
     */
    public String getLocationFieldText() {
        log.entering("RunModeOptions", "getLocationFieldText");
        log.exiting("RunModeOptions", "getLocationFieldText", locationField.getText());
        return locationField.getText();
    }

    /**
     * Sets the contents of the Manufacturer location field.
     *
     * @param locationField the contents of the database location field.
     */
    public void setLocationFieldText(String locationField) {
        log.entering("RunModeOptions", "setLocationFieldText", locationField);
        this.locationField.setText(locationField);
        log.exiting("RunModeOptions", "setLocationFieldText");
    }

    /**
     * Configures whether the location field is enabled or not.
     *
     * @param enabled true if the location field is enabled.
     */
    public void setLocationFieldEnabled(boolean enabled) {
        log.entering("RunModeOptions", "setLocationFieldEnabled", enabled);
        this.locationField.setEnabled(enabled);
        log.exiting("RunModeOptions", "setLocationFieldEnabled");
    }

    /**
     * Configures whether the browse button is enabled or not.
     *
     * @param enabled true if the browse button is enabled.
     */
    public void setBrowseButtonEnabled(boolean enabled) {
        log.entering("RunModeOptions", "setBrowseButtonEnabled", enabled);
        this.browseButton.setEnabled(enabled);
        log.exiting("RunModeOptions", "setBrowseButtonEnabled");
    }

    /**
     * Returns the contents of the port number text field.
     *
     * @return the contents of the port number text field.
     */
    public String getPortNumberText() {
        log.entering("RunModeOptions", "getPortNumberText");
        log.exiting("RunModeOptions", "getPortNumberText", portNumber.getText());
        return portNumber.getText();
    }

    /**
     * Sets the contents of the port number text field.
     *
     * @param portNumber the contents of the port number text field.
     */
    public void setPortNumberText(String portNumber) {
        log.entering("RunModeOptions", "setPortNumberText", portNumber);
        this.portNumber.setText(portNumber);
        log.exiting("RunModeOptions", "setPortNumberText");
    }

    /**
     * Configures whether the port number field is enabled or not.
     *
     * @param enabled true if the port number field is enabled.
     */
    public void setPortNumberEnabled(boolean enabled) {
        log.entering("RunModeOptions", "setPortNumberEnabled", enabled);
        this.portNumber.setEnabled(enabled);
        log.exiting("RunModeOptions", "setPortNumberEnabled");
    }

    /**
     * Returns an instance of the Observable class. Observers can
     * register themselves with this class in order to receive updates as
     * things change within this panel.
     *
     * @return an instance of the Observable class.
     */
    public Observable getObservable() {
        log.entering("RunModeOptions", "getObservable");
        log.exiting("RunModeOptions", "getObservable", observerRunModeOptions);
        return observerRunModeOptions;
    }

    /**
     * Our Observable class - a class that Observers can register themselves
     * with in order to receive updates as things change within this panel.
     */
    private class RunModeObservable extends Observable {
        /** {@inheritDoc} */
        public void setChanged() {
            super.setChanged();
        }
    }
}

Compiling Our Source File With the -cp and -d Options

Open your command line editor:

Change to directory  cd c:\_Case_Study\src\client

Compile RunModeOptions.java using the java compiler with the -cp and -d options
  javac -cp ..\..\classes -d ..\..\classes RunModeOptions.java

The following screenshot shows that we get a clean compile on the above classes and also the ManufacturerApplication, SavedRunModeOptions and RunModeOptions classes are now compiled into the classes\client directory.

compile Startup Runmode

Related Java6 Tutorials

Objects & Classes - Arrays
Objects & Classes - Class Structure and Syntax
Objects & Classes - Reference Variables
Objects & Classes - Methods
Objects & Classes - Instance Variables & Scope
Objects & Classes - Constructors
Objects & Classes - Static Members
Objects & Classes - Enumerations
OO Concepts - Encapsulation
Swing - RMI - Serialization


What's Next?

In the next section of the site we do the first part of the controller code for the case study.

go to home page Homepage go to home page Top