Lab 4
NodeNet

Out September 22, due by midnight, Thursday, September 29

New code for the lab is available: SDNodeNet.jar. Be sure to note the changes below.

The old version of the lab is here.

Overview

This lab focuses on debugging and testing as well as their role in incremental development. You will spend much of your time in this lab exploring programs that do not always work, predicting where they will fail, and learning to design fixes and tests for these fixes. This lab also reinforces the idea of coding to an interface and extends the set of basic java constructs that you are using to include exceptions.

Before you start this lab, you should read the book chapter on exceptions (chapter 10). You will probably also want to review the parts of chapter 2 that deal with incremental development, debugging and testing. (Begin with the section on "Building the Program") You should of course also be familiar with the material that we have covered in preceding labs (chapters 1-8), especially with the sections on reading and implementing interfaces.

Although you will not be writing a great deal of code in this lab, you will be writing and testing the same code over and over. You will need to come to lab with a good development plan, including the various stages of development that you will build, the behavior that you expect to see at each stage of the plan, the tests that will verify that behavior, and the tests that you would expect that code to fail. This staged development and testing plan is a required part of your lab check-in.

For this assignment, you may discuss the code for the project in as much detail as you like with your classmates, but you should do the testing of networks in the prelab as well as the writeup on your own. You may also get comments from other students on all portions of your writeup before turning it in, if you wish. Please include the names of anyone with whom you collaborate, in any way, on this assignment, and indicate the nature of the collaboration. If you do not collaborate at all, please indicate this as well.

You will be turning in the fully documented final code that you write for this lab. This code must be your own. We do encourage you, however, to ask your classmates for help debugging during lab. Helping someone else to debug their code is a great way to improve your own programming skills.

This assignment emphasizes the following topics

You should read through this entire assignment and complete the Lab preparation section before you come to lab.

This assignment is due at midnight on Thursday, September 29, 2005. You should send electronic versions to sd-psets@lists.olin.edu and paper versions to Katie.


Contents

You should read through this entire assignment before you begin.


Preparing for the Lab

1. Experiment with the application.

This week's laboratory project involves a network routing simulation. In the simulation, routers (nodes) send and receive packets (pieces of information) to each other along various routes (channels). The nodes could be computers, for instance, sending and receiving information from each other across the internet. This problem set could be a scaled down (very scaled down) version of a commercially available product.

To use the code, download the SDNodeNet.jar file. You can run the program from a command prompt in the directory to which you downloaded nodenet.jar by typing

java -jar SDNodeNet.jar

To set up a NetBeans project, open NetBeans, select New Project from the File menu, click "Java Application" from the list, and hit the Next button. Name your project "nodenet" or something equally clever, and hit Finish.

Now right-click "Libraries", choose "Add JAR/Folder", and find the jar file you downloaded. Finally, you need to tell NetBeans the name of the main class, so right-click the project name, select "Properties" and "Run", and set the name of the main class to "nodenet.ui.Main" (without the quotes, for either version).

Go ahead and run the code now.

The idea of the simulation is to experiment with various network configurations and empirically determine their behaviors. In other words, play with the application and see what happens. When the GUI pops up, you will see three panels, side by side. The panel in the middle, which is currently empty, is where all of the simulations will take place. The panel on the left contains all of the available node behaviors. The panel on the right allows you to adjust the properties of the parts of the simulation. To use the simulator in its most basic way, you first construct a network and then set it in motion. The necessary steps are described below.

One of the main things you need in a simulator are nodes. In order to add a node to your simulator, select one of the behaviors from the panel on the right, then click on the middle drawing panel to place it somewhere. There are three types of nodes initially:

You can create a node by selecting its behavior and clicking in the middle panel. To remove an element, type delete, or hit the Delete button at the bottom of the screen.

Souces and sinks display the number of packets they have produced or consumed, respectively.

The other crucial element in the simulator is a channel. Channels run from one node to another, and are represented by a curved black line connecting the two nodes. In order to add a channel to your simulator, double click on the first node, then move your mouse to the second node and click again. You can also click the first node, type the letter 'C', and click on the second node.

Channels have directions: they go from the node you start with to the node you end with. Packets travel along the curve in a clockwise direction. It is possible to have two channels going in opposite directions between the same two nodes. It's even possible to have two channels go in the same direction between the same two nodes, although it would be hard to see. To remove a channel, click on it and then type the 'delete' key or hit the Delete button at the bottom of the screen.

To start objects moving through the demo, click the "Run" button at the bottom of the screen. You can pause the simulation using the "Pause" button, or allow everything to drain by clicking "Stop sources." To reset the simulation (reset all counters and remove any packets still in the system), hit the "Reset" button.

