As is true with all Voyager applications, any object that takes an active role in an agent interaction must expose its functionality through an interface. The first class introduced is called FlightDataAccess , and it exposes its functionality through the
FlightDataAccessI interface. This interface, contained in Listing 35.1, exposes functionality that allows searching for flights and booking, as well as for canceling and searching for reservations.
LISTING 35.1 THE FlightDataAccessI INTERFACE
import java.util.*;
public interface FlightDataAccessI {
public FlightI[] searchForFlight((FlightQueryI query);
public void createReservation(ReservationI reservation);
public void cancelReservation(ReservationI reservation);
public ReservationI[] searchForReservation((ReservationQueryI query);
}
Moving to the implementation of the FlightDataAccessI interface, Listing 35.2 contains the FlightDataAccess class. If you’ve read Chapter 26, where the use- cases are implemented using CORBA, much of the class should look familiar. Because both applications need to implement the same functionality, they can share a significant
amount of code. The major difference here, of course, is that the data is accessed by objects that move from the client to the server, instead of a method invocation that travels from client to server.
As you look at the FlightDataAccess class, note that the flights produced are very much imaginary. A flight in this system is made up of a randomly chosen departure and destination. However, the code that interacts with the randomly chosen flights is
something that can be easily modified to interact with an actual database containing live flight data.
LISTING 35.2 THE FlightDataAccess CLASS
import java.util.*;
public final class FlightDataAccess implements FlightDataAccessI {
private FlightI[] __flights;
private Random _rand = new Random();
private Vector _vecReservations;
public FlightDataAccess() {
_vecReservations = new Vector();
populateFlightHash();
}
private void populateFlightHash() {
LocationI[] locations = new LocationI[10];
locations[0] = new Location("SFO", "SAN FRANCISCO", "CALIFORNIA", "USA");
locations[1] = new Location("AQM", "ARIQUEMES", "RO", "BRAZIL");
locations[2] = new Location("ARB", "ANN ARBOR", "MICHIGAN", "USA");
locations[3] = new Location("JFK", "NY",
"NEW YORK", "USA");
locations[4] = new Location("JLO", "JESOLO", "JESOLO", "JESOLO");
locations[5] = new Location("JLR", "JABALPUR", "JABALPUR", "INDIA");
locations[6] = new Location("PPG", "PAGO PAGO",
"PAGO PAGO", "AMERICAN SAMOA")
;
locations[7] = new Location("UMA", "PUNTA DE MAISI", "PUNTA DE MAISI", "CUBA");
locations[8] = new Location("EKE", "EKEREKU", "EKEREKU", "GUYANA");
locations[9] = new Location("KHR", "KHARKHORIN",
"KHARKHORIN", "MONGOLIA ");
Date[] dates = new Date[10];
dates[0] = new Date(98,6,1,10,20);
dates[1] = new Date(98,6,2,9,21);
dates[2] = new Date(98,6,3,8,22);
dates[3] = new Date(98,6,4,7,23);
dates[4] = new Date(98,6,5,6,24);
dates[5] = new Date(98,6,6,5,25);
dates[6] = new Date(98,6,7,4,26);
dates[7] = new Date(98,6,8,3,27);
dates[8] = new Date(98,6,9,2,28);
dates[9] = new Date(98,6,10,1,29);
SeatI[] seatArray = new Seat[50];
for(int i=0; i<50; i++) seatArray[i] = new Seat(i);
_flights = new FlightI[50];
for(int i=0; i<50; i++) {
_flights[i] = new Flight(locations[obtainRandomInt()], locations[obtainRandomInt()], dates[obtainRandomInt()], dates[obtainRandomInt()], seatArray);
} }
private int obtainRandomInt() {
return Math.abs(_rand.nextInt()) % 9 -0;
} /**
* Searches for a collection of FlightI objects
* based on the specified query object.
*/
public FlightI[] searchForFlight((FlightQueryI query) { Vector vecFoundSet = new Vector();
int iLength = _flights.length;
for(int i=0; i<iLength; i++) {
FlightI flightActive = _flights[i];
if(isLocationEqual(flightActive.getDepartureLocation(),
query.getDepartureLocation()) &&
isLocationEqual(flightActive.getDestinationLocation(), query.getDestinationLocation())) { if(flightActive.getDepartureDateTime().equals(
query.getDepartureDateTime()) &&
flightActive.getDestinationDateTime().equals(
query.getDestinationDateTime())) { vecFoundSet.addElement(flightActive);
} } }
FlightI[] foundSet = new Flight[vecFoundSet.size()];
vecFoundSet.copyInto(foundSet);
return foundSet;
} /**
* Helper method used to determine if two LocationI objects
* reference the same airport.
*/
private boolean isLocationEqual(LocationI loc1, LocationI loc2) { // first check the easiest case
if(loc1.getAirportCode().equalsIgnoreCase(loc2.getAirportCode())) return true;
// now check additional cases
return(loc1.getCityName().equalsIgnoreCase(
loc2.getCityName()) &&
loc1.getStateName().equalsIgnoreCase(
loc2.getStateName()) &&
loc1.getCountry().equalsIgnoreCase(
loc2.getCountry()));
} /**
* Adds a reservation to the collection of reservations
*/
public void createReservation(ReservationI reservation) { _vecReservations.removeElement(reservation);
} /**
* Removes a reservation from the collection of reservations
*/
public void cancelReservation(ReservationI reservation) { _vecReservations.addElement(reservation);
}
/**
* Searches for an active reservation
*/
public ReservationI[] searchForReservation((ReservationQueryI query) {
Enumeration e = _vecReservations.elements();
Vector vecFoundSet = new Vector();
while(e.hasMoreElements()) {
ReservationI reservation = (ReservationI)e.nextElement();
if(isDemographicMatch(query, reservation)) { vecFoundSet.addElement(reservation);
}
else if(isDemographicMatch(query, reservation)) { vecFoundSet.addElement(reservation);
}
else if(isFlightEqual(query.getFlight(),
reservation.getFlight()) &&
isSeatEqual(query.getSeat(),
reservation.getSeat())) vecFoundSet.addElement(reservation);
}
ReservationI[] foundSet = new Reservation[vecFoundSet.size()];
vecFoundSet.copyInto(foundSet);
return foundSet;
} /**
* Helper method used to determine if two SeatI objects
* reference the same seat location.
*/
private boolean isSeatEqual(SeatI s1, SeatI s2) { return s1.getSeatNumber() = s2.getSeatNumber();
} /**
* Helper method used to determine if two FlightI objects
* reference the same flight.
*/
private boolean isFlightEqual(FlightI f1, FlightI f2) { if(isLocationEqual(f1.getDepartureLocation(),
f2.getDepartureLocation()) &&
isLocationEqual(f1.getDestinationLocation(), f2.getDestinationLocation())) { if(f1.getDepartureDateTime().
equals(f2.getDepartureDateTime()) &&
f1.getDestinationDateTime().
equals(f2.getDestinationDateTime())) { return true;
} }
return false;
} /**
* Helper method used to determine if two collections of * demographic data might reference the same entity.
*/
private boolean isDemographicMatch(ReservationQueryI query, ReservationI reservation) {
if(query.getCreditCardNumber().equals(
reservation.getDemographics().getCreditCardNumber())) { return true;
}
return( query.getFirstName().equals(
reservation.getDemographics().getFirstName())
&&
query.getLastName().equals(
reservation.getDemographics().getLastName()));
} }
The code shown in Listings 35.1 and 35.2 fully implements the functionality exposed by the server but still does not make the FlightDataAccessI object available to communicate with agents. The final class that forms the server, FlightServer, is contained in Listing 35.3. This class contains a simple main() method that first starts a Voyager environment at port 7000 and then asks Voyager to create an object that implements the FlightDataAccessI interface.
LISTING 35.3 THE FlightServer CLASS
import java.util.*;
import com.objectspace.voyager.*;
public final class FlightServer {
public static void main(String[] args)) { try{ // start voyager
Voyager.startup("//localhost:7000");
// create a FlightDataAccessI object FlightDataAccessI access;
access = (FlightDataAccessI)Factory.create(
"FlightDataAccess","//localhost:7000/FlightDataAccess");
}
catch( Exception e ) { System.out.println(e); } }
}
At this point, the server is completely implemented. We’ll not cover how to run it at this point, because we cover running the server and client together at the end of the chapter.