The final step of implementing the Airline Reservation System is to develop the client software. As with the CORBA example, this implementation only interacts with the parts of the server that allow for searching of available flights. The main purpose of the exercise is to demonstrate how a collection of use-cases are realized using Voyager—
filling the pages with lines and lines of GUI code would just confuse matters.
The client application contains two classes, FlightClient and SearchDialog, and also exposes SearchDialog’s functionality via the SearchDialogI interface. The FlightClient class contains a main() method and also builds the initial user interface. It exposes a list where available flights are displayed and also a button. When clicked, the button causes the display of a SearchDialog object. The SearchDialog object collects search parameters, passes them into a FlightSearcher agent, and sends that agent off to the server. The SearchDialog object then waits for a response, which when received causes a results display back at the FlightClient object, and finally closes itself.
Taking a sequential tour through the application, we’ll begin with Listing 35.13, which contains the FlightClient class.
LISTING 35.13 THE FlightClient CLASS
import java.awt.*;
import java.awt.event.*;
import com.objectspace.voyager.*;
public class FlightClient extends Frame implements ActionListener {
private FlightSearcherI _flightSearcher;
private List _lstResults;
private Button _btnSearch;
public FlightClient() {
super("Search For A Flight");
try{ // start up voyager
Voyager.startup("//localhost:9000");
// create a FlightSearcherI object
_flightSearcher = (FlightSearcherI)Factory.
create("FlightSearcher",
"//localhost:9000/searcher");
}
catch( Exception e ) {}
setLayout(new BorderLayout(10,10));
add(_btnSearch = new Button("Search"), BorderLayout.NORTH);
add(_lstResults = new List(), BorderLayout.CENTER);
_btnSearch.addActionListener(this);
}
class ComponentWithLabel extends Panel {
public ComponentWithLabel(String sLabelText, Component component) { setLayout(new BorderLayout());
add(new Label(sLabelText), BorderLayout.NORTH);
add(component, BorderLayout.CENTER);
} }
public void actionPerformed(ActionEvent ae) { try{ doSearch(); }
catch( Exception e ) { System.out.println(e); } }
private void doSearch() throws Exception {
// ask the Voyager environment to create a SearchDialogI object
Object[] params = {this, _flightSearcher, _lstResults};
SearchDialogI dialog;
dialog = (SearchDialogI)Factory.create("SearchDialog", params,
"//localhost:9000/SearchDialog");
dialog.pack();
dialog.setVisible(true);
}
public static void main(String[] args)) { FlightClient client = new FlightClient();
client.setSize(300,300);
client.setVisible(true);
} }
As you examine Listing 35.13, focus your attention on the code between the try-catch block in the constructor. This code first creates a new Voyager environment at port 9000 and then asks the environment to create a FlightSearcher object at that port. The FlightSearcher object is assigned to a member variable and is then passed into the SearchDialog object when constructed.
Moving your focus to the bottom of the FlightClient class, spend some time with the doSearch() method. This method, invoked when the search button is clicked, causes the display of a SearchDialog object. Due to the fact that the SearchDialog object will be the target of a callback from the agent when it returns from the server, it must expose its functionality through an interface and also be constructed via Voyager. In this method, notice the overloaded version of Factory.create() that’s used. This method accepts an array of objects that are passed into the constructor of the object being constructed. The SearchDialogI interface, exposed by this class, is contained in Listing 35.14. As you look over this interface, note that in addition to exposing the flightSearchResults() callback method, we also expose the pack() and setVisible() methods inherited from the java.awt.Dialog class (and its parents). These methods must also be exposed via the interface to allow for controlling display issues without the expensive task of casting the object as a Dialog object.
LISTING 35.14 THE SearchDialogI INTERFACE
public interface SearchDialogI {
public void flightSearchResults(FlightI[] flights));
public void pack();
public void setVisible(boolean how);
}
The final entity in the client application is the SearchDialog class, contained in Listing 35.15. As you look over this listing, don’t let yourself get bogged down in any of the UI code. You should concentrate your attention on the executeSearch() and
flightSearchResults() methods. The executeSearch() method is invoked when the user enters search criteria and clicks the Search button. The
flightSearchResults() method is invoked by the agent when it returns from its search mission.
LISTING 35.15 THE SearchDialog CLASS import java.awt.*;
import java.awt.event.*;
public class SearchDialog extends Dialog
implements ActionListener, SearchDialogI {
private FlightSearcherI _flightSearcher;
private LocationOptionsPanel _departureLocation;
private LocationOptionsPanel _destinationLocation;
private DateTimeOptionsPanel _departureDateTime;
private DateTimeOptionsPanel _destinationDateTime;
private List _lstResults;
private Button _btnSearch;
public SearchDialog(Frame f,
FlightSearcherI flightSearcher, List lstResults) {
super(f, "Search For A Flight", true);
_flightSearcher = flightSearcher;
_lstResults = lstResults;
// build the UI
_departureLocation = new LocationOptionsPanel();
_destinationLocation = new LocationOptionsPanel();
_departureDateTime = new DateTimeOptionsPanel();
_destinationDateTime = new DateTimeOptionsPanel();
setLayout(new GridLayout(3,2,10,10));
add(new ComponentWithLabel("Departure Location", _departureLocation));
add(new ComponentWithLabel("Destination Location", _destinationLocation));
add(new ComponentWithLabel("Departure Date / Time", _departureDateTime));
add(new ComponentWithLabel("Destination Date / Time", _destinationDateTime));
Panel pnlButtonHolder = new Panel();
pnlButtonHolder.setLayout(new FlowLayout(FlowLayout.RIGHT));
pnlButtonHolder.add(_btnSearch = new Button("Execute Search"));
add(new Label(""));
add(pnlButtonHolder);
_btnSearch.addActionListener(this);
}
class ComponentWithLabel extends Panel {
public ComponentWithLabel(String sLabelText, Component component) { setLayout(new BorderLayout());
add(new Label(sLabelText), BorderLayout.NORTH);
add(component, BorderLayout.CENTER);
} }
public void actionPerformed(ActionEvent ae) { executeSearch();
} /**
* Invoked when the Agent returns with the results
* of our search.
*/
public void flightSearchResults(FlightI[] foundSet)) { int iLength = foundSet.length;
for(int i=0; i<iLength; i++) {
_lstResults.addItem("Flight: "+
foundSet[i].getDepartureLocation() .getAirportCode()+
" "> "+
foundSet[i].getDestinationLocation()
.getAirportCode());
}
// close the frame
setVisible(false);
} /**
* Starts a search */
private void executeSearch() { // create the query object
FlightQueryI query = new FlightQuery(
_departureLocation.getAsLocationObject(),
_destinationLocation.getAsLocationObject()
_departureDateTime.getAsDateObject(),
_destinationDateTime.getAsDateObject());
// ask the agent to perform the search _flightSearcher.searchForFlight(query);
// return immediately, and wait for the results }
}
PUTTING IT ALL TOGETHER
Now that you’ve fully covered the code in Voyager implementation of the reservation application, you’re ready to fire it up and see it in action. First, install the Voyager
software contained on the CD-ROM and then enter in and compile all the code in Listings 35.1 to 35.15. Now start the server by typing
java FlightServer
and start the client by typing java FlightClient
Figure 35.2 shows the application running with the results of a flight search being displayed.
Figure 35.2: The reservation application in action.
FROM HERE
This chapter completed the series of exercises that implement the airline reservation application use-cases. In studying these chapters, you should note the manner in which all solved a common problem using very different technologies. As you go out into the world and start building applications, remember the material covered in these chapters—
it will help you when making technology decisions. If you haven’t already read them, or you need to refresh your memory, the following chapters supplement what was covered in this chapter:
• Chapter 6, “The Airline Reservation System Model”
• Chapter 14, “Socket-Based Implementation of the Airline Reservation System”
• Chapter 16, “RMI-Based Implementation of the Airline Reservation System”
• Chapter 19, “Servlet-Based Implementation of the Airline Reservation System”
• Chapter 26, “CORBA-Based Implementation of the Airline Reservation System”
• Chapter 34, “Voyager Agent Technology”
Part VIII: Summary and References
Chapter List
Chapter 36: Summary
Appendix A: Useful Resources Appendix B: Quick References
Appendix C: How to Get the Most from the CD-ROM
Chapter 36: Summary
Overview
Wait. Before you do anything, stop, reach your left hand up in the air, and pat yourself on the back. If you’re so inclined, pick out a great bottle of wine, decant it, and let it breath as you finish this chapter.
At this point, you’ve learned just about everything that this book has to offer. The 35 chapters that precede this summary detail everything you need to know in order to get up and running with distributed objects. Of course, in order to be completely ready to rock and roll, you’ll need to actually start coding your own applications, but you’re now ready to take this last step. This last chapter takes a look at the topics addressed in earlier chapters and then discusses additional steps you can take to further your understanding of distributed objects. The rest of the book following this chapter serves as a listing for further study and also as a reference of popular entities you’ll encounter in your development plan.
If you flipped to this chapter before actually reading the rest of the book, do feel free to finish up the chapter. Don’t worry, I don’t give away the fact that the butler did it, but I do provide an overview of the material covered in this book. If you are standing in Borders Books and Music reading this, trying to decide whether you should buy the book, you’ve landed on a great decision-making chapter.