Understanding the Order Processor Code

Joseph Bergin

assisted by Fred Grossman

Code Discussed here.

OrderProcessor.java
Order.java
Invoice.java
Customer.java
OrderItem.java
InventoryManager.java
BillingTerms.java
OrderEntry.java
Address.java
CalculationCalendar.java
Maintenance.java

The code is all available from a zip file named: OP2012.zip. This README tells how to install it with Eclipse.

This page is currently NOT up to date. The code has been modified since this was written. It is now Java 5 compliant and uses the Java Collections Framework. However, the overall structure of the code has not changed.

I will use this page to explain the above code. It doesn't use any Java advanced features, such as thread and internet programming, but it is relatively sophisticated code. Feel free to add to the discussion or to ask questions. You can also ask me to develop some topic in Java. The code represents the starting point of a software engineering project to develop an Order Processing system. It is a partial solution to a problem whose requirements are expressed in the following high level data flow diagram.

The project code was split over 11 files, one for each class. This is the Java standard practice: one class per file. It isn't really enforced, but helps you find your code. The file must have the same name (capitalization included) of the (only) public class in the file. The system does enforce only one public class in a file. All of the files start out with a package statement:

package orderprocessing; 

It is considered good style to split up your code into packages, one or more per project. This makes it easier to define classes without worrying about the names of classes in other packages. Only one top-level class with a given name in a package is allowed. (Top-level means not "inner").

Each file then has a number of import statements. Here is the list from OrderProcessor.java.


import java.util.ArrayList; 
import java.util.Iterator; 
import java.util.StringTokenizer;
import java.io.IOException; import java.io.ObjectInputStream; ...

Imports make the names of classes more easily available, but are not really required. Within the OrderProcessor file we can now access java.util.ArrayList by saying just ArrayList. Without this import statement, we would need to use the full qualified name: java.util.ArrayList for every reference.

There are two forms of import. If we say "import java.io.*;" we import all public classes from java.io, such as java.io.FileReader and java.io.IOException that are used here. Actually this is considered poor form, and the second form, naming an individual class as we have done here, is preferred. It makes the dependencies of your code clear, so that if the core libraries change, you can easily see which files need to be updated. Eclipse has an Arrange Imports command (Source Menu) that will help with this by taking a * import and figuring out which specific classes are needed.

Note that the OrderProcessor class has one main function for this program. As usual, its prototype is public static void main (String [] args). This is required. Also as usual, this function is very short. It just sends the close message to itslef, which has the effect of reinitializing the program's object database. When this message returns, our program can quit.

The CustomerEntry class also has a main function. This one opens the database by sending a static message to the OrderProcessor class itself and then creates a new CustomerEntry object.

new CustomerEntry(); 

The new indicates we are creating an object. Note that we don't even "name" this object as we don't have a variable to refer to it.

When a Java application runs it can take some information from the command line that causes it to run. This is in the form of an array of String objects. The first String in the array has index zero (always zero for Java arrays). For this program we don't need any such information here, but this is the purpose of the parameter to the main function. The command line arguments become the entries of the array..

For each instance created (with new) we must see to correctly initializing any instance variables of the object. This can be done either in the constructor or by simply giving the value that the variable should be initialized with in the declaration itself. For example, look at the Order class in Order.java. We use the latter method for the boolean variable named cancelled. In this case we use the value false:

private boolean cancelled = false; 

Most of the other fields of this class are initialized in the constructors, of which there are two in the Order class. This is because we need values from the creating client to initialize them. One constructor defers the operations to the other with the this(...) message.

