Project 6 -  A Versatile Peer-to-Peer (P2P) Service Manager with File Sharing

Due May 14, 6:00PM

Once again, we start with some of the same basic concepts as in Project 5, but add significant additional functionality.  In particular, you will write a general service manager that can provide any service that is registered with it.  Services could include functionality such as the simple message execution implemented for project 5, file sharing, or a chat window.  In addition to the service manager, you will write one instance of a service - a file sharing service similar to Gnutella (a P2P version of Napster) that provides access to files.

Service Manager

Your service manager implements the ServiceManager interface, which provides methods to return the set of services registered in a service manager, and to register and un-register a service.  All services are Java objects, so registering a service just means telling the service manager that the service object has been created.  Inquires about the services a service manager currently supports are by class, meaning that the request is for all service objects that are of the specified class, or one of its subclasses.  All services that match a given request should be returned by a call to getServices().

Messages

The abstract class Message is very similar to the one in Project 5, with a few changes.  First, the Message class has a static final field that specifies a maximum hop count for all messages (for any class derived from Message), which limits the number of clients through which any message can pass. The message creator must also specify a time-to-live for the message, which also limits the number of hops a message can propagate.  Both of these conditions are checked in Message.shouldPropagate(), and enforced by decrementing the time-to-live and current hop count for a message when the message is serialized for transmission to another client.  An IllegalStateException is thrown if a message is propagated when it shouldn't be.  A message class can also implement a wantsToPropagate() method, to perform message-specific checking, which is also enforced by the shouldPropagate() method.  Finally, instead of executing a run() method when a message is received,  the process() method should be called, with the local service manager as an argument (so that the service manager can return the local service(s) that can handle the message).

As for project 5, when a message arrives, check to see if a message with an identical GUID has arrived recently (e.g., 1-5 minutes). If so, ignore the message, and otherwise

You should still limit the number of outstanding messages you send to any given remote client, and if in initiating or forwarding a message you get an error, you should remove that client from your list of known live service managers.

Discovery and Robustness

The discover mechanism is the same as for project 5, including passing known clients as strings on the command line, and using Discovery.broadcast() and Discovery.receive().  We will run a client at  rmi://savoir.cs.umd.edu/wp43301 for you to connect to.  You must still run an RMIRegistry and register your client there.

You should catch exceptions to deal with message errors.  In particular, you must catch RemoteExceptions to deal with a remote client failing while yours is sending it a message, and you must deal properly with slow or otherwise uncooperative clients using threads.  You still need to allow code for stubs and Messages from other clients to be downloaded into your JVM, and you also need to allow your stub and any message classes you define to be downloaded to other clients, with the proper security enforced.

File sharing service

You must also implement a file sharing service to register with your service manager.  Files are searched for with a String keyword.  This service implements the FileSharingServer interface, allowing both requesting a lookup service object that can then be used to perform searches for files, and a method for registering files with the server.  A FileSharingListener object is part of a file lookup request (see the FileQueryMessage class specification), so that the listener can be invoked on each file found that matches the query at a file server.

Documentation and implementation

Overall, you must write clases that implement the following functionality, and we provide the rest of the required classes:

  1. a ClientImpl class that implements the RemoteClient and LocalClient interfaces, which should be very similar to the one implemented for project 5
  2. a ServiceManagerImpl class that implements the ServiceManager interface, and
  3. a FileSharingServerImpl class that implements the FileSharingServer interface.

You can override the classes we provide to test your code, and we will use additional services and alternate implementations of the provided classes (e.g., a FileSharingListener that actually downloads the file from the given URL) to test and grade your code.

The Java documentation for both the interfaces and classes you will implement and those we provide are here.  A jar file containing the Java code for the interfaces and classes is here, and is also available on the cluster in Dr. Pugh's and Dr. Sussman's accounts.

Note that all the provided interfaces and classes are in a set of packages rooted at cmsc433.p6.  Your class implementations should be placed in a package named cmsc433.userid.p6 , with userid replaced with your class account ID.

We also provide sample client driver classes that initiate TextMessages and FileQueryMessages.

Web Accessibility