View Part 2 - Validate Run Mode OptionsJ8 Home « View Part 2 - Validate Run Mode Options
In our final section on coding the case study we complete the view code elements. We start the section by coding the RunModeDialog
class which creates a dialog box to accept and
validate run mode options for the Manufacturer application.
Validate Run Mode Options Top
In the first part of the lesson we code up the RunModeDialog
class which creates a dialog box to accept and validate run mode options for the Manufacturer application. The class
provides a standard dialog box which allows the user to select the location of the file (which may be a physical file in NON_NETWORK_CLIENT
mode, or the address (and, optionally, the
port) of the server for NETWORK_CLIENT
mode. The class implements the observer class which means it wants to be informed of changes in observable objects, which in our case is changes
to the values in the panel of the RunModeOptions
class.
Creating The RunModeDialog
Class Top
The RunModeDialog
class creates a dialog box to accept and validate run mode options for the Manufacturer application. This class provides a standard dialog box which allows the user
to select the location of the file (which may be a physical file in NON_NETWORK_CLIENT mode, or the address (and, optionally, the port) of the server for NETWORK_CLIENT mode. This class implements
the Observer
interface. What this means is that class will be notified whenever changes are made within the run mode options panel of the RunModeOptions
class, as that class
has an inner class that extends the java.util.Observable
class; which represents an observable object, or "data" in the model-view paradigm.
These classes are based on the Observer pattern where the subject, in this case RunModeOptions
can have many observers which for us means the RunModeDialog
class.
We extend the WindowAdapter
class so we can action a callback method when a WindowEvent
has been actioned by the user. In our case an event handler to process situations
where the user has closed the window rather than clicking one of the buttons. See the windowClosing()
method for details.
Create the RunModeDialog
class in the client
package and cut and paste the following code into it.
package client;
import java.awt.Frame;
import java.awt.event.*;
import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Observable;
import java.util.Observer;
import java.util.logging.*;
import javax.swing.*;
/**
* Dialog box to accept and validate run mode options for the Manufacturer application.
* This class provides a standard dialog box which allows the user to select the location
* of the file (which may be a physical file in NON_NETWORK_CLIENT mode, or the address
* (and, optionally, the port) of the server for NETWORK_CLIENT mode.
*/
public class RunModeDialog extends WindowAdapter implements ActionListener, Observer {
/**
* The Logger instance. All log messages from this class are routed through
* this member. The Logger namespace is J8CaseStudy
.
*/
private static Logger log = Logger.getLogger("J8CaseStudy");
/*
* The strings for the title and buttons in the dialog box.
*/
private static final String TITLE = "Please enter Manufacturer file location";
private static final String CONNECT = "Connect";
private static final String EXIT = "Exit";
/*
* Some port range values to help determine what sort of port was specified.
*/
private static final int LOWEST_PORT = 0;
private static final int HIGHEST_PORT = 65535;
private static final int SYSTEM_PORT_BOUNDARY = 1024;
/*
* Global components for our dialog box that we can disable / enable
* as a user enters valid information.
*/
private JOptionPane options;
private JDialog dialog;
private JButton connectButton = new JButton(CONNECT);
private JButton exitButton = new JButton(EXIT);
/*
* Common panel used by both the client and the server for
* specifying file location.
*/
private RunModeOptions runModeOptions;
/*
* Flags to validate application startup.
*/
private boolean validFilePathName = false;
private boolean validPort = false;
/*
* Details specified in the RunModeOptions pane detailing where the file is.
*/
private String filePathName;
private String port = null;
/**
* Creates a dialog where the user can specify the location of the
* file, and IP address and port number(networked client), or
* search and select the file on a local drive if this is a
* non-networked client.
*
* @param parent Defines the Component that is used as the parent of this
* dialog box.
* @param userMode Specifies the type of connection (non-networked or networked)
* @see JOptionPane
*/
public RunModeDialog(Frame parent, RunMode userMode) {
log.entering("RunModeDialog", "RunModeDialog");
runModeOptions = (new RunModeOptions(userMode));
runModeOptions.getObservable().addObserver(this);
// Load saved configuration
SavedRunModeOptions savedRunModeOptions =
SavedRunModeOptions.getSavedRunModeInstance();
// Port not required for stand alone mode
if (userMode == RunMode.NON_NETWORK_CLIENT) {
validPort = true;
filePathName = savedRunModeOptions.getParameter(SavedRunModeOptions.FILE_LOCATION);
} else {
/*
* There is always at least a default port number, so we don't have
* to validate this.
*/
port = savedRunModeOptions.getParameter(SavedRunModeOptions.SERVER_PORT);
runModeOptions.setPortNumberText(port);
validPort = true;
filePathName = savedRunModeOptions.getParameter(SavedRunModeOptions.SERVER_ADDRESS);
}
/*
* There may not be a default file location, so we had better
* validate before using the returned value.
*/
if (filePathName != null) {
runModeOptions.setLocationFieldText(filePathName);
validFilePathName = true;
}
options = new JOptionPane(runModeOptions, JOptionPane.QUESTION_MESSAGE,
JOptionPane.OK_CANCEL_OPTION);
connectButton.setActionCommand(CONNECT);
connectButton.addActionListener(this);
boolean allValid = validFilePathName && validPort;
connectButton.setEnabled(allValid);
exitButton.setActionCommand(EXIT);
exitButton.addActionListener(this);
options.setOptions(new Object[] {connectButton, exitButton});
dialog = options.createDialog(parent, TITLE);
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
dialog.addWindowListener(this);
dialog.setVisible(true);
log.exiting("RunModeDialog", "RunModeDialog");
}
/*
* Callback methods.
*/
/**
* Callback event handler to process situations where the user has closed
* the window rather than clicking one of the buttons.
*/
public void windowClosing(WindowEvent we) {
log.entering("RunModeDialog", "windowClosing");
log.exiting("RunModeDialog", "windowClosing");
processCommand(EXIT);
}
/**
* Callback event handler to process clicks on any of the buttons.
*/
public void actionPerformed(ActionEvent ae) {
log.entering("RunModeDialog", "actionPerformed");
processCommand(ae.getActionCommand());
log.exiting("RunModeDialog", "actionPerformed");
}
/**
* Common event handling code - can handle desirable actions (such as
* buttons being clicked) and undesirable actions (the window being
* closed) all in a common location.
*
* @param command a String representing the action that occurred.
*/
private void processCommand(String command) {
log.entering("RunModeDialog", "processCommand");
dialog.setVisible(false);
if (CONNECT.equals(command)) {
options.setValue(JOptionPane.OK_OPTION);
} else {
options.setValue(JOptionPane.CANCEL_OPTION);
}
log.exiting("RunModeDialog", "processCommand");
}
/**
* Let the caller of this dialog know whether the user connected or
* cancelled.
*
* @return true if the user cancelled or closed the window.
*/
public boolean userCancelled() {
if (options.getValue() instanceof Integer) {
int status = (Integer) options.getValue();
return status != JOptionPane.OK_OPTION;
} else {
return false;
}
}
/**
* Callback method to process modifications in the common RunModeOptions
* panel. RunModeOptions sends updates to registered Observers whenever
* anything changes. When something changes we validate here and if
* changes are valid we enable the "Connect" button of the dialog box.
*/
public void update(Observable o, Object arg) {
log.entering("RunModeDialog", "update");
/*
* we are going to ignore the Observable object, since we are only
* observing one object. All we are interested in is the argument.
*/
if (!(arg instanceof RunModeOptionsUpdate)) {
log.log(Level.WARNING, "Run Mode Dialog received update type: "
+ arg, new IllegalArgumentException());
return;
}
RunModeOptionsUpdate runModeOptionsUpdate = (RunModeOptionsUpdate) arg;
// Load saved configuration
SavedRunModeOptions savedRunModeOptions =
SavedRunModeOptions.getSavedRunModeInstance();
// Process changes
switch (runModeOptionsUpdate.getUpdateType()) {
case FILE_LOCATION_MODIFIED:
filePathName = (String) runModeOptionsUpdate.getPayload();
if (runModeOptions.getApplicationMode()
== RunMode.NON_NETWORK_CLIENT) {
File f = new File(filePathName);
if (f.exists() && f.canRead() && f.canWrite()) {
validFilePathName = true;
log.info("File chosen " + filePathName);
savedRunModeOptions.setParameter
(SavedRunModeOptions.FILE_LOCATION,
filePathName);
} else {
log.warning("Invalid file " + filePathName);
}
} else {
try {
if (filePathName.matches("\\d+\\.\\d+\\.\\d+\\.\\d+")) {
String[] quads = filePathName.split("\\.");
byte[] address = new byte[quads.length];
for (int i = 0; i < quads.length; i++) {
address[i] = new Integer(quads[i]).byteValue();
}
InetAddress.getByAddress(address);
} else {
InetAddress.getAllByName(filePathName);
}
log.info("Server specified " + filePathName);
validFilePathName = true;
savedRunModeOptions.setParameter(SavedRunModeOptions.SERVER_ADDRESS,
filePathName);
} catch (UnknownHostException uhe) {
log.warning("Unknown host: " + filePathName);
validFilePathName = false;
}
}
break;
case PORT_MODIFIED:
port = (String) runModeOptionsUpdate.getPayload();
int p = Integer.parseInt(port);
// Log an info message for port numbers
if (p >= LOWEST_PORT && p < HIGHEST_PORT) {
if (p < SYSTEM_PORT_BOUNDARY) {
log.info("User chose System port " + port);
} else {
log.info("User chose dynamic port " + port);
}
validPort = true;
savedRunModeOptions.setParameter(SavedRunModeOptions.SERVER_PORT, port);
} else {
validPort = false;
}
break;
default:
log.warning("Unknown update: " + runModeOptionsUpdate);
break;
}
boolean allValid = validFilePathName && validPort;
connectButton.setEnabled(allValid);
log.exiting("RunModeDialog", "update");
}
/*
* Getter methods.
*/
/**
* Returns the location of the file, which may be either the path to
* the local file, or the address of the network server hosting the
* file.
*
* @return The location of the file.
*/
public String getLocation() {
log.entering("RunModeDialog", "getLocation");
log.exiting("RunModeDialog", "getLocation", this.filePathName);
return this.filePathName;
}
/**
* Returns the port number the network server should be listening on for
* client connections.
*
* @return The port number for connecting to the network server.
*/
public String getPort() {
log.entering("RunModeDialog", "getPort");
log.exiting("RunModeDialog", "getPort", this.port);
return this.port;
}
}
The following screenshot shows the client
package structure after adding the RunModeDialog
class.
Lesson 15 Complete
In this lesson we coded the View elements of the MVC pattern that relate to the run mode options.
Related Java Tutorials
Fundamentals - Primitive Variables
Fundamentals - if
Construct
Fundamentals - switch
Construct
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
OO Concepts - Inheritance Concepts - Using the super
keyword
Exceptions - Handling Exceptions
API Contents - Inheritance - Using the package
keyword
API Contents - Inheritance - Using the import
keyword
API Contents - Java I/O Overview - The java.io.File
Class
Swing - Containers - The javax.swing.JFrame
Class
Swing - Event Handling - Using the ActionListener
Interface
Swing - Dialogs
Swing - Components
What's Next?
In the next lesson we code the View elements of the MVC pattern that relate to the server.