Most of what we want to do in the constructor of Order (in most constructor's actually) is initialize the member variables that we couldn't initialize statically in their declarations.

Java I/O

When the application isn't running all of the "data" objects in the system are saved in an object stream which serves as a simple database. When the application starts up, the objects are read back in so the application takes up where it left off.

Note that the basic structure of the rather complex Java I/O libraries is that of the Decorator pattern. The ObjectInputStream provides "decoration" in the form of unmarshalling object data for any other InputStream. My home page has a paper that explains the basic I/O library structure and Decorator can be found in the Patterns Literature. In OrderProcessor, an ObjectInputStream is used to decorate a FileInputStream. The file stream provides the data and the object stream knows how to turn this data back into objects. See the open static method of OrderProcessor.

However, the creation of the FileInputStream may fail if the file with the given name doesn't exist or is otherwise inaccessible. If the creation fails an IOException (from class io, also) will be raised and this is an exception that we must catch and deal with. That is why we enclose the above statement in a try...catch block. You can enclose one or more statements in a try and if any of them raise an exception, the system will halt the execution of the try block and search the (perhaps several) catch clauses for a handler of the exception. The matching is done by type. It will look through the clauses one at a time searching for one that names a type exactly the same as the exception raised or some supertype of it. When it gets a match, it binds the exception object that was raised to the variable in the catch clause and then executes the statement part of the catch block.

In this case, if the file can't be opened, we print an informative message on the System.out stream. We could then halt the program with System.exit(1);

The Java compiler will inform you if you need a try block. You will then need to decide how big its scope should be. Generally speaking, if the statement requiring the try is creating information then the scope can be small only if you will halt the computation in the catch or if you can provide default values there. Otherwise the scope of the try should cover all uses of the information that couldn't be created.

NOTES: Notice the naming convention we use for classes and methods. Class names start with a capital letter and field and method names do not. Class names are singular nouns. Generally speaking methods that don't return anything are verbs or short verb phrases with the words run together and each word after the first capitalized. Methods that do return a value are given noun names (or noun phrase) that describe the result of calling the method.

Many of our methods have local variables. Local variables are only visible in the method and only exist while the method is executing. They can all be defined at the beginning of a method, but they can be defined anywhere within it as long as the definition precedes the first use. The String class is actually imported from java.lang, but we don't need to specify an import for classes in this one package. The compiler knows about it already. ArrayList and Calendar both come from java.util and we do import these specifically when needed. An ArrayList is like an array except that it can grow and shrink at the right end efficiently. The Calendar class can handle dates in many formats, including international formats. We extend this class here to CalculationCalendar to get the ability to add an int to one of the date fields to obtain a different date in the future (or past).

The InventoryManager class is just a stub. It doesn't really manage anything. If we ask it if something is available it always says yes, without checking. Eventually it will need a database and perhaps links to suppliers. This class doesn't currently need a constructor as it has no instance variables. We supply a dummy one in any case, but would not need to. It is there for you to modify in the future and because I just naturally put a constructor in most classes. It has one public method, available, which takes an OrderItem describing a product and a quantity (at least) and it now just returns an new OrderItem with the same value. It doesn't just return the same object, however, but a clone of the object. This is because the incoming OrderItem might be modified in later processing of the program and that wouldn't necessarily imply changing the outgoing one. Therefore we don't return a reference to the original object, but create a new "identical" one and return a reference to it instead. The clone method is one you may need to implement in some of your classes. We will talk about this in other posts here.

The method available has a special comment preceding it (so does the class itself) called a JavaDoc comment. It begins with /** and ends with */. These comments are read by a special tool (JavaDoc) which creates html files nicely formatted with the contents.

InventoryManager has one static field in which it holds an instance of this class itself. This inventory manager can be used, but, since the constructor of InventoryManager is public other InventoryManager objects could also be created. Imagine an order processing system in which there are several inventory managers.

The Customer class is used to define individual customer objects and also to serve as a repository for all customer objects. The key field (customer number) is assigned by the system internally when an object is created and is not supplied as a constructor parameter. The newly created object is then placed into a HashMap with its customer number as the key. Customer objects previously created can be retrieved from the customer class using the static get method if you know the customer number or using the Iterator valued function customers. The Customer class also knows how to read and write an output file containing all of the customers as well as the next available customer number. This uses an ObjectOutputStream. The Order and Invoice classes also have this ability for objects that they create. Eventually Product will need such a capability. The Customer class also "delegates" the details of addresses to the Address class, simply maintaining references to address objects. It does this with billing terms also.

The BillingTerms class is simple but sophisticated. This class implements a pattern called Immutable Object, since the instance variables are set at creation time (the constructor) and cannot be modified after that as there is no protocol for doing so. Immutable Object is an important pattern. If objects can't change then it is easier to reason about them. The BillingTerms class is a Warehouse (pattern). You ask the class for one of its BillingTerms objects with the static get method, supplying a parameter. It gives you one of its predefined objects and doesn't create a new one. This way you can't get one that is illegal according to the business rules. To achieve this, the constructor is private so that it can be executed only from within this class. Here we execute it only as part of the static startup of the program.

The toString method is notable. Most classes should implement this method, since the system knows about it and will call it automatically if the object is sent to a print stream. So if we say System.out.println(aCustomer), then what will appear is the string produced by the toString method of the class. Also, if you catenate an object onto a String with the String catenation operator (+), then this method will automatically be called and its result used. The display method on the other hand is uninteresting. It is only here for quick and dirty viewing in these skeletons. In future it can be used for debugging output, but you will want to do better things with output.

Note that Customer implements the Serializable interface. This interface has no requirements (it is an empty interface), but the system knows about it and will permit such objects to be saved in files directly without the usual field packing and unpacking that the programmer has to do in other languages. This class was made Serializable since you almost certainly want to store your customers in a customer data base of some kind. Some of the other classes here are also Serializable. Watch for it. Actually most classes you write should be Serializable. The exceptions are the classes that maintain secure information that should not be written to persistent storage.

Class OrderItem is also immutable and Serializable. Objects in this class are used in two different ways. They appear both in Orders (what is wanted) and in Invoices (what is shipped). In future it may need to be separated into two classes. OrderItem has 4 fields, one of type int (32 bits so values of about (+/-) 2 billion are possible), long (64 bits), double (64 bit real value) and String (an object). Java has no fixed point numbers like COBOL does. Sophisticated monetary processing must be carefully done with well designed classes. See the first chapters of Analysis Patterns by Martin Fowler for a discussion of Money objects.

OrderItem has accessor methods for its fields and these have the same names as the fields. Actually, the interface of an object (its methods) and the internal storage variables (its fields) should be independent of each other. The interface gives a logical view, useful to a client, and the fields give an implementation view in which efficiency may be more important than anything else. Of course it must be possible to compute the values in the interface view from the values stored, but there isn't necessarily a 1-1 relationship as there is here. In fact, lots of such 1-1 relationships between fields and methods would make an experienced designer question the quality of the design.

The clone method is notable as it is part of the infrastructure of Java. When you make an assignment of an object to a class valued variable, you don't get a copy of the value on the right side. You get an alias instead--two references to the same object. Sometimes you want the copy however. See the InventoryMangager class for a use of this method. To correctly implement the clone method you must make a faithful copy of the parameter and return it, but you should also make the class that contains the method Cloneable by implementing the interface. Note that the prototype for the clone method is always

public Object clone(); 

rather than having a more specific return type. This is required so that Java recognizes this method as an override of the version from the Object class that is the ultimate super class of all Java classes. If you try to clone an object that doesn't correctly implement the clone method, then an exception will be raised.

ArrayList and Iterator are related, and both are imported from java.util. An ArrayList is like an array, except that it can grow efficiently (amortized constant time) at the right. A ArrayList has a length() method and it has cells indexed from zero to one less than the length. The element in the k'th cell of a ArrayList v is

v.get(k)

You can put a new element, t, into this cell with

v.set(k, t) 

You can make the ArrayList grow by one cell at the right storing an element t in the new cell with

v.add(t)

The length will then increase by one. Any given extension may be very fast or quite slow, but on the average it is constant time. An ArrayList is more efficient on the average than a doubly linked list, but occasionally an extension will be slow.

An ArrayList is an example of a Collection. Other kinds of collections (speaking generically, not necessarily about Java) are sets, lists, stacks, and the like. The standard way to get access to the elements of a collection in Java is by means of an Iterator. An Iterator is an object related to a collection that knows how to "walk" through the elements, yielding them up one at a time. Iterator is one of the fundamental design patterns, by the way. (See Patterns in Java by Mark Grand, for example, or your book: Design Patterns Explained, by Shalloway and Trott). You get an Iterator for a given collection by asking the collection for it. So for our ArrayList v we can say:

Iterator e = v.iterator();

The iterator method gives us an Iterator appropriate for the collection to which you send the message. The iterator method, by the way, represents an instance of another pattern: Factory Method.

An Iterator in Java is designed to work well with a while loop (rather than a for loop). An Iterator always has two methods: hasNext, returning a boolean, and next, returning the next element in the collection, provided that the last execution of hasNext returned true. Otherwise, next might not return anything.

So, the standard way to use an Iterator is shown in the display method of class Order, where the collection here is "what":

	public void display()
	{ ... 
		Iterator items = orderedItems(); 
		while(items.hasNext()) 
		{ ((OrderItem)items.next()).display();
		}
		 ... 
	}

Notice that we defer the acquisition of the Iterator to the orderedItems() method, rather than doing it directly:

public Iterator orderedItems(){return orderedItems.iterator();}

There is a rather subtle point going on here that is worth a few moments reflection. Notice that the ArrayList what that stores the order items for this order is private. Some other code may need access to these items. We therefore provide a method orderedItems() to give such access. But notice that this method doesn't return the ArrayList itself. To do so would be poor design and would leave us open to hard to diagnose bugs in the future. This is because if we return the ArrayList itself, the receiver could modify the ArrayList by inserting additional items or removing them. This would have the effect of changing the order, since the ArrayList isn't copied, just a reference would be returned. Instead of returning the ArrayList, we return an Iterator over the ArrayList. This would give client code access to the items, without being able to insert or remove items. But note that if the items themselves are not immutable, then a client would be able to modify these. This might be desirable or not. (NOTE, actually an iterator can be used to remove items from the collection over which it iterates. There is a standard solution to this problem, but I won't go over it here. In fact, this makes Iterator dangerous in this program as some things like invoices should never be removed from such a system and the program should enforce this business rule.)

The Invoice class is very much like the Order class and so needs no additional explanation. In fact it is almost a copy of it except for the name.

Currently the OrderProcessor class is the heart of our application. In using this code to develop the project, this may change as other parts reach the same sophistication (for example the InventoryManager). To create an OrderProcessor we need to let it know what (single) InventoryManager it will work with. There could be more than one, but there aren't now. This class has one constructor, some public instance methods (newOrder, generateInvoice), some public static methods (open, close...), some more private methods (which can only be used within this class), some static fields, one holding a new instance of this class and one instance variable: the InventoryManager. This class actually has a private constructor, and since that is the only constructor, no other code can create an OrderProcessor. The pattern here is called Singleton Object. The class itself must create any instance and here we just use a static field to contain the only instance. In general a class might have private constructors but provide a factory method to create instances, rather than having public constructors. This would be the case if the class represented the root of a hierarchy and which type of thing created depended on various factors and we want to insulate the client from those details. See the Factory Method and Abstract Factory patterns in the literature.

One of our public methods is used as a factory method to return new Order objects from a description of its requirements. The input to the method newOrder is a set of parameters describing the customer (the customer number), a code for the billing terms, an ArrayList of Strings describing the items to be ordered and three Calendar objects. We look up the customer in a customer database (in the Customer class) and return a reference to that existing customer.

The newOrder method defers the creation of the OrderItem objects to a parsing method genOrderItem of the OrderItem class, which creates an object from a String description. Here the product being ordered would normally be stored in a database and would need to be looked up. Here we just assume that the String description is accurate. Note that we use an Iterator over the String ArrayList to get the individual strings one at a time and create an OrderItem for each of them, storing the resulting items in a new ArrayList which becomes part of the new Order object that is returned from newOrder.

This method parseInt called from genOrderItem might fail and throw a NumberFormatException, but this one doesn't need to be caught, though if it is thrown and not caught, the computation will halt.

Likewise, class java.lang.Double can extract a Double from a string with method valueOf, which might also throw a NumberFormatException. This method returns a Double object, however, not a double numeric type. Each of the numeric types has a corresponding object type for situations in which you want to put numeric values into collections, which require objects. We therefore have to get a double from the Double and doubleValue will do this. We cascade the two messages to do this, sending the second message (doubleValue) to the object returned by the first (valueOf).

The fact that there is a try block enclosing the double parsing and not the integer or long parse, is not significant and is probably an error on my part.

One subtle point here deals with the local variable unitPrice. This will be used at the end of genOrderItem to initialize the new OrderItem object. Java guarantees that this value will have been set by the time it is used. We set unitPrice in the try block, but the try block may fail if an exception is thrown. That would leave us in the catch clause in which there is no setting of the unitPrice variable. Therefore, the declaration of unitPrice contains an initialization (0.0) to guarantee that it has some value whether or not the exception is thrown. Erase this initialization (= 0.0) and compile the code to see the effect. You will get an ERROR, not a warning, that tells you the variable may not have been given a value when we reach the last statement.

The public method generateInvoice has a similar structure to newOrder and it returns a new Invoice object. It is more than just a factory method, however, as it always does various business level processing to create the object, whereas newOrder really acts just like a constructor, though it insulates the client from some details. Here the customer of the Invoice is the same customer from the order, so we don't create another object but use a reference to the same object. We run through the ArrayList in the Order (an ArrayList of OrderItems, created in newOrder) and check that each is available in inventory by asking the inventory manager. In general, we get back a different object from this query (we may be able to ship some, but not all of what the customer wants) and we save the resulting OrderItems (the fulfilled items) in a new ArrayList that becomes part of the new Invoice object. Our error handling here, in the case that the quantity available is zero is not adequate. Blasting a message to the standard output is not processing. This needs to be replaced, probably by an exception handled somewhere by storing the order for future delivery. In fact we don't handle partial deliveries here at all.

The interface with this system is the OrderEntry class, which is a GUI. It uses the principles defined in my Event Patterns paper. More examples of similar things can be found in the Building GUI's Correctly paper also. The constructor defines the GUI and all of its elements. The buttons are associated with ActionListeners which are defined in inner (nested) classes within the OrderEntry class. The actionPerformed method of an attached listener defines what happens when the button is pushed. The listeners need to register with the button they will handle. This is the Observer pattern (see Grand). Almost all of the work of the application is defined in these action listeners.

We haven't talked about the design of this code, just its details. For completeness, here is a class diagram.It doesn't show inheritance, however.

The Maintenance and test classes will be discussed separately.

Last Updated: September 3, 2006