Objectives:
Overview:
In this laboratory you will write and test a shared file repository based on Java RMI. The project is divided on three parts:
FileRepository object from a main program.
Note: Prior to starting this laboratory you should be sure that you have successfully run the SimpleHello remote server. If you have any problems in doing this, see your instructor.
Requirements:
Part I: The nonremote implementation
As part of this assignment, you will need to implement two interfaces:
the Directory and the FileObject
(e.g., DirectoryImpl and FileObjectImpl).
In Parts II and III, the Directory
will become a remote interface
and FileObject will be passed to a remote object.
You will need to modify them as described below.
DirectoryImplNonRemote class
that implements the Directory interface:
public interface Directory {
public void create(String filename) throws Exception;
public FileObject getFile(String filename) throws Exception;
public Vector getListing( ) throws Exception;
public void remove(String filename) throws Exception;
public void update(FileObject f) throws Exception;
}
Your implementation should keep a Vector of the filenames
of the FileObjects that have already
been created in the repository.
The Vector should be ordered alphabetically.
Your implementation should
keep the FileObjects of the repository
in a hash table. Use the
Hashtable class for this.
create method creates a new
FileObject object, puts the filename
in its Vector
of filenames and puts the FileObject in the Hashtable
using the filename as the hash key.
The create method throws an Exception if a
FileObject with that filename already
exists in the repository or if the object creation or insertion into
the repository fails.
getFile method returns a FileObject
with the current contents of the file indicated by filename.
The getFile method throws an Exception if an
FileObject with that filename does not
exist in the repository.
getListing method returns the Vector with names
of the FileObjects currently in the repository. If the
repository is empty, an empty Vector will be returned.
remove method removes the FileObject
from the repository with the designated.
The remove method should also
invalidate the FileObject as described below.
The remove method throws an Exception if
the object is not in the repository.
update method replaces the data of FileObject
of the same name as f with data of f. The
read and
write methods of the FileObject are used.
The
update method throws an Exception if the
object is not in the repository.
FileObjectImpl class that
implements the FileObject interface:
public interface FileObject {
public String getName();
public int getSize();
public int getVersion( );
public byte [] read( ) throws Exception;
public void write (byte [] b) throws Exception;
}
The FileObject
represents a file that has been put in the repository.
getName method returns the filename
of the object.
getSize method returns the number of
bytes of data in the file represented by the object.
getVersion method returns the
version number of the file represented by the object.
read method returns an array of bytes
containing a copy of the data in the file. The read
method throws an Exception if there was an
error in reading the file or in creating the array of bytes
to return.
write method replaces the data in the
file with the bytes from the array b and
increments the version number. The write method
also updates the size. The write should first
create a new local file to hold the data before removing
the old one. The write method throws an
Exception if it is unable perform the replacement.
In your implementation, you
must store the data for the FileObject in a
disk file. Your FileObjectImpl should also
implement a finalize method that removes the
local data file associated with the FileObject.
The finalize method will be called when the
object is garbage collected.
Your FileObjectImpl should have a constructor
that takes a String parameter filename.
A newly created FileObjectImp must initially be
empty. You will call the write method to
actually put data in the file.
main method of DirectoryImpl or
write a separate test class.
Part II: Remote version with no synchronization
In Part II you will convert the Directory interface and the
DirectoryImpl class to support remote invocation. As in part I,
you
can design a server class that instantiates a
Directory object and registers it with registry. Alternatively,
you can include that code in the main method of
DirectoryImpl. In either case, pass
the port number of the registry and the name that the Directory
object will be registered under as command line arguments. These values should
should be into the constructor of the DirectoryImpl class.
The FileObject interface represents a local object that will
be passed remotely by value. In the remote implementation, the FileObjectImpl
class must implement Serializable. The added complication in this
problem is that the default technique for serialization will probably not work,
because data from the object is kept on disk and local files only have meaning
in a local environment. You will need to define your own methods with
the following signature:
private void readObject (ObjectInputStream in) throws
IOException, ClassNotFoundException;
private void writeObject (ObjectOutputStream out)
throws IOException;
You can call:
in.defaultReadObject( );
in the readObject to read in the default serialization first.
You can call:
out.defaultWriteObject( );
in the writeObject method to write the default serialization
before writing the special information.
Note: it would be wise to test the serialization of FileObjectImpl
locally before trying to pass it by value in a remote call.
You should test your remote invocation and all of the methods with a single client.
Part III: Synchronization for multiple clients
If more than one client accesses your remote objects, you must provide synchronization.
Each java object has its own monitor. When you declare a method to be synchronized, e.g.:
public synchronized Vector getList( ) throws RemoteException
the code within the method is executed mutually exclusively with the other
synchronized methods in the object. The simplest way to handle synchronization,
is to declare each method to be synchronized. This approach can
be very inefficient. To receive full credit, you must implement a readers-writer
type synchronization for your DirectoryImpl. You must also include
in your writeup a discussion of your approach.
Test your synchronization by creating multiple simultaneous clients to access the repository.
client.policy
takes care of writing, reading, and
deleting files in one's home directory or subdirectories:
permission java.io.FilePermission "${user.home}${/}-", "read,write,delete";