Assignment 5

Due Monday, April 13, 2009 6:00pm on-line

Supplemental pages

Your assignment

Your assignment is to use Java RMI to write a program to find the five nearest airports to a given town. You will have two server programs that are contacted through remote methods: one is responsible for looking up places, returning the longitude and latitude for a place; the other is responsible for taking a latitude and longitude as input and returning the five nearest airports.

The following figure illustrates the process:

Details

You will be writing two servers and one client for this assignment:

Client (Client.java)

The client is designed to test your servers. It accepts a simple command-line interface:

java Client [ -h rmiregistryserver ] [ -p port ] city state 

where:

  • rmiregistryserver is the name of the server where you are running the rmiregistry with which the servers will register themselves (typically the same system as the servers are running on). The -h rmiregistryserver is optional. If it is omitted, localhost is used as a default.
  • port is the number of the port on which the rmiregistry is listening. If -p port is omitted, the default rmiregistry port, 1099, is used.
  • city state arguments identify the city and state for the query (for example, Princeton NJ, "New Brunswick" NJ; note the use of quotes to ensure that the shell treats New Brunswick as one argument).

The client looks up the two RMI services: the first for looking up places and the second for looking airports. It then contacts the first service to look up the place (city, state) to find its latitude and longitude and then contacts the second service to get a list of nearest airports. In summary:

  1. look up the places server
  2. look up the airports server
  3. (place name, state, latitude, longitude) = find_place(city, state)
  4. print full place name, state, latitude, longitude
  5. list of five nearest: (airport code, state, distance) = find_airports(latitude, longitude)
  6. print each airport code, airport name, distance

For example:

$ java Client Princeton NJ Princeton borough, NJ: 40.352206, -74.657071 code=TTN, name=Trenton, state=NJ distance: 10 miles code=WRI, name=Mcguire AFB, state=NJ distance: 23 miles code=PNE, name=North Philadelphia, state=PA distance: 27 miles code=NXX, name=Willow Grove, state=PA distance: 28 miles code=NEL, name=Lakehurst, state=NJ distance: 28 miles $ java Client Anchorage AK Anchorage municipality, AK: 61.1919, -149.762097 code=MRI, name=Anchorage, state=AK distance: 2 miles code=ANC, name=Anchorage, state=AK distance: 8 miles code=PAQ, name=Palmer, state=AK distance: 38 miles code=ENA, name=Kenai, state=AK distance: 65 miles code=SKW, name=Skwentna, state=AK distance: 72 miles

Place server

The place server comprises three programs:

  1. server (PlaceServer.java, startup and registration)
  2. interface definition
  3. service class (Places.java, the stuff that does the work)

You may also need a Java file to define a data structure to store state, city, latitude, and longitude information.

Your place server [1] accepts an optional argument identifying the port number on which the rmiregistry is listening (see the rmi-example sample program). The rmiregistry process runs on the same server as this server. The server's only function is to parse arguments, install a security manager, and register the places service with the RMI registry. You can pretty much copy SampleServer.java and change the names.

The interface definition [2] defines the interface for the lookup function, which accepts a location and state (two strings) and returns a data structure containing place information.

You can use the code in sample-rmi as a pattern: SampleInterface.java defines the method exposed via the remote interface whose implementation is in the server code – Sample.java.

For this assignment, you will define two interfaces:

  1. an interface that defines the places service: a method that takes a city and state and returns information about the place.
  2. an interface that defines the airport info service: a method that takes a latitude and longitude and returns an array of nearest airports.

The two server functions implement these interfaces (one each). For example, your PlaceServer.java program might instantiate a class called Places that implements the remote interface ( Naming.rebind(url, new Places())). Places.java implements PlacesInterface, which defines a find_place method that returns a class (data structure) that's populated with information about the place.

