Please get started on this right away. If you have any questions, ask them sooner rather than later.
This project is divided into two parts. In the first you will develop another application using the pipe and filter architecture of Project 4. Specifically, you will develop an online chicken sorting simulation. You are required to use our FilterImpl and FilterBufferImpl classes. They are provided below.
In the second part you will adapt your implementation to modify the application to use RMI so that filters can run on distributed nodes.
This application consists of three kinds of filters: Router, Station, and Bin. These filters must be attached in a specific hierarchy as detailed below. The data exchanged by these filters via buffers will be encoded chicken parts of the following form:
<begin chicken>type weight id<end chicken>
For example:
<begin chicken>thigh 86 T342<end chicken> <begin chicken>wing 24 W91<end chicken>
Note that although whitespace is required between the <begin chicken> and <end chicken> tags to separate the fields, no whitespace is required between the <end chicken> of one chicken part and the <begin chicken> of the next chicken part.
The table below lists the four types of chicken parts, along with a hypothetical approximate weight. These weights won't be used when implementing this project -- they're just there to give you a conceptual idea of the average size of each type relative to the other types.
| Type | Approx. Weight |
|---|---|
| breast | 150g |
| thigh | 85g |
| drum | 50g |
| wing | 25g |
Chicken parts are represented by a ChickenPart class. Most of this class has been implemented. You must implement the fromString() method. The fromString() method takes as input a string formatted as a tagged chicken part (see above) and returns a ChickenPart object representing the tagged chicken part string. If fromString() is called with an improperly formatted string, then a MalformedChickenPartException is thrown.
Chicken part types are represented by a ChickenPartType class. Again, a lot of this class has already been implemented. You must fill in the missing pieces. Your completed implementation should strictly follow the TypeSafe Enum pattern.
Here is a description of the three Compute (as defined in Project 4) classes you will write for this application:
By round robin fashion we mean that the first buffer (at index 0 in the array returned by getOutputBuffers()) gets the first chicken part. The second buffer (at index 1 in the array returned by getOutputBuffers()) gets the second chicken part and so on. If, for example, getOutputBuffers() returned only two buffers, then the scheme would wrap around and the third chicken part would go to the first output buffer.
Routers' output buffers are the input buffers of Stations.
The first output buffer (at index 0 in the array returned by getOutputBuffer()) is for wings only. The second buffer is for drumsticks only. The third and fourth buffers are mixed (they take all types of chicken parts.) A working Station always has exactly four output buffers. The goal of a Station is to distribute chicken parts among the four output buffers in the following way:
To simplify our grading your implementation should follow a specific order. There is an embedded round-robin rotation. For example, the first wing should go to the wings only (the first) output buffer. The second wing will go to the third output buffer. The third wing should go to the first output buffer and the fourth to the fourth buffer. Then the rotation should repeat. Drumstick distribution follows the same scheme as wings. When distributing thighs, the first thigh should go to the third output buffer. The second thigh should go to the fourth output buffer and then the rotation should repeat. Breast distribution follows the same scheme as thighs.
Stations' output buffers are the input buffers of Bins.
Packages have a preferred minimum weight and preferred maximum weight. Upon receiving a chicken part, the Bin adds the chicken part to the current package. (You should probably update other state based on the type and weight of the chicken part). If the total weight of all chicken parts in the current package is greater than the preferred minimum, ship the package (print the package contents to System.out). If the total weight of all chicken parts in the current package, plus the expected weight of the next chicken part, is greater than the preferred maximum, ship the package. Otherwise, don't ship the package yet. If the input buffer is closed and there are no remaining chicken parts to be processed, ship the package.
The expected weight of the next chicken part is the average weight of all chicken parts processed by the Bin so far.
Shipping a package involves printing the contents of the package to System.out in the following format:
[Bin ID] [Total weight of package] [IDs of all chicken parts in package]For example, the following output shows a shipped package from a bin with ID (Station 2) Mixed1, a total package weight of 335, and containing four chicken parts -- with IDs T48, D18, W35, and B111.
(Station 2) Mixed1 335 T48 D18 W35 B111
After a package is shipped, the Bin is now empty and processing continues (except if the input buffer was closed, in which case the Bin filter stops running.)
The constructor for Bin's Compute takes three arguments. The first argument is a String identifying the Bin, the second is an int representing the preferred minimum weight of the Bin's packages, and the third is the preferred maximum weight of the Bin's packages.
A sample driver program that instantiates Router, Station, and Bin Filters and connects them in a proper configuration is given in Chicken.java. This driver also requires the file ChickenData.java.
Part I of the project will only work if all objects are running on a single machine. In this part of the project, you will use RMI to remove this limitation.
To do this you will need to make several changes to your solution to Part I. These include:
FilterFactory.main()'s function is to initialize Filters and allow them to be connected to other Filters running on (other) machines. To do this it will generally perform the following steps (you should be able to tell what is already completed for you and what you must fill in yourself):
For each requested Filter:
Note: Depending on where and how many times FilterFactory is run, it is possible that the "remote" and "local" registries may be the same.
FilterFactory.main()'s command line arguments are given in the following form:
java -Dregport=portNum1 -Dfileport=portNum2 FilterFactory record1 record2 ... recordn
Record formats are described by the following grammar:
<record> := <router> | <station> | <bin>
<router> := Router InBufferName InBufferSize <output>
<station> := Station InBufferLocatorString <output>
<bin> := Bin BinName PrefMin PrefMax InBufferLocatorString <output>
<output> := OutputBufferName OutputBufferSize <output> |
OutputBufferName OutputBufferSize
Where,
We are providing an initial driver called RemoteChicken. RemoteChicken will look up the input buffer for the initial Router and then will write chicken parts to that buffer. RemoteChicken might be started up in the following way:
java RemoteChicken rmi://nauseous.csic.umd.edu:330XX/rtrInput
Here is a set of sample scripts for starting up the same example you saw in Part I. Please start the scripts in the order listed.
(on nauseous.csic.umd.edu) ./startRouter.sh 331XX 330XX (on bilious.csic.umd.edu) ./startStation.sh nauseous.csic.umd.edu:330XX 331XX 330XX (on churning.csic.umd.edu) ./startBin.sh bilious.csic.umd.edu:330XX 331XX 330XX (on squeamish.csic.umd.edu) ./startRemoteChicken.sh nauseous.csic.umd.edu:330XX
Please make sure to download our java.policy file. You must put it in the code directory. Filter and FilterImpl have also changed as a result of introducing the new RemoteFilterBuffer interface.
Fill in the missing parts of the ChickenPartType class before implementing the fromString() method in the ChickenPart class.
Bins never write to their output buffers.
In Part II, the old FilterBuffer interface has also changed. This was done so you can use Chicken.java to test your implementation after modifying your Router, Station, and Bin classes to work with RemoteFilterBuffer, but before proceeding to work on RemoteFilterBufferImpl and FilterFactory.
Use rmic to generate stubs.
After you have completed Part II, to test you implemented everything correctly, start the Chicken Sorting chain distributed across many nodes. Then, open another terminal, create an empty directory and copy the following classes and policy file to that directory:
BufTooSmallException ChickenData ChickenPart ChickenPartType java.policy MalformedChickenPartException RemoteChicken RemoteChickenInputThread RemoteFilterBufferYou should be able to succesfully run RemoteChicken with just these files. If you look at the terminal where you started Router (via FilterFactory), you should see that RemoteChicken downloaded stub files from Router's mini webserver.