COMP 310
Spring 2017
|
HW07: Remote task
execution
|
|
Today's example has a "compute engine" (ICompute) on the server which is served
out as a remote object. The client then sends a "compute task"
(ITask) to
the server for it to execute, returning the result to the client. The
key issue here is that the server does not know a priori what the client will
have it do.
Before starting this assignment, be sure that you
can run the demo from Lab08,
which includes configuring your computer for use with RMI.
This assignment, and all future assignments will use TCP
ports in the ranges: 2001-2002 and 2099-2102.
References:
Obtaining and Runnning the demo
The code is available by setting the svn:externals
property (under Team/Set Property) of your
src folder to "provided
https://svn.rice.edu/r/comp310/course/ComputeEngine/provided"
Be sure to set the working directory of both the
client and server launch configurations to your the "bin"
directory in your project.
Also, set both the client and engine (server) launch configurations to be
"shared" so that they will always be set correctly.
See
the Eclipse Resources page for directions
Ports that need to be opened (see the code for
the values):
- In-bound on Server:
- IRemoteTaskViewAdapter.BOUND_PORT_SERVER
-- Used by IRemoteTaskViewAdapter sent from
server to client to display back on server's view.
- ICompute.BOUND_PORT-- The port the
ComputeEngine is bound in the Registry.
- IRMI_Defs.CLASS_SERVER_PORT_SERVER --
The class server the server uses.
- IRMI_Defs.REGISTRY_PORT -- The port the
Registry uses on the server.
- In-bound on Client:
- IRemoteTaskViewAdapter.BOUND_PORT_CLIENT
-- Used by IRemoteTaskViewAdapter sent from
client to server to display back on client's view.
- IRMI_Defs.CLASS_SERVER_PORT_CLIENT --
The class server the client uses.
Click for full-size image
Features
- Via the remote ICompute interface, the
server will execute any ITask implementation
sent to it, returning its results in a type-safe manner.
- When a task arrives at the server, it's
setTaskViewAdapter() method is called to attach it to the server's
view, so that any status output from the task is displayed on the server's
view.
- Not only are the tasks sent from the client to the server, but also, the
ICompute interface provides a
setTextAdapter() method enables the client to send a stub of a view
adapter to the server so that the server can display information on the
client's view plus that same method will return a stub of a view adapter
that will enable the client to display information on the server's view.
- Object serialization:
- Serializable interface tells the
compiler that this object can be serialized, i.e. its data (not its
code!) can be turned into a byte stream and sent over the network.
- Code, if needed, is transmitted separately and automatically.
The client's java.rmi.server.codebase
value is imbedded in the serialized byte stream. The
receiver's Java class loader will look at this value and find the
class file server on the sender and then issue an http-type request
to download the associated class file.
- Note that the class file server does not have to be co-located
with the serialized object's sender. The class file
server can be a separate machine altogether, e.g. a central class
file repository.
- transient fields are not serialized.
- Optional readObject method in
Pi2 and GetInfo is used for
custom deserialization processes, here to reinitialize the
transient taskView
field. The server will attach its own ITaskView adapter so the transmitted task can communicate to the
server.
- IRMIUtils:
- Has services for creating and/or locating the Registry for the
client and server use, plus to obtain the local IP address in a
consistent manner across multiple operating systems.
- Has services to start and stop the RMI sub-system with minimal
effort and maximum reliability.
- Abstracts and encapsulates the Registry obtainment process.
- Uses techniques for composing lambdas to enable the methods to send
multiple messages to multiple output targets.
- Note: There are some typos still running
around where "IRMIUtils" (or its concrete
implementation, RMIUtils) are still referred
to by their old name, "RegistryFactory"
- The client can send a message that will appear on the compute engine's
view and vice versa.
Important concepts:
Stubs retrieved from remote Registries
-- The ICompute stub that the client retrieves via
the Registry delegates its calls back to its
ComputeEngine implementation on the server.
Stubs sent and returned by stubs (stubs as factories)
-- IRemoteTaskViewAdapter stubs are both sent to the
server via a method in the ICompute stub in the
client as well as returned by the ICompute stub as a
return value. Thus a single stub can serve as a factory for all the other
stubs that are needed, eliminating the need for multitudes of objects bound in
the Registry--only a single factory needs to be
bound.
Entire objects being serialized and sent via stubs
-- the ITask objects are being completely serialized
and sent over the network from the client to the server. They are not sent
as stubs.
Automatic remote dynamic class loading of
serialized objects -- If the server does not have the code for the
concrete ITask sent to it, the RMI system settings
that the client and server set up automatically cause the code for the task to
be dynamically loaded from across the network, from the client's class server to
the server. Likewise, this is done for the stubs that are sent back and
forth.
Requirements:
- Special note for teams where the members are running a mix of
32-bit and 64-bit Java computers (this is very rare these days): You will need to use a
special "svn:ignore" property to enable the
different computers to separately and properly compile your code.
Please see the following directions on
how to set the
svn:ignore parameter to ignore
the .classpath file.
You will need to create your OWN client and engine packages,
including their own controller, view and model sub-packages. You can start by simply
copying the provided client and engine package code to your own packages (be sure to rename
the package internally!) and modifying from there.
- Be sure to modify the controller code in both the
copied client and engine packages so that your models and views are being
instantiated, not the provided ones.
- Do NOT copy the
provided.compute
package!
- Do NOT copy or modify the
provided.rmiUtils
or
provide.utils
packages either.
- It is not necessary to copy the
provided.client.model.task
package
except as a convenience.
You may NOT change any of the provided code
-- you will receive a commit error if you do so!
Functionality of the provided
code:
As given, the provided
code
is fully functional in these aspects:
- The client is capable of connecting to the compute engine. But,
upon initial connection
- No verification on the client of the succesful reception of the
IRemoteTaskViewAdapter
stub from the engine.
- No connection verification message sent from client to the engine upon initial
connection.
- No connection verification message sent from the engine to the
client upon initial
connection.
- The
Pi2
and GetInfo
tasks can be sent from the client to engine and are
executed and their results displayed both on the engine and the client.
- Internal status messages generated during the task's execution (i.e.
inside of the task's
execute
method) are displayed on the
compute engine's view.
- The client's
Send msg to remote host's view
text field will
NOT send the given string message to a connected compute
engine's view because the client is missing the stub to do so.
- The compute engines's
Send msg to remote client's view
text
field will NOT send the given string message to a connected
client's view because the engine is missing the stub to do so.
There are 4
locations in the provided code where the student must
implement missing code in their copies (Search the project for "STUDENT TODO") :
-
client.model.ClientModel:
connectTo()
method -- 2 locations
-
engine.model.ComputeEngine
:
remoteTaskViewAdpt
field
setTextAdapter()
method
There are directions in the code as to what needs to be
inserted in each location. Multiple lines of code may need to be inserted.
Correct implementation of the missing code will result in the fixing
all of the missing functionality listed above.
Student work:
- You must copy the
provided.client
and provided.engine
packages to your own client and engine packages.
- You are to fill in the missing parts of the
provided
code
and bring the copied code to full functionality, i.e. without any of the limitations
listed above.
- You are free to make any other changes to the client and engine code
as needed to implement your desired GUI and/or other functionality.
- The compute engine, tasks, local task adapters and remote
task adapters MUST conform to the interfaces defined in the
provided.compute
package. (Or your code will not work
with non-team people's code!)
- You are to create 3 new ITasks that can be
sent across the network from a client to a remote server to be executed.
- You will need to modify the given view client code (in your own
packages) to accommodate your new tasks.
- You are encouraged to create a better GUI and associated adapters to
create a more flexible and extensible task management system, e.g. more
along the lines of how BallWorld was done.
- You must be able to run both the client and the server on your and your
partner's machines:
- Connecting client to server on the same machine
- Connecting client to server on different machines (either way on
your and your partner's machines).
- You must test both your client and compute engine with at least 10
people (on 10 different computers) who are not your partner.
- You must create and save in your repository, run (launch) configurations
for both the client and the computer engine.
Note that the provided.compute
package contains all the interfaces that BOTH the client and the server need to
talk to each other. Do NOT copy or modify this package!
Testing
Testing RMI programs can be tricky. You can
easily be fooled into thinking that your code runs properly if you test
insufficiently. In particular, if both ends of your test contain all
the code, the remote dynamic class loading will not be tested. Here's a
more complete test:
- Create a separate project with the
unmodified provided code in it. Run
the demo code's compute engine and test your client
against it. The task should run but with the limitations
described above.
- Create a separate project that is another checkout of your own code.
Delete your custom tasks from this code and then run the compute engine
only. DO NOT EVER COMMIT THIS CODE! Test
the client from your main project against this engine. This will
test the remote dynamic class loading of your tasks as well as your
implementations of the missing
provided
code.
- Be sure to do the above test across different machines! This
will test all aspects of your code. Testing
against someone else's code is NOT the same as testing against your own
code! There are errors that will ONLY show up when
testing against a someone else's implementation!
Most Common Errors
- Firewall ports not open -- typically shows up a "connection
refused/timed out" error
- Run (launch) configurations not set properly -- working directory not
set, which typically shows up a security manager error on startup.
- Editing the provided code -- shows up as a commit error
- Transmitting the RMI server object instead of its stub. --
typically shows up a "(de)serialization" or "(un)marshalling" error.
Grading Guidelines
- The tasks must return a value whose type is NOT
BigDecimal. The tasks should return at least 2 different
types of results. - 30 pts
- The tasks' results should be displayed on the client and engine's
views. - 5 pts
- The task execution must display some sort of status message on the server when it
is run. That is, the task's
execute
method should
utilize the ILocalTaskViewAdapter
given to it by the
compute engine to display a status message. - 5 pts
- Stub properly created from
ClientModel.clientTVA
RMI server
instance. - 5 pts
ComputeEngine.remoteTaskViewAdpt
RMI
server instance properly implemented as per Javadocs in code. - 5 pts
- Stub properly created from
ComputeEngine.remoteTaskViewAdpt
RMI server instance.- 5 pts
- Upon intial connection, client view shows
verification of successful reception of engine's
IRemoteTaskViewAdapter
stub and successfully sends verfication
message to engine using that stub. - 5 pts
- Upon initial connection, compute engine's view shows verification of
successful reception of clients's
IRemoteTaskViewAdapter
stub
and successfully sends verfication message to client using that stub. - 5 pts
- Able to send string message from client's view to connected compute
engine's view. - 5 pts
- Able to send string message from compute engine's view to connected
client's view.- 5 pts
- The task should run properly when both the client and server are on the
same machine. - 5 pts
- The task should run properly when the client and server are on different
machines. Test this between your and your partner's machines! Your code
will be tested against a course staff machine. - 5 pts
- List, in your
Readme.txt
file, the NetID's of 10 people
(individuals, not groups) with whom you have successfully tested
both your client and computer engine (i.e. can
successfully send and process all tasks). You must test with that
person's personal computer, i.e. in the end, you must have tested against at
least 10 different computers. Different people in the same group do count
as separate individuals, except one's own partner(s) which are to be tested
as part of #12 above. - 10 pts
- Run configurations created and saved in repository for both client and
compute engine. - 5 pts
Note that the above requirements mean that you cannot change
anything in
provided.compute package!
© 2017 by Stephen Wong