When you select a node or a channel, the panel on the right shows some settings you can manipulate. The most important one is for a channel. At the end of the list is a checkbox labeled "Enabled". By unchecking it, you can disable the channel, or re-enable it by clicking it again. You can also change the amount of time it takes a packet to pass through a channel, and the total number of packets the channel can hold at any one time.

For a node, you can change the rate it produces packets for a source, the rate it consumes packets for a sink, or the rate it transfers packets for an intermediate node.

Experiment with the network for a few minutes. Don't get too caught up yet... Can you get the channels to fill up? Can you create any other interesting behaviors? Remember that you can disable channels using the "Enabled" checkbox while the simulation is running.

You may want to keep a record of your experiments to compare your later results with. Your record should include both network topology (how things are connected) and dynamic behavior (what you did and what it did).

The IntermediateBehavior is a pretty well behaved intermediate node type. We have also provided two less functional types of connecting nodes: BadBehaviorA and BadBehaviorB. You can load these into the simulation by restarting it with an argument (or more) from the command line:

java -jar SDNodeNet.jar nodenet.model.BadBehaviorA nodenet.model.BadBehaviorB
You can also right-click on the project in NetBeans, choose "Properties" and "Run", then fill in the Arguments with "nodenet.model.BadBehaviorA nodenet.model.BadBehaviorB" (without the quotes).

Try this now. You should see the new node type in the left-hand panel. Although IntermediateBehavior is still there, you should probably ignore it for the remainder of your experimentation.

At this point, your job is to characterize BadBehaviorA, and once you are satisfied with your characterization, do the same for BadBehaviorB. First, you should see how the node type works under simple conditions. Use your notes to record how each node type behaves. Try different network conditions. Remember that you can add, disable, and remove Nodes and Channels (though you should only do so while the simulation is stopped). NB: You should be able to reset a particular configuration by saving it and then reloading it, but we do not promise that this feature will work under all conditions.

Your immediate goal is to find at least one configuration under which BadBehaviorA does something that seems inherently unreasonable to you. You should also find at least one such configuration for BadBehaviorB. Ideally, though, you should go beyond just finding a single configuration that "breaks" the node type. You should spend some time characterizing (and recording) how the node type responds to a variety of conditions to see whether you can figure out what types of mistaken assumptions or other errors it contains. Also try to predict how the node type will behave under certain conditions, then experiment to see whether you are right. Again, record these predictions as well as their outcomes. Do not spend a long time over the characterization task (total).

2. Familiarizing yourself with the code.

In the coding portion of this lab, you're going to create your own behavior for a Node. You will do this by creating a class that implements NodeBehavior. You will probably want to look at the code for the NodeBehavior interface now.

Your NodeBehavior class will not implement Runnable or Animate; instead it will be called by a Node, which has its own Animator and will call the NodeBehavior's method. The heart of Node's act method does nothing more than find the node's NodeBehavior implementation and call transmitPacket on it.

new parameter types
(were Vectors)
public void transmitPacket(InputChannelList inputs,
                           OutputChannelList outputs);

Since transmitPacket( ) will be called over and over again, you only have to handle one object at a time. You should read at most one object from one channel and write it out.

The transmitPacket method takes two arguments. The first argument is an InputChannelList, and the second argument is an OutputChannelList. Both InputChannelList and OutputChannelList are essentially Lists that have been tuned to take InputChannel and OutputChannel objects, respectively. That is, the two arguments to transmitPacket are Lists of the possible InputChannels and OutputChannels respectively. You can't get a packet out of an InputChannelList. Instead, you have to use the InputChannelLists's get(int index) method to get a single InputChannel, and then get the packet from the InputChannel.

Inside your transmitPacket method, then, you'll need to select a particular InputChannel from the InputChannelVector. Each InputChannel in the InputChannelList has the following method:

new method name
(was readObject)
public Object readPacket() throws ChannelEmptyException, 
                                    ChannelDisabledException;

