Assignment 5 FAQ, Errata, and Addenda
Last update: Wednesday, April 8, 2009 10:16 EDT
Common Java-related Questions
- I cannot run rmic on remus.
- Add /usr/local/java/bin to your PATH environment or run /usr/local/java/bin/rmic.
-
When I run the demo program and pass the arg,
"this is just a test", it actually treats each of the words in that single string as separate. So instead of printing:tset a tsuj si sihtit prints:
siht si tsuj a tset - The java environment on remus (and possibly other Rutgers machines) is seriously messed up. The program you're really executing is /usr/local/bin/java, which is a buggy c-shell script that not only doesn't handle arguments properly but also somehow messes up the resolution of localhost. Use /usr/local/java/bin/java to run your programs. It's still a buggy ksh script but seems to work ok in this case.
- I'm getting a java.lang.ClassNotFoundException: Sample_Stub exception.
-
There are two things you should check:
- Make sure that your CLASSPATH includes the directory where the stub file(s) live when running the rmiregistry.
- If you start your rmiregistry on a different port than the default 1099, make sure that your server and client are modified appropriately to access that port and that you're not connecting to somebody else's instance of rmiregistry that is listening on another port.
- I get a Sample server failed:access denied (java.net.SocketPermission 127.0.0.1:1099 connect,resolve) error.
-
Again, there are a couple of things to check:
- check that you have an rmiregistry running
- check that you have the policy file in the directory where you are running java -Djava.security.policy=policy SampleServer
- How do I set a CLASSPATH?
-
If you're using bash, ksh, or sh, set it via:
CLASSPATH=$CLASSPATH:/ug/u0/pxk/src/rmihello export CLASSPATH
Where /ug/u0/pxk/src/rmihello is replaced with the directory where your files live. Alternatively, if you plan on starting all services from that directory, you can add . to the CLASSPATH instead of the full pathname to tell java to search the current directory. If you're using csh or tcsh, you can set a CLASSPATH via:setenv CLASSPATH /ug/u0/pxk/src/rmihello
- I want to run rmiregistry, the client, and the server on different machines. What files must I copy?
-
For the client, you need
SampleClient.class, SampleInterface.class, Sample_Stub.class.
For the server, you need Sample.class, SampleInterface.class, SampleServer.class, Sample_Stub.class, policy.
For rmiregistry, you need SampleInterface.class, Sample_Stub.class. - Does the rmiregistry have to run on the same machine as the server?
- Unfortunately, it does. 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.
- When I run the rmiregistry command, I can specify the port on the command line. How do I tell the client to connect to whatever port that I specify there?
-
In your client, you need to specify the host and port of the rmi registry when you do a lookup. This is a URI-named entity of the form rmi://hostname:port/interfacename (for example, rmi://localhost:4422/Weather). If :port is missing, the default is :1099. You'll have to construct this name on the fly (i.e., concatenate strings).
In your server, you'll need to tell the server to bind to a particular rmi registry. This is done in a similar manner, where you will create a string containing the URI. For example: Naming.rebind("rmi://localhost:4422/Weather", new Weather())
-
I get this error when I run the SampleServer on remus:
Sample server failed:Unknown host: localhost; nested exception is: java.net.UnknownHostException: localhost - I believe this is due to the messed-up java environment on remus. (and possibly other machines). Use /usr/local/java/bin/java to run your programs.
FAQ
- Does java have convenient command line parsing libraries so I can parse command-line options (similar to getopt for C)?
- I don't know of any good command line parsing libraries but I've never searched for them. I'm sure there are getopt clones but I've always done my own work of iterating through the arg list. It might be lame but it was quick (and dirty). See this example.
- Should multiple clients connect to the rmi server ? In other words, do we have to make the server a multi-threaded one ?
- No, it need not be multi-threaded.
-
A student points out that some of my distance calculations are incorrect. Even though we're using the same formula, some of the values are slightly different. I still didn't track down where the mistake is. The bottom line is: if you're getting sensible answers, don't worry if they don't match what is posted in the assignment. For example, the student's output, which I believe is more correct is:
$ java Client Princeton NJ Princeton borough, NJ: 40.352206, -74.6570715 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=NEL, name=Lakehurst, state=NJ distance: 28 miles code=NXX, name=Willow Grove, state=PA distance: 28 miles $ java Client Anchorage AK Anchorage municipality, AK: 61.1919, -149.762097 code=MRI, name=Anchorage, state=AK distance: 4 miles code=ANC, name=Anchorage, state=AK distance: 9 miles code=PAQ, name=Palmer, state=AK distance: 36 miles code=ENA, name=Kenai, state=AK distance: 66 miles code=SKW, name=Skwentna, state=AK distance: 72 miles - You say that for the servers, there should be an "optional" port number argument? So if a port is not provided then should the 1099 port number be assumed? Also, how do I make sure that the port that the client is trying to run on is the same port that the server is running on? Or does the client need to know ahead of time?
- The port you're specifying on the servers is the port on which the rmiregistry is running. If you don't specify one then you should assume 1099, the default rmiregistry port. The client will also need to specify a port so it can do a lookup on the rmiregistry. There's no way to make sure that it's accessing the same one that the server is using - the user just has to enter the correct port numbers.
- If the user specifies a host name, do I have to change anything on the server code? For example, the PlaceServer and AirportServer both have url's which have "localhost" in them. Should this still remain or should this be changed if the used passes in a host number? Or is the server always run on localhost and it's the client's job to figure out where the server is running on?
- There's nothing you need to do on the server. The rmiregistry runs on the server and the server processes bind to it with a url such as //localhost:12345/Airports, where 12345 is the port number of the rmiregistry (for example).
-
My standalone functions work fine. When I try to put everything together and run it, I get the following error on the client side:
Client exception: java.rmi.UnmarshalException: error unmarshalling return; nested exception is: java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: PlaceNode -
The data structure that you're returning needs to be defined to "implements Serializable". Just change
class PlaceNode { String name; String state; double latitude; double longitude; }to
class PlaceNode implements Serializable { String name; String state; double latitude; double longitude; }and you should be fine. There's nothing else you need to do to implement Serializable. Just by adding that declaration, Java will serialize the entire data structure (class) by going through each of the elements and invoking the serialize() method. All of the basic Java types support it.
-
Update:
I've updated the
airport-locations.txtfile in places.zip to fix eight entries that were missing state names. Your code should not have to change to handle this file.