The places service itself [3] accepts two arguments: the name of the place and a two-letter abbreviation for the state. It returns a structure containing:

  • full place name (useful if you're doing a match on the leading substring)
  • state
  • latitude
  • longitude
Be sure to return the latitude and longitude not as strings but of type float or double.

A null is returned if the name is not found.

Upon startup, the service reads in the contents of the file places2k.txt (extract it from places.zip), a list of place names compiled by the U.S. Census. The places file contains data for all Incorporated and Census Designated places in the 50 states, the District of Columbia and Puerto Rico as of the January 1, 2000. The file is plain ASCII text, one line per record:

columns meaning
1-2 United States Postal Service State Abbreviation
3-4 State Federal Information Processing Standard (FIPS) code
5-9 Place FIPS Code
10-73 Name
74-82 Total Population (2000)
83-91 Total Housing Units (2000)
92-105 Land Area (square meters) - Created for statistical purposes only.
106-119 Water Area(square meters) - Created for statistical purposes only.
120-131 Land Area (square miles) - Created for statistical purposes only.
132-143 Water Area (square miles) - Created for statistical purposes only.
144-153 Latitude (decimal degrees) First character is blank or "-" denoting North or South latitude respectively
154-164 Longitude (decimal degrees) First character is blank or "-" denoting East or West longitude respectively

Airport server

The airport server comprises three programs:

  1. server (AirportServer.java, startup and registration)
  2. interface definition
  3. service class (Airports.java, the stuff that does the work)
You may also need a Java file to define a data structure to store data such as the airport code, name, state, latitude, and longitude.

Your airport server [1] accepts an optional argument identifying the port number on which the rmiregistry is listening (see the rmi-example sample program). The rmiregistry process runs on the same server as this server. The server's only function is to parse arguments, install a security manager, and register the places service with the RMI registry. You can pretty much copy SampleServer.java and change the names.

The interface definition [2] defines the interface for the lookup function, which accepts a latitude and longitude (two floats or doubles) and returns an array of the five closest airports.

The airport service itself [3] accepts two arguments: the latitude and longitude that was found from the places service. It returns an array of the closest airports, with each structure containing:

  • Airport code
  • Airport name
  • Airport's latitude (float or double)
  • Airport's longitude (float or double)
  • Distance from search city (miles)

Upon startup, the service reads in the contents of the file airport-locations.txt (extract it from places.zip), which contains a list of 1,065 airport locations in the U.S. The file is plain ASCII text, one line per record but includes blank lines and a header on the first line. Its format is:

[airport_code] latitude longitude city

Implementation Advice

  1. Before starting this assignment, make sure that you can understand, compile, and run programs that use Java RMI. Read the recitation notes for programming Java RMI (see the RPC lecture). Then download the sample program rmi-example.tar (or rmi-example.zip for the zip version). Extract it with:
    tar xvf rmi-example.tar
    (or unzip rmi-example.zip). This will create a directory named rmi-example with a bunch of files in it, including a README file.
  2. I recommend writing a standalone version first just to ensure that you're doing all the parsing correctly and getting the correct results.
  3. Reading and parsing places2k.txt: Open the file using FileReader and BufferedReader and read the lines one at a time using the readLine method. Since the data occupy fixed fields, each datum can be extracted via the substring method. Use trim to remove extra whitespace that you might have grabbed. For example:
    String name = line.substring(9,73).trim();
    
    You can parse the latitude and longitude with the parseDouble method of the Double class.
  4. Storing place information: It's up to you to pick a decent data structure to make searching easy. Don't get carried away. Go with something simple that works (at least as a first pass). Using a Vector, for example, is perfectly fine. The only thing you shouldn't use is a fixed-length array. If you're serious about this, realize that there's only one key: all your searches are by city.
  5. Searching places: I just search for a place name where the string given by the user matches the leading string of the name (e.g., using regionMatches). This way, the user doesn't have to worry about the peculiarities of typing things like "princeton borough." There might be cases where this could give you a false match but I didn't worry about that. Neither should you. Doing a case-insensitive match up to the length of the string given by the user for the place name is fine for this assignment. (You don't need to use regionMatches to match strings. I used that instead of startsWith so I could specify a case-insensitive match without having to convert both strings to a known case. There are other ways of doing this.)
  6. Reading and parsing airport-locations.txt: To weed out lines that don't contain airport info, you can just skip any lines that don't have a comma; it will save checking if a line is blank or is a header. The airport code, latitude, and longitude occupy fixed columns: you can extract that data with substring. The airport name is everything between a tab and a comma. The state is everything after the comma. You can use substring again but you'll need to set markers with indexOf.
  7. Calculating distance: You can approximate the distance between two points by using spherical trigonometry and calculating the great circle distance. The distance in nautical miles between two points is:
    d = 60 cos-1( sin(lat1) sin(lat2) + cos(lat1) cos(lat2) cos(lon2-lon1))
    Where lat is latitude and lon is longitude. Both are expressed in degrees. In Java, you'll have to convert the values to radians (Math.toRadians) before calling Math.sin or Math.cos and convert the result from Math.acos back to degrees with Math.toDegrees. Finally, you'll need to convert the result from nautical miles to statute miles by multiplying by 1.1507794 (1 nautical mile = 1.1507794 statute miles).
  8. Your assignment does not have to be multi-threaded.
  9. rmiregistry has to run on the same machine as your server. You should use localhost as the hostname on your server. You will lose many points for using hard-coded names such as remus or eden or romulus.

Submission

Before submitting, create a file named id that contains your full name on the first line and your id number on the second line. Make sure you have a newline at the end of the second line.

To submit the assignment, you will create a tar archive of all the files that are needed to compile the no class files.

So that I can remain sane while testing your program, be sure that you name your test client Client.java, your airport info server AirportServer.java, and your place server PlaceServer.java. Name the class that implements place lookup Places.java and the class that implements airport lookup Airports.java.

Before sending the file to me, make sure that all the components are there. If I can't compile it, you will lose virtually all credit:

        mkdir test
	cd test
        tar xvf a5.tar
        javac *.java
	rmic Places
	rmic Airports

Also, make sure that no stray files are present (e.g. .class files or emacs temporary files). You will lose points for sloppy submissions. In particular, be sure that you do not submit the places2k.txt and airport-locations.txt files. I already have those and you did not modify them.

Hand the assignment in using the web-based handin procedure. Go to https://handin.rutgers.edu/. If you never used web-based handin, check out the instructions at https://handin.rutgers.edu/handin/manual/stud/stud.html . The project name for this assignment is Assignment 5.