Previous Page TOC Next Page See Page



10


The Order Entry System: Exception Handling and Browser Interaction


by Michael Girdley

Many languages do not have built-in capabilities to allow you to detect and deal with errors and mishaps efficiently. Luckily, Java gives you ways to handle these problems simply and effectively.

This chapter explores the process of handling exceptions and errors. In other words, you'll plan on a certain progression through your code, but you also will implement code that will cover situations when things don't go your way. One such instance when things don't go right generates an exception called ClassNotFoundException. This, of course, is generated when the runtime looks for a class and cannot find it.

Different types of mishaps are defined in the Java libraries, each in separate classes. Each of these separate classes describes what kind of mishap occurs. You also can define your own Exception classes to customize how you are going to deal with something that goes awry in your program.

Handling exceptions and errors accomplishes several things. First, you want to minimize data loss. Also, you want to alert the user that something has gone wrong and try to specify exactly what went wrong as much as possible. And finally, you want get out of the program as cleanly as possible and minimize the effect this process may have on other applications or processes.

This chapter covers in-depth these concepts and the command structures to implement them.

This chapter also explores how you can get your applets to communicate and interact with the browser displaying them. You can instruct the browser to load and display a different URL, for example. The process of interacting with the browser also is covered in depth in this chapter.

Finally, you will finish up the Order Entry system in this chapter. You will add the capability to interact with the browser. You also will learn the ways you can get the information in the applet back to your server. A complete final listing is included at the end of this chapter.

Error and Exception Handling


Why should you use exceptions and error handling? The following code structure should look familiar to you if you have ever tried to "home-brew" some code to deal with what now are called exceptions:

int errcode = goGetaFile();
if (err != ALLOK) {
    // deal with things. .
} else {
    // we're cool . .
}

What's wrong with this? Well, a number of things. First, you have to recode the method used to deal with a certain type of mishap over and over. But suppose that you implement a function to handle this. So, for every different error type, you'll need to create a different function to handle the error. Second, you cannot always return an error code from a function. What if you want to handle errors that might result from a function that returns an integer? How would you set which value specifies an error? And finally, what if you have nested procedures or method calls? How are you going to deal with saving the data saved in higher level classes? The answer is that you can't. There must be a better way, and there is.

Error and exception classes, as defined in Java, enable you to safely and easily deal with situations in which you want to handle errors and abnormal occurrences. Suppose that your program calls a nonexistent method in another class, or an image cannot be loaded; these are different types of exceptions. An example of a Java error is the OutofMemoryError, which is an error resulting from a lack of necessary free memory space.

The goal of this whole process is to remove the kind of home-brewed code demonstrated earlier in this section. It should enable you to develop an easy way to identify when mishaps occur and then specify another handler function to deal with them. When an exception or error occurs, your code throws an instance of the class that defines it. It then is caught by another segment of code designed to deal with the mishap.



If you have any Ada or C++ programming experience, the exception-handling format discussed later in this chapter should be pretty familiar to you. Java is designed to extend and simplify exception and error handling. Ada has five exception classes, for example, whereas Java has more than three times that. C++ has only two types of exception classes. You also will notice that Java divides exceptions that normally are grouped into one category in other languages into two groups: exceptions and errors.

Both errors and exceptions are implemented in library classes that descend from the class Java.lang.Throwable. Figure 10.1 shows the inheritance path of the Exception and Error classes in the java.lang package.

Figure 10.1. The inheritance hierarchy of the Exception and Error classes. Notice that both are descendants of the Throwable class.

Different types of exceptions and errors are extensions of these two classes. The available Java exceptions follow:

StringIndexOutOfBoundsException

The available Java Error classes follow:

VirtualMachineError

So, why the difference between exceptions and errors? The organizational difference is needed because of the ways the different types need to be handled. Errors and the classes that derive from the Error class result from errors inside the system, such as lack of memory or some other error beyond your control. The idea in these instances is just to keep your program from crashing hard and simply to exit cleanly or figure a way around the problem. For this reason, your programming will not have to deal with these thrown Errors, because they usually are implemented by other classes that make sure those kind of errors don't occur and are handled nicely (instead of, for example, locking up the machine or crashing the operating system). In other words, you don't need to worry about handling OutofMemoryErrors, StackOverflowErrors and so on; they generally already are handled for you.

You can concentrate on handling the different types of exceptions that can rear their ugly heads during your programs. Runtime exceptions normally result from your own coding mistakes. For this reason, you should plan on incorporating this process of exception handling in order to cover for your own mistakes. This makes for much more effective and robust code.



Error handling and exception handling are implemented by the same process. They are both thrown and caught. Situations in which you will need to handle errors are very rare. Runtime exceptions are your main concern, because they are usually your fault. A number of other exceptions are available, such as ClassNotFoundException or IOException, which you may want to use only as a means to prompt the user that something in his installation or setup of your program is wrong. If you notice when you try to load an applet that is specified by your HTML document but isn't there, for example, a ClassNotFoundException is reported by Netscape.


Implementing Exception and Error Handling


What if you could just say, in an easily understood format, "Hey, I want you to try and do this stuff here and if anything goes wrong with any of the code, I want you to execute this code here to handle it." Well, that is exactly what happens in the case of handling exceptions and errors.

Four words are reserved in Java to enact the handling of Throwable objects. Remember that exceptions and errors are both descendants of the Throwable class. These four words are try, catch, finally, and throw.

Using try and catch


To implement exception handling around one specific block of code, the words try and catch are positioned in the following structure:

try {
    // Some code that might throw an exception. .
}
catch (SomeException EX)
{
    // Do something appropriate in response . .
}