You only need to read one packet from one input channel on each time around the interactive control loop. (The packets are of type java.lang.Object, and you shouldn't worry about what kind of Object it actually is.) Be careful, though: a given input channel may be empty or disabled, in which case it will throw an appropriate exception.

The second argument to transmitPacket( ) is an OutputChannelList. An active non-full output channel would be a good place to put any packet you may have picked up. As a corollary to InputChannel, OutputChannel has

new method name
(was writeObject)
public void writePacket( Object ) throws ChannelFullException,
                                         ChannelDisabledException;
But be careful: when an output channel is full, it will throw an exception if you try to write to it. Eventually, you'll have to make sure that you don't drop any packets if this happens, or write packets that don't exist.

3. Design your code.

The main piece of your coding will be to implement the transmitPacket( )method of NodeBehavior. This method should get an object from a single InputChannel from inputChannels (using readPacket()) and feed it to an OutputChannel in outputChannels (using writePacket()). Remember that you may have multiple InputChannels and OutputChannels, and that some of them may be disabled.

To begin with, you should write a piece of code that compiles. This will involve writing a class that implements the NodeBehavior interface and starting up your application with that class loaded. It is perfectly fine if you cannot move any packets on that initial load; compiling and running the application is always a good place to start.

You should develop a plan for how you will slowly build up good functionality. For each step, you should indicate what code you will write, what tests you will use to determine whether your code works, and at least one test on which you expect your code to fail. Then go on to the next step; what will you build next, how will you know whether it works, and what will it not be able to do? This sequence of construction and testing is your development plan. Your development plan should have at least four steps with associated tests (and may have many more) before you come to lab.

Ultimately, you will need to think about strategies for how you want to read packets from channels. There are obviously several ways that you can choose the input and output channels from their respective Lists. Think of at least two, and record these strategies. The more creative you can be, the more interesting your lab will be. You should design code for at least one of these strategies, and ideally for more than one. (It's OK, and even sometimes preferred, that you include at least one very simple strategy.)

One of the main points of this lab is to observe the effects of different strategies on the behavior of your network as a whole. Is your strategy fair? Does it drop packets? Create them? Do packets cluster in certain parts of your network? Can you come up with a strategy that behaves differently?

4. Helpful references.

The interfaces used in this lab are

You should be aware that both InputChannelList and OutputChannelList contain a method, size(), which returns the size of the List; additionally, both contain a method, isEmpty, which returns true if the List is empty.

The get(int index) method of InputChannelList and OutputChannelList gets the appropriate channel from the list with the given index. Remember that numbering begins with 0.

Channels occasionally throw exceptions. You need to be concerned about three of these:

Make sure that your code is robust to these exceptions, and does not lose objects.

Some utilities that you might want to use:

public static int cs101.util.MoreMath.randomInt( int range );
returns an int between 0 and range, inclusive. You can refer to it as MoreMath.randomInt if you include the line import cs101.util.*; at the top of your file.

public static void Thread.sleep( int millis )
     throws InterruptedException;
causes the current Thread to sleep for millis milliseconds. This allows you to put extra delays in your nodes. Warning: You will have to catch the exception, though you don't necessarily have to do anything with it.

If you have other ideas, design them and then ask us about them.

What to bring to lab

You will need a record of your experimentation with TypeAConnectingNode and TypeCConnectingNode, a development plan containing at least four steps with testing strategies, and two different channel selection strategies before you come to lab. You should also be able to sit down and write the simplest piece of code that you will test (i.e., what you need to get it to compile) when you first come to lab. This means that you will need to be able to answer the question marked with a Q, below.

Building your code.

Your job in lab is to implement one or more node behaviors, to test these behaviors on your own examples, and to exchange example networks with other students in the class. During lab, we will use the whiteboards to share any interesting topologies that you create. Test data development should be pooled, and sharing of test data is encouraged. Discussion of why networks behave as they do is strongly encouraged. Talk to the people next to you to get good ideas for test networks.

Begin the lab by implementing a node behavior. You will need to define a new class, say MyClass. What should you call the file it's defined in? What does it need to extend or implement? What methods does it have? (Remember that the interactive control loop is already defined for you, but it expects to be able to call your transmitPacket() method with two lists.

The first lines of your file, before your class definition, will need to say:

package nodenet;
Also, you should be sure that your class is public.

Once your code compiles, you should try running it. To run your code, you will need to supply the name of your node behavior class to nodenet. You can do this by supplying the fully-qualified name of your class just as you did with nodenet.TypeAConnectingNode, etc. Remember that the fully-qualified class name includes the package the class is in: nodenet.MyClass. (assuming that MyClass is the name of your class, and also that you've already compiled your class.)

You can now test your code using a the network(s) that you have designed for this purpose. Does it work as you expected? Does it break as you expected? Record your observations. When you have verified that your network works as you expected (or not, and you have understood why not), go on to the next step in your development plan.

Don't forget to tell the course staff about your networks, so that we can use them, too :)

Writing a class that compiles, runs, and attempts to forward packets is the target exercise for this lab. It need not forward packets perfectly, just make some progress on sane networks.

Post-Lab, AKA What To Turn In

Your completed assignment should include: