|
Remote Method Invocation
An Introduction |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
Marshalling/Unmarshalling
Stubs and Skeletons
import java.io.Serializable;
/**
* A Course
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class Course implements Serializable
{
private int number;
private String department, title;
/**
* Explicit Value Constructor
*
* @param department The department code
* @param number The course number
* @param title The course title
*/
public Course(String department, int number, String title)
{
this.department = department;
this.number = number;
this.title = title;
}
/**
* Get the course designation
*
* @return The course designation
*/
public String getDesignation()
{
return department+number;
}
/**
* Get the course title
*
* @return The course title
*/
public String getTitle()
{
return title;
}
}
/**
* Methods that must be implemented by a database of Course objects
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public interface CourseDatabase
{
/**
* Add a Course
*
* @param course The Course to add
*/
public void add(Course course);
/**
* Get a Course
*
* @param course The Course to add
*/
public Course get(String department, int number);
/**
* Remove a Course
*
*
* @param department The department code
* @param number The course number
*/
public void remove(String department, int number);
}
import java.util.*;
/**
* The implementation of a database of Course objects
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class CourseDatabaseImpl implements CourseDatabase
{
private HashMap<String, Course> db;
/**
* Default Constructor
*/
public CourseDatabaseImpl()
{
db = new HashMap<String, Course>();
}
/**
* Add a Course
*
* @param course The Course to add
*/
public void add(Course course)
{
db.put(course.getDesignation(), course);
}
/**
* Get a Course
*
* @param course The Course to get
*/
public Course get(String department, int number)
{
return db.get(department+number);
}
/**
* Remove a Course
*
* @param department The department code
* @param number The course number
*/
public void remove(String department, int number)
{
db.remove(department+number);
}
}
import java.io.*;
import java.net.*;
/**
* A simple stub for a remote database of Course objects
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class CourseDatabaseStub implements CourseDatabase
{
private ObjectOutputStream out;
private ObjectInputStream in;
private Socket s;
/**
* Constructor
*/
public CourseDatabaseStub(String host, int port)
{
try
{
s = new Socket(host, port);
out = new ObjectOutputStream(s.getOutputStream());
in = new ObjectInputStream(s.getInputStream());
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
/**
* Add a Course
*
* @param course The Course to add
*/
public void add(Course course)
{
try
{
out.writeObject("add");
out.writeObject(course);
out.flush();
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
/**
* Get a Course
*
* @param course The Course to add
*/
public Course get(String department, int number)
{
Course course;
course = null;
try
{
out.writeObject("get");
out.writeObject(department);
out.writeInt(number);
out.flush();
course = (Course)in.readObject();
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
catch (ClassNotFoundException cnfe)
{
cnfe.printStackTrace();
}
return course;
}
/**
* Remove a Course
*
* @param department The department code
* @param number The course number
*/
public void remove(String department, int number)
{
try
{
out.writeObject("remove");
out.writeObject(department);
out.writeInt(number);
out.flush();
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
}
import java.io.*;
import java.net.*;
import java.util.*;
/**
* A simple skeleton for a database of Course objects.
*
* Note: This approach does not use a registry.
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class CourseDatabaseSkeleton implements Runnable
{
private int port;
private Thread controlThread;
private CourseDatabase implementation;
private ObjectInputStream in;
private ObjectOutputStream out;
/**
* Constructor
*/
public CourseDatabaseSkeleton(CourseDatabase implementation,
int port)
{
this.implementation = implementation;
this.port = port;
}
/**
* Add a Course
*/
public void add() throws ClassNotFoundException, IOException
{
Course course;
// Get arguments from the stub
course = (Course)in.readObject();
// Make the call to the implementation
implementation.add(course);
}
/**
* Get a Course
*/
public void get() throws ClassNotFoundException, IOException
{
Course course;
int number;
String department;
// Get arguments from the stub
department = (String)in.readObject();
number = in.readInt();
// Make the call to the implementation
course = implementation.get(department, number);
// Return course to the stub
out.writeObject(course);
out.flush();
}
/**
* Read a method invocation from the stub
*/
public void readFromStub()
{
String method;
try
{
method = (String)in.readObject();
if (method.equals("add")) add();
else if (method.equals("get")) get();
else if (method.equals("remove")) remove();
}
catch (IOException ioe)
{
// Ignore
}
catch (ClassNotFoundException cnfe)
{
// Ignore
}
}
/**
* Remove a Course
*/
public void remove() throws ClassNotFoundException, IOException
{
int number;
String department;
// Get arguments from the stub
department = (String)in.readObject();
number = in.readInt();
// Make the call to the implementation
implementation.remove(department, number);
}
/**
* Entry point for the thread
*/
public void run()
{
ServerSocket ss;
Socket s;
try
{
ss = new ServerSocket(port);
s = ss.accept();
in = new ObjectInputStream(s.getInputStream());
out = new ObjectOutputStream(s.getOutputStream());
while (true)
{
readFromStub();
}
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
/**
* Start this skeleton.
*/
public void start()
{
if (controlThread == null)
{
controlThread = new Thread(this);
controlThread.start();
}
}
}
import java.io.*;
/**
* A factory that can be used to create objects that implement the
* CourseDatabase interface
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class CourseDatabaseFactory
{
public static final int port = 9100;
public static final String host = "localhost";
/**
* Create a CourseDatabase
*/
public static CourseDatabase createCourseDatabase()
{
return (new CourseDatabaseImpl());
}
/**
* Create a stub that can access a remote CourseDatabase
* server
*/
public static CourseDatabase createCourseDatabaseStub()
throws IOException
{
return (new CourseDatabaseStub(host, port));
}
}
/**
* The client in a homegrown example of remote method invocation
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class ClientDriver
{
/**
* The entry point
*
* @param args The command line arguments
*/
public static void main(String[] args)
{
Course course;
CourseDatabase db;
try {
db = CourseDatabaseFactory.createCourseDatabaseStub();
db.add(new Course("CS",139,"Algorithm Development"));
db.add(new Course("CS",240,"Data Structures and Algorithms"));
db.add(new Course("CS",349,"Developing Multimedia Content"));
db.add(new Course("CS",462,"Network Applications Development"));
course = db.get("CS",462);
System.out.println(course.getDesignation()+"\t"+
course.getTitle());
System.out.flush();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
/**
* A server that uses a homegrown version of remote method invocation
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class ServerDriver
{
/**
* The entry point
*
* @param args The command line arguments
*/
public static void main(String[] args)
{
CourseDatabase implementation;
CourseDatabaseSkeleton skeleton;
try
{
implementation = new CourseDatabaseImpl();
skeleton = new CourseDatabaseSkeleton(implementation,
CourseDatabaseFactory.port);
skeleton.start();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
One Possible Design