So what's going on in this segment? Well, the statement says, "OK, I want you to try this code here and if anything in there throws an exception, the catch statements coming up are going to figure out what to do. If you are accessing something using the URL for that location, for example, you can use this code:

try {
    // Doing something with a URL . .
}
catch (MalformedURLException EX) {
    // Do something appropriate to deal with the problem . .
}

You also can catch multiple exceptions by using a try statement:

try {
    // Doing something  . .
        .
        .
        .
}
catch (MalformedURLException EX) {
    // Do something appropriate to deal with the problem . .
}
catch (Exception E) {
    // Do something appropriate to deal an exception in general . .
}

If some method or statement executed in the try block throws an exception, it is caught by the catch statement, which accepts the appropriate exception type and then executes the code inside its block.

Using finally


Suppose that you want some code to be executed no matter what happens in the try statement. You can use the finally clause after your try/catch block:

try {
    // Some code that might throw an exception . .
}
catch (SomeException SE) {
    // What to do if some exception is thrown. . .
} finally {
    // I want you to do this no matter what, if things go wrong or right.
}

What happens? The code in the try block is executed. If some exception is thrown, the catch statement deals with it. And then, whether things go right or wrong, the code in the finally block executes.

This code is useful, for example, if you are modifying a file on disk and you want the file to revert back to its old state without keeping any changes, regardless of what happens. The finally block includes the code (or a call to a method) to close the file and then copies the backup you designated as the main file.

The code also is useful if you are in the process of transmitting data across a network, for example. Even if everything goes right or something goes wrong, you want to alert the other computer that it should not be expecting any more data from you. The following code represents this process:

try {
    // Transmit data . .
}
catch (Error E) {
    System.out.print("Error " + E + " resulted.")
}
catch (Exception E) {
    System.out.print("Exception " + E + " resulted.");
}
finally  {
    // Tell the other computer the transmission is over . .
}

It is important to know that as soon as code in the try block generates any class descendant from Throwable, the execution of the code stops. If the thrown class is handled in the following catch, it is handled there. Otherwise, it propagates up the class line. To reiterate, when something is thrown by code in a try block, the execution of that code is halted immediately.



When catching exceptions or errors, when you specify one type of exception or error, that catch statement will catch that class along with every descendant class. For example, you might use the following code:


catch (Throwable T) {

This will deal with everything that throws any instance of the Throwable class, along with every descendant of the Throwable class (remember the Throwable inheritance hierarchy in Fig. 10.1).

Suppose that you use this code:

catch (Exception E) {

This catches instances of the Exception class, along with every descendant of that class.


Throwing Exceptions


OK, it is apparent that other classes and their methods throw exceptions, so you also want your own code and classes to be able to throw them. To throw an exception called EX, for example, you simply insert the following:

throw EX;

If you place this statement in a try block, you can catch the exception you just threw in the catch block following it:

AnException EX = new AnException();
try {
    // Something bad happens. .
    throw FX;
}
catch (AnException AnotherFX) {
    // Do something about it . .
}

Why would you want to do this? Suppose that you want to do something if a certain function returns a value of 0. You use that function in the try block, and then, if the value returned is 0, you throw the ZeroValueException. Then you catch it in the catch block and deal with it accordingly.

Using Throws


Suppose that you want to have your own class or a method throw exceptions. You would define your class as the following:

public class ThrowSomething throws SomeException {

By adding the throws to the class or method definition, you alert other classes or methods that use it that they should expect the possibility of having to catch some kind of exception from your class' execution. You also can specify that you want to alert everyone else that you might want to throw more than one type of exception. To do this, simply separate multiple exception types in the declaration with commas. The following class might throw a SomeException class or AnotherException class:

public class ThrowTwoSomethings throws SomeException, AnotherException {



Class declarations can get pretty heavy duty in Java. The following is a valid declaration:



This declares a class, CrazeeDeclaration, which can throw some exception types, is an extension of the Applet class, and implements Runnable (a declaration dealing with threads, which is covered in Chapter 16, "Multithreading with Java").



Don't go around setting all your classes and methods to throw errors and RuntimeExceptions, or any of their descendants. All the RuntimeExceptions or any of the Error class and their descendants already are handled without your intervention. You simply don't have to worry about them.

To specify when to throw an exception, simply insert the throw clause inside a class that throws an exception type. The following class demonstrates this:

public class SomeSuckerClass throws SomeException {
    // Do some stuff . .
    // More stuff . .
     // If something went wrong . .
    If (CurrentValue == BadValue) {
        SomeException SE = new SomeException ();
        throw(SE);
    }
}

What happens? The code is acted on, and then if some bad thing happens that you want to throw an exception for, you create a new instance of your extension of the Exception class and then throw it. At that point, the code execution stops, the exception is thrown, and it travels up the hierarchy until it is handled. The execution does not come back to your code, so you should expect that when you throw an exception or an error class, you aren't coming back to execute the next line of code.

So, to sum things up, you simply alert the world that you are going to throw an exception through the throw clause. Then, you create an instance of an exception and you throw it.

At times, you will want to throw your own exceptions. On these occasions, you declare your own extension of the Exception class. Notice that this was used previously when you threw an instance of AnException. The details of creating your own exception classes are covered in the next section.

Declaring Your Own Exceptions


Why do you want to declare your own instances of the Exception class? Well, there are a couple of reasons. First, if you have an exception that isn't handled adequately by any of the standard library exceptions, you can declare your own. Second, it enhances readability. But be sure not to go overboard in creating exceptions, because they easily clutter your code.

To create your own exception, simply extend the exception type or any of its descendants. Then create constructors for your class:

public class MyVeryOwnException extends Exception {
    // The constructor.
    MyVeryOwnException () {
    }
    MyVeryOwnException (String message) {
        super(message);
    }
}



Why the second constructor? It is typical practice for the descendants of the Throwable class to allow a message to be included in the class. To include a message when you declare an instance of a Throwable class (or one of its descendants), simply send a message as a parameter when you declare the class. The following code declares a MalFormedURLException and sets the message:



To retrieve the message, you can use this code:



This places the message contained in the MFURLE class into the string AString.


Using Exceptions in the Order Entry System


The first place you'll use exceptions is in the UpdateValues method. You might remember that the UpdateValues method is called whenever a change is made to the User Interface values. It recomputes the new price per item, the subtotal, and the total displayed by the applet. Listing 10.1 shows the updateValues method of the Order Entry system without the exception handling you will be adding.

Listing 10.1. The UpdateValues void code listing.

    /* This void will change all of the values to match any changes
       in the input settings. First, it declares a number of variables
       local to the method.  Then, it sets a modifier variable and a
       base price variable depending on which items are selected in the
       choice box, the list, and the slider.  Then, it inserts those
       values onto the applet panel.
    */
    private void updateValues() {
    // The index of the selected size.
            int WhichChoice = SizeChoice.getSelectedIndex();
    // The amount of items desired.
    int AmountSelected = OrderAmountSlider.getValue();
    // The index of the selected product.
    int WhichProduct = ProductList.getSelectedIndex();
    /* The initial base price and modifier.  Remember,
       the modifier is the amount the base price is multiplied
       by to get the price per item.
*/
    double CurrentBasePrice = 0.0;
    double CurrentModifier = 0.0;
    /* This switch statement compares the index of the product
       list, held in WhichProduct, and sets the inital

BasePrice accordingly.

*/
    switch (WhichProduct) {
                    case 0:
                    CurrentBasePrice = ProdOneBaseValue;
                    break;
        case 1:
                    CurrentBasePrice = ProdTwoBaseValue;
                    break;
        case 2:
                    CurrentBasePrice = ProdThreeBaseValue;
                    break;
        case 3:
                    CurrentBasePrice = ProdFourBaseValue;
                    break;
           }
    /* This switch statement compares the WhichChoice variable
       (which is the selected index in the sizeChoice choice
       box) to the different indexes.  And then sets the modifier
        accordingly.
    */
    switch (WhichChoice) {
                    case 3:
                    CurrentModifier = multiplierSmall;
                    break;
        case 2:
         CurrentModifier = multiplierMedium;
         break;
        case 1:
                    CurrentModifier = multiplierLarge;
                    break;
                   case 0:
                    CurrentModifier = multiplierJumbo;
                    break;
            }
        // Insert the number on the slider to the applet.
        AmountLabel.setText(Integer.toString(AmountSelected)+ " ");
        // Compute the price per item and insert it onto the applet panel.
        double PricePerItem = (CurrentBasePrice*CurrentModifier);
        PricePerItemLabel.setText(Double.toString(PricePerItem)+ " ");
        // The subtotal is the number ordered times the price per item.
        double SubTotal = (CurrentBasePrice*CurrentModifier*AmountSelected);
        // Insert the subtotal onto the applet panel.
        SubTotalLabel.setText(Double.toString(SubTotal)+ " ");
        /* Since the total is the same as the subtotal
           (cause we only have one item to be ordered
            at a time), we can simply use the value in
            the subtotal.
        */
        TotalLabel.setText(SubTotalLabel.getText());
        }

If you examine the Order Entry system so far, you'll have a hard time finding instances that just scream Use exception handling here! So, you'll create one that will make for a simple example.

One thing that you might want to look for is that the AmountSelected is not 0. If it is 0, you don't really need to update the values. So, you can implement your own version of exception and have the updateValues method throw it to signify that the value is 0.



Using exceptions in this case is a bad idea since they are completely unnecessary. You should use exceptions in much more important areas such as dealing with input and output or network connections.

The first step is to define your own Exception class. You'll simply extend the Exception class in general:

Exception ZeroValueException = new Exception ("Zero Value Encountered.");

You will place this in the updateValues method itself. Then, you'll say that the updateValues method possibly will throw an instance of your new exception. This will be done by changing the class-method declaration for the updateValues method. The new declaration for the method follows:

public void updateValues throws Exception {

So, the next step is that if you come across a 0 value for the AmountSelected, you will throw the ZeroValueException you created before by saying this:

if (AmountSelected == 0) {
    throw(ZeroValueException);
}

This throws your exception and jumps out of the method right there before anything is computed.

Finally, you'll need to have code to handle the exception you are throwing. To do this, you'll add a try/catch block around the calling of the updateValues method in the action and handleEvent methods of the Order Entry System applet. To do this, you'll use this code:

try {
    updateValues();
}
catch (Exception E) {
    System.out(E.getMessage());
}

This simply tries the updateValues() method and then catches any instances of descendants of the Exception class that are thrown.

This (unproductive) addition to the Order Entry system is included in Listing 10.2. The code changes are shown in bold type.

Interacting with the Browser


It would be a waste to simply have your applets be static and encapsulated programs inside a browser. Java is designed to allow your applets to communicate with the browser and with each other.

Suppose that you want to get information in one applet and display it to another applet to be displayed. Or, you might want to tell the browser to display another Web page or load and play an audio clip. The next section tells you how to do these things.

The AppletContext interface is an interface designed to let applets communicate with the browser. Table 10.1 summarizes the methods that are available to you as part of the AppletContext interface.

Table 10.1. Methods available in the AppletContext interface.

Method Function Applet getApplet(String name); Gets an applet named name. If it can't find it, null is returned. AudioClip getAudioClip(URL url); Gets an audio clip at URL url. Enumeration getApplet(); Lists the applets available in the current context. In other words, the list of those currently displayed. Image getImage(URL url); Gets an image at URL url. public void showDocument Shows a new document in a target (URL url, String target); window or frame. This may be ignored. Accepts the target strings: _self:show in current frame, parent:show in parent frame, top:show in top-most frame, blank:show in new unnamed top-level window, and <other>:show in new top-level window named <other>. void showDocument(URL url); Tells the browser to show a document at URL url. Note: This may be ignored. void showStatus(String status); Sets the status string shown.

These methods are all implemented by the different browsers that can display Java applets. Notice that some of the interface methods can be ignored by the browser at their discretion. You should plan your applets accordingly. To find out how specific browsers treat the optional methods is a trial and error process. The extent to which these methods are implemented by each browser is dependent upon the manufacturer's preference.

So how do you implement these methods? Suppose that you want your applet to get an image at a specific URL. You can use this code to load an image and then store it in the Image class:

Image NetImage = getImage(url);



For more information on the URL class, see Chapter 12, "Network Programming with Java."

If you want to tell the browser to load another document contained at URL

http://mega.dinky.com/~girdleyj/a.html

you can use this code:

URL aURL = new URL("http://mega.dinky.com/~girdleyj/a.html");
getAppletcontext().showdocument(aurl);

This constructs a new instance of the URL class and then sets it. The next line then tells the browser to show that document at the URL specified.

Another version of the showDocument method is available. As summarized before, it takes this form:

getAppletContext().showDocument (URL aURL, String Target);

The URL specified tells the browser which document to load. Target tells the browser where to put it. You can tell the browser to display the document and those constants in many places (refer to Table 10.1). The most powerful of these constants are those that allow you to tell the browser to create a new frame, which can be a frame inside of a viewer or a new window itself.

Suppose that you want to tell the browser to display a document in the current frame. You can use this code:

getAppletContext().showDocument (aURL, "_self");

Or, if you want to create a new browser window named Billy, you can use this code:

getAppletContext().showDocument (aURL, "Billy");

And it's just that easy. Figure 10.2 shows the output from the Netscape 3.0 when displaying an applet that instructs the browser to display a new window with another HTML file. In this case, the new window simply displays a junk text file.

Figure 10.2. The output from telling the browser to open a new window using the showDocument command.

You'll use this feature to call up a new browser window that displays a help file in HTML format. You'll add this later in the chapter when you update the Order Entry System.



Why do some of the interface methods require that you first specify the getAppletContext() method before you can use them? Well, if you look at the actual implementation of the Applet class, you will notice that sometimes you can simply just use these functions from the AppletContext interface without specifying the interface itself, because they are declared again by the Applet class. To use the showDocument method in general, for example, you can use this code:


getAppletContext().showDocument(. . . );

If you are unable to get a method to work that you know is in the interface, you might want to try this code to call it directly instead of going through the applet itself.

Using Parameters in Applets


The java.awt.Applet class specifies a method called getParameter, which allows you to get parameters specified in the HTML document containing your applet. The parameters are referenced by name.



See Chapter 5, "Writing a Java Applet: The Order Entry System," to learn how to specify parameters for your applets.



The getParameter function returns a string that is the value sent in. Suppose that you have the following applet declaration:



To retrieve the value stored in parameter Pone, you can use this code:



Notice that the parameter is always a string. If you want to send in values, you must convert the string to an integer. You can do this by using the Integer class, which is a wrapper for the integer type that provides different utility functions to deal with integers. One such method is the ParseInt function, which enables you to parse a string and return an integer. If you want to get the value stored in the Pone parameter, for example, you can use this code:



This places the number in the InPone variable into the AnInt integer. Easy. This feature is useful, for example, if you are making an applet in which you want to allow users implementing it to have different choices for the colors, borders, and so on for your applet without creating a new version for each combination of choices.


Looking At the Final Listing of the Order Entry System


This chapter set a couple of goals for improving the Order Entry system with the concepts presented here. First, you'll set things so that an "about" document describing the Order Entry system appears in a new window after the Order button is clicked, as shown in Figure 10.3.

** 10WPJ03.pcx **

Figure 10.3. The final appearance of the Order Entry system with separate window functions added.

You will use the showDocument method in the AppletContext interface. The showDocument method accepts an instance of the class URL and then displays it in a target you specify. First, you'll want to create your own instance of the URL class that points to the about.html file. Use this code:

try {
     URL HelpURL = new URL (getDocumentBase(), "about.html");
} catch (Exception e) {
            System.out.print(e.getMessage());
          }

Why the try statement? Well, the constructor for the URL class might throw an exception, so you have to deal with it. If there is a problem, you need to catch the exception and deal with it appropriately.

Next, you need to tell the browser to display that document at that URL:

getAppletContext().showDocument(HelpURL);

And that's it. The new browser window loads with the about.html document displayed.

You also will want to implement the (frivolous) exception handling that was described previously in the final version.

Listing 10.2 shows the final version of the Order Entry system, with the changes made in this chapter displayed in bold type.

Listing 10.2. The Order Entry System Revisited

import java.awt.*;
import java.applet.*;
import java.net.*;
public class OrderEntrySystem extends Applet {
    OrderEntryFrameType OESFrame;
    Button Order = new Button("Click to Order");
    Image ProductImage;
    public void init()    {
          add(Order);
        }
    public boolean handleEvent(Event InEvent) {
         // Load the logo image. .
           Image LogoInApplet = getImage(getDocumentBase(), "OESLogo.gif");
        if (InEvent.target == Order) {
          Order.disable();
              // Try to create a new URL . .
          try {
             URL HelpURL = new URL (getDocumentBase(), "about.html");
             // Show the applet in a new window. .
                getAppletContext().showDocument(HelpURL,
                       "About the Order Entry System");
          } catch (Exception e) {
            System.out.print(e.getMessage());
          }
          // Display the new window . .
          OESFrame = new OrderEntryFrameType("Order Entry System");
          OESFrame.resize(430,500);
          OESFrame.setup(LogoInApplet);
          OESFrame.show();
        }
        return super.handleEvent(InEvent);
    }
}
class OrderEntryFrameType extends Frame {
    OrderEntryFrameType (String InTitle) {
        // Call the Frame constructor . .
        super(InTitle);
        // Set the background color for the Applet frame. .
        setBackground(Color.white);
        }
    WarningDialog WDialog = new WarningDialog(this,
    "You have not entered a name. ");
    Panel Pan = new Panel();
    public void setup(Image LogoInApplet) {
        // Set the initial grid bag layout for the frame.
        GridBagLayout PrimaryLayout = new GridBagLayout();
        setLayout(PrimaryLayout);
        // Declare the constraints for the Logo.
        GridBagConstraints LogoConstraints = new GridBagConstraints();
        // Construct the new canvas. .
        LogoCanvas Logo = new LogoCanvas(LogoInApplet);
        LogoConstraints.gridwidth = GridBagConstraints.REMAINDER;
        // Set the constraints for the logoinApplet.
        PrimaryLayout.setConstraints(Logo, LogoConstraints);
        // Add the logo canvas to the applet face.
        add(Logo);
        // Declare the constraints for the Logo.
        GridBagConstraints HBarConstraints = new GridBagConstraints();
        // Construct the new canvas. .
        HorizBar ProdBar = new HorizBar("Product", 425);
        // Say that we want the logo to be the last thing on the line.
        HBarConstraints.gridwidth = GridBagConstraints.REMAINDER;
        // Set the constraints for the logoinApplet.
        PrimaryLayout.setConstraints(ProdBar, HBarConstraints);
        // Add the logo canvas to the applet face.
        add(ProdBar);
        // Declare and initialize the product panel.
        Panel ProductPanel = new Panel();
        // Set the layout for the product panel and set the constraints for
        // the components inside of the product panel.
        GridBagLayout ProductPanelLayout = new GridBagLayout();
        GridBagConstraints InProductPanelConstraints =
             new GridBagConstraints();
        ProductPanel.setLayout(ProductPanelLayout);
        // Here we will set the list panel, which will hold the
        // list choice method and insertion.
        Panel ListPanel = new Panel();
        ListPanel.setLayout(new BorderLayout());
        Label ProductLabel = new Label("Products");
        ListPanel.add("North", ProductLabel);
        // Create the list, 4 items visible, no multiple
        // selections.
        ProductList = new List(4, false);
        // AddItems to the List.
        ProductList.addItem("Oscar");
        ProductList.addItem("Lionhead");
        ProductList.addItem("Jack Dempsey");
        ProductList.addItem("Angelfish");
        // Add the List to the list panel.
        ListPanel.add("Center",ProductList);
        // Add the imbedded panel to the product panel.
        InProductPanelConstraints.anchor = GridBagConstraints.NORTH;
        ProductPanelLayout.setConstraints(ListPanel,
               InProductPanelConstraints);
ProductPanel.add(ListPanel);
        // Another panel which will be imbedded in the product panel.
        Panel SizePanel = new Panel();
        SizePanel.setLayout(new BorderLayout());
        // Add a label to the choice of sizes.
        SizePanel.add("North", new Label("Size:"));
        // Create the Choice box.
        SizeChoice = new Choice();
        // AddItems to the List.
        SizeChoice.addItem("Jumbo");
        SizeChoice.addItem("Large");
        SizeChoice.addItem("Medium");
        SizeChoice.addItem("Small");
        // Add the Choice to the Applet panel.
        SizePanel.add("Center",SizeChoice);
        // Add the imbedded panel to the product panel.
        ProductPanelLayout.setConstraints(SizePanel,
              InProductPanelConstraints);
        ProductPanel.add(SizePanel);
        // Another panel that will be imbedded in
           the product panel.
        Panel AmountPanel = new Panel();
        AmountPanel.setLayout(new BorderLayout());
        // Add a label to the slider.
        AmountPanel.add("North", new Label("Amount:"));
        // Another imbedded panel that will contain
           the slider and the output label.
        Panel SliderPanel = new Panel();
        SliderPanel.setLayout(new FlowLayout());
        // Insert the label that says how many are to be ordered
        // of the item.
        SliderPanel.add(AmountLabel);
        // Create a vertical slider, initial value of 0,
        // minimum value of 0, maximum value of 144.
        OrderAmountSlider = new
              Scrollbar(Scrollbar.HORIZONTAL, 0, 0, 0, 144);
        // Insert the slider to the Applet panel.
        SliderPanel.add(OrderAmountSlider);
        AmountPanel.add("Center", SliderPanel);
        // Add the imbedded panel to the product panel.
        ProductPanelLayout.setConstraints(AmountPanel,
             InProductPanelConstraints);
        ProductPanel.add(AmountPanel);
        // The last panel that will be imbedded in the product panel.
        Panel TotalPanel = new Panel();
        TotalPanel.setLayout(new BorderLayout());
        // Add the subtotal label and a label saying that it is the subtotal.
        TotalPanel.add("North", new Label("Total: "));
        TotalPanel.add("South",TotalLabel);
        ProductPanelLayout.setConstraints(TotalPanel,
             InProductPanelConstraints);
        ProductPanel.add(TotalPanel);
        // Add the imbedded panel to the product panel.
        ProductPanelLayout.setConstraints(TotalPanel,
             InProductPanelConstraints);
        ProductPanel.add(TotalPanel);
        // Set the constraints for the product panel,
           which will contain product choices, size, etc.
        GridBagConstraints ProductPanelConstraints = new GridBagConstraints();
        // The product panel will take up the rest of the space on this line.
        ProductPanelConstraints.gridwidth = GridBagConstraints.REMAINDER;
        // Set the constraints for the product panel's insertion.
        PrimaryLayout.setConstraints(ProductPanel, ProductPanelConstraints);
        // Add the product panel to the frame.
        add(ProductPanel);
        // Construct the new canvas. .
        HorizBar InfoBar = new HorizBar("Your Information", 425);
        // Say that we want the logo to be the last thing on the line.
        HBarConstraints.gridwidth = GridBagConstraints.REMAINDER;
        // Set the constraints for the logoinApplet.
        PrimaryLayout.setConstraints(InfoBar, HBarConstraints);
        // Add the logo canvas to the applet face.
        add(InfoBar);
        // The second panel to be imbedded in the frame is the info panel.
        // This panel gets the information about the user.
        GridBagLayout InfoPanelLayout = new GridBagLayout();
        Panel InfoPanel = new Panel();
        GridBagConstraints InfoPanelConstraints = new GridBagConstraints();
        InfoPanelConstraints.gridwidth = GridBagConstraints.RELATIVE;
        InfoPanel.setLayout(InfoPanelLayout);
        GridBagConstraints InInfoConstraints = new GridBagConstraints();
        InInfoConstraints.gridwidth = GridBagConstraints.REMAINDER;
        InInfoConstraints.anchor = GridBagConstraints.WEST;
        Label InfoLabel = new Label("Your information: ");
        InfoPanelLayout.setConstraints(InfoLabel, InInfoConstraints);
        InfoPanel.add(InfoLabel);
        // The name entry field area.
        Panel NameFieldPanel = new Panel();
        NameFieldPanel.setLayout(new BorderLayout());
        NameFieldPanel.add("West",new Label("Name:"));
        NameFieldPanel.add("East",NameEntryField);
        InInfoConstraints.anchor = GridBagConstraints.EAST;
        InfoPanelLayout.setConstraints(NameFieldPanel,
              InInfoConstraints);
        InfoPanel.add(NameFieldPanel);
        // The Street entry area implementation.
        Panel StreetFieldPanel = new Panel();
        StreetFieldPanel.setLayout(new BorderLayout());
        StreetFieldPanel.add("West",new Label("Street:"));
        StreetFieldPanel.add("East",StreetEntryField);
        InfoPanelLayout.setConstraints(StreetFieldPanel,
             InInfoConstraints);
        InfoPanel.add(StreetFieldPanel);
        Panel CityFieldPanel = new Panel();
        CityFieldPanel.setLayout = new BorderLayout());
        CityFieldPanel.add("West",new Label("City:"));
        CityFieldPanel.add("East",CityEntryField);
        InfoPanelLayout.setConstraints(CityFieldPanel, InInfoConstraints);
        InfoPanel.add(CityFieldPanel);
        // The zip entry field implementation.
        Panel ZipFieldPanel = new Panel();
        ZipFieldPanel.setLayout(new BorderLayout());
        ZipFieldPanel.add("West",new Label("Zip:"));
        ZipFieldPanel.add("East",ZipEntryField);
        InfoPanelLayout.setConstraints(ZipFieldPanel, InInfoConstraints);
        InfoPanel.add(ZipFieldPanel);
        PrimaryLayout.setConstraints(InfoPanel, InfoPanelConstraints);
        // Add the info panel to the frame layout.
        add(InfoPanel);
        Panel CommentPanel = new Panel();
        GridBagLayout CommentPanelLayout = new GridBagLayout();
        GridBagConstraints CommentPanelConstraints =
             new GridBagConstraints();
        CommentPanelConstraints.gridwidth = GridBagConstraints.REMAINDER;
        CommentPanel.setLayout(CommentPanelLayout);
        GridBagConstraints InCommentConstraints = new GridBagConstraints();
        // The comment label.
        InCommentConstraints.anchor = GridBagConstraints.WEST;
        InCommentConstraints.gridwidth = GridBagConstraints.REMAINDER;
        Label CommentLabel = new Label("Comments: ");
        CommentPanelLayout.setConstraints(CommentLabel, InCommentConstraints);
        CommentPanel.add(CommentLabel);
        // Add the comment box.
        InCommentConstraints.anchor = GridBagConstraints.CENTER;
        InCommentConstraints.gridwidth = GridBagConstraints.REMAINDER;
        CommentPanelLayout.setConstraints(CommentTextArea,
        InCommentConstraints);
        CommentPanel.add(CommentTextArea);
        PrimaryLayout.setConstraints(CommentPanel, CommentPanelConstraints);
        // Add the info panel to the frame layout.
        add(CommentPanel);
// Add and create the repeat customer checkbox.
        Panel ContactPanel = new Panel();
        ContactPanel.setLayout(new BorderLayout());
        // Add a label to the ContactMethodGroup.
        ContactPanel.add("North",new
               Label("How would you like to be contacted? "));
        // Declare the checkbox group, and allocate space.
        CheckboxGroup ContactMethodGroup;
        ContactMethodGroup = new CheckboxGroup();
        // Create some checkboxes to put in the group.
        Checkbox EmailBox = new Checkbox("Email",ContactMethodGroup,true);
        Checkbox PhoneBox = new
             Checkbox("Phone",ContactMethodGroup,false);
        Checkbox MailBox = new
             Checkbox("US Mail",ContactMethodGroup,false);
        // Add the checkboxes into the applet panel.
        ContactPanel.add("West",EmailBox);
        ContactPanel.add("Center",PhoneBox);
        ContactPanel.add("East",MailBox);
        // Sets the constraints for the contact panel.
        GridBagConstraints ContactPanelConstraints =
             new GridBagConstraints();
        ContactPanelConstraints.gridwidth = 2;
        ContactPanelConstraints.weightx = 2.0;
        PrimaryLayout.setConstraints(ContactPanel, ContactPanelConstraints);
        add(ContactPanel);
        // Insert the different checkboxes into the panel.
        GridBagConstraints CustCheckBoxConstraints =  new GridBagConstraints();
        CustCheckBoxConstraints.weightx =1.0;
        CustCheckBoxConstraints.gridwidth = GridBagConstraints.REMAINDER;
        Checkbox RepeatCustCheckBox = new Checkbox("Repeat Customer?");
        PrimaryLayout.setConstraints(RepeatCustCheckBox,
        CustCheckBoxConstraints);
        add(RepeatCustCheckBox);
        // Construct the new canvas. .
        HorizBar ButtonBar = new HorizBar("Commands", 425);
        // Set the constraints for the logoin applet.
        PrimaryLayout.setConstraints(ButtonBar, HBarConstraints);
        // Add the logo canvas to the applet face.
        add(ButtonBar);
        GridBagConstraints ButtonConstraints = new GridBagConstraints();
        ButtonConstraints.gridx = GridBagConstraints.RELATIVE;
        // Spreads the buttons out across the window.
        ButtonConstraints.weightx = 1.0;
        ButtonConstraints.weighty = 1.0;
        // Declare, set, and add the "Submit" button.
        SubmitButton = new Button("Submit");
        PrimaryLayout.setConstraints(SubmitButton, ButtonConstraints);
        add(SubmitButton);
        // Declare, set, and add the "Clear" button.
        ClearButton = new Button("Clear");
        PrimaryLayout.setConstraints(ClearButton, ButtonConstraints);
        add(ClearButton);
        // Set the constraints and insert the quit button.  This button
        // due to the REMAINDER setting will be the last on the line.
        GridBagConstraints LastButtonConstraints = new GridBagConstraints();
        LastButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;
        QuitButton = new Button("Quit");
        PrimaryLayout.setConstraints(QuitButton, LastButtonConstraints);
        add(QuitButton);
        // Method that resets all of the internal values.
        resetValues();
        }
    // The subtotal and total variables.
    private double SubTotalOne = 0.0;
    private double Total = 0.0;
    // The price multipliers for each different product size.
    private double multiplierSmall = 0.5;
    private double multiplierMedium = 1.0;
    private double multiplierLarge = 1.5;
    private double multiplierJumbo = 2.25;
    // The local constant base prices.
    static double ProdOneBaseValue = 1.0;
    static double ProdTwoBaseValue = 1.33;
    static double ProdThreeBaseValue = 1.75;
    static double ProdFourBaseValue = 8.75;
    // Declare all of the variables we'll use.
    private Button SubmitButton;
    private Button ClearButton;
    private Button QuitButton;
    private Checkbox RepeatCustCheckBox;
    private Checkbox MailBox;
    private Checkbox EmailBox;
    private Checkbox PhoneBox;
    private List ProductList;
    private Choice SizeChoice;
    private Scrollbar OrderAmountSlider;
    // The labels that will be variable and change when
    // the other selections are changed.
    private Label SubTotalLabel = new Label("$0.0 ");
    private Label TotalLabel = new Label("$0.0 ");
    private Label AmountLabel = new Label("0 ");
    private Label PricePerItemLabel = new Label("$0.0 ");
    // The entry field for the user to enter his name.
    private TextField NameEntryField = new TextField(25);
    private TextField ZipEntryField = new TextField(6);
    private TextField StreetEntryField = new TextField(25);
    private TextField CityEntryField = new TextField(25);
    // The comment entry area.
    private TextArea CommentTextArea = new TextArea(4, 25);
    // Our own exception . .
    private Exception ZeroValueException;
    private void updateValues() throws Exception {
        int WhichChoice = SizeChoice.getSelectedIndex();
        int AmountSelected = OrderAmountSlider.getValue();
        int WhichProduct = ProductList.getSelectedIndex();
        double CurrentBasePrice = 0.0;
        double CurrentModifier = 0.0;
       if (AmountSelected == 0) {
        throw(ZeroValueException);
       }
        switch (WhichProduct) {
            case 0:
                CurrentBasePrice = ProdOneBaseValue;
                break;
            case 1:
                CurrentBasePrice = ProdTwoBaseValue;
                break;
            case 2:
                CurrentBasePrice = ProdThreeBaseValue;
                break;
            case 3:
                CurrentBasePrice = ProdFourBaseValue;
                break;
        }
        switch (WhichChoice) {
            case 3:
                CurrentModifier = multiplierSmall;
                break;
            case 2:
                CurrentModifier = multiplierMedium;
                break;
            case 1:
                CurrentModifier = multiplierLarge;
                break;
            case 0:
                CurrentModifier = multiplierJumbo;
                break;
        }
        AmountLabel.setText(Integer.toString(AmountSelected)+ " ");
        double PricePerItem = (CurrentBasePrice*CurrentModifier);
        PricePerItemLabel.setText(Double.toString(PricePerItem)+ " ");
        double SubTotal = (CurrentBasePrice*CurrentModifier*AmountSelected);
        SubTotalLabel.setText(Double.toString(SubTotal)+ " ");
        TotalLabel.setText(SubTotalLabel.getText());
    }
    // This method will be called when the user presses the "Clear" button and
    // also when the applet is initialized in the init() method.
    public void resetValues() {
        // Reset all of these labels to zero.
        SubTotalLabel.setText("$0.0 ");
        TotalLabel.setText("$0.0 ");
        AmountLabel.setText("0 ");
        PricePerItemLabel.setText("$0.0 ");
        // Clear all of the lists and choices.
        ProductList.select(0);
        SizeChoice.select(0);
        OrderAmountSlider.setValue(0);
        // Clear all of the text fields.
        NameEntryField.setText("");
        StreetEntryField.setText("");
        CityEntryField.setText("");
        ZipEntryField.setText("");
    }
    public boolean handleEvent(Event InEvent) {
        if (InEvent.id == Event.SCROLL_LINE_UP ||
            InEvent.id == Event.SCROLL_LINE_DOWN)  {
                try {
                     updateValues();
                } catch (Exception e) {}
        } else
        if (InEvent.target == ProductList) {
                try {
                     updateValues();
                } catch (Exception e) {}
        } else
        if (InEvent.target == ClearButton) {
                    resetValues();
        } else
        if (InEvent.target == QuitButton)  {
        // Quit the applet.
            this.dispose();
        } else
        if (InEvent.target == SubmitButton) {
         // Submit the order.
        }
        return super.handleEvent(InEvent);
    }
    public boolean action (Event InEvent, Object SomeObject) {
        if (InEvent.target == SizeChoice) {
                try {
                     updateValues();
                } catch (Exception e) {}
        return true;
        }
        else
        if (InEvent.target == NameEntryField) {
            // Is the field empty?  If so, you could add a
            // pop-up dialog box to alert the user that he
            // has not entered his name.
            WDialog.show();
            return true;
            } else
        return false;
    }
}
class WarningDialog extends Dialog {
    private Button OkButton = new Button("OK");
    private Label ALabel;
    WarningDialog(Frame HostFrame, String Message)  {
        super(HostFrame, "Warning!", false);
        ALabel = new Label(Message);
        resize(180,100);
        setLayout(new FlowLayout());
        add(ALabel);
        add(OkButton);
    }
    public boolean action (Event InEvent, Object Param)  {
        if (InEvent.target == OkButton)  {
            hide();
        }
        return true;
    }
}
class LogoCanvas extends Canvas {
    private Image LogoImage;
    LogoCanvas (Image LogoInCanvas) {
         // Get the image and place it in LogoImage. .
         LogoImage = LogoInCanvas;
         // Resize the canvas to fit the Logo exactly.
        resize (425, 87);
    }
    public void paint(Graphics g)  {
        // Draw the logo on the canvas.
        g.drawImage(LogoImage,0,0,this);
    }
}
class HorizBar extends Canvas {
    private String LineString;
    private int Width;
    HorizBar(String InString, int InWidth) {
        // Set the size of the canvas.
        resize(InWidth, 25);
        // Set the local variables equal to parameters so that
        // we can use the values in the paint method.
        Width = InWidth;
        LineString = InString;
    }
    public void paint(Graphics g)  {
        // Set the font and font metrics class.
        Font f = new Font("TimesRoman", Font.BOLD, 16);
        FontMetrics FM = getFontMetrics(f);
        g.setFont(f);
        // Draw a line from x = 0 to x = 15.
        g.drawLine(0, 20, 15, 20);
        // Draw the string.
        g.drawString(LineString, 20, 20);
        // Draw the rest of the line.
        g.drawLine(FM.stringWidth(LineString) + 25, 20, Width, 20);
    }
}

And that's it.

What's Wrong with the Order Entry System?


The big problem remaining with the Order Entry system as of right now is getting the information back to you. All the ways to do this involve opening a connection back to your server and then transferring the data in one of many ways. One of these ways involves opening an SMTP connection and then mailing the information back to you. Another means is through creating a script on your server to process the information. And finally, you can write a program that listens on a specific port waiting for you to make a connection and transfer the data. The process of constructing these and other network connections is covered in Chapter 12, "Network Programming with Java."

And finally, the Order Entry system has been developed to mimic the use of similar applets in the real world. To make it the best example possible and include as many of Java's features, however, it is not a completely realistic applet. It did give you a good feel for what Java can do and how it is done, though.

Summary


This chapter covered quite a bit of ground. First, you learned about the concepts of error and exception handling in Java. Then you learned about the implementation of these concepts into your own programs and examined many of the different Java reserved words such as finally, throws, try, and catch. You also learned how to declare your own exceptions and utilize them and how to use the AppletContext interface to interact with the browser displaying your applet. This skill will prove useful in your own applet programming.

And finally, you made many changes in the Order Entry system and implemented them. I also included a listing of the final version of the Order Entry system. Next, Chapter 11, "Reading and Writing with Java," will cover the details of inputting and outputting data with Java.

Previous Page Page Top TOC Next Page See Page